|
|
1.1 root 1: /*
2: * Copyright (c) 1983 Regents of the University of California.
3: * All rights reserved. The Berkeley software License Agreement
4: * specifies the terms and conditions for redistribution.
5: */
6:
7: #ifndef lint
8: char copyright[] =
9: "@(#) Copyright (c) 1983 Regents of the University of California.\n\
10: All rights reserved.\n";
11: #endif not lint
12:
13: #ifndef lint
14: static char sccsid[] = "@(#)rlogin.c 5.11 (Berkeley) 8/7/86";
15: #endif not lint
16:
17: /*
18: * rlogin - remote login
19: */
20: #include <sys/param.h>
21: #include <sys/errno.h>
22: #include <sys/file.h>
23: #include <sys/socket.h>
24: #include <sys/time.h>
25: #include <sys/resource.h>
26: #include <sys/wait.h>
27:
28: #include <netinet/in.h>
29:
30: #include <stdio.h>
31: #include <sgtty.h>
32: #include <errno.h>
33: #include <pwd.h>
34: #include <signal.h>
35: #include <setjmp.h>
36: #include <netdb.h>
37:
38: # ifndef TIOCPKT_WINDOW
39: # define TIOCPKT_WINDOW 0x80
40: # endif TIOCPKT_WINDOW
41:
42: /* concession to sun */
43: # ifndef SIGUSR1
44: # define SIGUSR1 30
45: # endif SIGUSR1
46:
47: char *index(), *rindex(), *malloc(), *getenv(), *strcat(), *strcpy();
48: struct passwd *getpwuid();
49: char *name;
50: int rem;
51: char cmdchar = '~';
52: int eight;
53: int litout;
54: char *speeds[] =
55: { "0", "50", "75", "110", "134", "150", "200", "300",
56: "600", "1200", "1800", "2400", "4800", "9600", "19200", "38400" };
57: char term[256] = "network";
58: extern int errno;
59: int lostpeer();
60: int dosigwinch = 0;
61: #ifndef sigmask
62: #define sigmask(m) (1 << ((m)-1))
63: #endif
64: #ifdef sun
65: struct winsize {
66: unsigned short ws_row, ws_col;
67: unsigned short ws_xpixel, ws_ypixel;
68: };
69: #endif sun
70: struct winsize winsize;
71: int sigwinch(), oob();
72:
73: /*
74: * The following routine provides compatibility (such as it is)
75: * between 4.2BSD Suns and others. Suns have only a `ttysize',
76: * so we convert it to a winsize.
77: */
78: #ifdef sun
79: int
80: get_window_size(fd, wp)
81: int fd;
82: struct winsize *wp;
83: {
84: struct ttysize ts;
85: int error;
86:
87: if ((error = ioctl(0, TIOCGSIZE, &ts)) != 0)
88: return (error);
89: wp->ws_row = ts.ts_lines;
90: wp->ws_col = ts.ts_cols;
91: wp->ws_xpixel = 0;
92: wp->ws_ypixel = 0;
93: return (0);
94: }
95: #else sun
96: #define get_window_size(fd, wp) ioctl(fd, TIOCGWINSZ, wp)
97: #endif sun
98:
99: main(argc, argv)
100: int argc;
101: char **argv;
102: {
103: char *host, *cp;
104: struct sgttyb ttyb;
105: struct passwd *pwd;
106: struct servent *sp;
107: int uid, options = 0, oldmask;
108: int on = 1;
109:
110: host = rindex(argv[0], '/');
111: if (host)
112: host++;
113: else
114: host = argv[0];
115: argv++, --argc;
116: if (!strcmp(host, "rlogin"))
117: host = *argv++, --argc;
118: another:
119: if (argc > 0 && !strcmp(*argv, "-d")) {
120: argv++, argc--;
121: options |= SO_DEBUG;
122: goto another;
123: }
124: if (argc > 0 && !strcmp(*argv, "-l")) {
125: argv++, argc--;
126: if (argc == 0)
127: goto usage;
128: name = *argv++; argc--;
129: goto another;
130: }
131: if (argc > 0 && !strncmp(*argv, "-e", 2)) {
132: cmdchar = argv[0][2];
133: argv++, argc--;
134: goto another;
135: }
136: if (argc > 0 && !strcmp(*argv, "-8")) {
137: eight = 1;
138: argv++, argc--;
139: goto another;
140: }
141: if (argc > 0 && !strcmp(*argv, "-L")) {
142: litout = 1;
143: argv++, argc--;
144: goto another;
145: }
146: if (host == 0)
147: goto usage;
148: if (argc > 0)
149: goto usage;
150: pwd = getpwuid(getuid());
151: if (pwd == 0) {
152: fprintf(stderr, "Who are you?\n");
153: exit(1);
154: }
155: sp = getservbyname("login", "tcp");
156: if (sp == 0) {
157: fprintf(stderr, "rlogin: login/tcp: unknown service\n");
158: exit(2);
159: }
160: cp = getenv("TERM");
161: if (cp)
162: (void) strcpy(term, cp);
163: if (ioctl(0, TIOCGETP, &ttyb) == 0) {
164: (void) strcat(term, "/");
165: (void) strcat(term, speeds[ttyb.sg_ospeed]);
166: }
167: (void) get_window_size(0, &winsize);
168: (void) signal(SIGPIPE, lostpeer);
169: /* will use SIGUSR1 for window size hack, so hold it off */
170: oldmask = sigblock(sigmask(SIGURG) | sigmask(SIGUSR1));
171: rem = rcmd(&host, sp->s_port, pwd->pw_name,
172: name ? name : pwd->pw_name, term, 0);
173: if (rem < 0)
174: exit(1);
175: if (options & SO_DEBUG &&
176: setsockopt(rem, SOL_SOCKET, SO_DEBUG, &on, sizeof (on)) < 0)
177: perror("rlogin: setsockopt (SO_DEBUG)");
178: uid = getuid();
179: if (setuid(uid) < 0) {
180: perror("rlogin: setuid");
181: exit(1);
182: }
183: doit(oldmask);
184: /*NOTREACHED*/
185: usage:
186: fprintf(stderr,
187: "usage: rlogin host [ -ex ] [ -l username ] [ -8 ] [ -L ]\n");
188: exit(1);
189: }
190:
191: #define CRLF "\r\n"
192:
193: int child;
194: int catchild();
195: int copytochild(), writeroob();
196:
197: int defflags, tabflag;
198: int deflflags;
199: char deferase, defkill;
200: struct tchars deftc;
201: struct ltchars defltc;
202: struct tchars notc = { -1, -1, -1, -1, -1, -1 };
203: struct ltchars noltc = { -1, -1, -1, -1, -1, -1 };
204:
205: doit(oldmask)
206: {
207: int exit();
208: struct sgttyb sb;
209:
210: (void) ioctl(0, TIOCGETP, (char *)&sb);
211: defflags = sb.sg_flags;
212: tabflag = defflags & TBDELAY;
213: defflags &= ECHO | CRMOD;
214: deferase = sb.sg_erase;
215: defkill = sb.sg_kill;
216: (void) ioctl(0, TIOCLGET, (char *)&deflflags);
217: (void) ioctl(0, TIOCGETC, (char *)&deftc);
218: notc.t_startc = deftc.t_startc;
219: notc.t_stopc = deftc.t_stopc;
220: (void) ioctl(0, TIOCGLTC, (char *)&defltc);
221: (void) signal(SIGINT, SIG_IGN);
222: setsignal(SIGHUP, exit);
223: setsignal(SIGQUIT, exit);
224: child = fork();
225: if (child == -1) {
226: perror("rlogin: fork");
227: done(1);
228: }
229: if (child == 0) {
230: mode(1);
231: if (reader(oldmask) == 0) {
232: prf("Connection closed.");
233: exit(0);
234: }
235: sleep(1);
236: prf("\007Connection closed.");
237: exit(3);
238: }
239:
240: /*
241: * We may still own the socket, and may have a pending SIGURG
242: * (or might receive one soon) that we really want to send to
243: * the reader. Set a trap that simply copies such signals to
244: * the child.
245: */
246: (void) signal(SIGURG, copytochild);
247: (void) signal(SIGUSR1, writeroob);
248: (void) sigsetmask(oldmask);
249: (void) signal(SIGCHLD, catchild);
250: writer();
251: prf("Closed connection.");
252: done(0);
253: }
254:
255: /*
256: * Trap a signal, unless it is being ignored.
257: */
258: setsignal(sig, act)
259: int sig, (*act)();
260: {
261: int omask = sigblock(sigmask(sig));
262:
263: if (signal(sig, act) == SIG_IGN)
264: (void) signal(sig, SIG_IGN);
265: (void) sigsetmask(omask);
266: }
267:
268: done(status)
269: int status;
270: {
271: int w;
272:
273: mode(0);
274: if (child > 0) {
275: /* make sure catchild does not snap it up */
276: (void) signal(SIGCHLD, SIG_DFL);
277: if (kill(child, SIGKILL) >= 0)
278: while ((w = wait((union wait *)0)) > 0 && w != child)
279: /*void*/;
280: }
281: exit(status);
282: }
283:
284: /*
285: * Copy SIGURGs to the child process.
286: */
287: copytochild()
288: {
289:
290: (void) kill(child, SIGURG);
291: }
292:
293: /*
294: * This is called when the reader process gets the out-of-band (urgent)
295: * request to turn on the window-changing protocol.
296: */
297: writeroob()
298: {
299:
300: if (dosigwinch == 0) {
301: sendwindow();
302: (void) signal(SIGWINCH, sigwinch);
303: }
304: dosigwinch = 1;
305: }
306:
307: catchild()
308: {
309: union wait status;
310: int pid;
311:
312: again:
313: pid = wait3(&status, WNOHANG|WUNTRACED, (struct rusage *)0);
314: if (pid == 0)
315: return;
316: /*
317: * if the child (reader) dies, just quit
318: */
319: if (pid < 0 || pid == child && !WIFSTOPPED(status))
320: done((int)(status.w_termsig | status.w_retcode));
321: goto again;
322: }
323:
324: /*
325: * writer: write to remote: 0 -> line.
326: * ~. terminate
327: * ~^Z suspend rlogin process.
328: * ~^Y suspend rlogin process, but leave reader alone.
329: */
330: writer()
331: {
332: char c;
333: register n;
334: register bol = 1; /* beginning of line */
335: register local = 0;
336:
337: for (;;) {
338: n = read(0, &c, 1);
339: if (n <= 0) {
340: if (n < 0 && errno == EINTR)
341: continue;
342: break;
343: }
344: /*
345: * If we're at the beginning of the line
346: * and recognize a command character, then
347: * we echo locally. Otherwise, characters
348: * are echo'd remotely. If the command
349: * character is doubled, this acts as a
350: * force and local echo is suppressed.
351: */
352: if (bol) {
353: bol = 0;
354: if (c == cmdchar) {
355: bol = 0;
356: local = 1;
357: continue;
358: }
359: } else if (local) {
360: local = 0;
361: if (c == '.' || c == deftc.t_eofc) {
362: echo(c);
363: break;
364: }
365: if (c == defltc.t_suspc || c == defltc.t_dsuspc) {
366: bol = 1;
367: echo(c);
368: stop(c);
369: continue;
370: }
371: if (c != cmdchar)
372: (void) write(rem, &cmdchar, 1);
373: }
374: if (write(rem, &c, 1) == 0) {
375: prf("line gone");
376: break;
377: }
378: bol = c == defkill || c == deftc.t_eofc ||
379: c == deftc.t_intrc || c == defltc.t_suspc ||
380: c == '\r' || c == '\n';
381: }
382: }
383:
384: echo(c)
385: register char c;
386: {
387: char buf[8];
388: register char *p = buf;
389:
390: c &= 0177;
391: *p++ = cmdchar;
392: if (c < ' ') {
393: *p++ = '^';
394: *p++ = c + '@';
395: } else if (c == 0177) {
396: *p++ = '^';
397: *p++ = '?';
398: } else
399: *p++ = c;
400: *p++ = '\r';
401: *p++ = '\n';
402: (void) write(1, buf, p - buf);
403: }
404:
405: stop(cmdc)
406: char cmdc;
407: {
408: mode(0);
409: (void) signal(SIGCHLD, SIG_IGN);
410: (void) kill(cmdc == defltc.t_suspc ? 0 : getpid(), SIGTSTP);
411: (void) signal(SIGCHLD, catchild);
412: mode(1);
413: sigwinch(); /* check for size changes */
414: }
415:
416: sigwinch()
417: {
418: struct winsize ws;
419:
420: if (dosigwinch && get_window_size(0, &ws) == 0 &&
421: bcmp(&ws, &winsize, sizeof (ws))) {
422: winsize = ws;
423: sendwindow();
424: }
425: }
426:
427: /*
428: * Send the window size to the server via the magic escape
429: */
430: sendwindow()
431: {
432: char obuf[4 + sizeof (struct winsize)];
433: struct winsize *wp = (struct winsize *)(obuf+4);
434:
435: obuf[0] = 0377;
436: obuf[1] = 0377;
437: obuf[2] = 's';
438: obuf[3] = 's';
439: wp->ws_row = htons(winsize.ws_row);
440: wp->ws_col = htons(winsize.ws_col);
441: wp->ws_xpixel = htons(winsize.ws_xpixel);
442: wp->ws_ypixel = htons(winsize.ws_ypixel);
443: (void) write(rem, obuf, sizeof(obuf));
444: }
445:
446: /*
447: * reader: read from remote: line -> 1
448: */
449: #define READING 1
450: #define WRITING 2
451:
452: char rcvbuf[8 * 1024];
453: int rcvcnt;
454: int rcvstate;
455: int ppid;
456: jmp_buf rcvtop;
457:
458: oob()
459: {
460: int out = FWRITE, atmark, n;
461: int rcvd = 0;
462: char waste[BUFSIZ], mark;
463: struct sgttyb sb;
464:
465: while (recv(rem, &mark, 1, MSG_OOB) < 0)
466: switch (errno) {
467:
468: case EWOULDBLOCK:
469: /*
470: * Urgent data not here yet.
471: * It may not be possible to send it yet
472: * if we are blocked for output
473: * and our input buffer is full.
474: */
475: if (rcvcnt < sizeof(rcvbuf)) {
476: n = read(rem, rcvbuf + rcvcnt,
477: sizeof(rcvbuf) - rcvcnt);
478: if (n <= 0)
479: return;
480: rcvd += n;
481: } else {
482: n = read(rem, waste, sizeof(waste));
483: if (n <= 0)
484: return;
485: }
486: continue;
487:
488: default:
489: return;
490: }
491: if (mark & TIOCPKT_WINDOW) {
492: /*
493: * Let server know about window size changes
494: */
495: (void) kill(ppid, SIGUSR1);
496: }
497: if (!eight && (mark & TIOCPKT_NOSTOP)) {
498: (void) ioctl(0, TIOCGETP, (char *)&sb);
499: sb.sg_flags &= ~CBREAK;
500: sb.sg_flags |= RAW;
501: (void) ioctl(0, TIOCSETN, (char *)&sb);
502: notc.t_stopc = -1;
503: notc.t_startc = -1;
504: (void) ioctl(0, TIOCSETC, (char *)¬c);
505: }
506: if (!eight && (mark & TIOCPKT_DOSTOP)) {
507: (void) ioctl(0, TIOCGETP, (char *)&sb);
508: sb.sg_flags &= ~RAW;
509: sb.sg_flags |= CBREAK;
510: (void) ioctl(0, TIOCSETN, (char *)&sb);
511: notc.t_stopc = deftc.t_stopc;
512: notc.t_startc = deftc.t_startc;
513: (void) ioctl(0, TIOCSETC, (char *)¬c);
514: }
515: if (mark & TIOCPKT_FLUSHWRITE) {
516: (void) ioctl(1, TIOCFLUSH, (char *)&out);
517: for (;;) {
518: if (ioctl(rem, SIOCATMARK, &atmark) < 0) {
519: perror("ioctl");
520: break;
521: }
522: if (atmark)
523: break;
524: n = read(rem, waste, sizeof (waste));
525: if (n <= 0)
526: break;
527: }
528: /*
529: * Don't want any pending data to be output,
530: * so clear the recv buffer.
531: * If we were hanging on a write when interrupted,
532: * don't want it to restart. If we were reading,
533: * restart anyway.
534: */
535: rcvcnt = 0;
536: longjmp(rcvtop, 1);
537: }
538:
539: /*
540: * oob does not do FLUSHREAD (alas!)
541: */
542:
543: /*
544: * If we filled the receive buffer while a read was pending,
545: * longjmp to the top to restart appropriately. Don't abort
546: * a pending write, however, or we won't know how much was written.
547: */
548: if (rcvd && rcvstate == READING)
549: longjmp(rcvtop, 1);
550: }
551:
552: /*
553: * reader: read from remote: line -> 1
554: */
555: reader(oldmask)
556: int oldmask;
557: {
558: #if !defined(BSD) || BSD < 43
559: int pid = -getpid();
560: #else
561: int pid = getpid();
562: #endif
563: int n, remaining;
564: char *bufp = rcvbuf;
565:
566: (void) signal(SIGTTOU, SIG_IGN);
567: (void) signal(SIGURG, oob);
568: ppid = getppid();
569: (void) fcntl(rem, F_SETOWN, pid);
570: (void) setjmp(rcvtop);
571: (void) sigsetmask(oldmask);
572: for (;;) {
573: while ((remaining = rcvcnt - (bufp - rcvbuf)) > 0) {
574: rcvstate = WRITING;
575: n = write(1, bufp, remaining);
576: if (n < 0) {
577: if (errno != EINTR)
578: return (-1);
579: continue;
580: }
581: bufp += n;
582: }
583: bufp = rcvbuf;
584: rcvcnt = 0;
585: rcvstate = READING;
586: rcvcnt = read(rem, rcvbuf, sizeof (rcvbuf));
587: if (rcvcnt == 0)
588: return (0);
589: if (rcvcnt < 0) {
590: if (errno == EINTR)
591: continue;
592: perror("read");
593: return (-1);
594: }
595: }
596: }
597:
598: mode(f)
599: {
600: struct tchars *tc;
601: struct ltchars *ltc;
602: struct sgttyb sb;
603: int lflags;
604:
605: (void) ioctl(0, TIOCGETP, (char *)&sb);
606: (void) ioctl(0, TIOCLGET, (char *)&lflags);
607: switch (f) {
608:
609: case 0:
610: sb.sg_flags &= ~(CBREAK|RAW|TBDELAY);
611: sb.sg_flags |= defflags|tabflag;
612: tc = &deftc;
613: ltc = &defltc;
614: sb.sg_kill = defkill;
615: sb.sg_erase = deferase;
616: lflags = deflflags;
617: break;
618:
619: case 1:
620: sb.sg_flags |= (eight ? RAW : CBREAK);
621: sb.sg_flags &= ~defflags;
622: /* preserve tab delays, but turn off XTABS */
623: if ((sb.sg_flags & TBDELAY) == XTABS)
624: sb.sg_flags &= ~TBDELAY;
625: tc = ¬c;
626: ltc = &noltc;
627: sb.sg_kill = sb.sg_erase = -1;
628: if (litout)
629: lflags |= LLITOUT;
630: break;
631:
632: default:
633: return;
634: }
635: (void) ioctl(0, TIOCSLTC, (char *)ltc);
636: (void) ioctl(0, TIOCSETC, (char *)tc);
637: (void) ioctl(0, TIOCSETN, (char *)&sb);
638: (void) ioctl(0, TIOCLSET, (char *)&lflags);
639: }
640:
641: /*VARARGS*/
642: prf(f, a1, a2, a3, a4, a5)
643: char *f;
644: {
645:
646: fprintf(stderr, f, a1, a2, a3, a4, a5);
647: fprintf(stderr, CRLF);
648: }
649:
650: lostpeer()
651: {
652:
653: (void) signal(SIGPIPE, SIG_IGN);
654: prf("\007Connection closed.");
655: done(1);
656: }
657:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.