Commit | Line | Data |
---|---|---|
66dc50f6 | 1 | /* |
17f00b96 KB |
2 | * Copyright (c) 1983, 1990, 1993 |
3 | * The Regents of the University of California. All rights reserved. | |
438b541c | 4 | * |
86dc635c | 5 | * %sccs.include.redist.c% |
f42904bc DF |
6 | */ |
7 | ||
8 | #ifndef lint | |
17f00b96 KB |
9 | static char copyright[] = |
10 | "@(#) Copyright (c) 1983, 1990, 1993\n\ | |
11 | The Regents of the University of California. All rights reserved.\n"; | |
438b541c | 12 | #endif /* not lint */ |
f42904bc | 13 | |
5567b76f | 14 | #ifndef lint |
17f00b96 | 15 | static char sccsid[] = "@(#)rlogin.c 8.1 (Berkeley) %G%"; |
438b541c | 16 | #endif /* not lint */ |
5567b76f | 17 | |
4ca10280 SL |
18 | /* |
19 | * rlogin - remote login | |
20 | */ | |
545e8847 | 21 | #include <sys/param.h> |
5567b76f | 22 | #include <sys/socket.h> |
a9b12987 KM |
23 | #include <sys/time.h> |
24 | #include <sys/resource.h> | |
840fc587 | 25 | #include <sys/wait.h> |
86a16a64 | 26 | |
c6c678f1 | 27 | #include <netinet/in.h> |
66dc50f6 MK |
28 | #include <netinet/in_systm.h> |
29 | #include <netinet/ip.h> | |
86a16a64 | 30 | |
999d0d08 | 31 | #include <errno.h> |
e113d331 KB |
32 | #include <fcntl.h> |
33 | #include <netdb.h> | |
5567b76f | 34 | #include <pwd.h> |
e113d331 KB |
35 | #include <setjmp.h> |
36 | #include <sgtty.h> | |
37 | #include <signal.h> | |
afe1e594 | 38 | #include <stdio.h> |
e113d331 | 39 | #include <stdlib.h> |
38dde0cd | 40 | #include <string.h> |
e113d331 | 41 | #include <unistd.h> |
e86d8e67 | 42 | |
bbd924bb KB |
43 | #ifdef __STDC__ |
44 | #include <stdarg.h> | |
45 | #else | |
46 | #include <varargs.h> | |
47 | #endif | |
48 | ||
afe1e594 | 49 | #ifdef KERBEROS |
4f10ae0d | 50 | #include <kerberosIV/des.h> |
63fc53d2 | 51 | #include <kerberosIV/krb.h> |
afe1e594 | 52 | |
e113d331 KB |
53 | #include "krb.h" |
54 | ||
afe1e594 KB |
55 | CREDENTIALS cred; |
56 | Key_schedule schedule; | |
cae07225 | 57 | int use_kerberos = 1, doencrypt; |
afe1e594 | 58 | char dst_realm_buf[REALM_SZ], *dest_realm = NULL; |
afe1e594 KB |
59 | #endif |
60 | ||
61 | #ifndef TIOCPKT_WINDOW | |
62 | #define TIOCPKT_WINDOW 0x80 | |
63 | #endif | |
64 | ||
65 | /* concession to Sun */ | |
66 | #ifndef SIGUSR1 | |
67 | #define SIGUSR1 30 | |
545e8847 | 68 | #endif |
afe1e594 | 69 | |
afe1e594 | 70 | int eight, litout, rem; |
999d0d08 KB |
71 | |
72 | int noescape; | |
73 | u_char escapechar = '~'; | |
74 | ||
afe1e594 KB |
75 | char *speeds[] = { |
76 | "0", "50", "75", "110", "134", "150", "200", "300", "600", "1200", | |
77 | "1800", "2400", "4800", "9600", "19200", "38400" | |
78 | }; | |
79 | ||
5f8f5f64 | 80 | #ifdef OLDSUN |
545e8847 MK |
81 | struct winsize { |
82 | unsigned short ws_row, ws_col; | |
83 | unsigned short ws_xpixel, ws_ypixel; | |
84 | }; | |
e113d331 KB |
85 | #else |
86 | #define get_window_size(fd, wp) ioctl(fd, TIOCGWINSZ, wp) | |
afe1e594 | 87 | #endif |
a9b12987 | 88 | struct winsize winsize; |
86a16a64 | 89 | |
e113d331 KB |
90 | void catch_child __P((int)); |
91 | void copytochild __P((int)); | |
92 | __dead void doit __P((long)); | |
93 | __dead void done __P((int)); | |
94 | void echo __P((char)); | |
95 | u_int getescape __P((char *)); | |
96 | void lostpeer __P((int)); | |
97 | void mode __P((int)); | |
98 | void msg __P((char *)); | |
99 | void oob __P((int)); | |
100 | int reader __P((int)); | |
101 | void sendwindow __P((void)); | |
102 | void setsignal __P((int)); | |
103 | void sigwinch __P((int)); | |
104 | void stop __P((char)); | |
105 | __dead void usage __P((void)); | |
106 | void writer __P((void)); | |
107 | void writeroob __P((int)); | |
108 | ||
109 | #ifdef KERBEROS | |
110 | void warning __P((const char *, ...)); | |
111 | #endif | |
5f8f5f64 | 112 | #ifdef OLDSUN |
e113d331 | 113 | int get_window_size __P((int, struct winsize *)); |
afe1e594 | 114 | #endif |
a9b12987 | 115 | |
e113d331 | 116 | int |
5567b76f BJ |
117 | main(argc, argv) |
118 | int argc; | |
e113d331 | 119 | char *argv[]; |
5567b76f | 120 | { |
afe1e594 KB |
121 | extern char *optarg; |
122 | extern int optind; | |
123 | struct passwd *pw; | |
86a16a64 | 124 | struct servent *sp; |
afe1e594 KB |
125 | struct sgttyb ttyb; |
126 | long omask; | |
127 | int argoff, ch, dflag, one, uid; | |
128 | char *host, *p, *user, term[1024]; | |
afe1e594 KB |
129 | |
130 | argoff = dflag = 0; | |
131 | one = 1; | |
132 | host = user = NULL; | |
afe1e594 KB |
133 | |
134 | if (p = rindex(argv[0], '/')) | |
135 | ++p; | |
5567b76f | 136 | else |
afe1e594 KB |
137 | p = argv[0]; |
138 | ||
139 | if (strcmp(p, "rlogin")) | |
140 | host = p; | |
0b6d50a1 | 141 | |
afe1e594 KB |
142 | /* handle "rlogin host flags" */ |
143 | if (!host && argc > 2 && argv[1][0] != '-') { | |
144 | host = argv[1]; | |
145 | argoff = 1; | |
0b6d50a1 | 146 | } |
afe1e594 KB |
147 | |
148 | #ifdef KERBEROS | |
999d0d08 | 149 | #define OPTIONS "8EKLde:k:l:x" |
afe1e594 | 150 | #else |
999d0d08 | 151 | #define OPTIONS "8EKLde:l:" |
afe1e594 KB |
152 | #endif |
153 | while ((ch = getopt(argc - argoff, argv + argoff, OPTIONS)) != EOF) | |
154 | switch(ch) { | |
155 | case '8': | |
156 | eight = 1; | |
157 | break; | |
999d0d08 KB |
158 | case 'E': |
159 | noescape = 1; | |
160 | break; | |
0783ed7b KB |
161 | case 'K': |
162 | #ifdef KERBEROS | |
163 | use_kerberos = 0; | |
164 | #endif | |
165 | break; | |
afe1e594 KB |
166 | case 'L': |
167 | litout = 1; | |
168 | break; | |
169 | case 'd': | |
170 | dflag = 1; | |
171 | break; | |
172 | case 'e': | |
888732ab | 173 | noescape = 0; |
999d0d08 | 174 | escapechar = getescape(optarg); |
afe1e594 KB |
175 | break; |
176 | #ifdef KERBEROS | |
177 | case 'k': | |
178 | dest_realm = dst_realm_buf; | |
179 | (void)strncpy(dest_realm, optarg, REALM_SZ); | |
180 | break; | |
181 | #endif | |
182 | case 'l': | |
183 | user = optarg; | |
184 | break; | |
afe1e594 KB |
185 | case '?': |
186 | default: | |
187 | usage(); | |
52bf4a7f | 188 | } |
afe1e594 KB |
189 | optind += argoff; |
190 | argc -= optind; | |
191 | argv += optind; | |
52bf4a7f | 192 | |
afe1e594 KB |
193 | /* if haven't gotten a host yet, do so */ |
194 | if (!host && !(host = *argv++)) | |
195 | usage(); | |
0b6d50a1 | 196 | |
afe1e594 KB |
197 | if (*argv) |
198 | usage(); | |
199 | ||
200 | if (!(pw = getpwuid(uid = getuid()))) { | |
201 | (void)fprintf(stderr, "rlogin: unknown user id.\n"); | |
5567b76f BJ |
202 | exit(1); |
203 | } | |
afe1e594 KB |
204 | if (!user) |
205 | user = pw->pw_name; | |
206 | ||
0783ed7b | 207 | sp = NULL; |
afe1e594 | 208 | #ifdef KERBEROS |
0783ed7b | 209 | if (use_kerberos) { |
cae07225 | 210 | sp = getservbyname((doencrypt ? "eklogin" : "klogin"), "tcp"); |
0783ed7b KB |
211 | if (sp == NULL) { |
212 | use_kerberos = 0; | |
213 | warning("can't get entry for %s/tcp service", | |
cae07225 | 214 | doencrypt ? "eklogin" : "klogin"); |
0783ed7b | 215 | } |
028330cc | 216 | } |
028330cc | 217 | #endif |
0783ed7b KB |
218 | if (sp == NULL) |
219 | sp = getservbyname("login", "tcp"); | |
afe1e594 KB |
220 | if (sp == NULL) { |
221 | (void)fprintf(stderr, "rlogin: login/tcp: unknown service.\n"); | |
222 | exit(1); | |
86a16a64 | 223 | } |
afe1e594 KB |
224 | |
225 | (void)strcpy(term, (p = getenv("TERM")) ? p : "network"); | |
119312d1 | 226 | if (ioctl(0, TIOCGETP, &ttyb) == 0) { |
afe1e594 | 227 | (void)strcat(term, "/"); |
e113d331 | 228 | (void)strcat(term, speeds[(int)ttyb.sg_ospeed]); |
5567b76f | 229 | } |
afe1e594 KB |
230 | |
231 | (void)get_window_size(0, &winsize); | |
232 | ||
233 | (void)signal(SIGPIPE, lostpeer); | |
a9b12987 | 234 | /* will use SIGUSR1 for window size hack, so hold it off */ |
afe1e594 | 235 | omask = sigblock(sigmask(SIGURG) | sigmask(SIGUSR1)); |
9bccbd7c KM |
236 | /* |
237 | * We set SIGURG and SIGUSR1 below so that an | |
238 | * incoming signal will be held pending rather than being | |
239 | * discarded. Note that these routines will be ready to get | |
240 | * a signal by the time that they are unblocked below. | |
241 | */ | |
242 | (void)signal(SIGURG, copytochild); | |
243 | (void)signal(SIGUSR1, writeroob); | |
0b6d50a1 | 244 | |
afe1e594 | 245 | #ifdef KERBEROS |
028330cc | 246 | try_connect: |
afe1e594 | 247 | if (use_kerberos) { |
e113d331 KB |
248 | struct hostent *hp; |
249 | ||
250 | /* Fully qualify hostname (needed for krb_realmofhost). */ | |
05d73ecb EA |
251 | hp = gethostbyname(host); |
252 | if (hp != NULL && !(host = strdup(hp->h_name))) { | |
e113d331 KB |
253 | (void)fprintf(stderr, "rlogin: %s\n", |
254 | strerror(ENOMEM)); | |
05d73ecb EA |
255 | exit(1); |
256 | } | |
257 | ||
028330cc | 258 | rem = KSUCCESS; |
afe1e594 | 259 | errno = 0; |
e0817634 KF |
260 | if (dest_realm == NULL) |
261 | dest_realm = krb_realmofhost(host); | |
262 | ||
afe1e594 KB |
263 | rem = krcmd(&host, sp->s_port, user, term, 0, |
264 | dest_realm); | |
e0817634 | 265 | if (rem < 0) { |
028330cc | 266 | use_kerberos = 0; |
c458f00a | 267 | sp = getservbyname("login", "tcp"); |
afe1e594 KB |
268 | if (sp == NULL) { |
269 | (void)fprintf(stderr, | |
270 | "rlogin: unknown service login/tcp.\n"); | |
c458f00a KF |
271 | exit(1); |
272 | } | |
e0817634 | 273 | if (errno == ECONNREFUSED) |
afe1e594 | 274 | warning("remote host doesn't support Kerberos"); |
e0817634 | 275 | if (errno == ENOENT) |
afe1e594 | 276 | warning("can't provide Kerberos auth data"); |
028330cc | 277 | goto try_connect; |
0b6d50a1 KF |
278 | } |
279 | } else { | |
afe1e594 | 280 | rem = rcmd(&host, sp->s_port, pw->pw_name, user, term, 0); |
0b6d50a1 | 281 | } |
028330cc | 282 | #else |
afe1e594 | 283 | rem = rcmd(&host, sp->s_port, pw->pw_name, user, term, 0); |
8293b217 | 284 | #endif /* KERBEROS */ |
0b6d50a1 | 285 | |
afe1e594 | 286 | if (rem < 0) |
0b6d50a1 KF |
287 | exit(1); |
288 | ||
afe1e594 KB |
289 | if (dflag && |
290 | setsockopt(rem, SOL_SOCKET, SO_DEBUG, &one, sizeof(one)) < 0) | |
291 | (void)fprintf(stderr, "rlogin: setsockopt: %s.\n", | |
292 | strerror(errno)); | |
66dc50f6 MK |
293 | one = IPTOS_LOWDELAY; |
294 | if (setsockopt(rem, IPPROTO_IP, IP_TOS, (char *)&one, sizeof(int)) < 0) | |
295 | perror("rlogin: setsockopt TOS (ignored)"); | |
afe1e594 KB |
296 | |
297 | (void)setuid(uid); | |
298 | doit(omask); | |
86a16a64 | 299 | /*NOTREACHED*/ |
5567b76f BJ |
300 | } |
301 | ||
afe1e594 KB |
302 | int child, defflags, deflflags, tabflag; |
303 | char deferase, defkill; | |
304 | struct tchars deftc; | |
305 | struct ltchars defltc; | |
306 | struct tchars notc = { -1, -1, -1, -1, -1, -1 }; | |
307 | struct ltchars noltc = { -1, -1, -1, -1, -1, -1 }; | |
86a16a64 | 308 | |
e113d331 | 309 | void |
afe1e594 KB |
310 | doit(omask) |
311 | long omask; | |
5567b76f | 312 | { |
9da647e3 | 313 | struct sgttyb sb; |
5567b76f | 314 | |
afe1e594 | 315 | (void)ioctl(0, TIOCGETP, (char *)&sb); |
9da647e3 | 316 | defflags = sb.sg_flags; |
c887373b | 317 | tabflag = defflags & TBDELAY; |
c64cdfb4 | 318 | defflags &= ECHO | CRMOD; |
9da647e3 SL |
319 | deferase = sb.sg_erase; |
320 | defkill = sb.sg_kill; | |
e113d331 KB |
321 | (void)ioctl(0, TIOCLGET, &deflflags); |
322 | (void)ioctl(0, TIOCGETC, &deftc); | |
9da647e3 SL |
323 | notc.t_startc = deftc.t_startc; |
324 | notc.t_stopc = deftc.t_stopc; | |
e113d331 | 325 | (void)ioctl(0, TIOCGLTC, &defltc); |
afe1e594 | 326 | (void)signal(SIGINT, SIG_IGN); |
e113d331 KB |
327 | setsignal(SIGHUP); |
328 | setsignal(SIGQUIT); | |
86a16a64 SL |
329 | child = fork(); |
330 | if (child == -1) { | |
afe1e594 | 331 | (void)fprintf(stderr, "rlogin: fork: %s.\n", strerror(errno)); |
c3140eff | 332 | done(1); |
86a16a64 | 333 | } |
86a16a64 | 334 | if (child == 0) { |
e86d8e67 | 335 | mode(1); |
afe1e594 KB |
336 | if (reader(omask) == 0) { |
337 | msg("connection closed."); | |
c3140eff MK |
338 | exit(0); |
339 | } | |
c887373b | 340 | sleep(1); |
afe1e594 KB |
341 | msg("\007connection closed."); |
342 | exit(1); | |
5567b76f | 343 | } |
a9b12987 KM |
344 | |
345 | /* | |
afe1e594 | 346 | * We may still own the socket, and may have a pending SIGURG (or might |
9bccbd7c KM |
347 | * receive one soon) that we really want to send to the reader. When |
348 | * one of these comes in, the trap copytochild simply copies such | |
349 | * signals to the child. We can now unblock SIGURG and SIGUSR1 | |
350 | * that were set above. | |
a9b12987 | 351 | */ |
afe1e594 KB |
352 | (void)sigsetmask(omask); |
353 | (void)signal(SIGCHLD, catch_child); | |
86a16a64 | 354 | writer(); |
afe1e594 | 355 | msg("closed connection."); |
c3140eff | 356 | done(0); |
5567b76f BJ |
357 | } |
358 | ||
afe1e594 | 359 | /* trap a signal, unless it is being ignored. */ |
e113d331 KB |
360 | void |
361 | setsignal(sig) | |
afe1e594 | 362 | int sig; |
a9b12987 KM |
363 | { |
364 | int omask = sigblock(sigmask(sig)); | |
365 | ||
e113d331 | 366 | if (signal(sig, exit) == SIG_IGN) |
afe1e594 KB |
367 | (void)signal(sig, SIG_IGN); |
368 | (void)sigsetmask(omask); | |
a9b12987 KM |
369 | } |
370 | ||
e113d331 | 371 | __dead void |
c3140eff MK |
372 | done(status) |
373 | int status; | |
5567b76f | 374 | { |
cae07225 | 375 | int w, wstatus; |
5567b76f BJ |
376 | |
377 | mode(0); | |
a9b12987 | 378 | if (child > 0) { |
afe1e594 KB |
379 | /* make sure catch_child does not snap it up */ |
380 | (void)signal(SIGCHLD, SIG_DFL); | |
a9b12987 | 381 | if (kill(child, SIGKILL) >= 0) |
cae07225 | 382 | while ((w = wait(&wstatus)) > 0 && w != child); |
a9b12987 | 383 | } |
c3140eff | 384 | exit(status); |
5567b76f BJ |
385 | } |
386 | ||
afe1e594 | 387 | int dosigwinch; |
a9b12987 | 388 | |
e86d8e67 KM |
389 | /* |
390 | * This is called when the reader process gets the out-of-band (urgent) | |
391 | * request to turn on the window-changing protocol. | |
392 | */ | |
afe1e594 | 393 | void |
e113d331 KB |
394 | writeroob(signo) |
395 | int signo; | |
e86d8e67 | 396 | { |
ffc36ece | 397 | if (dosigwinch == 0) { |
bedc18e4 | 398 | sendwindow(); |
afe1e594 | 399 | (void)signal(SIGWINCH, sigwinch); |
ffc36ece | 400 | } |
e86d8e67 | 401 | dosigwinch = 1; |
e86d8e67 KM |
402 | } |
403 | ||
afe1e594 | 404 | void |
e113d331 KB |
405 | catch_child(signo) |
406 | int signo; | |
33953861 EW |
407 | { |
408 | union wait status; | |
409 | int pid; | |
410 | ||
afe1e594 | 411 | for (;;) { |
47820fac | 412 | pid = wait3((int *)&status, WNOHANG|WUNTRACED, NULL); |
afe1e594 KB |
413 | if (pid == 0) |
414 | return; | |
415 | /* if the child (reader) dies, just quit */ | |
e113d331 | 416 | if (pid < 0 || (pid == child && !WIFSTOPPED(status))) |
afe1e594 KB |
417 | done((int)(status.w_termsig | status.w_retcode)); |
418 | } | |
419 | /* NOTREACHED */ | |
33953861 EW |
420 | } |
421 | ||
5567b76f | 422 | /* |
86a16a64 | 423 | * writer: write to remote: 0 -> line. |
999d0d08 KB |
424 | * ~. terminate |
425 | * ~^Z suspend rlogin process. | |
426 | * ~<delayed-suspend char> suspend rlogin process, but leave reader alone. | |
5567b76f | 427 | */ |
e113d331 | 428 | void |
86a16a64 | 429 | writer() |
5567b76f | 430 | { |
afe1e594 | 431 | register int bol, local, n; |
999d0d08 | 432 | char c; |
5567b76f | 433 | |
afe1e594 KB |
434 | bol = 1; /* beginning of line */ |
435 | local = 0; | |
4d3ce186 | 436 | for (;;) { |
afe1e594 | 437 | n = read(STDIN_FILENO, &c, 1); |
119312d1 SL |
438 | if (n <= 0) { |
439 | if (n < 0 && errno == EINTR) | |
33953861 | 440 | continue; |
119312d1 SL |
441 | break; |
442 | } | |
86a16a64 | 443 | /* |
afe1e594 KB |
444 | * If we're at the beginning of the line and recognize a |
445 | * command character, then we echo locally. Otherwise, | |
446 | * characters are echo'd remotely. If the command character | |
447 | * is doubled, this acts as a force and local echo is | |
448 | * suppressed. | |
86a16a64 | 449 | */ |
4d3ce186 JB |
450 | if (bol) { |
451 | bol = 0; | |
999d0d08 | 452 | if (!noescape && c == escapechar) { |
4d3ce186 JB |
453 | local = 1; |
454 | continue; | |
86a16a64 | 455 | } |
4d3ce186 JB |
456 | } else if (local) { |
457 | local = 0; | |
458 | if (c == '.' || c == deftc.t_eofc) { | |
459 | echo(c); | |
460 | break; | |
461 | } | |
462 | if (c == defltc.t_suspc || c == defltc.t_dsuspc) { | |
463 | bol = 1; | |
464 | echo(c); | |
465 | stop(c); | |
466 | continue; | |
5567b76f | 467 | } |
999d0d08 | 468 | if (c != escapechar) |
999d0d08 | 469 | (void)write(rem, &escapechar, 1); |
5567b76f | 470 | } |
0b6d50a1 | 471 | |
0b6d50a1 | 472 | if (write(rem, &c, 1) == 0) { |
afe1e594 | 473 | msg("line gone"); |
0b6d50a1 KF |
474 | break; |
475 | } | |
4d3ce186 | 476 | bol = c == defkill || c == deftc.t_eofc || |
c3140eff | 477 | c == deftc.t_intrc || c == defltc.t_suspc || |
4d3ce186 | 478 | c == '\r' || c == '\n'; |
119312d1 SL |
479 | } |
480 | } | |
481 | ||
e113d331 KB |
482 | void |
483 | #if __STDC__ | |
484 | echo(register char c) | |
485 | #else | |
4d3ce186 | 486 | echo(c) |
e113d331 KB |
487 | register char c; |
488 | #endif | |
4d3ce186 | 489 | { |
afe1e594 | 490 | register char *p; |
4d3ce186 | 491 | char buf[8]; |
4d3ce186 | 492 | |
afe1e594 | 493 | p = buf; |
4d3ce186 | 494 | c &= 0177; |
999d0d08 | 495 | *p++ = escapechar; |
4d3ce186 JB |
496 | if (c < ' ') { |
497 | *p++ = '^'; | |
498 | *p++ = c + '@'; | |
499 | } else if (c == 0177) { | |
500 | *p++ = '^'; | |
501 | *p++ = '?'; | |
502 | } else | |
503 | *p++ = c; | |
504 | *p++ = '\r'; | |
505 | *p++ = '\n'; | |
999d0d08 | 506 | (void)write(STDOUT_FILENO, buf, p - buf); |
4d3ce186 JB |
507 | } |
508 | ||
e113d331 KB |
509 | void |
510 | #if __STDC__ | |
511 | stop(char cmdc) | |
512 | #else | |
119312d1 SL |
513 | stop(cmdc) |
514 | char cmdc; | |
e113d331 | 515 | #endif |
119312d1 | 516 | { |
119312d1 | 517 | mode(0); |
afe1e594 KB |
518 | (void)signal(SIGCHLD, SIG_IGN); |
519 | (void)kill(cmdc == defltc.t_suspc ? 0 : getpid(), SIGTSTP); | |
520 | (void)signal(SIGCHLD, catch_child); | |
119312d1 | 521 | mode(1); |
e113d331 | 522 | sigwinch(0); /* check for size changes */ |
119312d1 SL |
523 | } |
524 | ||
afe1e594 | 525 | void |
e113d331 KB |
526 | sigwinch(signo) |
527 | int signo; | |
119312d1 SL |
528 | { |
529 | struct winsize ws; | |
530 | ||
a9b12987 | 531 | if (dosigwinch && get_window_size(0, &ws) == 0 && |
afe1e594 | 532 | bcmp(&ws, &winsize, sizeof(ws))) { |
119312d1 | 533 | winsize = ws; |
e86d8e67 | 534 | sendwindow(); |
5567b76f | 535 | } |
5567b76f BJ |
536 | } |
537 | ||
e86d8e67 KM |
538 | /* |
539 | * Send the window size to the server via the magic escape | |
540 | */ | |
e113d331 | 541 | void |
e86d8e67 KM |
542 | sendwindow() |
543 | { | |
afe1e594 | 544 | struct winsize *wp; |
e86d8e67 | 545 | char obuf[4 + sizeof (struct winsize)]; |
e86d8e67 | 546 | |
afe1e594 | 547 | wp = (struct winsize *)(obuf+4); |
e86d8e67 KM |
548 | obuf[0] = 0377; |
549 | obuf[1] = 0377; | |
550 | obuf[2] = 's'; | |
551 | obuf[3] = 's'; | |
552 | wp->ws_row = htons(winsize.ws_row); | |
553 | wp->ws_col = htons(winsize.ws_col); | |
554 | wp->ws_xpixel = htons(winsize.ws_xpixel); | |
555 | wp->ws_ypixel = htons(winsize.ws_ypixel); | |
0b6d50a1 | 556 | |
afe1e594 | 557 | (void)write(rem, obuf, sizeof(obuf)); |
e86d8e67 KM |
558 | } |
559 | ||
c3140eff MK |
560 | /* |
561 | * reader: read from remote: line -> 1 | |
562 | */ | |
563 | #define READING 1 | |
564 | #define WRITING 2 | |
565 | ||
afe1e594 KB |
566 | jmp_buf rcvtop; |
567 | int ppid, rcvcnt, rcvstate; | |
568 | char rcvbuf[8 * 1024]; | |
c3140eff | 569 | |
afe1e594 | 570 | void |
e113d331 KB |
571 | oob(signo) |
572 | int signo; | |
5567b76f | 573 | { |
e86d8e67 | 574 | struct sgttyb sb; |
afe1e594 KB |
575 | int atmark, n, out, rcvd; |
576 | char waste[BUFSIZ], mark; | |
5567b76f | 577 | |
ce27669d | 578 | out = O_RDWR; |
afe1e594 | 579 | rcvd = 0; |
5f8f5f64 | 580 | while (recv(rem, &mark, 1, MSG_OOB) < 0) { |
c3140eff | 581 | switch (errno) { |
c3140eff MK |
582 | case EWOULDBLOCK: |
583 | /* | |
afe1e594 KB |
584 | * Urgent data not here yet. It may not be possible |
585 | * to send it yet if we are blocked for output and | |
586 | * our input buffer is full. | |
c3140eff MK |
587 | */ |
588 | if (rcvcnt < sizeof(rcvbuf)) { | |
589 | n = read(rem, rcvbuf + rcvcnt, | |
afe1e594 | 590 | sizeof(rcvbuf) - rcvcnt); |
c3140eff MK |
591 | if (n <= 0) |
592 | return; | |
593 | rcvd += n; | |
594 | } else { | |
595 | n = read(rem, waste, sizeof(waste)); | |
596 | if (n <= 0) | |
597 | return; | |
598 | } | |
599 | continue; | |
c3140eff MK |
600 | default: |
601 | return; | |
5f8f5f64 | 602 | } |
5567b76f | 603 | } |
c3140eff | 604 | if (mark & TIOCPKT_WINDOW) { |
afe1e594 KB |
605 | /* Let server know about window size changes */ |
606 | (void)kill(ppid, SIGUSR1); | |
e86d8e67 | 607 | } |
c3140eff | 608 | if (!eight && (mark & TIOCPKT_NOSTOP)) { |
afe1e594 | 609 | (void)ioctl(0, TIOCGETP, (char *)&sb); |
e86d8e67 KM |
610 | sb.sg_flags &= ~CBREAK; |
611 | sb.sg_flags |= RAW; | |
afe1e594 | 612 | (void)ioctl(0, TIOCSETN, (char *)&sb); |
9da647e3 SL |
613 | notc.t_stopc = -1; |
614 | notc.t_startc = -1; | |
afe1e594 | 615 | (void)ioctl(0, TIOCSETC, (char *)¬c); |
5567b76f | 616 | } |
c3140eff | 617 | if (!eight && (mark & TIOCPKT_DOSTOP)) { |
afe1e594 | 618 | (void)ioctl(0, TIOCGETP, (char *)&sb); |
e86d8e67 KM |
619 | sb.sg_flags &= ~RAW; |
620 | sb.sg_flags |= CBREAK; | |
afe1e594 | 621 | (void)ioctl(0, TIOCSETN, (char *)&sb); |
9da647e3 SL |
622 | notc.t_stopc = deftc.t_stopc; |
623 | notc.t_startc = deftc.t_startc; | |
afe1e594 | 624 | (void)ioctl(0, TIOCSETC, (char *)¬c); |
5567b76f | 625 | } |
c3140eff | 626 | if (mark & TIOCPKT_FLUSHWRITE) { |
afe1e594 | 627 | (void)ioctl(1, TIOCFLUSH, (char *)&out); |
c3140eff MK |
628 | for (;;) { |
629 | if (ioctl(rem, SIOCATMARK, &atmark) < 0) { | |
afe1e594 KB |
630 | (void)fprintf(stderr, "rlogin: ioctl: %s.\n", |
631 | strerror(errno)); | |
c3140eff MK |
632 | break; |
633 | } | |
634 | if (atmark) | |
635 | break; | |
636 | n = read(rem, waste, sizeof (waste)); | |
637 | if (n <= 0) | |
638 | break; | |
639 | } | |
640 | /* | |
afe1e594 KB |
641 | * Don't want any pending data to be output, so clear the recv |
642 | * buffer. If we were hanging on a write when interrupted, | |
643 | * don't want it to restart. If we were reading, restart | |
644 | * anyway. | |
c3140eff MK |
645 | */ |
646 | rcvcnt = 0; | |
647 | longjmp(rcvtop, 1); | |
648 | } | |
a9b12987 | 649 | |
afe1e594 | 650 | /* oob does not do FLUSHREAD (alas!) */ |
a9b12987 | 651 | |
c3140eff | 652 | /* |
afe1e594 KB |
653 | * If we filled the receive buffer while a read was pending, longjmp |
654 | * to the top to restart appropriately. Don't abort a pending write, | |
655 | * however, or we won't know how much was written. | |
c3140eff MK |
656 | */ |
657 | if (rcvd && rcvstate == READING) | |
658 | longjmp(rcvtop, 1); | |
5567b76f BJ |
659 | } |
660 | ||
afe1e594 | 661 | /* reader: read from remote: line -> 1 */ |
e113d331 | 662 | int |
afe1e594 KB |
663 | reader(omask) |
664 | int omask; | |
5567b76f | 665 | { |
5f8f5f64 CT |
666 | int pid, n, remaining; |
667 | char *bufp; | |
afe1e594 | 668 | |
5f8f5f64 CT |
669 | #if BSD >= 43 || defined(SUNOS4) |
670 | pid = getpid(); /* modern systems use positives for pid */ | |
545e8847 | 671 | #else |
5f8f5f64 | 672 | pid = -getpid(); /* old broken systems use negatives */ |
545e8847 | 673 | #endif |
afe1e594 KB |
674 | (void)signal(SIGTTOU, SIG_IGN); |
675 | (void)signal(SIGURG, oob); | |
545e8847 | 676 | ppid = getppid(); |
afe1e594 KB |
677 | (void)fcntl(rem, F_SETOWN, pid); |
678 | (void)setjmp(rcvtop); | |
679 | (void)sigsetmask(omask); | |
5f8f5f64 | 680 | bufp = rcvbuf; |
5567b76f | 681 | for (;;) { |
c3140eff MK |
682 | while ((remaining = rcvcnt - (bufp - rcvbuf)) > 0) { |
683 | rcvstate = WRITING; | |
999d0d08 | 684 | n = write(STDOUT_FILENO, bufp, remaining); |
c3140eff MK |
685 | if (n < 0) { |
686 | if (errno != EINTR) | |
e113d331 | 687 | return (-1); |
c3140eff MK |
688 | continue; |
689 | } | |
690 | bufp += n; | |
691 | } | |
692 | bufp = rcvbuf; | |
693 | rcvcnt = 0; | |
694 | rcvstate = READING; | |
0b6d50a1 | 695 | |
0b6d50a1 | 696 | rcvcnt = read(rem, rcvbuf, sizeof (rcvbuf)); |
c3140eff MK |
697 | if (rcvcnt == 0) |
698 | return (0); | |
699 | if (rcvcnt < 0) { | |
86a16a64 | 700 | if (errno == EINTR) |
5567b76f | 701 | continue; |
afe1e594 KB |
702 | (void)fprintf(stderr, "rlogin: read: %s.\n", |
703 | strerror(errno)); | |
e113d331 | 704 | return (-1); |
5567b76f | 705 | } |
5567b76f BJ |
706 | } |
707 | } | |
708 | ||
e113d331 | 709 | void |
5567b76f | 710 | mode(f) |
e113d331 | 711 | int f; |
5567b76f | 712 | { |
9da647e3 SL |
713 | struct ltchars *ltc; |
714 | struct sgttyb sb; | |
afe1e594 KB |
715 | struct tchars *tc; |
716 | int lflags; | |
c64cdfb4 | 717 | |
afe1e594 KB |
718 | (void)ioctl(0, TIOCGETP, (char *)&sb); |
719 | (void)ioctl(0, TIOCLGET, (char *)&lflags); | |
720 | switch(f) { | |
c64cdfb4 | 721 | case 0: |
9da647e3 SL |
722 | sb.sg_flags &= ~(CBREAK|RAW|TBDELAY); |
723 | sb.sg_flags |= defflags|tabflag; | |
c64cdfb4 | 724 | tc = &deftc; |
9da647e3 SL |
725 | ltc = &defltc; |
726 | sb.sg_kill = defkill; | |
727 | sb.sg_erase = deferase; | |
39a44641 | 728 | lflags = deflflags; |
c64cdfb4 | 729 | break; |
c64cdfb4 | 730 | case 1: |
9da647e3 SL |
731 | sb.sg_flags |= (eight ? RAW : CBREAK); |
732 | sb.sg_flags &= ~defflags; | |
c887373b | 733 | /* preserve tab delays, but turn off XTABS */ |
9da647e3 SL |
734 | if ((sb.sg_flags & TBDELAY) == XTABS) |
735 | sb.sg_flags &= ~TBDELAY; | |
c64cdfb4 | 736 | tc = ¬c; |
9da647e3 SL |
737 | ltc = &noltc; |
738 | sb.sg_kill = sb.sg_erase = -1; | |
39a44641 JB |
739 | if (litout) |
740 | lflags |= LLITOUT; | |
c64cdfb4 | 741 | break; |
c64cdfb4 SL |
742 | default: |
743 | return; | |
5567b76f | 744 | } |
afe1e594 KB |
745 | (void)ioctl(0, TIOCSLTC, (char *)ltc); |
746 | (void)ioctl(0, TIOCSETC, (char *)tc); | |
747 | (void)ioctl(0, TIOCSETN, (char *)&sb); | |
748 | (void)ioctl(0, TIOCLSET, (char *)&lflags); | |
749 | } | |
750 | ||
751 | void | |
e113d331 KB |
752 | lostpeer(signo) |
753 | int signo; | |
afe1e594 KB |
754 | { |
755 | (void)signal(SIGPIPE, SIG_IGN); | |
756 | msg("\007connection closed."); | |
757 | done(1); | |
5567b76f BJ |
758 | } |
759 | ||
afe1e594 KB |
760 | /* copy SIGURGs to the child process. */ |
761 | void | |
e113d331 KB |
762 | copytochild(signo) |
763 | int signo; | |
5567b76f | 764 | { |
afe1e594 KB |
765 | (void)kill(child, SIGURG); |
766 | } | |
a9b12987 | 767 | |
e113d331 | 768 | void |
afe1e594 KB |
769 | msg(str) |
770 | char *str; | |
771 | { | |
772 | (void)fprintf(stderr, "rlogin: %s\r\n", str); | |
5567b76f BJ |
773 | } |
774 | ||
afe1e594 KB |
775 | #ifdef KERBEROS |
776 | /* VARARGS */ | |
e113d331 KB |
777 | void |
778 | #if __STDC__ | |
779 | warning(const char *fmt, ...) | |
780 | #else | |
781 | warning(fmt, va_alist) | |
782 | char *fmt; | |
783 | va_dcl | |
784 | #endif | |
5567b76f | 785 | { |
afe1e594 | 786 | va_list ap; |
afe1e594 KB |
787 | |
788 | (void)fprintf(stderr, "rlogin: warning, using standard rlogin: "); | |
e113d331 KB |
789 | #ifdef __STDC__ |
790 | va_start(ap, fmt); | |
791 | #else | |
afe1e594 | 792 | va_start(ap); |
e113d331 | 793 | #endif |
afe1e594 KB |
794 | vfprintf(stderr, fmt, ap); |
795 | va_end(ap); | |
796 | (void)fprintf(stderr, ".\n"); | |
797 | } | |
798 | #endif | |
a9b12987 | 799 | |
e113d331 | 800 | __dead void |
afe1e594 KB |
801 | usage() |
802 | { | |
803 | (void)fprintf(stderr, | |
804 | "usage: rlogin [ -%s]%s[-e char] [ -l username ] host\n", | |
805 | #ifdef KERBEROS | |
47820fac | 806 | "8EKL", " [-k realm] "); |
afe1e594 | 807 | #else |
999d0d08 | 808 | "8EL", " "); |
afe1e594 KB |
809 | #endif |
810 | exit(1); | |
5567b76f | 811 | } |
028330cc | 812 | |
afe1e594 | 813 | /* |
5f8f5f64 | 814 | * The following routine provides compatibility (such as it is) between older |
afe1e594 KB |
815 | * Suns and others. Suns have only a `ttysize', so we convert it to a winsize. |
816 | */ | |
5f8f5f64 | 817 | #ifdef OLDSUN |
e113d331 | 818 | int |
afe1e594 KB |
819 | get_window_size(fd, wp) |
820 | int fd; | |
821 | struct winsize *wp; | |
028330cc | 822 | { |
afe1e594 KB |
823 | struct ttysize ts; |
824 | int error; | |
825 | ||
826 | if ((error = ioctl(0, TIOCGSIZE, &ts)) != 0) | |
e113d331 | 827 | return (error); |
afe1e594 KB |
828 | wp->ws_row = ts.ts_lines; |
829 | wp->ws_col = ts.ts_cols; | |
830 | wp->ws_xpixel = 0; | |
831 | wp->ws_ypixel = 0; | |
e113d331 | 832 | return (0); |
028330cc | 833 | } |
afe1e594 | 834 | #endif |
999d0d08 | 835 | |
e113d331 | 836 | u_int |
999d0d08 KB |
837 | getescape(p) |
838 | register char *p; | |
839 | { | |
840 | long val; | |
841 | int len; | |
842 | ||
843 | if ((len = strlen(p)) == 1) /* use any single char, including '\' */ | |
e113d331 | 844 | return ((u_int)*p); |
999d0d08 KB |
845 | /* otherwise, \nnn */ |
846 | if (*p == '\\' && len >= 2 && len <= 4) { | |
e113d331 | 847 | val = strtol(++p, NULL, 8); |
999d0d08 KB |
848 | for (;;) { |
849 | if (!*++p) | |
e113d331 | 850 | return ((u_int)val); |
999d0d08 KB |
851 | if (*p < '0' || *p > '8') |
852 | break; | |
853 | } | |
854 | } | |
855 | msg("illegal option value -- e"); | |
856 | usage(); | |
857 | /* NOTREACHED */ | |
858 | } |