1 /*
2     rlogin.c - remote login client
3     Copyright (C) 2003  Guus Sliepen <guus@sliepen.eu.org>
4 
5     This program is free software; you can redistribute it and/or modify
6     it under the terms of the GNU General Public License version 2 as published
7 	by the Free Software Foundation.
8 
9     This program is distributed in the hope that it will be useful,
10     but WITHOUT ANY WARRANTY; without even the implied warranty of
11     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12     GNU General Public License for more details.
13 
14     You should have received a copy of the GNU General Public License
15     along with this program; if not, write to the Free Software
16     Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
17 */
18 
19 #include <stdio.h>
20 #include <stdlib.h>
21 #include <stdint.h>
22 #include <stdbool.h>
23 #include <unistd.h>
24 #include <pwd.h>
25 #include <sys/types.h>
26 #include <sys/socket.h>
27 #include <sys/poll.h>
28 #include <netdb.h>
29 #include <string.h>
30 #include <errno.h>
31 #include <termios.h>
32 #include <signal.h>
33 #include <sys/ioctl.h>
34 #include <fcntl.h>
35 
36 #ifdef SHISHI
37 
38 #include <shishi.h>
39 
40 #define SERVICE "host"
41 #define AUTH_OK 0
42 
43 #endif
44 
45 #define BUFLEN 0x10000
46 
47 char *argv0;
48 
49 #ifdef SHISHI
50 
51 void
usage(void)52 usage (void)
53 {
54   fprintf (stderr,
55 	   "Usage: rlogin [-46vsx] [-l user] [-p port] [user@]host\n");
56 }
57 
58 #else
59 
60 void
usage(void)61 usage (void)
62 {
63   fprintf (stderr, "Usage: rlogin [-46v] [-l user] [-p port] [user@]host\n");
64 }
65 
66 #endif
67 
68 /* Make sure everything gets written */
69 
70 ssize_t
safewrite(int fd,const void * buf,size_t count)71 safewrite (int fd, const void *buf, size_t count)
72 {
73   int written = 0, result;
74 
75   while (count)
76     {
77       result = write (fd, buf, count);
78       if (result == -1)
79 	{
80 	  if (errno == EINTR)
81 	    continue;
82 	  else
83 	    return result;
84 	}
85       written += result;
86       buf += result;
87       count -= result;
88     }
89 
90   return written;
91 }
92 
93 /* Safe and fast string building */
94 
95 void
safecpy(char ** dest,int * len,char * source,bool terminate)96 safecpy (char **dest, int *len, char *source, bool terminate)
97 {
98   while (*source && *len)
99     {
100       *(*dest)++ = *source++;
101       (*len)--;
102     }
103 
104   if (terminate && *len)
105     {
106       *(*dest)++ = 0;
107       (*len)--;
108     }
109 }
110 
111 /* Convert termios speed to a string */
112 
113 char *
termspeed(speed_t speed)114 termspeed (speed_t speed)
115 {
116   switch (speed)
117     {
118     case B0:
119       return "0";
120     case B50:
121       return "50";
122     case B75:
123       return "75";
124     case B110:
125       return "110";
126     case B134:
127       return "134";
128     case B150:
129       return "150";
130     case B200:
131       return "200";
132     case B300:
133       return "300";
134     case B600:
135       return "600";
136     case B1200:
137       return "1200";
138     case B1800:
139       return "1800";
140     case B2400:
141       return "2400";
142     case B4800:
143       return "4800";
144     case B9600:
145       return "9600";
146     case B19200:
147       return "19200";
148     case B38400:
149       return "38400";
150     case B57600:
151       return "57600";
152     case B115200:
153       return "115200";
154     case B230400:
155       return "230400";
156     case B460800:
157       return "460800";
158     case B500000:
159       return "500000";
160     case B576000:
161       return "576000";
162     case B921600:
163       return "921600";
164     case B1000000:
165       return "1000000";
166     case B1152000:
167       return "1152000";
168     case B1500000:
169       return "1500000";
170     case B2000000:
171       return "2000000";
172     case B2500000:
173       return "2500000";
174     case B3000000:
175       return "3000000";
176     case B3500000:
177       return "3500000";
178     case B4000000:
179       return "4000000";
180     default:
181       return "9600";
182     }
183 }
184 
185 #ifdef SHISHI
186 
187 /* read encrypted data on socket */
188 int
readenc(Shishi * h,int sock,char * buf,int * len,char * iv,int * ivlen,Shishi_key * enckey)189 readenc (Shishi * h, int sock, char *buf, int *len, char *iv, int *ivlen,
190 	 Shishi_key * enckey)
191 {
192   char *out;
193   char *outbis;
194   char *iv2;
195 
196   int rc;
197   int val;
198   int outlen;
199   int dlen = 0, blocksize, enctype, hashsize;
200 
201   /* read size of message */
202   read (sock, &dlen, sizeof (int));
203 
204   dlen = ntohl (dlen);
205   /* if 0 put read size to 0 */
206   if (!dlen)
207     {
208       *len = dlen;
209       return SHISHI_OK;
210     }
211 
212   /* convert size to encryption size */
213   enctype = shishi_key_type (enckey);
214 
215   blocksize = shishi_cipher_blocksize (enctype);
216   hashsize =
217     shishi_checksum_cksumlen (shishi_cipher_defaultcksumtype (enctype));
218 
219   dlen += blocksize - 1 + 4;
220   if (shishi_key_type (enckey) != SHISHI_DES3_CBC_HMAC_SHA1_KD)
221     dlen += hashsize;
222   else
223     dlen += blocksize;
224 
225   dlen /= blocksize;
226   dlen *= blocksize;
227 
228   if (shishi_key_type (enckey) == SHISHI_DES3_CBC_HMAC_SHA1_KD)
229     dlen += hashsize;
230 
231   /* read encrypted data */
232   outbis = malloc (dlen);
233   if (outbis == NULL)
234     {
235       printf ("Malloc error!\n");
236       return 1;
237     }
238 
239   rc = read (sock, outbis, dlen);
240   if (rc != dlen)
241     {
242       printf ("Error during read socket\n");
243       return 1;
244     }
245 
246   /* decrypt it */
247   rc =
248     shishi_decrypt_ivupdate (h, enckey, 1026, iv, *ivlen, &iv2, ivlen, outbis,
249 			     dlen, &out, &outlen);
250   if (rc != SHISHI_OK)
251     {
252       printf ("decryption error\n");
253       return 1;
254     }
255 
256   /* len = first 4 bytes of decrypted data */
257   *len = ntohl (*((int *) out));
258 
259   /* update iv */
260   memcpy (iv, iv2, *ivlen);
261 
262   /* Temp patch to remove 5 unidentified bytes data from server */
263   memset (buf, 0, BUFLEN);
264   if ((unsigned char) out[4] == 255)
265     val = 5 + sizeof (int);
266   else
267     val = sizeof (int);
268 
269   /* copy decrypted data to output */
270   memcpy (buf, out + val, strlen (out + val));
271 
272 
273   free (out);
274   free (outbis);
275 
276   return SHISHI_OK;
277 }
278 
279 /* write encrypted data to socket */
280 int
writeenc(Shishi * h,int sock,char * buf,int wlen,int * len,char * iv,int * ivlen,Shishi_key * enckey)281 writeenc (Shishi * h, int sock, char *buf, int wlen, int *len, char *iv,
282 	  int *ivlen, Shishi_key * enckey)
283 {
284   char *out;
285   char *bufbis;
286 
287   char *iv2;
288 
289   int rc;
290   int dlen, outlen;
291 
292   dlen = wlen;
293   dlen = htonl (dlen);
294 
295   /* data to encrypt = size + data */
296   bufbis = malloc (wlen + sizeof (int));
297   memcpy (bufbis, (char *) &dlen, sizeof (int));
298   memcpy (bufbis + sizeof (int), buf, wlen);
299 
300   /* encrypt it */
301   rc =
302     shishi_encrypt_ivupdate (h, enckey, 1026, iv, *ivlen, &iv2, ivlen, bufbis,
303 			     wlen + sizeof (int), &out, &outlen);
304   if (rc != SHISHI_OK)
305     {
306       printf ("decryption error\n");
307       return 1;
308     }
309 
310   free (bufbis);
311 
312   /* data to send = original size + encrypted data */
313   bufbis = malloc (outlen + sizeof (int));
314   if (bufbis == NULL)
315     {
316       printf ("Malloc error!\n");
317       return 1;
318     }
319   memcpy (bufbis, (char *) &dlen, sizeof (int));
320   memcpy (bufbis + sizeof (int), out, outlen);
321 
322   /* send it */
323   write (sock, bufbis, outlen + sizeof (int));
324   *len = wlen;
325 
326   /* update iv */
327   memcpy (iv, iv2, *ivlen);
328 
329   free (bufbis);
330   free (out);
331 
332   return SHISHI_OK;
333 
334 
335 }
336 
337 /* shishi authentication */
338 int
auth(Shishi * h,int verbose,const char * cname,const char * sname,int sock,char * cmd,char * port,Shishi_key ** enckey,Shishi_key * deckey)339 auth (Shishi * h, int verbose, const char *cname, const char *sname, int sock,
340       char *cmd, char *port, Shishi_key ** enckey, Shishi_key * deckey)
341 {
342   Shishi_ap *ap;
343   Shishi_tkt *tkt;
344   Shishi_tkts_hint hint;
345 
346   int rc;
347   char *out;
348   int outlen;
349   int krb5len, msglen;
350   char auth;
351   /* KERBEROS 5 SENDAUTH MESSAGE */
352   char krb5sendauth[] = "KRB5_SENDAUTH_V1.0";
353   /* PROTOCOL VERSION */
354   char krb5sendclient[] = "KCMDV0.2";
355   /* to store error msg sent by server */
356   char errormsg[101];
357   char cksumdata[101];
358 
359   /* size of KRB5 auth message */
360   krb5len = strlen (krb5sendauth) + 1;
361   msglen = htonl (krb5len);
362   safewrite (sock, &msglen, sizeof (int));
363   /* KRB5 authentication message */
364   safewrite (sock, krb5sendauth, krb5len);
365   /* size of client message */
366   krb5len = strlen (krb5sendclient) + 1;
367   msglen = htonl (krb5len);
368   safewrite (sock, &msglen, sizeof (int));
369   /* KRB5 client message */
370   safewrite (sock, krb5sendclient, krb5len);
371 
372   /* get answer from server 0 = ok, 1 = error with message */
373   read (sock, &auth, 1);
374   if (auth)
375     {
376       read (sock, errormsg, 100);
377       errormsg[100] = '\0';
378 
379       printf ("Error during server authentication : %s\n", errormsg);
380       return 1;
381     }
382 
383   if (verbose)
384     {
385       printf ("Client: %s\n", cname);
386       printf ("Server: %s\n", sname);
387     }
388 
389   /* Get a ticket for the server. */
390 
391   memset (&hint, 0, sizeof (hint));
392 
393   hint.client = (char *) cname;
394   hint.server = (char *) sname;
395 
396   tkt = shishi_tkts_get (shishi_tkts_default (h), &hint);
397   if (!tkt)
398     {
399       printf ("cannot find ticket for \"%s\"\n", sname);
400       return 1;
401     }
402 
403   if (verbose)
404     shishi_tkt_pretty_print (tkt, stderr);
405 
406   /* Create Authentication context */
407 
408   rc = shishi_ap_tktoptions (h, &ap, tkt, SHISHI_APOPTIONS_MUTUAL_REQUIRED);
409   if (rc != SHISHI_OK)
410     {
411       printf ("cannot create authentication context\n");
412       return 1;
413     }
414 
415 
416   /* checksum = port: terminal name */
417 
418   snprintf (cksumdata, 100, "%s:%s%s", port, cmd, cname);
419 
420   /* add checksum to authenticator */
421 
422   shishi_ap_authenticator_cksumdata_set (ap, cksumdata, strlen (cksumdata));
423   /* To be compatible with MIT rlogind */
424   shishi_ap_authenticator_cksumtype_set (ap, SHISHI_RSA_MD5);
425 
426   /* create der encoded AP-REQ */
427 
428   rc = shishi_ap_req_der (ap, &out, &outlen);
429   if (rc != SHISHI_OK)
430     {
431       printf ("cannot build authentication request: %s\n",
432 	      shishi_strerror (rc));
433 
434       return 1;
435     }
436 
437   if (verbose)
438     shishi_authenticator_print (h, stderr, shishi_ap_authenticator (ap));
439 
440   /* extract subkey if present from ap exchange for secure connection */
441 
442   shishi_authenticator_get_subkey (h, shishi_ap_authenticator (ap), enckey);
443 
444   /* send size of AP-REQ to the server */
445 
446   msglen = htonl (outlen);
447   safewrite (sock, (char *) &msglen, sizeof (int));
448 
449   /* send AP-REQ to the server */
450 
451   safewrite (sock, out, outlen);
452 
453   /* read a respond from server - what ? */
454 
455   read (sock, &auth, sizeof (int));
456 
457   /* For mutual authentication, wait for server reply. */
458 
459   if (shishi_apreq_mutual_required_p (h, shishi_ap_req (ap)))
460     {
461       if (verbose)
462 	printf ("Waiting for server to authenticate itself...\n");
463 
464       /* read size of the AP-REP */
465 
466       read (sock, (char *) &outlen, sizeof (int));
467 
468       /* read AP-REP */
469       outlen = ntohl (outlen);
470       outlen = read (sock, out, outlen);
471 
472       rc = shishi_ap_rep_verify_der (ap, out, outlen);
473       if (rc == SHISHI_OK)
474 	{
475 	  if (verbose)
476 	    printf ("AP-REP verification OK...\n");
477 	}
478       else
479 	{
480 	  if (rc == SHISHI_APREP_VERIFY_FAILED)
481 	    printf ("AP-REP verification failed...\n");
482 	  else
483 	    printf ("AP-REP verification error: %s\n", shishi_strerror (rc));
484 	  return 1;
485 	}
486 
487       /* The server is authenticated. */
488       if (verbose)
489 	printf ("Server authenticated.\n");
490     }
491 
492   /* We are now authenticated. */
493   if (verbose)
494     printf ("User authenticated.\n");
495 
496   return AUTH_OK;
497 
498 }
499 
500 #endif
501 
502 int
main(int argc,char ** argv)503 main (int argc, char **argv)
504 {
505   char *user = NULL;
506   char *luser = NULL;
507   char *host = NULL;
508   char *port = "login";
509   char *p;
510   char lport[5];
511 
512   struct passwd *pw;
513 
514   int af = AF_UNSPEC;
515   struct addrinfo hint, *ai, *aip, *lai;
516   int err, i;
517 
518   int opt;
519 
520   bool verbose = false;
521 
522   int sock = -1;
523   bool winchsupport = false;
524 
525   char hostaddr[NI_MAXHOST];
526   char portnr[NI_MAXSERV];
527 
528   struct termios tios, oldtios;
529   char *term, *speed;
530 
531   char buf[2][BUFLEN], *bufp[2];
532   int len[2], wlen;
533 
534   fd_set infd, outfd, infdset, outfdset, exfd, exfdset;
535   int maxfd;
536 
537   int flags;
538 
539   int oldmask;
540 
541 #ifdef SHISHI
542 
543   Shishi *h;
544   Shishi_key *enckey = NULL, *deckey = NULL;
545   int rc;
546   char *sname = NULL;
547   int shishi = 0;
548   int encryption = 0;
549   int auth2 = 0;
550   char cmd[BUFLEN];
551   int hostlen;
552   struct hostent *hostdata;
553   char *iv = NULL;
554   char *iv2 = NULL;
555   int ivlen;
556   int ivlen2;
557 
558 #endif
559 
560   argv0 = argv[0];
561 
562   /* Lookup local username */
563 
564   if (!(pw = getpwuid (getuid ())))
565     {
566       fprintf (stderr, "%s: Could not lookup username: %s\n", argv0,
567 	       strerror (errno));
568       return 1;
569     }
570 
571   /* Process options */
572 #ifdef SHISHI
573   while ((opt = getopt (argc, argv, "+l:p:46vsx")) != -1)
574 #else
575   while ((opt = getopt (argc, argv, "+l:p:46v")) != -1)
576 #endif
577     {
578       switch (opt)
579 	{
580 	case 'l':
581 	  user = optarg;
582 	  break;
583 	case 'p':
584 	  port = optarg;
585 	  break;
586 	case '4':
587 	  af = AF_INET;
588 	  break;
589 	case '6':
590 	  af = AF_INET6;
591 	  break;
592 	case 'v':
593 	  verbose = true;
594 	  break;
595 #ifdef SHISHI
596 	case 's':
597 	  shishi = 1;
598 	  if (!encryption)
599 	    port = "543";
600 	  break;
601 	case 'x':
602 	  encryption = 1;
603 	  port = "2105";
604 	  break;
605 #endif
606 	default:
607 	  fprintf (stderr, "%s: Unknown option!\n", argv0);
608 	  usage ();
609 	  return 1;
610 	}
611     }
612 
613   if (optind == argc)
614     {
615       fprintf (stderr, "%s: No host specified!\n", argv0);
616       usage ();
617       return 1;
618     }
619 
620 #ifdef SHISHI
621 
622   if (!shishi)
623     {
624       luser = pw->pw_name;
625       if (!user)
626 	user = luser;
627     }
628 #endif
629 
630   host = argv[optind++];
631 
632   if ((p = strchr (host, '@')))
633     {
634       user = host;
635       *p = '\0';
636       host = p + 1;
637     }
638 
639   /* Resolve hostname and try to make a connection */
640 
641   memset (&hint, '\0', sizeof (hint));
642   hint.ai_family = af;
643   hint.ai_socktype = SOCK_STREAM;
644 
645   err = getaddrinfo (host, port, &hint, &ai);
646 
647   if (err)
648     {
649       fprintf (stderr, "%s: Error looking up host: %s\n", argv0,
650 	       gai_strerror (err));
651       return 1;
652     }
653 
654   hint.ai_flags = AI_PASSIVE;
655 
656   for (aip = ai; aip; aip = aip->ai_next)
657     {
658       if (getnameinfo
659 	  (aip->ai_addr, aip->ai_addrlen, hostaddr, sizeof (hostaddr), portnr,
660 	   sizeof (portnr), NI_NUMERICHOST | NI_NUMERICSERV))
661 	{
662 	  fprintf (stderr, "%s: Error resolving address: %s\n", argv0,
663 		   strerror (errno));
664 	  return 1;
665 	}
666       if (verbose)
667 	fprintf (stderr, "Trying %s port %s...", hostaddr, portnr);
668 
669       if ((sock =
670 	   socket (aip->ai_family, aip->ai_socktype, aip->ai_protocol)) == -1)
671 	{
672 	  if (verbose)
673 	    fprintf (stderr, " Could not open socket: %s\n",
674 		     strerror (errno));
675 	  continue;
676 	}
677 
678       hint.ai_family = aip->ai_family;
679 
680       /* Bind to a privileged port */
681 
682       for (i = 1023; i >= 512; i--)
683 	{
684 	  snprintf (lport, sizeof (lport), "%d", i);
685 	  err = getaddrinfo (NULL, lport, &hint, &lai);
686 	  if (err)
687 	    {
688 	      fprintf (stderr, " Error looking up localhost: %s\n",
689 		       gai_strerror (err));
690 	      return 1;
691 	    }
692 
693 	  err = bind (sock, lai->ai_addr, lai->ai_addrlen);
694 
695 	  freeaddrinfo (lai);
696 
697 	  if (err)
698 	    continue;
699 	  else
700 	    break;
701 	}
702 
703       if (err)
704 	{
705 	  if (verbose)
706 	    fprintf (stderr, " Could not bind to privileged port: %s\n",
707 		     strerror (errno));
708 	  continue;
709 	}
710 
711       if (connect (sock, aip->ai_addr, aip->ai_addrlen) == -1)
712 	{
713 	  if (verbose)
714 	    fprintf (stderr, " Connection failed: %s\n", strerror (errno));
715 	  continue;
716 	}
717       if (verbose)
718 	fprintf (stderr, " Connected.\n");
719       break;
720     }
721 
722   if (!aip)
723     {
724       fprintf (stderr, "%s: Could not make a connection.\n", argv0);
725       return 1;
726     }
727 
728   freeaddrinfo (ai);
729 
730   /* Drop privileges */
731 
732   if (setuid (getuid ()))
733     {
734       fprintf (stderr, "%s: Unable to drop privileges: %s\n", argv0,
735 	       strerror (errno));
736       return 1;
737     }
738 
739   /* Send required information to the server */
740 
741   term = getenv ("TERM") ? : "network";
742 
743   if (tcgetattr (0, &tios))
744     {
745       fprintf (stderr, "%s: Unable to get terminal attributes: %s\n", argv0,
746 	       strerror (errno));
747       return 1;
748     }
749 
750   speed = termspeed (cfgetispeed (&tios));
751 
752   bufp[0] = buf[0];
753   len[0] = sizeof (buf[0]);
754 
755 #ifdef SHISHI
756 
757   if (shishi)
758     {
759       if (!shishi_check_version (SHISHI_VERSION))
760 	{
761 	  printf ("shishi_check_version() failed:\n"
762 		  "Header file incompatible with shared library.\n");
763 	  return 1;
764 	}
765 
766       rc = shishi_init (&h);
767       if (rc != SHISHI_OK)
768 	{
769 	  printf ("error initializing shishi: %s\n", shishi_strerror (rc));
770 	  return 1;
771 	}
772 
773       hostdata = gethostbyname (host);
774       hostlen = strlen (hostdata->h_name) + strlen (SERVICE) + 2;
775       sname = malloc (hostlen);
776       snprintf (sname, hostlen, "%s/%s", SERVICE, hostdata->h_name);
777 
778       snprintf (cmd, BUFLEN, "%s/%s", term, speed);
779 
780       if (!user)
781 	user = (char *) shishi_principal_default (h);
782 
783       safewrite (sock, "", 1);
784 
785       if (auth (h, 0, user, sname, sock, cmd, port, &enckey, deckey) !=
786 	  AUTH_OK)
787 	return 1;
788 
789     }
790   else
791     {
792       safecpy (&bufp[0], &len[0], "", 1);
793       safecpy (&bufp[0], &len[0], luser, 1);
794     }
795 
796 #else
797   safecpy (&bufp[0], &len[0], "", 1);
798   safecpy (&bufp[0], &len[0], luser, 1);
799 #endif
800 
801   safecpy (&bufp[0], &len[0], user, 1);
802   safecpy (&bufp[0], &len[0], term, 0);
803   safecpy (&bufp[0], &len[0], "/", 0);
804   safecpy (&bufp[0], &len[0], speed, 0);
805 
806   for (; optind < argc; optind++)
807     {
808       safecpy (&bufp[0], &len[0], "/", 0);
809       safecpy (&bufp[0], &len[0], argv[optind], 0);
810     }
811 
812 #ifdef SHISHI
813   if (shishi)
814     {
815       safecpy (&bufp[0], &len[0], "", 1);
816       safecpy (&bufp[0], &len[0], user, 1);
817     }
818   else
819 #endif
820 
821     safecpy (&bufp[0], &len[0], "", 1);
822 
823   if (!len[0])
824     {
825       fprintf (stderr, "%s: Arguments too long!\n", argv0);
826       return 1;
827     }
828 
829   if (safewrite (sock, buf[0], bufp[0] - buf[0]) == -1)
830     {
831       fprintf (stderr, "%s: Unable to send required information: %s\n", argv0,
832 	       strerror (errno));
833       return 1;
834     }
835 
836 #ifdef SHISHI
837 
838   if (shishi)
839     {
840       safewrite (sock, &auth2, sizeof (int));
841     }
842 #endif
843 
844   /* Wait for acknowledgement from server */
845 
846   errno = 0;
847 
848   if (read (sock, buf[0], 1) != 1 || *buf[0])
849     {
850       fprintf (stderr, "%s: Didn't receive NULL byte from server: %s\n",
851 	       argv0, strerror (errno));
852       return 1;
853     }
854 
855 #ifdef SHISHI
856 
857   if (!encryption)
858     /* unidentified bytes */
859     read (sock, cmd, 5);
860   else
861     {
862       ivlen = ivlen2 = shishi_key_length (enckey);
863       iv = malloc (ivlen);
864       memset (iv, 1, ivlen);
865       iv2 = malloc (ivlen2);
866       memset (iv2, 0, ivlen2);
867     }
868 
869 #endif
870 
871   /* Set up terminal on the client */
872 
873   oldtios = tios;
874   tios.c_oflag &= ~(ONLCR | OCRNL);
875   tios.c_lflag &= ~(ECHO | ICANON | ISIG);
876   tios.c_iflag &= ~(ICRNL | ISTRIP | IXON);
877 
878   tios.c_cc[VTIME] = 1;
879   tios.c_cc[VMIN] = 1;
880 
881   /* How much of the stuff below is really needed?
882      tios.c_cc[VSUSP] = 255;
883      tios.c_cc[VEOL] = 255;
884      tios.c_cc[VREPRINT] = 255;
885      tios.c_cc[VDISCARD] = 255;
886      tios.c_cc[VWERASE] = 255;
887      tios.c_cc[VLNEXT] = 255;
888      tios.c_cc[VEOL2] = 255;
889    */
890 
891   tcsetattr (0, TCSADRAIN, &tios);
892 
893   /* Process input/output */
894 
895   flags = fcntl (sock, F_GETFL);
896   fcntl (sock, F_SETFL, flags | O_NONBLOCK);
897 
898   bufp[0] = buf[0];
899   bufp[1] = buf[1];
900 
901   maxfd = sock + 1;
902 
903   FD_ZERO (&infdset);
904   FD_ZERO (&outfdset);
905   FD_ZERO (&exfdset);
906   FD_SET (0, &infdset);
907   FD_SET (sock, &infdset);
908   FD_SET (sock, &exfdset);
909 
910   /* Handle SIGWINCH */
911 
912   void sigwinch_h (int signal)
913   {
914     char wbuf[12];
915     struct winsize winsize;
916 
917     if (winchsupport)
918       {
919 	wbuf[0] = wbuf[1] = (char) 0xFF;
920 	wbuf[2] = wbuf[3] = 's';
921 
922 	ioctl (0, TIOCGWINSZ, &winsize);
923 	*(uint16_t *) (wbuf + 4) = htons (winsize.ws_row);
924 	*(uint16_t *) (wbuf + 6) = htons (winsize.ws_col);
925 	*(uint16_t *) (wbuf + 8) = htons (winsize.ws_xpixel);
926 	*(uint16_t *) (wbuf + 10) = htons (winsize.ws_ypixel);
927 
928 	if (bufp[0] == buf[0])
929 	  len[0] = 0;
930 
931 	memcpy (bufp[0] + len[0], wbuf, 12);
932 	len[0] += 12;
933 
934 	FD_SET (sock, &outfdset);
935 	FD_CLR (0, &infdset);
936 	FD_CLR (0, &infd);
937       }
938   }
939 
940   if (signal (SIGWINCH, sigwinch_h) == SIG_ERR)
941     {
942       fprintf (stderr, "%s: signal() failed: %s\n", argv0, strerror (errno));
943       return 1;
944     }
945 
946   for (;;)
947     {
948       errno = 0;
949       infd = infdset;
950       outfd = outfdset;
951       exfd = exfdset;
952 
953       if (select (maxfd, &infd, &outfd, &exfd, NULL) <= 0)
954 	{
955 	  if (errno == EINTR)
956 	    continue;
957 	  else
958 	    break;
959 	}
960 
961       oldmask = sigblock (sigmask (SIGWINCH));
962 
963       if (FD_ISSET (sock, &exfd))
964 	{
965 	  len[1] = recv (sock, buf[1], 1, MSG_OOB);
966 	  if (len[1] <= 0)
967 	    {
968 	      break;
969 	    }
970 	  else
971 	    {
972 	      if (*buf[1] == (char) 0x80)
973 		{
974 		  winchsupport = true;
975 		  sigwinch_h (SIGWINCH);
976 		}
977 	    }
978 	}
979 
980       if (FD_ISSET (sock, &infd))
981 	{
982 #ifdef SHISHI
983 	  if (encryption)
984 	    {
985 	      rc = readenc (h, sock, buf[1], &len[1], iv, &ivlen, enckey);
986 	      if (rc != SHISHI_OK)
987 		break;
988 	    }
989 	  else
990 #endif
991 	    len[1] = read (sock, buf[1], BUFLEN);
992 	  if (len[1] <= 0)
993 	    {
994 	      if (errno != EINTR)
995 		break;
996 	    }
997 	  else
998 	    {
999 	      FD_SET (1, &outfdset);
1000 	      FD_CLR (sock, &infdset);
1001 	    }
1002 	}
1003 
1004       if (FD_ISSET (1, &outfd))
1005 	{
1006 	  wlen = write (1, bufp[1], len[1]);
1007 	  if (wlen <= 0)
1008 	    {
1009 	      if (errno != EINTR)
1010 		break;
1011 	    }
1012 	  else
1013 	    {
1014 	      len[1] -= wlen;
1015 	      bufp[1] += wlen;
1016 	      if (!len[1])
1017 		{
1018 		  FD_CLR (1, &outfdset);
1019 		  FD_SET (sock, &infdset);
1020 		  bufp[1] = buf[1];
1021 		}
1022 	    }
1023 	}
1024 
1025       if (FD_ISSET (0, &infd))
1026 	{
1027 	  len[0] = read (0, buf[0], BUFLEN);
1028 	  if (len[0] <= 0)
1029 	    {
1030 	      if (errno != EINTR)
1031 		{
1032 		  FD_CLR (0, &infdset);
1033 		  shutdown (sock, SHUT_WR);
1034 		}
1035 	    }
1036 	  else
1037 	    {
1038 	      FD_SET (sock, &outfdset);
1039 	      FD_CLR (0, &infdset);
1040 	    }
1041 	}
1042 
1043       if (FD_ISSET (sock, &outfd))
1044 	{
1045 #ifdef SHISHI
1046 	  if (encryption)
1047 	    {
1048 	      rc =
1049 		writeenc (h, sock, bufp[0], len[0], &wlen, iv2, &ivlen2,
1050 			  enckey);
1051 	      if (rc != SHISHI_OK)
1052 		break;
1053 	    }
1054 	  else
1055 #endif
1056 	    wlen = write (sock, bufp[0], len[0]);
1057 	  if (wlen <= 0)
1058 	    {
1059 	      if (errno != EINTR)
1060 		break;
1061 	    }
1062 	  else
1063 	    {
1064 	      len[0] -= wlen;
1065 	      bufp[0] += wlen;
1066 	      if (!len[0])
1067 		{
1068 		  FD_CLR (sock, &outfdset);
1069 		  FD_SET (0, &infdset);
1070 		  bufp[0] = buf[0];
1071 		}
1072 	    }
1073 	}
1074 
1075       sigsetmask (oldmask);
1076     }
1077 
1078   /* Clean up */
1079 
1080   if (errno)
1081     fprintf (stderr, "%s: %s\n", argv0, strerror (errno));
1082 
1083   tcsetattr (0, TCSADRAIN, &oldtios);
1084 
1085 #ifdef SHISHI
1086 
1087   if (shishi)
1088     {
1089       shishi_done (h);
1090       if (encryption)
1091 	{
1092 	  free (iv);
1093 	  free (iv2);
1094 	}
1095     }
1096 
1097 #endif
1098 
1099   close (sock);
1100 
1101   return 0;
1102 }
1103