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