1 /*
2 * Copyright (c) 1989, 1993
3 * The Regents of the University of California. 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 /* baesd on @(#)sys_term.c 8.1 (Berkeley) 6/4/93 */
35
36 #include <autoconf.h>
37
38 #include "telnetd.h"
39 #include "pathnames.h"
40 #include <com_err.h>
41
42 #ifndef LOGIN_PROGRAM
43 #define LOGIN_PROGRAM _PATH_LOGIN
44 #endif
45
46 #include <libpty.h>
47 #if defined(AUTHENTICATION)
48 #include <libtelnet/auth.h>
49 #endif
50
51 #if defined(KRB5)
52 #include <krb5.h>
53 #include "k5-platform.h"
54 #endif
55
56 char *login_program = LOGIN_PROGRAM;
57
58 #ifdef NEWINIT
59 #include <initreq.h>
60 int utmp_len = MAXHOSTNAMELEN; /* sizeof(init_request.host) */
61 #else /* NEWINIT*/
62
63 #ifdef HAVE_UTMP_H
64 #include <utmp.h>
65 #endif
66
67 #ifdef _PATH_WTMP
68 char wtmpf[] = _PATH_WTMP;
69 #else
70 char wtmpf[] = "/usr/adm/wtmp";
71 #endif
72
73 #ifdef _PATH_UTMP
74 char utmpf[] = _PATH_UTMP;
75 #else
76 char utmpf[] = "/etc/utmp";
77 #endif
78
79 # ifdef CRAY
80 #include <tmpdir.h>
81 #include <sys/wait.h>
82 # if defined(_SC_CRAY_SECURE_SYS) && !defined(SCM_SECURITY)
83 /*
84 * UNICOS 6.0/6.1 do not have SCM_SECURITY defined, so we can
85 * use it to tell us to turn off all the socket security code,
86 * since that is only used in UNICOS 7.0 and later.
87 */
88 # undef _SC_CRAY_SECURE_SYS
89 # endif
90
91 # if defined(_SC_CRAY_SECURE_SYS)
92 #include <sys/sysv.h>
93 #include <sys/secstat.h>
94 extern int secflag;
95 extern struct sysv sysv;
96 # endif /* _SC_CRAY_SECURE_SYS */
97 # endif /* CRAY */
98 #endif /* NEWINIT */
99
100 #ifdef STREAMSPTY
101 #ifdef HAVE_SAC_H
102 #include <sac.h>
103 #endif
104 #include <sys/stropts.h>
105 #endif
106
107 #define SCPYN(a, b) (void) strncpy(a, b, sizeof(a))
108 #define SCMPN(a, b) strncmp(a, b, sizeof(a))
109
110 #ifdef HAVE_SYS_STREAM_H
111 #include <sys/stream.h>
112 #endif
113 #ifdef __hpux
114 #include <sys/resource.h>
115 #include <sys/proc.h>
116 #endif
117 /* For what platforms do we really need sys/tty.h? */
118 #ifdef HAVE_SYS_TTY_H
119 #include <sys/tty.h>
120 #endif
121
122 #ifdef t_erase
123 #undef t_erase
124 #undef t_kill
125 #undef t_intrc
126 #undef t_quitc
127 #undef t_startc
128 #undef t_stopc
129 #undef t_eofc
130 #undef t_brkc
131 #undef t_suspc
132 #undef t_dsuspc
133 #undef t_rprntc
134 #undef t_flushc
135 #undef t_werasc
136 #undef t_lnextc
137 #endif
138
139 #if defined(UNICOS5) && defined(CRAY2) && !defined(EXTPROC)
140 # define EXTPROC 0400
141 #endif
142
143 #ifndef USE_TERMIO
144 struct termbuf {
145 struct sgttyb sg;
146 struct tchars tc;
147 struct ltchars ltc;
148 int state;
149 int lflags;
150 } termbuf, termbuf2;
151 # define cfsetospeed(tp, val) (tp)->sg.sg_ospeed = (val)
152 # define cfsetispeed(tp, val) (tp)->sg.sg_ispeed = (val)
153 # define cfgetospeed(tp) (tp)->sg.sg_ospeed
154 # define cfgetispeed(tp) (tp)->sg.sg_ispeed
155 #else /* USE_TERMIO */
156 # ifdef SYSV_TERMIO
157 # define termios termio
158 # endif
159 # ifndef TCSANOW
160 # ifdef TCSETS
161 # define TCSANOW TCSETS
162 # define TCSADRAIN TCSETSW
163 # define tcgetattr(f, t) ioctl(f, TCGETS, (char *)t)
164 # else
165 # ifdef TCSETA
166 # define TCSANOW TCSETA
167 # define TCSADRAIN TCSETAW
168 # define tcgetattr(f, t) ioctl(f, TCGETA, (char *)t)
169 # else
170 # define TCSANOW TIOCSETA
171 # define TCSADRAIN TIOCSETAW
172 # define tcgetattr(f, t) ioctl(f, TIOCGETA, (char *)t)
173 # endif
174 # endif
175 # define tcsetattr(f, a, t) ioctl(f, a, t)
176 # define cfsetospeed(tp, val) (tp)->c_cflag &= ~CBAUD; \
177 (tp)->c_cflag |= (val)
178 # define cfgetospeed(tp) ((tp)->c_cflag & CBAUD)
179 # ifdef CIBAUD
180 # define cfsetispeed(tp, val) (tp)->c_cflag &= ~CIBAUD; \
181 (tp)->c_cflag |= ((val)<<IBSHIFT)
182 # define cfgetispeed(tp) (((tp)->c_cflag & CIBAUD)>>IBSHIFT)
183 # else
184 # define cfsetispeed(tp, val) (tp)->c_cflag &= ~CBAUD; \
185 (tp)->c_cflag |= (val)
186 # define cfgetispeed(tp) ((tp)->c_cflag & CBAUD)
187 # endif
188 # endif /* TCSANOW */
189 struct termios termbuf, termbuf2; /* pty control structure */
190 # ifdef STREAMSPTY
191 int ttyfd = -1;
192 # endif
193 #endif /* USE_TERMIO */
194
195 #ifndef SETPGRP_TWOARG
196 #define setpgrp(a,b) setpgrp()
197 #endif
198
199 int dup_tty(int);
200 static char **addarg(char **, char *);
201
202 /*
203 * init_termbuf()
204 * copy_termbuf(cp)
205 * set_termbuf()
206 *
207 * These three routines are used to get and set the "termbuf" structure
208 * to and from the kernel. init_termbuf() gets the current settings.
209 * copy_termbuf() hands in a new "termbuf" to write to the kernel, and
210 * set_termbuf() writes the structure into the kernel.
211 */
212
213 void
init_termbuf()214 init_termbuf()
215 {
216 #ifndef USE_TERMIO
217 (void) ioctl(pty, TIOCGETP, (char *)&termbuf.sg);
218 (void) ioctl(pty, TIOCGETC, (char *)&termbuf.tc);
219 (void) ioctl(pty, TIOCGLTC, (char *)&termbuf.ltc);
220 # ifdef TIOCGSTATE
221 (void) ioctl(pty, TIOCGSTATE, (char *)&termbuf.state);
222 # endif
223 #else
224 # ifdef STREAMSPTY
225 (void) tcgetattr(ttyfd, &termbuf);
226 # else
227 (void) tcgetattr(pty, &termbuf);
228 # endif
229 #endif
230 termbuf2 = termbuf;
231 }
232
233 #if defined(LINEMODE) && defined(TIOCPKT_IOCTL)
234 void
copy_termbuf(cp,len)235 copy_termbuf(cp, len)
236 char *cp;
237 int len;
238 {
239 if (len > sizeof(termbuf))
240 len = sizeof(termbuf);
241 memcpy(&termbuf, cp, len);
242 termbuf2 = termbuf;
243 }
244 #endif /* defined(LINEMODE) && defined(TIOCPKT_IOCTL) */
245
246 void
set_termbuf()247 set_termbuf()
248 {
249 /*
250 * Only make the necessary changes.
251 */
252 #ifndef USE_TERMIO
253 if (memcmp((char *)&termbuf.sg, (char *)&termbuf2.sg, sizeof(termbuf.sg)))
254 (void) ioctl(pty, TIOCSETN, (char *)&termbuf.sg);
255 if (memcmp((char *)&termbuf.tc, (char *)&termbuf2.tc, sizeof(termbuf.tc)))
256 (void) ioctl(pty, TIOCSETC, (char *)&termbuf.tc);
257 if (memcmp((char *)&termbuf.ltc, (char *)&termbuf2.ltc,
258 sizeof(termbuf.ltc)))
259 (void) ioctl(pty, TIOCSLTC, (char *)&termbuf.ltc);
260 if (termbuf.lflags != termbuf2.lflags)
261 (void) ioctl(pty, TIOCLSET, (char *)&termbuf.lflags);
262 #else /* USE_TERMIO */
263 if (memcmp((char *)&termbuf, (char *)&termbuf2, sizeof(termbuf)))
264 # ifdef STREAMSPTY
265 (void) tcsetattr(ttyfd, TCSANOW, &termbuf);
266 # else
267 (void) tcsetattr(pty, TCSANOW, &termbuf);
268 # endif
269 # if defined(CRAY2) && defined(UNICOS5)
270 needtermstat = 1;
271 # endif
272 #endif /* USE_TERMIO */
273 }
274
275
276 /*
277 * spcset(func, valp, valpp)
278 *
279 * This function takes various special characters (func), and
280 * sets *valp to the current value of that character, and
281 * *valpp to point to where in the "termbuf" structure that
282 * value is kept.
283 *
284 * It returns the SLC_ level of support for this function.
285 */
286
287 #ifndef USE_TERMIO
288 int
spcset(func,valp,valpp)289 spcset(func, valp, valpp)
290 int func;
291 cc_t *valp;
292 cc_t **valpp;
293 {
294 switch(func) {
295 case SLC_EOF:
296 *valp = termbuf.tc.t_eofc;
297 *valpp = (cc_t *)&termbuf.tc.t_eofc;
298 return(SLC_VARIABLE);
299 case SLC_EC:
300 *valp = termbuf.sg.sg_erase;
301 *valpp = (cc_t *)&termbuf.sg.sg_erase;
302 return(SLC_VARIABLE);
303 case SLC_EL:
304 *valp = termbuf.sg.sg_kill;
305 *valpp = (cc_t *)&termbuf.sg.sg_kill;
306 return(SLC_VARIABLE);
307 case SLC_IP:
308 *valp = termbuf.tc.t_intrc;
309 *valpp = (cc_t *)&termbuf.tc.t_intrc;
310 return(SLC_VARIABLE|SLC_FLUSHIN|SLC_FLUSHOUT);
311 case SLC_ABORT:
312 *valp = termbuf.tc.t_quitc;
313 *valpp = (cc_t *)&termbuf.tc.t_quitc;
314 return(SLC_VARIABLE|SLC_FLUSHIN|SLC_FLUSHOUT);
315 case SLC_XON:
316 *valp = termbuf.tc.t_startc;
317 *valpp = (cc_t *)&termbuf.tc.t_startc;
318 return(SLC_VARIABLE);
319 case SLC_XOFF:
320 *valp = termbuf.tc.t_stopc;
321 *valpp = (cc_t *)&termbuf.tc.t_stopc;
322 return(SLC_VARIABLE);
323 case SLC_AO:
324 *valp = termbuf.ltc.t_flushc;
325 *valpp = (cc_t *)&termbuf.ltc.t_flushc;
326 return(SLC_VARIABLE);
327 case SLC_SUSP:
328 *valp = termbuf.ltc.t_suspc;
329 *valpp = (cc_t *)&termbuf.ltc.t_suspc;
330 return(SLC_VARIABLE);
331 case SLC_EW:
332 *valp = termbuf.ltc.t_werasc;
333 *valpp = (cc_t *)&termbuf.ltc.t_werasc;
334 return(SLC_VARIABLE);
335 case SLC_RP:
336 *valp = termbuf.ltc.t_rprntc;
337 *valpp = (cc_t *)&termbuf.ltc.t_rprntc;
338 return(SLC_VARIABLE);
339 case SLC_LNEXT:
340 *valp = termbuf.ltc.t_lnextc;
341 *valpp = (cc_t *)&termbuf.ltc.t_lnextc;
342 return(SLC_VARIABLE);
343 case SLC_FORW1:
344 *valp = termbuf.tc.t_brkc;
345 *valpp = (cc_t *)&termbuf.ltc.t_lnextc;
346 return(SLC_VARIABLE);
347 case SLC_BRK:
348 case SLC_SYNCH:
349 case SLC_AYT:
350 case SLC_EOR:
351 *valp = (cc_t)0;
352 *valpp = (cc_t *)0;
353 return(SLC_DEFAULT);
354 default:
355 *valp = (cc_t)0;
356 *valpp = (cc_t *)0;
357 return(SLC_NOSUPPORT);
358 }
359 }
360
361 #else /* USE_TERMIO */
362
363 int
spcset(func,valp,valpp)364 spcset(func, valp, valpp)
365 int func;
366 cc_t *valp;
367 cc_t **valpp;
368 {
369
370 #define setval(a, b) *valp = termbuf.c_cc[a]; \
371 *valpp = &termbuf.c_cc[a]; \
372 return(b);
373 #define defval(a) *valp = ((cc_t)a); *valpp = (cc_t *)0; return(SLC_DEFAULT);
374
375 switch(func) {
376 case SLC_EOF:
377 setval(VEOF, SLC_VARIABLE);
378 case SLC_EC:
379 setval(VERASE, SLC_VARIABLE);
380 case SLC_EL:
381 setval(VKILL, SLC_VARIABLE);
382 case SLC_IP:
383 setval(VINTR, SLC_VARIABLE|SLC_FLUSHIN|SLC_FLUSHOUT);
384 case SLC_ABORT:
385 setval(VQUIT, SLC_VARIABLE|SLC_FLUSHIN|SLC_FLUSHOUT);
386 case SLC_XON:
387 #ifdef VSTART
388 setval(VSTART, SLC_VARIABLE);
389 #else
390 defval(0x13);
391 #endif
392 case SLC_XOFF:
393 #ifdef VSTOP
394 setval(VSTOP, SLC_VARIABLE);
395 #else
396 defval(0x11);
397 #endif
398 case SLC_EW:
399 #ifdef VWERASE
400 setval(VWERASE, SLC_VARIABLE);
401 #else
402 defval(0);
403 #endif
404 case SLC_RP:
405 #ifdef VREPRINT
406 setval(VREPRINT, SLC_VARIABLE);
407 #else
408 defval(0);
409 #endif
410 case SLC_LNEXT:
411 #ifdef VLNEXT
412 setval(VLNEXT, SLC_VARIABLE);
413 #else
414 defval(0);
415 #endif
416 case SLC_AO:
417 #if !defined(VDISCARD) && defined(VFLUSHO)
418 # define VDISCARD VFLUSHO
419 #endif
420 #ifdef VDISCARD
421 setval(VDISCARD, SLC_VARIABLE|SLC_FLUSHOUT);
422 #else
423 defval(0);
424 #endif
425 case SLC_SUSP:
426 #ifdef VSUSP
427 setval(VSUSP, SLC_VARIABLE|SLC_FLUSHIN);
428 #else
429 defval(0);
430 #endif
431 #ifdef VEOL
432 case SLC_FORW1:
433 setval(VEOL, SLC_VARIABLE);
434 #endif
435 #ifdef VEOL2
436 case SLC_FORW2:
437 setval(VEOL2, SLC_VARIABLE);
438 #endif
439 case SLC_AYT:
440 #ifdef VSTATUS
441 setval(VSTATUS, SLC_VARIABLE);
442 #else
443 defval(0);
444 #endif
445
446 case SLC_BRK:
447 case SLC_SYNCH:
448 case SLC_EOR:
449 defval(0);
450
451 default:
452 *valp = 0;
453 *valpp = 0;
454 return(SLC_NOSUPPORT);
455 }
456 }
457 #endif /* USE_TERMIO */
458
459 #ifdef CRAY
460 /*
461 * getnpty()
462 *
463 * Return the number of pty's configured into the system.
464 */
465 int
getnpty()466 getnpty()
467 {
468 #ifdef _SC_CRAY_NPTY
469 int numptys;
470
471 if ((numptys = sysconf(_SC_CRAY_NPTY)) != -1)
472 return numptys;
473 else
474 #endif /* _SC_CRAY_NPTY */
475 return 128;
476 }
477 #endif /* CRAY */
478
479 #ifndef convex
480 /*
481 * getpty()
482 *
483 * Allocate a pty. As a side effect, the external character
484 * array "line" contains the name of the slave side.
485 *
486 * Returns the file descriptor of the opened pty.
487 */
488 static char Xline[17];
489 char *line = Xline;
490
491 #ifdef CRAY
492 char *myline = "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0";
493 #endif /* CRAY */
494
495
496 #endif /* convex */
497
498 static pid_t slavepid = 0;
499
500 #ifdef LINEMODE
501 /*
502 * tty_flowmode() Find out if flow control is enabled or disabled.
503 * tty_linemode() Find out if linemode (external processing) is enabled.
504 * tty_setlinemod(on) Turn on/off linemode.
505 * tty_isecho() Find out if echoing is turned on.
506 * tty_setecho(on) Enable/disable character echoing.
507 * tty_israw() Find out if terminal is in RAW mode.
508 * tty_binaryin(on) Turn on/off BINARY on input.
509 * tty_binaryout(on) Turn on/off BINARY on output.
510 * tty_isediting() Find out if line editing is enabled.
511 * tty_istrapsig() Find out if signal trapping is enabled.
512 * tty_setedit(on) Turn on/off line editing.
513 * tty_setsig(on) Turn on/off signal trapping.
514 * tty_issofttab() Find out if tab expansion is enabled.
515 * tty_setsofttab(on) Turn on/off soft tab expansion.
516 * tty_islitecho() Find out if typed control chars are echoed literally
517 * tty_setlitecho() Turn on/off literal echo of control chars
518 * tty_tspeed(val) Set transmit speed to val.
519 * tty_rspeed(val) Set receive speed to val.
520 */
521
522 #ifdef convex
523 static int linestate;
524 #endif
525
526 int
tty_linemode()527 tty_linemode()
528 {
529 #ifndef convex
530 #ifndef USE_TERMIO
531 return(termbuf.state & TS_EXTPROC);
532 #else
533 return(termbuf.c_lflag & EXTPROC);
534 #endif
535 #else
536 return(linestate);
537 #endif
538 }
539
540 void
tty_setlinemode(on)541 tty_setlinemode(on)
542 int on;
543 {
544 #ifdef TIOCEXT
545 # ifndef convex
546 set_termbuf();
547 # else
548 linestate = on;
549 # endif
550 (void) ioctl(pty, TIOCEXT, (char *)&on);
551 # ifndef convex
552 init_termbuf();
553 # endif
554 #else /* !TIOCEXT */
555 # ifdef EXTPROC
556 if (on)
557 termbuf.c_lflag |= EXTPROC;
558 else
559 termbuf.c_lflag &= ~EXTPROC;
560 # endif
561 #endif /* TIOCEXT */
562 }
563 #endif /* LINEMODE */
564
565 int
tty_isecho()566 tty_isecho()
567 {
568 #ifndef USE_TERMIO
569 return (termbuf.sg.sg_flags & ECHO);
570 #else
571 return (termbuf.c_lflag & ECHO);
572 #endif
573 }
574
575 int
tty_flowmode()576 tty_flowmode()
577 {
578 #ifndef USE_TERMIO
579 return(((termbuf.tc.t_startc) > 0 && (termbuf.tc.t_stopc) > 0) ? 1 : 0);
580 #else
581 return((termbuf.c_iflag & IXON) ? 1 : 0);
582 #endif
583 }
584
585 int
tty_restartany()586 tty_restartany()
587 {
588 #ifndef USE_TERMIO
589 # ifdef DECCTQ
590 return((termbuf.lflags & DECCTQ) ? 0 : 1);
591 # else
592 return(-1);
593 # endif
594 #else
595 return((termbuf.c_iflag & IXANY) ? 1 : 0);
596 #endif
597 }
598
599 void
tty_setecho(on)600 tty_setecho(on)
601 int on;
602 {
603 #ifndef USE_TERMIO
604 if (on)
605 termbuf.sg.sg_flags |= ECHO|CRMOD;
606 else
607 termbuf.sg.sg_flags &= ~(ECHO|CRMOD);
608 #else
609 if (on)
610 termbuf.c_lflag |= ECHO;
611 else
612 termbuf.c_lflag &= ~ECHO;
613 #endif
614 }
615
616 int
tty_israw()617 tty_israw()
618 {
619 #ifndef USE_TERMIO
620 return(termbuf.sg.sg_flags & RAW);
621 #else
622 return(!(termbuf.c_lflag & ICANON));
623 #endif
624 }
625
626 #if defined (AUTHENTICATION) && defined(NO_LOGIN_F) && defined(LOGIN_R)
627 int
tty_setraw(on)628 tty_setraw(on)
629 {
630 # ifndef USE_TERMIO
631 if (on)
632 termbuf.sg.sg_flags |= RAW;
633 else
634 termbuf.sg.sg_flags &= ~RAW;
635 # else
636 if (on)
637 termbuf.c_lflag &= ~ICANON;
638 else
639 termbuf.c_lflag |= ICANON;
640 # endif
641 }
642 #endif
643
644 void
tty_binaryin(on)645 tty_binaryin(on)
646 int on;
647 {
648 #ifndef USE_TERMIO
649 if (on)
650 termbuf.lflags |= LPASS8;
651 else
652 termbuf.lflags &= ~LPASS8;
653 #else
654 if (on) {
655 termbuf.c_iflag &= ~ISTRIP;
656 } else {
657 termbuf.c_iflag |= ISTRIP;
658 }
659 #endif
660 }
661
662 void
tty_binaryout(on)663 tty_binaryout(on)
664 int on;
665 {
666 #ifndef USE_TERMIO
667 if (on)
668 termbuf.lflags |= LLITOUT;
669 else
670 termbuf.lflags &= ~LLITOUT;
671 #else
672 if (on) {
673 termbuf.c_cflag &= ~(CSIZE|PARENB);
674 termbuf.c_cflag |= CS8;
675 termbuf.c_oflag &= ~OPOST;
676 } else {
677 termbuf.c_cflag &= ~CSIZE;
678 termbuf.c_cflag |= CS7|PARENB;
679 termbuf.c_oflag |= OPOST;
680 }
681 #endif
682 }
683
684 int
tty_isbinaryin()685 tty_isbinaryin()
686 {
687 #ifndef USE_TERMIO
688 return(termbuf.lflags & LPASS8);
689 #else
690 return(!(termbuf.c_iflag & ISTRIP));
691 #endif
692 }
693
694 int
tty_isbinaryout()695 tty_isbinaryout()
696 {
697 #ifndef USE_TERMIO
698 return(termbuf.lflags & LLITOUT);
699 #else
700 return(!(termbuf.c_oflag&OPOST));
701 #endif
702 }
703
704 #ifdef LINEMODE
705 int
tty_isediting()706 tty_isediting()
707 {
708 #ifndef USE_TERMIO
709 return(!(termbuf.sg.sg_flags & (CBREAK|RAW)));
710 #else
711 return(termbuf.c_lflag & ICANON);
712 #endif
713 }
714
715 int
tty_istrapsig()716 tty_istrapsig()
717 {
718 #ifndef USE_TERMIO
719 return(!(termbuf.sg.sg_flags&RAW));
720 #else
721 return(termbuf.c_lflag & ISIG);
722 #endif
723 }
724
725 void
tty_setedit(on)726 tty_setedit(on)
727 int on;
728 {
729 #ifndef USE_TERMIO
730 if (on)
731 termbuf.sg.sg_flags &= ~CBREAK;
732 else
733 termbuf.sg.sg_flags |= CBREAK;
734 #else
735 if (on)
736 termbuf.c_lflag |= ICANON;
737 else
738 termbuf.c_lflag &= ~ICANON;
739 #endif
740 }
741
742 void
tty_setsig(on)743 tty_setsig(on)
744 int on;
745 {
746 #ifndef USE_TERMIO
747 if (on)
748 ;
749 #else
750 if (on)
751 termbuf.c_lflag |= ISIG;
752 else
753 termbuf.c_lflag &= ~ISIG;
754 #endif
755 }
756 #endif /* LINEMODE */
757
758 int
tty_issofttab()759 tty_issofttab()
760 {
761 #ifndef USE_TERMIO
762 return (termbuf.sg.sg_flags & XTABS);
763 #else
764 # ifdef OXTABS
765 return (termbuf.c_oflag & OXTABS);
766 # endif
767 # ifdef TABDLY
768 return ((termbuf.c_oflag & TABDLY) == TAB3);
769 # endif
770 #endif
771 }
772
773 void
tty_setsofttab(on)774 tty_setsofttab(on)
775 int on;
776 {
777 #ifndef USE_TERMIO
778 if (on)
779 termbuf.sg.sg_flags |= XTABS;
780 else
781 termbuf.sg.sg_flags &= ~XTABS;
782 #else
783 if (on) {
784 # ifdef OXTABS
785 termbuf.c_oflag |= OXTABS;
786 # endif
787 # ifdef TABDLY
788 termbuf.c_oflag &= ~TABDLY;
789 termbuf.c_oflag |= TAB3;
790 # endif
791 } else {
792 # ifdef OXTABS
793 termbuf.c_oflag &= ~OXTABS;
794 # endif
795 # ifdef TABDLY
796 termbuf.c_oflag &= ~TABDLY;
797 termbuf.c_oflag |= TAB0;
798 # endif
799 }
800 #endif
801 }
802
803 int
tty_islitecho()804 tty_islitecho()
805 {
806 #ifndef USE_TERMIO
807 return (!(termbuf.lflags & LCTLECH));
808 #else
809 # ifdef ECHOCTL
810 return (!(termbuf.c_lflag & ECHOCTL));
811 # endif
812 # ifdef TCTLECH
813 return (!(termbuf.c_lflag & TCTLECH));
814 # endif
815 # if !defined(ECHOCTL) && !defined(TCTLECH)
816 return (0); /* assumes ctl chars are echoed '^x' */
817 # endif
818 #endif
819 }
820
821 void
tty_setlitecho(on)822 tty_setlitecho(on)
823 int on;
824 {
825 #ifndef USE_TERMIO
826 if (on)
827 termbuf.lflags &= ~LCTLECH;
828 else
829 termbuf.lflags |= LCTLECH;
830 #else
831 # ifdef ECHOCTL
832 if (on)
833 termbuf.c_lflag &= ~ECHOCTL;
834 else
835 termbuf.c_lflag |= ECHOCTL;
836 # endif
837 # ifdef TCTLECH
838 if (on)
839 termbuf.c_lflag &= ~TCTLECH;
840 else
841 termbuf.c_lflag |= TCTLECH;
842 # endif
843 #endif
844 }
845
846 int
tty_iscrnl()847 tty_iscrnl()
848 {
849 #ifndef USE_TERMIO
850 return (termbuf.sg.sg_flags & CRMOD);
851 #else
852 return (termbuf.c_iflag & ICRNL);
853 #endif
854 }
855
856 /*
857 * A table of available terminal speeds
858 */
859 struct termspeeds {
860 int speed;
861 speed_t value;
862 } termspeeds[] = {
863 { 0, B0 }, { 50, B50 }, { 75, B75 },
864 { 110, B110 }, { 134, B134 }, { 150, B150 },
865 { 200, B200 }, { 300, B300 }, { 600, B600 },
866 { 1200, B1200 }, { 1800, B1800 }, { 2400, B2400 },
867 { 4800, B4800 }, { 9600, B9600 }, { 19200, B9600 },
868 { 38400, B9600 }, { -1, B9600 }
869 };
870
871 void
tty_tspeed(val)872 tty_tspeed(val)
873 int val;
874 {
875 register struct termspeeds *tp;
876
877 for (tp = termspeeds; (tp->speed != -1) && (val > tp->speed); tp++)
878 ;
879 cfsetospeed(&termbuf, tp->value);
880 }
881
882 void
tty_rspeed(val)883 tty_rspeed(val)
884 int val;
885 {
886 register struct termspeeds *tp;
887
888 for (tp = termspeeds; (tp->speed != -1) && (val > tp->speed); tp++)
889 ;
890 cfsetispeed(&termbuf, tp->value);
891 }
892
893 #if defined(CRAY2) && defined(UNICOS5)
894 int
tty_isnewmap()895 tty_isnewmap()
896 {
897 return((termbuf.c_oflag & OPOST) && (termbuf.c_oflag & ONLCR) &&
898 !(termbuf.c_oflag & ONLRET));
899 }
900 #endif
901
902
903 #ifndef NEWINIT
904 #endif
905
906 /*
907 * getptyslave()
908 *
909 * Open the slave side of the pty, and do any initialization
910 * that is necessary. The return value is a file descriptor
911 * for the slave side.
912 */
913 static void
getptyslave()914 getptyslave()
915 {
916 int t = -1;
917 long retval;
918
919 #if !defined(CRAY) || !defined(NEWINIT)
920 # ifdef LINEMODE
921 int waslm;
922 # endif
923 # ifdef TIOCGWINSZ
924 struct winsize ws;
925 extern int def_row, def_col;
926 # endif
927 extern int def_tspeed, def_rspeed;
928 /*
929 * Opening the slave side may cause initilization of the
930 * kernel tty structure. We need remember the state of
931 * if linemode was turned on
932 * terminal window size
933 * terminal speed
934 * so that we can re-set them if we need to.
935 */
936 # ifdef LINEMODE
937 waslm = tty_linemode();
938 # endif
939
940 if ( (retval = pty_open_slave (line, &t)) != 0 )
941 {
942 fatalperror(net, pty_error_message(retval));
943 }
944
945 #ifdef STREAMSPTY
946 #ifdef USE_TERMIO
947 ttyfd = t;
948 #endif
949 if (ioctl(pty, I_PUSH, "pckt") < 0) {
950 #ifndef _AIX
951 fatal(net, "I_PUSH pckt");
952 #endif
953 }
954 #endif
955
956 /*
957 * set up the tty modes as we like them to be.
958 */
959 init_termbuf();
960 # ifdef TIOCGWINSZ
961 if (def_row || def_col) {
962 memset(&ws, 0, sizeof(ws));
963 ws.ws_col = def_col;
964 ws.ws_row = def_row;
965 (void)ioctl(t, TIOCSWINSZ, (char *)&ws);
966 }
967 # endif
968
969 /*
970 * Settings for sgtty based systems
971 */
972 # ifndef USE_TERMIO
973 termbuf.sg.sg_flags |= CRMOD|ANYP|ECHO|XTABS;
974 # endif /* USE_TERMIO */
975
976 /*
977 * Settings for UNICOS (and HPUX)
978 */
979 # if defined(CRAY) || defined(__hpux)
980 termbuf.c_oflag = OPOST|ONLCR|TAB3;
981 termbuf.c_iflag = IGNPAR|ISTRIP|ICRNL|IXON;
982 termbuf.c_lflag = ISIG|ICANON|ECHO|ECHOE|ECHOK;
983 termbuf.c_cflag = EXTB|HUPCL|CS8;
984 # endif
985
986 /*
987 * Settings for all other termios/termio based
988 * systems, other than 4.4BSD. In 4.4BSD the
989 * kernel does the initial terminal setup.
990 */
991 # if defined(USE_TERMIO) && !(defined(CRAY) || defined(__hpux)) && (BSD <= 43)
992 # ifndef OXTABS
993 # define OXTABS 0
994 # endif
995 termbuf.c_lflag |= ECHO|ICANON|IEXTEN|ISIG;
996 termbuf.c_oflag |= ONLCR|OXTABS|OPOST;
997 termbuf.c_iflag |= ICRNL|IGNPAR;
998 termbuf.c_cflag |= HUPCL;
999 termbuf.c_iflag &= ~IXOFF;
1000 # endif /* defined(USE_TERMIO) && !defined(CRAY) && (BSD <= 43) */
1001 tty_rspeed((def_rspeed > 0) ? def_rspeed : 9600);
1002 tty_tspeed((def_tspeed > 0) ? def_tspeed : 9600);
1003 # ifdef LINEMODE
1004 if (waslm)
1005 tty_setlinemode(1);
1006 # endif /* LINEMODE */
1007
1008 /*
1009 * Set the tty modes, and make this our controlling tty.
1010 */
1011 set_termbuf();
1012 if (dup_tty(t) == -1)
1013 fatalperror(net, "dup_tty");
1014 #endif /* !defined(CRAY) || !defined(NEWINIT) */
1015 if (net > 2)
1016 (void) close(net);
1017 #if defined(AUTHENTICATION) && defined(NO_LOGIN_F) && defined(LOGIN_R)
1018 /*
1019 * Leave the pty open so that we can write out the rlogin
1020 * protocol for /bin/login, if the authentication works.
1021 */
1022 #else
1023 if (pty > 2) {
1024 (void) close(pty);
1025 pty = -1;
1026 }
1027 #endif
1028 }
1029
1030 #if !defined(CRAY) || !defined(NEWINIT)
1031 #ifndef O_NOCTTY
1032 #define O_NOCTTY 0
1033 #endif
1034 #endif /* !defined(CRAY) || !defined(NEWINIT) */
1035
1036
1037
1038 int
dup_tty(t)1039 dup_tty(t)
1040 int t;
1041 {
1042 if (t != 0)
1043 (void) dup2(t, 0);
1044 if (t != 1)
1045 (void) dup2(t, 1);
1046 if (t != 2)
1047 (void) dup2(t, 2);
1048 if (t > 2)
1049 close(t);
1050 return(0);
1051 }
1052
1053
1054 #ifdef NEWINIT
1055 char *gen_id = "fe";
1056 #endif
1057
1058 /*
1059 * startslave(host)
1060 *
1061 * Given a hostname, do whatever
1062 * is necessary to startup the login process on the slave side of the pty.
1063 */
1064
1065
1066 /* ARGSUSED */
1067 void
startslave(host,autologin,autoname)1068 startslave(host, autologin, autoname)
1069 char *host;
1070 int autologin;
1071 char *autoname;
1072 {
1073 int syncpipe[2];
1074 register int i;
1075 #ifdef NEWINIT
1076 extern char *ptyip;
1077 struct init_request request;
1078 void nologinproc();
1079 register int n;
1080 #endif /* NEWINIT */
1081
1082 if ( pipe(syncpipe) < 0 )
1083 fatal(net, "failed getting synchronization pipe");
1084
1085 #if defined(AUTHENTICATION)
1086 if (!autoname || !autoname[0])
1087 autologin = 0;
1088
1089 if (autologin < auth_level) {
1090 fatal(net, "Authorization failed");
1091 exit(1);
1092 }
1093 #endif
1094
1095 #ifndef NEWINIT
1096
1097 if ((i = fork()) < 0)
1098 fatalperror(net, "fork");
1099 if (i) {
1100 char c;
1101
1102 void sigjob (int);
1103 slavepid = i; /* So we can clean it up later */
1104 #ifdef CRAY
1105 (void) signal(WJSIGNAL, sigjob);
1106 #endif
1107
1108 /* Wait for child before writing to parent side of pty.*/
1109 (void) close(syncpipe[1]);
1110 if ( read(syncpipe[0], &c, 1) == 0 ) {
1111 /* Slave side died */
1112 fatal ( net, "Slave failed to initialize");
1113 }
1114
1115 close(syncpipe[0]);
1116
1117 } else {
1118
1119 pty_update_utmp (PTY_LOGIN_PROCESS, getpid(), "LOGIN", line,
1120 host, PTY_TTYSLOT_USABLE);
1121 getptyslave();
1122
1123 /* Notify our parent we're ready to continue.*/
1124 write(syncpipe[1],"y",1);
1125 close(syncpipe[0]);
1126 close(syncpipe[1]);
1127
1128 start_login(host, autologin, autoname);
1129 /*NOTREACHED*/
1130 }
1131 #else /* NEWINIT */
1132
1133 /*
1134 * Init will start up login process if we ask nicely. We only wait
1135 * for it to start up and begin normal telnet operation.
1136 */
1137 if ((i = open(INIT_FIFO, O_WRONLY)) < 0) {
1138 char tbuf[128];
1139 (void) snprintf(tbuf, sizeof(tbuf), "Can't open %s\n",
1140 INIT_FIFO);
1141 fatalperror(net, tbuf);
1142 }
1143 memset(&request, 0, sizeof(request));
1144 request.magic = INIT_MAGIC;
1145 SCPYN(request.gen_id, gen_id);
1146 SCPYN(request.tty_id, &line[8]);
1147 SCPYN(request.host, host);
1148 SCPYN(request.term_type, *terminaltype ? terminaltype : "network");
1149 #if !defined(UNICOS5)
1150 request.signal = SIGCLD;
1151 request.pid = getpid();
1152 #endif
1153 #ifdef BFTPDAEMON
1154 /*
1155 * Are we working as the bftp daemon?
1156 */
1157 if (bftpd) {
1158 SCPYN(request.exec_name, BFTPPATH);
1159 }
1160 #endif /* BFTPDAEMON */
1161 if (write(i, (char *)&request, sizeof(request)) < 0) {
1162 char tbuf[128];
1163 (void) snprintf(tbuf, sizeof(tbuf), "Can't write to %s\n",
1164 INIT_FIFO);
1165 fatalperror(net, tbuf);
1166 }
1167 (void) close(i);
1168 (void) signal(SIGALRM, nologinproc);
1169 for (i = 0; ; i++) {
1170 char tbuf[128];
1171 alarm(15);
1172 n = read(pty, ptyip, BUFSIZ);
1173 if (i == 3 || n >= 0 || !gotalarm)
1174 break;
1175 gotalarm = 0;
1176 snprintf(tbuf, sizeof(tbuf), "telnetd: waiting for /etc/init to start login process on %s\r\n", line);
1177 (void) write(net, tbuf, strlen(tbuf));
1178 }
1179 if (n < 0 && gotalarm)
1180 fatal(net, "/etc/init didn't start login process");
1181 pcc += n;
1182 alarm(0);
1183 (void) signal(SIGALRM, SIG_DFL);
1184
1185 return;
1186 #endif /* NEWINIT */
1187 }
1188
1189 char *envinit[3];
1190 extern char **environ;
1191
1192 void
init_env()1193 init_env()
1194 {
1195 extern char *getenv();
1196 char **envp;
1197
1198 envp = envinit;
1199 if ((*envp = getenv("TZ")))
1200 *envp++ -= 3;
1201 #if defined(CRAY) || defined(__hpux)
1202 else
1203 *envp++ = "TZ=GMT0";
1204 #endif
1205 *envp = 0;
1206 environ = envinit;
1207 }
1208
1209 #ifndef NEWINIT
1210
1211 /*
1212 * start_login(host)
1213 *
1214 * Assuming that we are now running as a child processes, this
1215 * function will turn us into the login process.
1216 */
1217
1218 void
start_login(host,autologin,name)1219 start_login(host, autologin, name)
1220 char *host;
1221 int autologin;
1222 char *name;
1223 {
1224 register char **argv;
1225 extern char *getenv();
1226
1227 #ifdef SOLARIS
1228 char *term;
1229 char termbuf[64];
1230 #endif
1231
1232
1233 /*
1234 * -h : pass on name of host.
1235 * WARNING: -h is accepted by login if and only if
1236 * getuid() == 0.
1237 * -p : don't clobber the environment (so terminal type stays set).
1238 *
1239 * -f : force this login, he has already been authenticated
1240 */
1241 argv = addarg(0, "login");
1242
1243 #if !defined(NO_LOGIN_H)
1244
1245 # if defined (AUTHENTICATION) && defined(NO_LOGIN_F) && defined(LOGIN_R)
1246 /*
1247 * Don't add the "-h host" option if we are going
1248 * to be adding the "-r host" option down below...
1249 */
1250 if ((auth_level < 0) || (autologin != AUTH_VALID))
1251 # endif
1252 {
1253 argv = addarg(argv, "-h");
1254 argv = addarg(argv, host);
1255 #ifdef SOLARIS
1256 /*
1257 * SVR4 version of -h takes TERM= as second arg, or -
1258 */
1259 term = getenv("TERM");
1260 if (term == NULL || term[0] == 0) {
1261 term = "-";
1262 } else {
1263 snprintf(termbuf, sizeof(termbuf), "TERM=%s", term);
1264 term = termbuf;
1265 }
1266 argv = addarg(argv, term);
1267 #endif
1268 }
1269 #endif
1270 #if !defined(NO_LOGIN_P)
1271 argv = addarg(argv, "-p");
1272 #endif
1273 #ifdef BFTPDAEMON
1274 /*
1275 * Are we working as the bftp daemon? If so, then ask login
1276 * to start bftp instead of shell.
1277 */
1278 if (bftpd) {
1279 argv = addarg(argv, "-e");
1280 argv = addarg(argv, BFTPPATH);
1281 } else
1282 #endif
1283 #if defined (SecurID)
1284 /*
1285 * don't worry about the -f that might get sent.
1286 * A -s is supposed to override it anyhow.
1287 */
1288 if (require_SecurID)
1289 argv = addarg(argv, "-s");
1290 #endif
1291 #if defined (AUTHENTICATION)
1292 if (auth_level >= 0 && autologin == AUTH_VALID) {
1293 if (name[0] == '-') {
1294 /*
1295 * Authenticated and authorized to log in to an
1296 * account starting with '-'? Even if that
1297 * unlikely case comes to pass, the current login
1298 * program will not parse the resulting command
1299 * line properly.
1300 */
1301 syslog(LOG_ERR, "user name cannot start with '-'");
1302 fatal(net, "user name cannot start with '-'");
1303 exit(1);
1304 }
1305 # if !defined(NO_LOGIN_F)
1306 #if defined(LOGIN_CAP_F)
1307 argv = addarg(argv, "-F");
1308 #else
1309 argv = addarg(argv, "-f");
1310 #endif
1311 argv = addarg(argv, "--");
1312 argv = addarg(argv, name);
1313 # else
1314 # if defined(LOGIN_R)
1315 /*
1316 * We don't have support for "login -f", but we
1317 * can fool /bin/login into thinking that we are
1318 * rlogind, and allow us to log in without a
1319 * password. The rlogin protocol expects
1320 * local-user\0remote-user\0term/speed\0
1321 */
1322
1323 if (pty > 2) {
1324 register char *cp;
1325 char speed[1024];
1326 int isecho, israw, xpty, len;
1327 extern int def_rspeed;
1328 # ifndef LOGIN_HOST
1329 /*
1330 * Tell login that we are coming from "localhost".
1331 * If we passed in the real host name, then the
1332 * user would have to allow .rhost access from
1333 * every machine that they want authenticated
1334 * access to work from, which sort of defeats
1335 * the purpose of an authenticated login...
1336 * So, we tell login that the session is coming
1337 * from "localhost", and the user will only have
1338 * to have "localhost" in their .rhost file.
1339 */
1340 # define LOGIN_HOST "localhost"
1341 # endif
1342 argv = addarg(argv, "-r");
1343 argv = addarg(argv, LOGIN_HOST);
1344
1345 xpty = pty;
1346 # ifndef STREAMSPTY
1347 pty = 0;
1348 # else
1349 ttyfd = 0;
1350 # endif
1351 init_termbuf();
1352 isecho = tty_isecho();
1353 israw = tty_israw();
1354 if (isecho || !israw) {
1355 tty_setecho(0); /* Turn off echo */
1356 tty_setraw(1); /* Turn on raw */
1357 set_termbuf();
1358 }
1359 len = strlen(name)+1;
1360 write(xpty, name, len);
1361 write(xpty, name, len);
1362 memset(speed, 0, sizeof(speed));
1363 snprintf(speed, sizeof(speed), "%s/%d",
1364 (cp = getenv("TERM")) ? cp : "",
1365 (def_rspeed > 0) ? def_rspeed : 9600);
1366 len = strlen(speed)+1;
1367 write(xpty, speed, len);
1368
1369 if (isecho || !israw) {
1370 init_termbuf();
1371 tty_setecho(isecho);
1372 tty_setraw(israw);
1373 set_termbuf();
1374 if (!israw) {
1375 /*
1376 * Write a newline to ensure
1377 * that login will be able to
1378 * read the line...
1379 */
1380 write(xpty, "\n", 1);
1381 }
1382 }
1383 pty = xpty;
1384 }
1385 # else
1386 argv = addarg(argv, "--");
1387 argv = addarg(argv, name);
1388 # endif
1389 # endif
1390 } else
1391 #endif
1392 if (getenv("USER")) {
1393 char *user = getenv("USER");
1394 if (user[0] == '-') {
1395 /* "telnet -l-x ..." */
1396 syslog(LOG_ERR, "user name cannot start with '-'");
1397 fatal(net, "user name cannot start with '-'");
1398 exit(1);
1399 }
1400 argv = addarg(argv, "--");
1401 argv = addarg(argv, user);
1402 #if defined(LOGIN_ARGS) && defined(NO_LOGIN_P)
1403 {
1404 register char **cpp;
1405 for (cpp = environ; *cpp; cpp++)
1406 if ((*cpp)[0] != '-')
1407 argv = addarg(argv, *cpp);
1408 }
1409 #endif
1410 /*
1411 * Assume that login will set the USER variable
1412 * correctly. For SysV systems, this means that
1413 * USER will no longer be set, just LOGNAME by
1414 * login. (The problem is that if the auto-login
1415 * fails, and the user then specifies a different
1416 * account name, he can get logged in with both
1417 * LOGNAME and USER in his environment, but the
1418 * USER value will be wrong.
1419 */
1420 unsetenv("USER");
1421 }
1422 #if defined(AUTHENTICATION) && defined(NO_LOGIN_F) && defined(LOGIN_R)
1423 if (pty > 2)
1424 close(pty);
1425 #endif
1426 closelog();
1427 execv(login_program, argv);
1428
1429 syslog(LOG_ERR, "%s: %m", login_program);
1430 fatalperror(net, login_program);
1431 /*NOTREACHED*/
1432 }
1433
1434 /*
1435 * This code returns a pointer to the first element of the array and
1436 * expects the same to be called with.
1437 * Therefore the -1 reference is legal.
1438 */
1439
1440 static char **
addarg(argv,val)1441 addarg(argv, val)
1442 register char **argv;
1443 register char *val;
1444 {
1445 register char **cpp;
1446
1447 if (argv == NULL) {
1448 /*
1449 * 10 entries, a leading length, and a null
1450 */
1451 argv = (char **)malloc(sizeof(*argv) * 12);
1452 if (argv == NULL)
1453 return(NULL);
1454 *argv++ = (char *)10;
1455 *argv = (char *)0;
1456 }
1457 for (cpp = argv; *cpp; cpp++)
1458 ;
1459 if (cpp == &argv[(long)argv[-1]]) {
1460 --argv;
1461 *argv = (char *)((long)(*argv) + 10);
1462 argv = (char **)realloc(argv, sizeof(*argv) * ((long)(*argv) + 2));
1463 if (argv == NULL)
1464 return(NULL);
1465 argv++;
1466 cpp = &argv[(long)argv[-1] - 10];
1467 }
1468 *cpp++ = val;
1469 *cpp = 0;
1470 return(argv);
1471 }
1472 #endif /* NEWINIT */
1473
1474 /*
1475 * cleanup()
1476 *
1477 * This is the routine to call when we are all through, to
1478 * clean up anything that needs to be cleaned up.
1479 */
1480 /* ARGSUSED */
1481 void
cleanup(sig)1482 cleanup(sig)
1483 int sig;
1484 {
1485 pty_cleanup(line,slavepid,1);
1486 #ifdef KRB5
1487 kerberos5_cleanup();
1488 #endif
1489
1490 (void) shutdown(net, 2);
1491 exit(1);
1492 }
1493
1494
1495
1496
1497
1498