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