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