]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - usr.bin/rlogin/rlogin.c
This commit was generated by cvs2svn to compensate for changes in r53910,
[FreeBSD/FreeBSD.git] / usr.bin / rlogin / rlogin.c
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 const 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 const char sccsid[] = "@(#)rlogin.c      8.1 (Berkeley) 6/6/93";
42 static const char rcsid[] =
43   "$FreeBSD$";
44 #endif /* not lint */
45
46 /*
47  * rlogin - remote login
48  */
49 #include <sys/param.h>
50 #include <sys/socket.h>
51 #include <sys/time.h>
52 #include <sys/resource.h>
53 #include <sys/wait.h>
54
55 #include <netinet/in.h>
56 #include <netinet/in_systm.h>
57 #include <netinet/ip.h>
58 #include <netinet/tcp.h>
59
60 #include <err.h>
61 #include <errno.h>
62 #include <fcntl.h>
63 #include <libutil.h>
64 #include <netdb.h>
65 #include <pwd.h>
66 #include <setjmp.h>
67 #include <sgtty.h>
68 #include <signal.h>
69 #include <stdio.h>
70 #include <stdlib.h>
71 #include <string.h>
72 #include <unistd.h>
73 #include <err.h>
74
75 #ifdef KERBEROS
76 #include <des.h>
77 #include <krb.h>
78
79 #include "../../bin/rcp/pathnames.h"
80 #include "krb.h"
81
82 CREDENTIALS cred;
83 Key_schedule schedule;
84 int use_kerberos = 1, doencrypt;
85 char dst_realm_buf[REALM_SZ], *dest_realm = NULL;
86 #endif
87
88 #ifndef TIOCPKT_WINDOW
89 #define TIOCPKT_WINDOW  0x80
90 #endif
91
92 /* concession to Sun */
93 #ifndef SIGUSR1
94 #define SIGUSR1 30
95 #endif
96
97 int eight, litout, rem;
98
99 int noescape;
100 u_char escapechar = '~';
101
102 char *speeds[] = {
103         "0", "50", "75", "110", "134", "150", "200", "300", "600", "1200",
104         "1800", "2400", "4800", "9600", "19200", "38400", "57600", "115200"
105 #define MAX_SPEED_LENGTH        (sizeof("115200") - 1)
106 };
107
108 #ifdef OLDSUN
109 struct winsize {
110         unsigned short ws_row, ws_col;
111         unsigned short ws_xpixel, ws_ypixel;
112 };
113 #else
114 #define get_window_size(fd, wp) ioctl(fd, TIOCGWINSZ, wp)
115 #endif
116 struct  winsize winsize;
117
118 void            catch_child __P((int));
119 void            copytochild __P((int));
120 void            doit __P((long)) __dead2;
121 void            done __P((int)) __dead2;
122 void            echo __P((char));
123 u_int           getescape __P((char *));
124 void            lostpeer __P((int));
125 void            mode __P((int));
126 void            msg __P((char *));
127 void            oob __P((int));
128 int             reader __P((int));
129 void            sendwindow __P((void));
130 void            setsignal __P((int));
131 void            sigwinch __P((int));
132 void            stop __P((char));
133 void            usage __P((void)) __dead2;
134 void            writer __P((void));
135 void            writeroob __P((int));
136
137 #ifdef OLDSUN
138 int             get_window_size __P((int, struct winsize *));
139 #endif
140
141 int
142 main(argc, argv)
143         int argc;
144         char *argv[];
145 {
146         extern char *optarg;
147         extern int optind;
148         struct passwd *pw;
149         struct servent *sp;
150         struct sgttyb ttyb;
151         long omask;
152         int argoff, ch, dflag, Dflag, one, uid;
153         char *host, *localname, *p, *user, term[1024];
154 #ifdef KERBEROS
155         char *k;
156 #endif
157
158         argoff = dflag = Dflag = 0;
159         one = 1;
160         host = localname = user = NULL;
161
162         if ((p = rindex(argv[0], '/')))
163                 ++p;
164         else
165                 p = argv[0];
166
167         if (strcmp(p, "rlogin"))
168                 host = p;
169
170         /* handle "rlogin host flags" */
171         if (!host && argc > 2 && argv[1][0] != '-') {
172                 host = argv[1];
173                 argoff = 1;
174         }
175
176 #ifdef KERBEROS
177 #define OPTIONS "8DEKLde:i:k:l:x"
178 #else
179 #define OPTIONS "8DEKLde:i:l:"
180 #endif
181         while ((ch = getopt(argc - argoff, argv + argoff, OPTIONS)) != -1)
182                 switch(ch) {
183                 case '8':
184                         eight = 1;
185                         break;
186                 case 'D':
187                         Dflag = 1;
188                         break;
189                 case 'E':
190                         noescape = 1;
191                         break;
192                 case 'K':
193 #ifdef KERBEROS
194                         use_kerberos = 0;
195 #endif
196                         break;
197                 case 'L':
198                         litout = 1;
199                         break;
200                 case 'd':
201                         dflag = 1;
202                         break;
203                 case 'e':
204                         noescape = 0;
205                         escapechar = getescape(optarg);
206                         break;
207                 case 'i':
208                         if (getuid() != 0)
209                                 errx(1, "-i user: permission denied");
210                         localname = optarg;
211                         break;
212 #ifdef KERBEROS
213                 case 'k':
214                         dest_realm = dst_realm_buf;
215                         (void)strncpy(dest_realm, optarg, REALM_SZ);
216                         break;
217 #endif
218                 case 'l':
219                         user = optarg;
220                         break;
221 #ifdef CRYPT
222 #ifdef KERBEROS
223                 case 'x':
224                         doencrypt = 1;
225                         break;
226 #endif
227 #endif
228                 case '?':
229                 default:
230                         usage();
231                 }
232         optind += argoff;
233
234         /* if haven't gotten a host yet, do so */
235         if (!host && !(host = argv[optind++]))
236                 usage();
237
238         if (argv[optind])
239                 usage();
240
241         if (!(pw = getpwuid(uid = getuid())))
242                 errx(1, "unknown user id");
243         if (!user)
244                 user = pw->pw_name;
245         if (!localname)
246                 localname = pw->pw_name;
247
248         sp = NULL;
249 #ifdef KERBEROS
250         k = auth_getval("auth_list");
251         if (k && !strstr(k, "kerberos"))
252             use_kerberos = 0;
253         if (use_kerberos) {
254                 sp = getservbyname((doencrypt ? "eklogin" : "klogin"), "tcp");
255                 if (sp == NULL) {
256                         use_kerberos = 0;
257                         warn("can't get entry for %s/tcp service",
258                             doencrypt ? "eklogin" : "klogin");
259                 }
260         }
261 #endif
262         if (sp == NULL)
263                 sp = getservbyname("login", "tcp");
264         if (sp == NULL)
265                 errx(1, "login/tcp: unknown service");
266
267 #define MAX_TERM_LENGTH (sizeof(term) - 1 - MAX_SPEED_LENGTH - 1)
268
269         (void)strncpy(term, (p = getenv("TERM")) ? p : "network",
270                       MAX_TERM_LENGTH);
271         term[MAX_TERM_LENGTH] = '\0';
272         if (ioctl(0, TIOCGETP, &ttyb) == 0) {
273                 (void)strcat(term, "/");
274                 (void)strcat(term, speeds[(int)ttyb.sg_ospeed]);
275         }
276
277         (void)get_window_size(0, &winsize);
278
279         (void)signal(SIGPIPE, lostpeer);
280         /* will use SIGUSR1 for window size hack, so hold it off */
281         omask = sigblock(sigmask(SIGURG) | sigmask(SIGUSR1));
282         /*
283          * We set SIGURG and SIGUSR1 below so that an
284          * incoming signal will be held pending rather than being
285          * discarded. Note that these routines will be ready to get
286          * a signal by the time that they are unblocked below.
287          */
288         (void)signal(SIGURG, copytochild);
289         (void)signal(SIGUSR1, writeroob);
290
291 #ifdef KERBEROS
292         if (use_kerberos) {
293                 setuid(getuid());
294                 rem = KSUCCESS;
295                 errno = 0;
296                 if (dest_realm == NULL)
297                         dest_realm = krb_realmofhost(host);
298
299 #ifdef CRYPT
300                 if (doencrypt) {
301                         rem = krcmd_mutual(&host, sp->s_port, user, term, 0,
302                             dest_realm, &cred, schedule);
303                         des_set_key(&cred.session, schedule);
304                 } else
305 #endif /* CRYPT */
306                         rem = krcmd(&host, sp->s_port, user, term, 0,
307                             dest_realm);
308                 if (rem < 0) {
309                         int i;
310                         char **newargv;
311
312                         sp = getservbyname("login", "tcp");
313                         if (sp == NULL)
314                                 errx(1, "unknown service login/tcp");
315                         if (errno == ECONNREFUSED)
316                                 warn("remote host doesn't support Kerberos");
317                         if (errno == ENOENT)
318                                 warn("can't provide Kerberos auth data");
319                         newargv = malloc((argc + 2) * sizeof(*newargv));
320                         if (newargv == NULL)
321                                 err(1, "malloc");
322                         newargv[0] = argv[0];
323                         newargv[1] = "-K";
324                         for(i = 1; i < argc; ++i)
325                         newargv[i + 1] = argv[i];
326                         newargv[argc + 1] = NULL;
327                         execv(_PATH_RLOGIN, newargv);
328                 }
329         } else {
330 #ifdef CRYPT
331                 if (doencrypt)
332                         errx(1, "the -x flag requires Kerberos authentication");
333 #endif /* CRYPT */
334                 rem = rcmd(&host, sp->s_port, localname, user, term, 0);
335         }
336 #else
337         rem = rcmd(&host, sp->s_port, localname, user, term, 0);
338 #endif /* KERBEROS */
339
340         if (rem < 0)
341                 exit(1);
342
343         if (dflag &&
344             setsockopt(rem, SOL_SOCKET, SO_DEBUG, &one, sizeof(one)) < 0)
345                 warn("setsockopt");
346         if (Dflag &&
347             setsockopt(rem, IPPROTO_TCP, TCP_NODELAY, &one, sizeof(one)) < 0)
348                 warn("setsockopt NODELAY (ignored)");
349
350         one = IPTOS_LOWDELAY;
351         if (setsockopt(rem, IPPROTO_IP, IP_TOS, (char *)&one, sizeof(int)) < 0)
352                 warn("setsockopt TOS (ignored)");
353
354         (void)setuid(uid);
355         doit(omask);
356         /*NOTREACHED*/
357 }
358
359 int child, defflags, deflflags, tabflag;
360 char deferase, defkill;
361 struct tchars deftc;
362 struct ltchars defltc;
363 struct tchars notc = { -1, -1, -1, -1, -1, -1 };
364 struct ltchars noltc = { -1, -1, -1, -1, -1, -1 };
365
366 void
367 doit(omask)
368         long omask;
369 {
370         struct sgttyb sb;
371
372         (void)ioctl(0, TIOCGETP, (char *)&sb);
373         defflags = sb.sg_flags;
374         tabflag = defflags & TBDELAY;
375         defflags &= ECHO | CRMOD;
376         deferase = sb.sg_erase;
377         defkill = sb.sg_kill;
378         (void)ioctl(0, TIOCLGET, &deflflags);
379         (void)ioctl(0, TIOCGETC, &deftc);
380         notc.t_startc = deftc.t_startc;
381         notc.t_stopc = deftc.t_stopc;
382         (void)ioctl(0, TIOCGLTC, &defltc);
383         (void)signal(SIGINT, SIG_IGN);
384         setsignal(SIGHUP);
385         setsignal(SIGQUIT);
386         child = fork();
387         if (child == -1) {
388                 warn("fork");
389                 done(1);
390         }
391         if (child == 0) {
392                 mode(1);
393                 if (reader(omask) == 0) {
394                         msg("connection closed.");
395                         exit(0);
396                 }
397                 sleep(1);
398                 msg("\007connection closed.");
399                 exit(1);
400         }
401
402         /*
403          * We may still own the socket, and may have a pending SIGURG (or might
404          * receive one soon) that we really want to send to the reader.  When
405          * one of these comes in, the trap copytochild simply copies such
406          * signals to the child. We can now unblock SIGURG and SIGUSR1
407          * that were set above.
408          */
409         (void)sigsetmask(omask);
410         (void)signal(SIGCHLD, catch_child);
411         writer();
412         msg("closed connection.");
413         done(0);
414 }
415
416 /* trap a signal, unless it is being ignored. */
417 void
418 setsignal(sig)
419         int sig;
420 {
421         int omask = sigblock(sigmask(sig));
422
423         if (signal(sig, exit) == SIG_IGN)
424                 (void)signal(sig, SIG_IGN);
425         (void)sigsetmask(omask);
426 }
427
428 void
429 done(status)
430         int status;
431 {
432         int w, wstatus;
433
434         mode(0);
435         if (child > 0) {
436                 /* make sure catch_child does not snap it up */
437                 (void)signal(SIGCHLD, SIG_DFL);
438                 if (kill(child, SIGKILL) >= 0)
439                         while ((w = wait(&wstatus)) > 0 && w != child);
440         }
441         exit(status);
442 }
443
444 int dosigwinch;
445
446 /*
447  * This is called when the reader process gets the out-of-band (urgent)
448  * request to turn on the window-changing protocol.
449  */
450 void
451 writeroob(signo)
452         int signo;
453 {
454         if (dosigwinch == 0) {
455                 sendwindow();
456                 (void)signal(SIGWINCH, sigwinch);
457         }
458         dosigwinch = 1;
459 }
460
461 void
462 catch_child(signo)
463         int signo;
464 {
465         union wait status;
466         int pid;
467
468         for (;;) {
469                 pid = wait3((int *)&status, WNOHANG|WUNTRACED, NULL);
470                 if (pid == 0)
471                         return;
472                 /* if the child (reader) dies, just quit */
473                 if (pid < 0 || (pid == child && !WIFSTOPPED(status)))
474                         done((int)(status.w_termsig | status.w_retcode));
475         }
476         /* NOTREACHED */
477 }
478
479 /*
480  * writer: write to remote: 0 -> line.
481  * ~.                           terminate
482  * ~^Z                          suspend rlogin process.
483  * ~<delayed-suspend char>      suspend rlogin process, but leave reader alone.
484  */
485 void
486 writer()
487 {
488         register int bol, local, n;
489         char c;
490
491         bol = 1;                        /* beginning of line */
492         local = 0;
493         for (;;) {
494                 n = read(STDIN_FILENO, &c, 1);
495                 if (n <= 0) {
496                         if (n < 0 && errno == EINTR)
497                                 continue;
498                         break;
499                 }
500                 /*
501                  * If we're at the beginning of the line and recognize a
502                  * command character, then we echo locally.  Otherwise,
503                  * characters are echo'd remotely.  If the command character
504                  * is doubled, this acts as a force and local echo is
505                  * suppressed.
506                  */
507                 if (bol) {
508                         bol = 0;
509                         if (!noescape && c == escapechar) {
510                                 local = 1;
511                                 continue;
512                         }
513                 } else if (local) {
514                         local = 0;
515                         if (c == '.' || c == deftc.t_eofc) {
516                                 echo(c);
517                                 break;
518                         }
519                         if (c == defltc.t_suspc || c == defltc.t_dsuspc) {
520                                 bol = 1;
521                                 echo(c);
522                                 stop(c);
523                                 continue;
524                         }
525                         if (c != escapechar)
526 #ifdef CRYPT
527 #ifdef KERBEROS
528                                 if (doencrypt)
529                                         (void)des_enc_write(rem,
530                                             (char *)&escapechar, 1,
531                                                 schedule, &cred.session);
532                                 else
533 #endif
534 #endif
535                                         (void)write(rem, &escapechar, 1);
536                 }
537
538 #ifdef CRYPT
539 #ifdef KERBEROS
540                 if (doencrypt) {
541                         if (des_enc_write(rem, &c, 1, schedule, &cred.session) == 0) {
542                                 msg("line gone");
543                                 break;
544                         }
545                 } else
546 #endif
547 #endif
548                         if (write(rem, &c, 1) == 0) {
549                                 msg("line gone");
550                                 break;
551                         }
552                 bol = c == defkill || c == deftc.t_eofc ||
553                     c == deftc.t_intrc || c == defltc.t_suspc ||
554                     c == '\r' || c == '\n';
555         }
556 }
557
558 void
559 #if __STDC__
560 echo(register char c)
561 #else
562 echo(c)
563         register char c;
564 #endif
565 {
566         register char *p;
567         char buf[8];
568
569         p = buf;
570         c &= 0177;
571         *p++ = escapechar;
572         if (c < ' ') {
573                 *p++ = '^';
574                 *p++ = c + '@';
575         } else if (c == 0177) {
576                 *p++ = '^';
577                 *p++ = '?';
578         } else
579                 *p++ = c;
580         *p++ = '\r';
581         *p++ = '\n';
582         (void)write(STDOUT_FILENO, buf, p - buf);
583 }
584
585 void
586 #if __STDC__
587 stop(char cmdc)
588 #else
589 stop(cmdc)
590         char cmdc;
591 #endif
592 {
593         mode(0);
594         (void)signal(SIGCHLD, SIG_IGN);
595         (void)kill(cmdc == defltc.t_suspc ? 0 : getpid(), SIGTSTP);
596         (void)signal(SIGCHLD, catch_child);
597         mode(1);
598         sigwinch(0);                    /* check for size changes */
599 }
600
601 void
602 sigwinch(signo)
603         int signo;
604 {
605         struct winsize ws;
606
607         if (dosigwinch && get_window_size(0, &ws) == 0 &&
608             bcmp(&ws, &winsize, sizeof(ws))) {
609                 winsize = ws;
610                 sendwindow();
611         }
612 }
613
614 /*
615  * Send the window size to the server via the magic escape
616  */
617 void
618 sendwindow()
619 {
620         struct winsize *wp;
621         char obuf[4 + sizeof (struct winsize)];
622
623         wp = (struct winsize *)(obuf+4);
624         obuf[0] = 0377;
625         obuf[1] = 0377;
626         obuf[2] = 's';
627         obuf[3] = 's';
628         wp->ws_row = htons(winsize.ws_row);
629         wp->ws_col = htons(winsize.ws_col);
630         wp->ws_xpixel = htons(winsize.ws_xpixel);
631         wp->ws_ypixel = htons(winsize.ws_ypixel);
632
633 #ifdef CRYPT
634 #ifdef KERBEROS
635         if(doencrypt)
636                 (void)des_enc_write(rem, obuf, sizeof(obuf),
637                         schedule, &cred.session);
638         else
639 #endif
640 #endif
641                 (void)write(rem, obuf, sizeof(obuf));
642 }
643
644 /*
645  * reader: read from remote: line -> 1
646  */
647 #define READING 1
648 #define WRITING 2
649
650 jmp_buf rcvtop;
651 int ppid, rcvcnt, rcvstate;
652 char rcvbuf[8 * 1024];
653
654 void
655 oob(signo)
656         int signo;
657 {
658         struct sgttyb sb;
659         int atmark, n, out, rcvd;
660         char waste[BUFSIZ], mark;
661
662         out = O_RDWR;
663         rcvd = 0;
664         while (recv(rem, &mark, 1, MSG_OOB) < 0) {
665                 switch (errno) {
666                 case EWOULDBLOCK:
667                         /*
668                          * Urgent data not here yet.  It may not be possible
669                          * to send it yet if we are blocked for output and
670                          * our input buffer is full.
671                          */
672                         if (rcvcnt < sizeof(rcvbuf)) {
673                                 n = read(rem, rcvbuf + rcvcnt,
674                                     sizeof(rcvbuf) - rcvcnt);
675                                 if (n <= 0)
676                                         return;
677                                 rcvd += n;
678                         } else {
679                                 n = read(rem, waste, sizeof(waste));
680                                 if (n <= 0)
681                                         return;
682                         }
683                         continue;
684                 default:
685                         return;
686                 }
687         }
688         if (mark & TIOCPKT_WINDOW) {
689                 /* Let server know about window size changes */
690                 (void)kill(ppid, SIGUSR1);
691         }
692         if (!eight && (mark & TIOCPKT_NOSTOP)) {
693                 (void)ioctl(0, TIOCGETP, (char *)&sb);
694                 sb.sg_flags &= ~CBREAK;
695                 sb.sg_flags |= RAW;
696                 (void)ioctl(0, TIOCSETN, (char *)&sb);
697                 notc.t_stopc = -1;
698                 notc.t_startc = -1;
699                 (void)ioctl(0, TIOCSETC, (char *)&notc);
700         }
701         if (!eight && (mark & TIOCPKT_DOSTOP)) {
702                 (void)ioctl(0, TIOCGETP, (char *)&sb);
703                 sb.sg_flags &= ~RAW;
704                 sb.sg_flags |= CBREAK;
705                 (void)ioctl(0, TIOCSETN, (char *)&sb);
706                 notc.t_stopc = deftc.t_stopc;
707                 notc.t_startc = deftc.t_startc;
708                 (void)ioctl(0, TIOCSETC, (char *)&notc);
709         }
710         if (mark & TIOCPKT_FLUSHWRITE) {
711                 (void)ioctl(1, TIOCFLUSH, (char *)&out);
712                 for (;;) {
713                         if (ioctl(rem, SIOCATMARK, &atmark) < 0) {
714                                 warn("ioctl");
715                                 break;
716                         }
717                         if (atmark)
718                                 break;
719                         n = read(rem, waste, sizeof (waste));
720                         if (n <= 0)
721                                 break;
722                 }
723                 /*
724                  * Don't want any pending data to be output, so clear the recv
725                  * buffer.  If we were hanging on a write when interrupted,
726                  * don't want it to restart.  If we were reading, restart
727                  * anyway.
728                  */
729                 rcvcnt = 0;
730                 longjmp(rcvtop, 1);
731         }
732
733         /* oob does not do FLUSHREAD (alas!) */
734
735         /*
736          * If we filled the receive buffer while a read was pending, longjmp
737          * to the top to restart appropriately.  Don't abort a pending write,
738          * however, or we won't know how much was written.
739          */
740         if (rcvd && rcvstate == READING)
741                 longjmp(rcvtop, 1);
742 }
743
744 /* reader: read from remote: line -> 1 */
745 int
746 reader(omask)
747         int omask;
748 {
749         int pid, n, remaining;
750         char *bufp;
751
752 #if BSD >= 43 || defined(SUNOS4)
753         pid = getpid();         /* modern systems use positives for pid */
754 #else
755         pid = -getpid();        /* old broken systems use negatives */
756 #endif
757         (void)signal(SIGTTOU, SIG_IGN);
758         (void)signal(SIGURG, oob);
759         ppid = getppid();
760         (void)fcntl(rem, F_SETOWN, pid);
761         (void)setjmp(rcvtop);
762         (void)sigsetmask(omask);
763         bufp = rcvbuf;
764         for (;;) {
765                 while ((remaining = rcvcnt - (bufp - rcvbuf)) > 0) {
766                         rcvstate = WRITING;
767                         n = write(STDOUT_FILENO, bufp, remaining);
768                         if (n < 0) {
769                                 if (errno != EINTR)
770                                         return (-1);
771                                 continue;
772                         }
773                         bufp += n;
774                 }
775                 bufp = rcvbuf;
776                 rcvcnt = 0;
777                 rcvstate = READING;
778
779 #ifdef CRYPT
780 #ifdef KERBEROS
781                 if (doencrypt)
782                         rcvcnt = des_enc_read(rem, rcvbuf, sizeof(rcvbuf),
783                                 schedule, &cred.session);
784                 else
785 #endif
786 #endif
787                         rcvcnt = read(rem, rcvbuf, sizeof (rcvbuf));
788                 if (rcvcnt == 0)
789                         return (0);
790                 if (rcvcnt < 0) {
791                         if (errno == EINTR)
792                                 continue;
793                         warn("read");
794                         return (-1);
795                 }
796         }
797 }
798
799 void
800 mode(f)
801         int f;
802 {
803         struct ltchars *ltc;
804         struct sgttyb sb;
805         struct tchars *tc;
806         int lflags;
807
808         (void)ioctl(0, TIOCGETP, (char *)&sb);
809         (void)ioctl(0, TIOCLGET, (char *)&lflags);
810         switch(f) {
811         case 0:
812                 sb.sg_flags &= ~(CBREAK|RAW|TBDELAY);
813                 sb.sg_flags |= defflags|tabflag;
814                 tc = &deftc;
815                 ltc = &defltc;
816                 sb.sg_kill = defkill;
817                 sb.sg_erase = deferase;
818                 lflags = deflflags;
819                 break;
820         case 1:
821                 sb.sg_flags |= (eight ? RAW : CBREAK);
822                 sb.sg_flags &= ~defflags;
823                 /* preserve tab delays, but turn off XTABS */
824                 if ((sb.sg_flags & TBDELAY) == XTABS)
825                         sb.sg_flags &= ~TBDELAY;
826                 tc = &notc;
827                 ltc = &noltc;
828                 sb.sg_kill = sb.sg_erase = -1;
829                 if (litout)
830                         lflags |= LLITOUT;
831                 break;
832         default:
833                 return;
834         }
835         (void)ioctl(0, TIOCSLTC, (char *)ltc);
836         (void)ioctl(0, TIOCSETC, (char *)tc);
837         (void)ioctl(0, TIOCSETN, (char *)&sb);
838         (void)ioctl(0, TIOCLSET, (char *)&lflags);
839 }
840
841 void
842 lostpeer(signo)
843         int signo;
844 {
845         (void)signal(SIGPIPE, SIG_IGN);
846         msg("\007connection closed.");
847         done(1);
848 }
849
850 /* copy SIGURGs to the child process. */
851 void
852 copytochild(signo)
853         int signo;
854 {
855         (void)kill(child, SIGURG);
856 }
857
858 void
859 msg(str)
860         char *str;
861 {
862         (void)fprintf(stderr, "rlogin: %s\r\n", str);
863 }
864
865 void
866 usage()
867 {
868         (void)fprintf(stderr,
869         "usage: rlogin [-%s]%s[-e char] [-i localname] [-l username] host\n",
870 #ifdef KERBEROS
871 #ifdef CRYPT
872             "8DEKLdx", " [-k realm] ");
873 #else
874             "8DEKLd", " [-k realm] ");
875 #endif
876 #else
877             "8DELd", " ");
878 #endif
879         exit(1);
880 }
881
882 /*
883  * The following routine provides compatibility (such as it is) between older
884  * Suns and others.  Suns have only a `ttysize', so we convert it to a winsize.
885  */
886 #ifdef OLDSUN
887 int
888 get_window_size(fd, wp)
889         int fd;
890         struct winsize *wp;
891 {
892         struct ttysize ts;
893         int error;
894
895         if ((error = ioctl(0, TIOCGSIZE, &ts)) != 0)
896                 return (error);
897         wp->ws_row = ts.ts_lines;
898         wp->ws_col = ts.ts_cols;
899         wp->ws_xpixel = 0;
900         wp->ws_ypixel = 0;
901         return (0);
902 }
903 #endif
904
905 u_int
906 getescape(p)
907         register char *p;
908 {
909         long val;
910         int len;
911
912         if ((len = strlen(p)) == 1)     /* use any single char, including '\' */
913                 return ((u_int)*p);
914                                         /* otherwise, \nnn */
915         if (*p == '\\' && len >= 2 && len <= 4) {
916                 val = strtol(++p, NULL, 8);
917                 for (;;) {
918                         if (!*++p)
919                                 return ((u_int)val);
920                         if (*p < '0' || *p > '8')
921                                 break;
922                 }
923         }
924         msg("illegal option value -- e");
925         usage();
926         /* NOTREACHED */
927 }