home *** CD-ROM | disk | FTP | other *** search
/ Geek Gadgets 1 / ADE-1.bin / ade-dist / inetutils-1.2-src.tgz / tar.out / fsf / inetutils / rlogin / rlogin.c < prev   
C/C++ Source or Header  |  1996-09-28  |  22KB  |  1,050 lines

  1. /*
  2.  * Copyright (c) 1983, 1990, 1993
  3.  *    The Regents of the University of California.  All rights reserved.
  4.  *
  5.  * Redistribution and use in source and binary forms, with or without
  6.  * modification, are permitted provided that the following conditions
  7.  * are met:
  8.  * 1. Redistributions of source code must retain the above copyright
  9.  *    notice, this list of conditions and the following disclaimer.
  10.  * 2. Redistributions in binary form must reproduce the above copyright
  11.  *    notice, this list of conditions and the following disclaimer in the
  12.  *    documentation and/or other materials provided with the distribution.
  13.  * 3. All advertising materials mentioning features or use of this software
  14.  *    must display the following acknowledgement:
  15.  *    This product includes software developed by the University of
  16.  *    California, Berkeley and its contributors.
  17.  * 4. Neither the name of the University nor the names of its contributors
  18.  *    may be used to endorse or promote products derived from this software
  19.  *    without specific prior written permission.
  20.  *
  21.  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
  22.  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  23.  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  24.  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
  25.  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  26.  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  27.  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  28.  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  29.  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  30.  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  31.  * SUCH DAMAGE.
  32.  */
  33.  
  34. #ifndef lint
  35. static char copyright[] =
  36. "@(#) Copyright (c) 1983, 1990, 1993\n\
  37.     The Regents of the University of California.  All rights reserved.\n";
  38. #endif /* not lint */
  39.  
  40. #ifndef lint
  41. static char sccsid[] = "@(#)rlogin.c    8.4 (Berkeley) 4/29/95";
  42. #endif /* not lint */
  43.  
  44. /*
  45.  * rlogin - remote login
  46.  */
  47.  
  48. #ifdef HAVE_CONFIG_H
  49. #include <config.h>
  50. #endif
  51.  
  52. #include <sys/param.h>
  53. #include <sys/socket.h>
  54. #include <sys/time.h>
  55. #include <sys/resource.h>
  56. #include <sys/wait.h>
  57. #include <sys/ioctl.h>
  58.  
  59. #include <netinet/in.h>
  60. #ifdef HAVE_NETINET_IN_SYSTM_H
  61. #include <netinet/in_systm.h>
  62. #endif
  63. #ifdef HAVE_NETINET_IP_H
  64. #include <netinet/ip.h>
  65. #endif
  66.  
  67. #include <errno.h>
  68. #include <fcntl.h>
  69. #include <netdb.h>
  70. #include <pwd.h>
  71. #include <setjmp.h>
  72. #include <termios.h>
  73. #include <signal.h>
  74. #include <stdio.h>
  75. #include <stdlib.h>
  76. #include <string.h>
  77. #include <unistd.h>
  78.  
  79. #ifdef __STDC__
  80. #include <stdarg.h>
  81. #else
  82. #include <varargs.h>
  83. #endif
  84.  
  85. #ifdef KERBEROS
  86. #include <kerberosIV/des.h>
  87. #include <kerberosIV/krb.h>
  88.  
  89. #include "krb.h"
  90.  
  91. CREDENTIALS cred;
  92. Key_schedule schedule;
  93. int use_kerberos = 1, doencrypt;
  94. char dst_realm_buf[REALM_SZ], *dest_realm = NULL;
  95. #endif
  96.  
  97. #ifndef TIOCPKT_WINDOW
  98. #define    TIOCPKT_WINDOW    0x80
  99. #endif
  100.  
  101. /* concession to Sun */
  102. #ifndef SIGUSR1
  103. #define    SIGUSR1    30
  104. #endif
  105.  
  106. int eight, litout, rem;
  107.  
  108. int noescape;
  109. u_char escapechar = '~';
  110.  
  111. #ifdef OLDSUN
  112. struct winsize {
  113.     unsigned short ws_row, ws_col;
  114.     unsigned short ws_xpixel, ws_ypixel;
  115. };
  116. #else
  117. #define    get_window_size(fd, wp)    ioctl(fd, TIOCGWINSZ, wp)
  118. #endif
  119. struct    winsize winsize;
  120.  
  121. void        catch_child __P((int));
  122. void        copytochild __P((int));
  123. void        doit __P((sigset_t *));
  124. void        done __P((int));
  125. void        echo __P((char));
  126. u_int        getescape __P((char *));
  127. void        lostpeer __P((int));
  128. void        mode __P((int));
  129. void        msg __P((char *));
  130. void        oob __P((int));
  131. int        reader __P((sigset_t *));
  132. void        sendwindow __P((void));
  133. void        setsignal __P((int));
  134. int        speed __P((int));
  135. void        sigwinch __P((int));
  136. void        stop __P((char));
  137. void        usage __P((void));
  138. void        writer __P((void));
  139. void        writeroob __P((int));
  140.  
  141. #ifdef    KERBEROS
  142. void        warning __P((const char *, ...));
  143. #endif
  144. #ifdef OLDSUN
  145. int        get_window_size __P((int, struct winsize *));
  146. #endif
  147.  
  148. int
  149. main(argc, argv)
  150.     int argc;
  151.     char *argv[];
  152. {
  153.     struct passwd *pw;
  154.     struct servent *sp;
  155.     sigset_t smask;
  156.     uid_t uid;
  157.     int argoff, ch, dflag, one;
  158.     char *host, *p, *user, term[1024];
  159. #ifdef HAVE_SIGACTION
  160.     struct sigaction sa;
  161. #else
  162. #ifdef HAVE_SIGVEC
  163.     struct sigvec sv;
  164. #endif
  165. #endif    
  166.  
  167. #ifndef HAVE___PROGNAME
  168.     extern char *__progname;
  169.     __progname = argv[0];
  170. #endif
  171.  
  172.     argoff = dflag = 0;
  173.     one = 1;
  174.     host = user = NULL;
  175.  
  176.     if (p = strrchr(argv[0], '/'))
  177.         ++p;
  178.     else
  179.         p = argv[0];
  180.  
  181.     if (strcmp(p, "rlogin") != 0)
  182.         host = p;
  183.  
  184.     /* handle "rlogin host flags" */
  185.     if (!host && argc > 2 && argv[1][0] != '-') {
  186.         host = argv[1];
  187.         argoff = 1;
  188.     }
  189.  
  190. #ifdef KERBEROS
  191. #define    OPTIONS    "8EKLde:k:l:x"
  192. #else
  193. #define    OPTIONS    "8EKLde:l:"
  194. #endif
  195.     while ((ch = getopt(argc - argoff, argv + argoff, OPTIONS)) != EOF)
  196.         switch(ch) {
  197.         case '8':
  198.             eight = 1;
  199.             break;
  200.         case 'E':
  201.             noescape = 1;
  202.             break;
  203.         case 'K':
  204. #ifdef KERBEROS
  205.             use_kerberos = 0;
  206. #endif
  207.             break;
  208.         case 'L':
  209.             litout = 1;
  210.             break;
  211.         case 'd':
  212.             dflag = 1;
  213.             break;
  214.         case 'e':
  215.             noescape = 0;
  216.             escapechar = getescape(optarg);
  217.             break;
  218. #ifdef KERBEROS
  219.         case 'k':
  220.             dest_realm = dst_realm_buf;
  221.             (void)strncpy(dest_realm, optarg, REALM_SZ);
  222.             break;
  223. #endif
  224.         case 'l':
  225.             user = optarg;
  226.             break;
  227. #ifdef CRYPT
  228. #ifdef KERBEROS
  229.         case 'x':
  230.             doencrypt = 1;
  231.             des_set_key(cred.session, schedule);
  232.             break;
  233. #endif
  234. #endif
  235.         case '?':
  236.         default:
  237.             usage();
  238.         }
  239.     optind += argoff;
  240.     argc -= optind;
  241.     argv += optind;
  242.  
  243.     /* if haven't gotten a host yet, do so */
  244.     if (!host && !(host = *argv++))
  245.         usage();
  246.  
  247.     if (*argv)
  248.         usage();
  249.  
  250.     if (!(pw = getpwuid(uid = getuid())))
  251.         errx(1, "unknown user id.");
  252.     /* Accept user1@host format, though "-l user2" overrides user1 */
  253.     p = strchr(host, '@');
  254.     if (p) {
  255.         *p = '\0';
  256.         if (!user && p > host)
  257.             user = host;
  258.         host = p + 1;
  259.         if (*host == '\0')
  260.             usage();
  261.     }
  262.     if (!user)
  263.         user = pw->pw_name;
  264.  
  265.     sp = NULL;
  266. #ifdef KERBEROS
  267.     if (use_kerberos) {
  268.         sp = getservbyname((doencrypt ? "eklogin" : "klogin"), "tcp");
  269.         if (sp == NULL) {
  270.             use_kerberos = 0;
  271.             warning("can't get entry for %s/tcp service",
  272.                 doencrypt ? "eklogin" : "klogin");
  273.         }
  274.     }
  275. #endif
  276.     if (sp == NULL)
  277.         sp = getservbyname("login", "tcp");
  278.     if (sp == NULL)
  279.         errx(1, "login/tcp: unknown service.");
  280.  
  281.     (void)snprintf(term, sizeof(term), "%s/%d",
  282.             ((p = getenv("TERM")) ? p : "network"),
  283.             speed(0));
  284.  
  285.     (void)get_window_size(0, &winsize);
  286.  
  287. #ifdef HAVE_SIGACTION
  288.     sigemptyset (&sa.sa_mask);
  289. #ifdef SA_RESTART
  290.     sa.sa_flags = SA_RESTART;
  291. #endif
  292.     sa.sa_handler = lostpeer;
  293.     sigaction (SIGPIPE, &sa, (struct sigaction *) 0);
  294.     /* will use SIGUSR1 for window size hack, so hold it off */
  295.     sigemptyset (&smask);
  296.     sigaddset (&smask, SIGURG);
  297.     sigaddset (&smask, SIGUSR1);
  298.     sigprocmask (SIG_SETMASK, &smask, &smask);
  299.     /*
  300.      * We set SIGURG and SIGUSR1 below so that an
  301.      * incoming signal will be held pending rather than being
  302.      * discarded. Note that these routines will be ready to get
  303.      * a signal by the time that they are unblocked below.
  304.      */
  305.     sa.sa_handler = copytochild;
  306.     sigaction (SIGURG, &sa, (struct sigaction *) 0);
  307.     sa.sa_handler = writeroob;
  308.     sigaction (SIGUSR1, &sa, (struct sigaction *) 0);
  309. #else /* !HAVE_SIGACTION */
  310. #ifdef HAVE_SIGVEC
  311.     sigemptyset (&sv.sv_mask);
  312.     sv.sv_handler = lostpeer;
  313.     sigvec (SIGPIPE, &sv, (struct sigvec *) 0);
  314.     /* will use SIGUSR1 for window size hack, so hold it off */
  315.     sigemptyset (&smask);
  316.     sigaddset (&smask, SIGURG);
  317.     sigaddset (&smask, SIGUSR1);
  318.     sigsetmask (smask);
  319.     /*
  320.      * We set SIGURG and SIGUSR1 below so that an
  321.      * incoming signal will be held pending rather than being
  322.      * discarded. Note that these routines will be ready to get
  323.      * a signal by the time that they are unblocked below.
  324.      */
  325.     sv.sv_handler = copytochild;
  326.     sigvec (SIGURG, &sv, (struct sigvec *) 0);
  327.     sv.sv_handler = writeroob;
  328.     sigvec (SIGUSR1, &sv, (struct sigvec *) 0);
  329. #else /* !HAVE_SIGVEC */
  330.     signal (SIGPIPE, lostpeer);
  331.     signal (SIGURG, copytochild);
  332.     signal (SIGUSR1, writeroob);
  333. #endif /* HAVE_SIGVEC */
  334. #endif /* HAVE_SIGACTION */
  335.  
  336. #ifdef KERBEROS
  337. try_connect:
  338.     if (use_kerberos) {
  339.         struct hostent *hp;
  340.  
  341.         /* Fully qualify hostname (needed for krb_realmofhost). */
  342.         hp = gethostbyname(host);
  343.         if (hp != NULL && !(host = strdup(hp->h_name)))
  344.             errx(1, "%s", strerror(ENOMEM));
  345.  
  346.         rem = KSUCCESS;
  347.         errno = 0;
  348.         if (dest_realm == NULL)
  349.             dest_realm = krb_realmofhost(host);
  350.  
  351. #ifdef CRYPT
  352.         if (doencrypt)
  353.             rem = krcmd_mutual(&host, sp->s_port, user, term, 0,
  354.                 dest_realm, &cred, schedule);
  355.         else
  356. #endif /* CRYPT */
  357.             rem = krcmd(&host, sp->s_port, user, term, 0,
  358.                 dest_realm);
  359.         if (rem < 0) {
  360.             use_kerberos = 0;
  361.             sp = getservbyname("login", "tcp");
  362.             if (sp == NULL)
  363.                 errx(1, "unknown service login/tcp.");
  364.             if (errno == ECONNREFUSED)
  365.                 warning("remote host doesn't support Kerberos");
  366.             if (errno == ENOENT)
  367.                 warning("can't provide Kerberos auth data");
  368.             goto try_connect;
  369.         }
  370.     } else {
  371. #ifdef CRYPT
  372.         if (doencrypt)
  373.             errx(1, "the -x flag requires Kerberos authentication.");
  374. #endif /* CRYPT */
  375.         rem = rcmd(&host, sp->s_port, pw->pw_name, user, term, 0);
  376.     }
  377. #else
  378.     rem = rcmd(&host, sp->s_port, pw->pw_name, user, term, 0);
  379. #endif /* KERBEROS */
  380.  
  381.     if (rem < 0)
  382.         exit(1);
  383.  
  384.     if (dflag &&
  385.         setsockopt(rem, SOL_SOCKET, SO_DEBUG, &one, sizeof(one)) < 0)
  386.          warn("setsockopt DEBUG (ignored)");
  387.  
  388. #if defined (IP_TOS) && defined (IPPROTO_IP) && defined (IPTOS_LOWDELAY)
  389.     one = IPTOS_LOWDELAY;
  390.     if (setsockopt(rem, IPPROTO_IP, IP_TOS, (char *)&one, sizeof(int)) < 0)
  391.          warn("setsockopt TOS (ignored)");
  392. #endif
  393.  
  394.     (void)setuid(uid);
  395.     doit(&smask);
  396.     /*NOTREACHED*/
  397. }
  398.  
  399. #if BSD >= 198810
  400. int
  401. speed(fd)
  402.     int fd;
  403. {
  404.     struct termios tt;
  405.  
  406.     (void)tcgetattr(fd, &tt);
  407.  
  408.     return ((int) cfgetispeed(&tt));
  409. }
  410. #else
  411. int    speeds[] = {    /* for older systems, B0 .. EXTB */
  412.     0, 50, 75, 110,
  413.     134, 150, 200, 300,
  414.     600, 1200, 1800, 2400,
  415.     4800, 9600, 19200, 38400
  416. };
  417.  
  418. int
  419. speed(fd)
  420.     int fd;
  421. {
  422.     struct termios tt;
  423.  
  424.     (void)tcgetattr(fd, &tt);
  425.  
  426.     return (speeds[(int)cfgetispeed(&tt)]);
  427. }
  428. #endif
  429.  
  430. pid_t child;
  431. struct termios deftt;
  432. struct termios nott;
  433.  
  434. void
  435. doit(smask)
  436.     sigset_t *smask;
  437. {
  438.     int i;
  439.     struct sigaction sa;
  440.  
  441.     for (i = 0; i < NCCS; i++)
  442.         nott.c_cc[i] = _POSIX_VDISABLE;
  443.     tcgetattr(0, &deftt);
  444.     nott.c_cc[VSTART] = deftt.c_cc[VSTART];
  445.     nott.c_cc[VSTOP] = deftt.c_cc[VSTOP];
  446.     sigemptyset(&sa.sa_mask);
  447.     sa.sa_flags = SA_RESTART;
  448.     sa.sa_handler = SIG_IGN;
  449.     (void)sigaction(SIGINT, &sa, (struct sigaction *) 0);
  450.     setsignal(SIGHUP);
  451.     setsignal(SIGQUIT);
  452.     child = fork();
  453.     if (child == -1) {
  454.          warn("fork");
  455.         done(1);
  456.     }
  457.     if (child == 0) {
  458.         mode(1);
  459.         if (reader(smask) == 0) {
  460.             msg("connection closed.");
  461.             exit(0);
  462.         }
  463.         sleep(1);
  464.         msg("\007connection closed.");
  465.         exit(1);
  466.     }
  467.  
  468.     /*
  469.      * We may still own the socket, and may have a pending SIGURG (or might
  470.      * receive one soon) that we really want to send to the reader.  When
  471.      * one of these comes in, the trap copytochild simply copies such
  472.      * signals to the child. We can now unblock SIGURG and SIGUSR1
  473.      * that were set above.
  474.      */
  475.     (void)sigprocmask(SIG_SETMASK, smask, (sigset_t *) 0);
  476.     sa.sa_handler = catch_child;
  477.     (void)sigaction(SIGCHLD, &sa, (struct sigaction *) 0);
  478.     writer();
  479.     msg("closed connection.");
  480.     done(0);
  481. }
  482.  
  483. /* trap a signal, unless it is being ignored. */
  484. void
  485. setsignal(sig)
  486.     int sig;
  487. {
  488.     struct sigaction sa;
  489.     sigset_t sigs;
  490.  
  491.     sigemptyset(&sigs);
  492.     sigaddset(&sigs, sig);
  493.     sigprocmask(SIG_BLOCK, &sigs, &sigs);
  494.  
  495.     sigemptyset(&sa.sa_mask);
  496.     sa.sa_handler = exit;
  497.     sa.sa_flags = SA_RESTART;
  498.     (void)sigaction(sig, &sa, &sa);
  499.     if (sa.sa_handler == SIG_IGN)
  500.         (void)sigaction(sig, &sa, (struct sigaction *) 0);
  501.  
  502.     (void)sigprocmask(SIG_SETMASK, &sigs, (sigset_t *) 0);
  503. }
  504.  
  505. void
  506. done(status)
  507.     int status;
  508. {
  509.     pid_t w;
  510.     int wstatus;
  511.     struct sigaction sa;
  512.  
  513.     mode(0);
  514.     if (child > 0) {
  515.         /* make sure catch_child does not snap it up */
  516.         sigemptyset(&sa.sa_mask);
  517.         sa.sa_handler = SIG_DFL;
  518.         sa.sa_flags = 0;
  519.         (void)sigaction(SIGCHLD, &sa, (struct sigaction *) 0);
  520.         if (kill(child, SIGKILL) >= 0)
  521.             while ((w = wait(&wstatus)) > 0 && w != child)
  522.                 continue;
  523.     }
  524.     exit(status);
  525. }
  526.  
  527. int dosigwinch;
  528.  
  529. /*
  530.  * This is called when the reader process gets the out-of-band (urgent)
  531.  * request to turn on the window-changing protocol.
  532.  */
  533. void
  534. writeroob(signo)
  535.     int signo;
  536. {
  537.     struct sigaction sa;
  538.  
  539.     if (dosigwinch == 0) {
  540.         sendwindow();
  541.         sigemptyset(&sa.sa_mask);
  542.         sa.sa_handler = sigwinch;
  543.         sa.sa_flags = SA_RESTART;
  544.         (void)sigaction(SIGWINCH, &sa, (struct sigaction *) 0);
  545.     }
  546.     dosigwinch = 1;
  547. }
  548.  
  549. void
  550. catch_child(signo)
  551.     int signo;
  552. {
  553.     int status;
  554.     pid_t pid;
  555.  
  556.     for (;;) {
  557.         pid = waitpid(-1, &status, WNOHANG|WUNTRACED);
  558.         if (pid == 0)
  559.             return;
  560.         /* if the child (reader) dies, just quit */
  561.         if (pid < 0 || (pid == child && !WIFSTOPPED(status)))
  562.             done(WEXITSTATUS(status) | WTERMSIG(status));
  563.     }
  564.     /* NOTREACHED */
  565. }
  566.  
  567. /*
  568.  * writer: write to remote: 0 -> line.
  569.  * ~.                terminate
  570.  * ~^Z                suspend rlogin process.
  571.  * ~<delayed-suspend char>    suspend rlogin process, but leave reader alone.
  572.  */
  573. void
  574. writer()
  575. {
  576.     register int bol, local, n;
  577.     char c;
  578.  
  579.     bol = 1;            /* beginning of line */
  580.     local = 0;
  581.     for (;;) {
  582.         n = read(STDIN_FILENO, &c, 1);
  583.         if (n <= 0) {
  584.             if (n < 0 && errno == EINTR)
  585.                 continue;
  586.             break;
  587.         }
  588.         /*
  589.          * If we're at the beginning of the line and recognize a
  590.          * command character, then we echo locally.  Otherwise,
  591.          * characters are echo'd remotely.  If the command character
  592.          * is doubled, this acts as a force and local echo is
  593.          * suppressed.
  594.          */
  595.         if (bol) {
  596.             bol = 0;
  597.             if (!noescape && c == escapechar) {
  598.                 local = 1;
  599.                 continue;
  600.             }
  601.         } else if (local) {
  602.             local = 0;
  603.             if (c == '.' || c == deftt.c_cc[VEOF]) {
  604.                 echo(c);
  605.                 break;
  606.             }
  607.             if (c == deftt.c_cc[VSUSP]
  608. #ifdef VDSUSP
  609.                 || c == deftt.c_cc[VDSUSP]
  610. #endif
  611.                 ) {
  612.                 bol = 1;
  613.                 echo(c);
  614.                 stop(c);
  615.                 continue;
  616.             }
  617.             if (c != escapechar)
  618. #ifdef CRYPT
  619. #ifdef KERBEROS
  620.                 if (doencrypt)
  621.                     (void)des_write(rem,
  622.                         (char *)&escapechar, 1);
  623.                 else
  624. #endif
  625. #endif
  626.                     (void)write(rem, &escapechar, 1);
  627.         }
  628.  
  629. #ifdef CRYPT
  630. #ifdef KERBEROS
  631.         if (doencrypt) {
  632.             if (des_write(rem, &c, 1) == 0) {
  633.                 msg("line gone");
  634.                 break;
  635.             }
  636.         } else
  637. #endif
  638. #endif
  639.             if (write(rem, &c, 1) == 0) {
  640.                 msg("line gone");
  641.                 break;
  642.             }
  643.         bol = c == deftt.c_cc[VKILL] || c == deftt.c_cc[VEOF] ||
  644.             c == deftt.c_cc[VINTR] || c == deftt.c_cc[VSUSP] ||
  645.             c == '\r' || c == '\n';
  646.     }
  647. }
  648.  
  649. void
  650. #if __STDC__
  651. echo(register char c)
  652. #else
  653. echo(c)
  654.     register char c;
  655. #endif
  656. {
  657.     register char *p;
  658.     char buf[8];
  659.  
  660.     p = buf;
  661.     c &= 0177;
  662.     *p++ = escapechar;
  663.     if (c < ' ') {
  664.         *p++ = '^';
  665.         *p++ = c + '@';
  666.     } else if (c == 0177) {
  667.         *p++ = '^';
  668.         *p++ = '?';
  669.     } else
  670.         *p++ = c;
  671.     *p++ = '\r';
  672.     *p++ = '\n';
  673.     (void)write(STDOUT_FILENO, buf, p - buf);
  674. }
  675.  
  676. void
  677. #if __STDC__
  678. stop(char cmdc)
  679. #else
  680. stop(cmdc)
  681.     char cmdc;
  682. #endif
  683. {
  684.     struct sigaction sa;
  685.  
  686.     mode(0);
  687.     sigemptyset(&sa.sa_mask);
  688.     sa.sa_handler = SIG_IGN;
  689.     sa.sa_flags = SA_RESTART;
  690.     (void)sigaction(SIGCHLD, &sa, (struct sigaction *) 0);
  691.     (void)kill(cmdc == deftt.c_cc[VSUSP] ? 0 : getpid(), SIGTSTP);
  692.     sa.sa_handler = catch_child;
  693.     (void)sigaction(SIGCHLD, &sa, (struct sigaction *) 0);
  694.     mode(1);
  695.     sigwinch(0);            /* check for size changes */
  696. }
  697.  
  698. void
  699. sigwinch(signo)
  700.     int signo;
  701. {
  702.     struct winsize ws;
  703.  
  704.     if (dosigwinch && get_window_size(0, &ws) == 0 &&
  705.         memcmp(&ws, &winsize, sizeof(ws))) {
  706.         winsize = ws;
  707.         sendwindow();
  708.     }
  709. }
  710.  
  711. /*
  712.  * Send the window size to the server via the magic escape
  713.  */
  714. void
  715. sendwindow()
  716. {
  717.     struct winsize *wp;
  718.     char obuf[4 + sizeof (struct winsize)];
  719.  
  720.     wp = (struct winsize *)(obuf+4);
  721.     obuf[0] = 0377;
  722.     obuf[1] = 0377;
  723.     obuf[2] = 's';
  724.     obuf[3] = 's';
  725.     wp->ws_row = htons(winsize.ws_row);
  726.     wp->ws_col = htons(winsize.ws_col);
  727.     wp->ws_xpixel = htons(winsize.ws_xpixel);
  728.     wp->ws_ypixel = htons(winsize.ws_ypixel);
  729.  
  730. #ifdef CRYPT
  731. #ifdef KERBEROS
  732.     if(doencrypt)
  733.         (void)des_write(rem, obuf, sizeof(obuf));
  734.     else
  735. #endif
  736. #endif
  737.         (void)write(rem, obuf, sizeof(obuf));
  738. }
  739.  
  740. /*
  741.  * reader: read from remote: line -> 1
  742.  */
  743. #define    READING    1
  744. #define    WRITING    2
  745.  
  746. jmp_buf rcvtop;
  747. pid_t ppid;
  748. int rcvcnt, rcvstate;
  749. char rcvbuf[8 * 1024];
  750.  
  751. void
  752. oob(signo)
  753.     int signo;
  754. {
  755.     struct termios tt;
  756.     int atmark, n, out, rcvd;
  757.     char waste[BUFSIZ], mark;
  758.  
  759.     out = O_RDWR;
  760.     rcvd = 0;
  761.     while (recv(rem, &mark, 1, MSG_OOB) < 0) {
  762.         switch (errno) {
  763.         case EWOULDBLOCK:
  764.             /*
  765.              * Urgent data not here yet.  It may not be possible
  766.              * to send it yet if we are blocked for output and
  767.              * our input buffer is full.
  768.              */
  769.             if (rcvcnt < sizeof(rcvbuf)) {
  770.                 n = read(rem, rcvbuf + rcvcnt,
  771.                     sizeof(rcvbuf) - rcvcnt);
  772.                 if (n <= 0)
  773.                     return;
  774.                 rcvd += n;
  775.             } else {
  776.                 n = read(rem, waste, sizeof(waste));
  777.                 if (n <= 0)
  778.                     return;
  779.             }
  780.             continue;
  781.         default:
  782.             return;
  783.         }
  784.     }
  785.     if (mark & TIOCPKT_WINDOW) {
  786.         /* Let server know about window size changes */
  787.         (void)kill(ppid, SIGUSR1);
  788.     }
  789.     if (!eight && (mark & TIOCPKT_NOSTOP)) {
  790.         tcgetattr(0, &tt);
  791.         tt.c_iflag &= ~(IXON | IXOFF);
  792.         tt.c_cc[VSTOP] = _POSIX_VDISABLE;
  793.         tt.c_cc[VSTART] = _POSIX_VDISABLE;
  794.         tcsetattr(0, TCSANOW, &tt);
  795.     }
  796.     if (!eight && (mark & TIOCPKT_DOSTOP)) {
  797.         tcgetattr(0, &tt);
  798.         tt.c_iflag |= (IXON|IXOFF);
  799.         tt.c_cc[VSTOP] = deftt.c_cc[VSTOP];
  800.         tt.c_cc[VSTART] = deftt.c_cc[VSTART];
  801.         tcsetattr(0, TCSANOW, &tt);
  802.     }
  803.     if (mark & TIOCPKT_FLUSHWRITE) {
  804. #ifdef TIOCFLUSH
  805.         (void)ioctl(1, TIOCFLUSH, (char *)&out);
  806. #endif
  807.         for (;;) {
  808.             if (ioctl(rem, SIOCATMARK, &atmark) < 0) {
  809.                 warn("ioctl SIOCATMARK (ignored)");
  810.                 break;
  811.             }
  812.             if (atmark)
  813.                 break;
  814.             n = read(rem, waste, sizeof (waste));
  815.             if (n <= 0)
  816.                 break;
  817.         }
  818.         /*
  819.          * Don't want any pending data to be output, so clear the recv
  820.          * buffer.  If we were hanging on a write when interrupted,
  821.          * don't want it to restart.  If we were reading, restart
  822.          * anyway.
  823.          */
  824.         rcvcnt = 0;
  825.         longjmp(rcvtop, 1);
  826.     }
  827.  
  828.     /* oob does not do FLUSHREAD (alas!) */
  829.  
  830.     /*
  831.      * If we filled the receive buffer while a read was pending, longjmp
  832.      * to the top to restart appropriately.  Don't abort a pending write,
  833.      * however, or we won't know how much was written.
  834.      */
  835.     if (rcvd && rcvstate == READING)
  836.         longjmp(rcvtop, 1);
  837. }
  838.  
  839. /* reader: read from remote: line -> 1 */
  840. int
  841. reader(smask)
  842.     sigset_t *smask;
  843. {
  844.     pid_t pid;
  845.     int n, remaining;
  846.     char *bufp;
  847.     struct sigaction sa;
  848.  
  849. #if BSD >= 43 || defined(SUNOS4)
  850.     pid = getpid();        /* modern systems use positives for pid */
  851. #else
  852.     pid = -getpid();    /* old broken systems use negatives */
  853. #endif
  854.     sigemptyset(&sa.sa_mask);
  855.     sa.sa_flags = SA_RESTART;
  856.     sa.sa_handler = SIG_IGN;
  857.     (void)sigaction(SIGTTOU, &sa, (struct sigaction *) 0);
  858.     sa.sa_handler = oob;
  859.     (void)sigaction(SIGURG, &sa, (struct sigaction *) 0);
  860.     ppid = getppid();
  861.     (void)fcntl(rem, F_SETOWN, pid);
  862.     (void)setjmp(rcvtop);
  863.     (void)sigprocmask(SIG_SETMASK, smask, (sigset_t *) 0);
  864.     bufp = rcvbuf;
  865.     for (;;) {
  866.         while ((remaining = rcvcnt - (bufp - rcvbuf)) > 0) {
  867.             rcvstate = WRITING;
  868.             n = write(STDOUT_FILENO, bufp, remaining);
  869.             if (n < 0) {
  870.                 if (errno != EINTR)
  871.                     return (-1);
  872.                 continue;
  873.             }
  874.             bufp += n;
  875.         }
  876.         bufp = rcvbuf;
  877.         rcvcnt = 0;
  878.         rcvstate = READING;
  879.  
  880. #ifdef CRYPT
  881. #ifdef KERBEROS
  882.         if (doencrypt)
  883.             rcvcnt = des_read(rem, rcvbuf, sizeof(rcvbuf));
  884.         else
  885. #endif
  886. #endif
  887.             rcvcnt = read(rem, rcvbuf, sizeof (rcvbuf));
  888.         if (rcvcnt == 0)
  889.             return (0);
  890.         if (rcvcnt < 0) {
  891.             if (errno == EINTR)
  892.                 continue;
  893.             warn("read");
  894.             return (-1);
  895.         }
  896.     }
  897. }
  898.  
  899. void
  900. mode(f)
  901.     int f;
  902. {
  903.     struct termios tt;
  904.  
  905.     switch (f) {
  906.     case 0:
  907.         tcsetattr(0, TCSADRAIN, &deftt);
  908.         break;
  909.     case 1:
  910.         tt = deftt;
  911.         tt.c_oflag &= ~(OPOST);
  912.         tt.c_lflag &= ~(ECHO | ICANON | IEXTEN | ISIG);
  913.         tt.c_iflag &= ~(ICRNL);
  914.         tt.c_cc[VMIN] = 1;
  915.         tt.c_cc[VTIME] = 0;
  916.         if (eight) {
  917.             tt.c_iflag &= ~(IXON | IXOFF | ISTRIP);
  918.             tt.c_cc[VSTOP] = _POSIX_VDISABLE;
  919.             tt.c_cc[VSTART] = _POSIX_VDISABLE;
  920.         }
  921.         /*if (litout)
  922.             lflags |= LLITOUT;*/
  923.         tcsetattr(0, TCSADRAIN, &tt);
  924.         break;
  925.  
  926.     default:
  927.         return;
  928.     }
  929. }
  930.  
  931. void
  932. lostpeer(signo)
  933.     int signo;
  934. {
  935.     struct sigaction sa;
  936.  
  937.     sigemptyset(&sa.sa_mask);
  938.     sa.sa_flags = SA_RESTART;
  939.     sa.sa_handler = SIG_IGN;
  940.     (void)sigaction(SIGPIPE, &sa, (struct sigaction *) 0);
  941.     msg("\007connection closed.");
  942.     done(1);
  943. }
  944.  
  945. /* copy SIGURGs to the child process. */
  946. void
  947. copytochild(signo)
  948.     int signo;
  949. {
  950.  
  951.     (void)kill(child, SIGURG);
  952. }
  953.  
  954. void
  955. msg(str)
  956.     char *str;
  957. {
  958.  
  959.     (void)fprintf(stderr, "rlogin: %s\r\n", str);
  960. }
  961.  
  962. #ifdef KERBEROS
  963. /* VARARGS */
  964. void
  965. #if __STDC__
  966. warning(const char *fmt, ...)
  967. #else
  968. warning(fmt, va_alist)
  969.     char *fmt;
  970.     va_dcl
  971. #endif
  972. {
  973.     va_list ap;
  974.  
  975.     (void)fprintf(stderr, "rlogin: warning, using standard rlogin: ");
  976. #ifdef __STDC__
  977.     va_start(ap, fmt);
  978. #else
  979.     va_start(ap);
  980. #endif
  981.     vfprintf(stderr, fmt, ap);
  982.     va_end(ap);
  983.     (void)fprintf(stderr, ".\n");
  984. }
  985. #endif
  986.  
  987. void
  988. usage()
  989. {
  990.     (void)fprintf(stderr,
  991.         "usage: rlogin [ -%s]%s[-e char] [ -l username ] [username@]host\n",
  992. #ifdef KERBEROS
  993. #ifdef CRYPT
  994.         "8EKLx", " [-k realm] ");
  995. #else
  996.         "8EKL", " [-k realm] ");
  997. #endif
  998. #else
  999.         "8EL", " ");
  1000. #endif
  1001.     exit(1);
  1002. }
  1003.  
  1004. /*
  1005.  * The following routine provides compatibility (such as it is) between older
  1006.  * Suns and others.  Suns have only a `ttysize', so we convert it to a winsize.
  1007.  */
  1008. #ifdef OLDSUN
  1009. int
  1010. get_window_size(fd, wp)
  1011.     int fd;
  1012.     struct winsize *wp;
  1013. {
  1014.     struct ttysize ts;
  1015.     int error;
  1016.  
  1017.     if ((error = ioctl(0, TIOCGSIZE, &ts)) != 0)
  1018.         return (error);
  1019.     wp->ws_row = ts.ts_lines;
  1020.     wp->ws_col = ts.ts_cols;
  1021.     wp->ws_xpixel = 0;
  1022.     wp->ws_ypixel = 0;
  1023.     return (0);
  1024. }
  1025. #endif
  1026.  
  1027. u_int
  1028. getescape(p)
  1029.     register char *p;
  1030. {
  1031.     long val;
  1032.     int len;
  1033.  
  1034.     if ((len = strlen(p)) == 1)    /* use any single char, including '\' */
  1035.         return ((u_int)*p);
  1036.                     /* otherwise, \nnn */
  1037.     if (*p == '\\' && len >= 2 && len <= 4) {
  1038.         val = strtol(++p, NULL, 8);
  1039.         for (;;) {
  1040.             if (!*++p)
  1041.                 return ((u_int)val);
  1042.             if (*p < '0' || *p > '8')
  1043.                 break;
  1044.         }
  1045.     }
  1046.     msg("illegal option value -- e");
  1047.     usage();
  1048.     /* NOTREACHED */
  1049. }
  1050.