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