Commit | Line | Data |
---|---|---|
5567b76f | 1 | #ifndef lint |
0975b26d | 2 | static 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 |
21 | char *index(), *rindex(), *malloc(), *getenv(); |
22 | struct passwd *getpwuid(); | |
86a16a64 | 23 | char *name; |
5567b76f BJ |
24 | int rem; |
25 | char cmdchar = '~'; | |
5567b76f BJ |
26 | int eight; |
27 | char *speeds[] = | |
28 | { "0", "50", "75", "110", "134", "150", "200", "300", | |
29 | "600", "1200", "1800", "2400", "4800", "9600", "19200", "38400" }; | |
86a16a64 SL |
30 | char term[64] = "network"; |
31 | extern int errno; | |
32 | int lostpeer(); | |
33 | ||
5567b76f BJ |
34 | main(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; | |
53 | another: | |
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 |
112 | usage: |
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 | 120 | int child; |
33953861 | 121 | int catchild(); |
5567b76f | 122 | |
9da647e3 SL |
123 | int defflags, tabflag; |
124 | char deferase, defkill; | |
125 | struct tchars deftc; | |
126 | struct ltchars defltc; | |
127 | struct tchars notc = { -1, -1, -1, -1, -1, -1 }; | |
128 | struct ltchars noltc = { -1, -1, -1, -1, -1, -1 }; | |
86a16a64 SL |
129 | |
130 | doit() | |
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 | ||
167 | done() | |
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 |
176 | catchild() |
177 | { | |
178 | union wait status; | |
179 | int pid; | |
180 | ||
181 | again: | |
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 | 199 | writer() |
5567b76f | 200 | { |
86a16a64 SL |
201 | char b[600], c; |
202 | register char *p; | |
33953861 | 203 | register n; |
5567b76f | 204 | |
86a16a64 SL |
205 | top: |
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 |
279 | oob() |
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 *)¬c); | |
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 *)¬c); | |
5567b76f BJ |
304 | } |
305 | } | |
306 | ||
86a16a64 SL |
307 | /* |
308 | * reader: read from remote: line -> 1 | |
309 | */ | |
310 | reader() | |
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 |
331 | mode(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 = ¬c; |
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 | 369 | prf(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 | 376 | lostpeer() |
5567b76f | 377 | { |
4ca10280 | 378 | signal(SIGPIPE, SIG_IGN); |
c887373b | 379 | prf("\007Connection closed."); |
86a16a64 | 380 | done(); |
5567b76f | 381 | } |