add swapbuf macro
[unix-history] / usr / src / usr.bin / rlogin / rlogin.c
CommitLineData
5567b76f 1#ifndef lint
840fc587 2static char sccsid[] = "@(#)rlogin.c 4.15 (Berkeley) 83/07/02";
5567b76f
BJ
3#endif
4
4ca10280
SL
5/*
6 * rlogin - remote login
7 */
5567b76f
BJ
8#include <sys/types.h>
9#include <sys/socket.h>
840fc587 10#include <sys/wait.h>
86a16a64 11
c6c678f1 12#include <netinet/in.h>
86a16a64
SL
13
14#include <stdio.h>
15#include <sgtty.h>
5567b76f
BJ
16#include <errno.h>
17#include <pwd.h>
86a16a64
SL
18#include <signal.h>
19#include <netdb.h>
5567b76f 20
5567b76f
BJ
21char *index(), *rindex(), *malloc(), *getenv();
22struct passwd *getpwuid();
86a16a64 23char *name;
5567b76f
BJ
24int rem;
25char cmdchar = '~';
5567b76f
BJ
26int eight;
27char *speeds[] =
28 { "0", "50", "75", "110", "134", "150", "200", "300",
29 "600", "1200", "1800", "2400", "4800", "9600", "19200", "38400" };
86a16a64
SL
30char term[64] = "network";
31extern int errno;
32int lostpeer();
33
5567b76f
BJ
34main(argc, argv)
35 int argc;
36 char **argv;
37{
86a16a64 38 char *host, *cp;
5567b76f
BJ
39 struct sgttyb ttyb;
40 struct passwd *pwd;
86a16a64 41 struct servent *sp;
b5f23952 42 int uid, options = 0;
5567b76f
BJ
43
44 host = rindex(argv[0], '/');
45 if (host)
46 host++;
47 else
48 host = argv[0];
49 argv++, --argc;
50 if (!strcmp(host, "rlogin"))
51 host = *argv++, --argc;
52another:
4659bf8e 53 if (argc > 0 && !strcmp(*argv, "-d")) {
5567b76f 54 argv++, argc--;
b5f23952 55 options |= SO_DEBUG;
5567b76f
BJ
56 goto another;
57 }
4659bf8e 58 if (argc > 0 && !strcmp(*argv, "-l")) {
5567b76f
BJ
59 argv++, argc--;
60 if (argc == 0)
61 goto usage;
62 name = *argv++; argc--;
63 goto another;
64 }
4659bf8e 65 if (argc > 0 && !strncmp(*argv, "-e", 2)) {
5567b76f
BJ
66 cmdchar = argv[0][2];
67 argv++, argc--;
68 goto another;
69 }
4659bf8e 70 if (argc > 0 && !strcmp(*argv, "-8")) {
5567b76f
BJ
71 eight = 1;
72 argv++, argc--;
73 goto another;
74 }
75 if (host == 0)
76 goto usage;
77 if (argc > 0)
78 goto usage;
79 pwd = getpwuid(getuid());
80 if (pwd == 0) {
81 fprintf(stderr, "Who are you?\n");
82 exit(1);
83 }
86a16a64
SL
84 sp = getservbyname("login", "tcp");
85 if (sp == 0) {
86 fprintf(stderr, "rlogin: login/tcp: unknown service\n");
87 exit(2);
88 }
f91500bc
SL
89 cp = getenv("TERM");
90 if (cp)
91 strcpy(term, cp);
c64cdfb4 92 if (ioctl(0, TIOCGETP, &ttyb)==0) {
5567b76f
BJ
93 strcat(term, "/");
94 strcat(term, speeds[ttyb.sg_ospeed]);
95 }
4ca10280 96 signal(SIGPIPE, lostpeer);
86a16a64 97 rem = rcmd(&host, sp->s_port, pwd->pw_name,
5567b76f
BJ
98 name ? name : pwd->pw_name, term, 0);
99 if (rem < 0)
100 exit(1);
b5f23952
SL
101 if (options & SO_DEBUG &&
102 setsockopt(rem, SOL_SOCKET, SO_DEBUG, 0, 0) < 0)
103 perror("rlogin: setsockopt (SO_DEBUG)");
86a16a64
SL
104 uid = getuid();
105 if (setuid(uid) < 0) {
106 perror("rlogin: setuid");
107 exit(1);
108 }
109 doit();
110 /*NOTREACHED*/
5567b76f
BJ
111usage:
112 fprintf(stderr,
c887373b 113 "usage: rlogin host [ -ex ] [ -l username ] [ -8 ]\n");
5567b76f
BJ
114 exit(1);
115}
116
5567b76f 117#define CRLF "\r\n"
5567b76f 118
86a16a64 119int child;
33953861 120int catchild();
5567b76f 121
9da647e3
SL
122int defflags, tabflag;
123char deferase, defkill;
124struct tchars deftc;
125struct ltchars defltc;
126struct tchars notc = { -1, -1, -1, -1, -1, -1 };
127struct ltchars noltc = { -1, -1, -1, -1, -1, -1 };
86a16a64
SL
128
129doit()
5567b76f 130{
5567b76f 131 int exit();
9da647e3 132 struct sgttyb sb;
5567b76f 133
9da647e3
SL
134 ioctl(0, TIOCGETP, (char *)&sb);
135 defflags = sb.sg_flags;
c887373b 136 tabflag = defflags & TBDELAY;
c64cdfb4 137 defflags &= ECHO | CRMOD;
9da647e3
SL
138 deferase = sb.sg_erase;
139 defkill = sb.sg_kill;
140 ioctl(0, TIOCGETC, (char *)&deftc);
141 notc.t_startc = deftc.t_startc;
142 notc.t_stopc = deftc.t_stopc;
143 ioctl(0, TIOCGLTC, (char *)&defltc);
4ca10280
SL
144 signal(SIGINT, exit);
145 signal(SIGHUP, exit);
146 signal(SIGQUIT, exit);
86a16a64
SL
147 child = fork();
148 if (child == -1) {
149 perror("rlogin: fork");
150 done();
151 }
4ca10280 152 signal(SIGINT, SIG_IGN);
33953861 153 mode(1);
86a16a64 154 if (child == 0) {
86a16a64 155 reader();
c887373b
SL
156 sleep(1);
157 prf("\007Connection closed.");
5567b76f
BJ
158 exit(3);
159 }
4ca10280 160 signal(SIGCHLD, catchild);
86a16a64 161 writer();
c887373b 162 prf("Closed connection.");
5567b76f
BJ
163 done();
164}
165
166done()
167{
168
169 mode(0);
86a16a64
SL
170 if (child > 0 && kill(child, SIGKILL) >= 0)
171 wait((int *)0);
5567b76f
BJ
172 exit(0);
173}
174
33953861
EW
175catchild()
176{
177 union wait status;
178 int pid;
179
180again:
181 pid = wait3(&status, WNOHANG|WUNTRACED, 0);
182 if (pid == 0)
183 return;
184 /*
185 * if the child (reader) dies, just quit
186 */
187 if (pid < 0 || pid == child && !WIFSTOPPED(status))
188 done();
189 goto again;
190}
191
5567b76f 192/*
86a16a64
SL
193 * writer: write to remote: 0 -> line.
194 * ~. terminate
195 * ~^Z suspend rlogin process.
b5f23952 196 * ~^Y suspend rlogin process, but leave reader alone.
5567b76f 197 */
86a16a64 198writer()
5567b76f 199{
86a16a64
SL
200 char b[600], c;
201 register char *p;
33953861 202 register n;
5567b76f 203
86a16a64
SL
204top:
205 p = b;
33953861 206 for (;;) {
86a16a64 207 int local;
5567b76f 208
33953861
EW
209 n = read(0, &c, 1);
210 if (n == 0)
211 break;
212 if (n < 0)
213 if (errno == EINTR)
214 continue;
215 else
216 break;
217
86a16a64
SL
218 if (eight == 0)
219 c &= 0177;
220 /*
221 * If we're at the beginning of the line
222 * and recognize a command character, then
223 * we echo locally. Otherwise, characters
224 * are echo'd remotely. If the command
225 * character is doubled, this acts as a
226 * force and local echo is suppressed.
227 */
228 if (p == b)
229 local = (c == cmdchar);
230 if (p == b + 1 && *b == cmdchar)
231 local = (c != cmdchar);
232 if (!local) {
233 if (write(rem, &c, 1) == 0) {
234 prf("line gone");
235 return;
236 }
237 if (eight == 0)
238 c &= 0177;
239 } else {
86a16a64 240 if (c == '\r' || c == '\n') {
c64cdfb4 241 char cmdc = b[1];
86a16a64 242
9da647e3 243 if (cmdc == '.' || cmdc == deftc.t_eofc) {
86a16a64
SL
244 write(0, CRLF, sizeof(CRLF));
245 return;
c64cdfb4 246 }
9da647e3
SL
247 if (cmdc == defltc.t_suspc ||
248 cmdc == defltc.t_dsuspc) {
86a16a64
SL
249 write(0, CRLF, sizeof(CRLF));
250 mode(0);
4ca10280 251 signal(SIGCHLD, SIG_IGN);
9da647e3 252 kill(cmdc == defltc.t_suspc ?
c64cdfb4 253 0 : getpid(), SIGTSTP);
4ca10280 254 signal(SIGCHLD, catchild);
86a16a64
SL
255 mode(1);
256 goto top;
5567b76f 257 }
86a16a64
SL
258 *p++ = c;
259 write(rem, b, p - b);
260 goto top;
5567b76f 261 }
86a16a64 262 write(1, &c, 1);
5567b76f 263 }
86a16a64 264 *p++ = c;
9da647e3 265 if (c == deferase) {
86a16a64
SL
266 p -= 2;
267 if (p < b)
268 goto top;
5567b76f 269 }
9da647e3 270 if (c == defkill || c == deftc.t_eofc ||
86a16a64
SL
271 c == '\r' || c == '\n')
272 goto top;
33953861
EW
273 if (p >= &b[sizeof b])
274 p--;
5567b76f 275 }
5567b76f
BJ
276}
277
5567b76f
BJ
278oob()
279{
4659bf8e 280 int out = 1+1, atmark;
86a16a64 281 char waste[BUFSIZ], mark;
5567b76f 282
86a16a64 283 ioctl(1, TIOCFLUSH, (char *)&out);
5567b76f 284 for (;;) {
4659bf8e 285 if (ioctl(rem, SIOCATMARK, &atmark) < 0) {
5567b76f
BJ
286 perror("ioctl");
287 break;
288 }
4659bf8e 289 if (atmark)
5567b76f 290 break;
86a16a64 291 (void) read(rem, waste, sizeof (waste));
5567b76f 292 }
4ca10280 293 recv(rem, &mark, 1, MSG_OOB);
5567b76f 294 if (mark & TIOCPKT_NOSTOP) {
9da647e3
SL
295 notc.t_stopc = -1;
296 notc.t_startc = -1;
297 ioctl(0, TIOCSETC, (char *)&notc);
5567b76f
BJ
298 }
299 if (mark & TIOCPKT_DOSTOP) {
9da647e3
SL
300 notc.t_stopc = deftc.t_stopc;
301 notc.t_startc = deftc.t_startc;
302 ioctl(0, TIOCSETC, (char *)&notc);
5567b76f
BJ
303 }
304}
305
86a16a64
SL
306/*
307 * reader: read from remote: line -> 1
308 */
309reader()
5567b76f 310{
86a16a64
SL
311 char rb[BUFSIZ];
312 register int cnt;
5567b76f 313
4ca10280 314 signal(SIGURG, oob);
5567b76f 315 { int pid = -getpid();
86a16a64 316 ioctl(rem, SIOCSPGRP, (char *)&pid); }
5567b76f 317 for (;;) {
86a16a64 318 cnt = read(rem, rb, sizeof (rb));
3a21fb62
SL
319 if (cnt == 0)
320 break;
321 if (cnt < 0) {
86a16a64 322 if (errno == EINTR)
5567b76f 323 continue;
5567b76f
BJ
324 break;
325 }
86a16a64 326 write(1, rb, cnt);
5567b76f
BJ
327 }
328}
329
5567b76f
BJ
330mode(f)
331{
9da647e3
SL
332 struct tchars *tc;
333 struct ltchars *ltc;
334 struct sgttyb sb;
86a16a64 335
9da647e3 336 ioctl(0, TIOCGETP, (char *)&sb);
c64cdfb4
SL
337 switch (f) {
338
339 case 0:
9da647e3
SL
340 sb.sg_flags &= ~(CBREAK|RAW|TBDELAY);
341 sb.sg_flags |= defflags|tabflag;
c64cdfb4 342 tc = &deftc;
9da647e3
SL
343 ltc = &defltc;
344 sb.sg_kill = defkill;
345 sb.sg_erase = deferase;
c64cdfb4
SL
346 break;
347
348 case 1:
9da647e3
SL
349 sb.sg_flags |= (eight ? RAW : CBREAK);
350 sb.sg_flags &= ~defflags;
c887373b 351 /* preserve tab delays, but turn off XTABS */
9da647e3
SL
352 if ((sb.sg_flags & TBDELAY) == XTABS)
353 sb.sg_flags &= ~TBDELAY;
c64cdfb4 354 tc = &notc;
9da647e3
SL
355 ltc = &noltc;
356 sb.sg_kill = sb.sg_erase = -1;
c64cdfb4
SL
357 break;
358
359 default:
360 return;
5567b76f 361 }
9da647e3
SL
362 ioctl(0, TIOCSLTC, (char *)ltc);
363 ioctl(0, TIOCSETC, (char *)tc);
364 ioctl(0, TIOCSETN, (char *)&sb);
5567b76f
BJ
365}
366
86a16a64 367/*VARARGS*/
5567b76f 368prf(f, a1, a2, a3)
86a16a64 369 char *f;
5567b76f
BJ
370{
371 fprintf(stderr, f, a1, a2, a3);
372 fprintf(stderr, CRLF);
373}
374
86a16a64 375lostpeer()
5567b76f 376{
4ca10280 377 signal(SIGPIPE, SIG_IGN);
c887373b 378 prf("\007Connection closed.");
86a16a64 379 done();
5567b76f 380}