Commit | Line | Data |
---|---|---|
5567b76f | 1 | #ifndef lint |
840fc587 | 2 | static 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 |
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; |
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; | |
52 | another: | |
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 |
111 | usage: |
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 | 119 | int child; |
33953861 | 120 | int catchild(); |
5567b76f | 121 | |
9da647e3 SL |
122 | int defflags, tabflag; |
123 | char deferase, defkill; | |
124 | struct tchars deftc; | |
125 | struct ltchars defltc; | |
126 | struct tchars notc = { -1, -1, -1, -1, -1, -1 }; | |
127 | struct ltchars noltc = { -1, -1, -1, -1, -1, -1 }; | |
86a16a64 SL |
128 | |
129 | doit() | |
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 | ||
166 | done() | |
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 |
175 | catchild() |
176 | { | |
177 | union wait status; | |
178 | int pid; | |
179 | ||
180 | again: | |
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 | 198 | writer() |
5567b76f | 199 | { |
86a16a64 SL |
200 | char b[600], c; |
201 | register char *p; | |
33953861 | 202 | register n; |
5567b76f | 203 | |
86a16a64 SL |
204 | top: |
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 |
278 | oob() |
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 *)¬c); | |
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 *)¬c); | |
5567b76f BJ |
303 | } |
304 | } | |
305 | ||
86a16a64 SL |
306 | /* |
307 | * reader: read from remote: line -> 1 | |
308 | */ | |
309 | reader() | |
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 |
330 | mode(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 = ¬c; |
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 | 368 | prf(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 | 375 | lostpeer() |
5567b76f | 376 | { |
4ca10280 | 377 | signal(SIGPIPE, SIG_IGN); |
c887373b | 378 | prf("\007Connection closed."); |
86a16a64 | 379 | done(); |
5567b76f | 380 | } |