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