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