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