]> git.saurik.com Git - apple/network_cmds.git/blob - telnetd.tproj/sys_term.c
network_cmds-85.tar.gz
[apple/network_cmds.git] / telnetd.tproj / sys_term.c
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 #ifndef lint
35 #if 0
36 static const char sccsid[] = "@(#)sys_term.c 8.2 (Berkeley) 12/15/93";
37 #endif
38 static const char rcsid[] =
39 "$FreeBSD: src/libexec/telnetd/sys_term.c,v 1.31 2001/07/09 09:23:42 brian Exp $";
40 #endif /* not lint */
41
42 #include <util.h>
43 #include "telnetd.h"
44 #include "pathnames.h"
45
46 #if defined(AUTHENTICATION)
47 #include <libtelnet/auth.h>
48 #endif
49
50 extern char *altlogin;
51
52 #if defined(CRAY) || defined(__hpux)
53 # define PARENT_DOES_UTMP
54 #endif
55
56 #ifdef NEWINIT
57 #include <initreq.h>
58 #else /* NEWINIT*/
59 # ifdef UTMPX
60 # include <utmpx.h>
61 struct utmpx wtmp;
62 # else
63 # include <utmp.h>
64 struct utmp wtmp;
65 # endif /* UTMPX */
66
67 # ifndef PARENT_DOES_UTMP
68 #ifdef _PATH_WTMP
69 char wtmpf[] = _PATH_WTMP;
70 #else
71 char wtmpf[] = "/usr/adm/wtmp";
72 #endif
73 #ifdef _PATH_UTMP
74 char utmpf[] = _PATH_UTMP;
75 #else
76 char utmpf[] = "/etc/utmp";
77 #endif
78 # else /* PARENT_DOES_UTMP */
79 char wtmpf[] = "/etc/wtmp";
80 # endif /* PARENT_DOES_UTMP */
81
82 # ifdef CRAY
83 #include <tmpdir.h>
84 #include <sys/wait.h>
85 # if defined(_SC_CRAY_SECURE_SYS) && !defined(SCM_SECURITY)
86 /*
87 * UNICOS 6.0/6.1 do not have SCM_SECURITY defined, so we can
88 * use it to tell us to turn off all the socket security code,
89 * since that is only used in UNICOS 7.0 and later.
90 */
91 # undef _SC_CRAY_SECURE_SYS
92 # endif
93
94 # if defined(_SC_CRAY_SECURE_SYS)
95 #include <sys/sysv.h>
96 #include <sys/secstat.h>
97 extern int secflag;
98 extern struct sysv sysv;
99 # endif /* _SC_CRAY_SECURE_SYS */
100 # endif /* CRAY */
101 #endif /* NEWINIT */
102
103 #ifdef STREAMSPTY
104 #include <sac.h>
105 #include <sys/stropts.h>
106 #endif
107
108 #define SCPYN(a, b) (void) strncpy(a, b, sizeof(a))
109 #define SCMPN(a, b) strncmp(a, b, sizeof(a))
110
111 #ifdef STREAMS
112 #include <sys/stream.h>
113 #endif
114 #ifdef __hpux
115 #include <sys/resource.h>
116 #include <sys/proc.h>
117 #endif
118 #include <sys/tty.h>
119 #ifdef t_erase
120 #undef t_erase
121 #undef t_kill
122 #undef t_intrc
123 #undef t_quitc
124 #undef t_startc
125 #undef t_stopc
126 #undef t_eofc
127 #undef t_brkc
128 #undef t_suspc
129 #undef t_dsuspc
130 #undef t_rprntc
131 #undef t_flushc
132 #undef t_werasc
133 #undef t_lnextc
134 #endif
135
136 #if defined(UNICOS5) && defined(CRAY2) && !defined(EXTPROC)
137 # define EXTPROC 0400
138 #endif
139
140 #ifndef USE_TERMIO
141 struct termbuf {
142 struct sgttyb sg;
143 struct tchars tc;
144 struct ltchars ltc;
145 int state;
146 int lflags;
147 } termbuf, termbuf2;
148 # define cfsetospeed(tp, val) (tp)->sg.sg_ospeed = (val)
149 # define cfsetispeed(tp, val) (tp)->sg.sg_ispeed = (val)
150 # define cfgetospeed(tp) (tp)->sg.sg_ospeed
151 # define cfgetispeed(tp) (tp)->sg.sg_ispeed
152 #else /* USE_TERMIO */
153 # ifdef SYSV_TERMIO
154 # define termios termio
155 # endif
156 # ifndef TCSANOW
157 # ifdef TCSETS
158 # define TCSANOW TCSETS
159 # define TCSADRAIN TCSETSW
160 # define tcgetattr(f, t) ioctl(f, TCGETS, (char *)t)
161 # else
162 # ifdef TCSETA
163 # define TCSANOW TCSETA
164 # define TCSADRAIN TCSETAW
165 # define tcgetattr(f, t) ioctl(f, TCGETA, (char *)t)
166 # else
167 # define TCSANOW TIOCSETA
168 # define TCSADRAIN TIOCSETAW
169 # define tcgetattr(f, t) ioctl(f, TIOCGETA, (char *)t)
170 # endif
171 # endif
172 # define tcsetattr(f, a, t) ioctl(f, a, t)
173 # define cfsetospeed(tp, val) (tp)->c_cflag &= ~CBAUD; \
174 (tp)->c_cflag |= (val)
175 # define cfgetospeed(tp) ((tp)->c_cflag & CBAUD)
176 # ifdef CIBAUD
177 # define cfsetispeed(tp, val) (tp)->c_cflag &= ~CIBAUD; \
178 (tp)->c_cflag |= ((val)<<IBSHIFT)
179 # define cfgetispeed(tp) (((tp)->c_cflag & CIBAUD)>>IBSHIFT)
180 # else
181 # define cfsetispeed(tp, val) (tp)->c_cflag &= ~CBAUD; \
182 (tp)->c_cflag |= (val)
183 # define cfgetispeed(tp) ((tp)->c_cflag & CBAUD)
184 # endif
185 # endif /* TCSANOW */
186 struct termios termbuf, termbuf2; /* pty control structure */
187 # ifdef STREAMSPTY
188 int ttyfd = -1;
189 # endif
190 #endif /* USE_TERMIO */
191
192 #include <sys/types.h>
193 #include <paths.h>
194
195 int cleanopen __P((char *));
196 void scrub_env __P((void));
197
198 /*
199 * init_termbuf()
200 * copy_termbuf(cp)
201 * set_termbuf()
202 *
203 * These three routines are used to get and set the "termbuf" structure
204 * to and from the kernel. init_termbuf() gets the current settings.
205 * copy_termbuf() hands in a new "termbuf" to write to the kernel, and
206 * set_termbuf() writes the structure into the kernel.
207 */
208
209 void
210 init_termbuf()
211 {
212 #ifndef USE_TERMIO
213 (void) ioctl(pty, TIOCGETP, (char *)&termbuf.sg);
214 (void) ioctl(pty, TIOCGETC, (char *)&termbuf.tc);
215 (void) ioctl(pty, TIOCGLTC, (char *)&termbuf.ltc);
216 # ifdef TIOCGSTATE
217 (void) ioctl(pty, TIOCGSTATE, (char *)&termbuf.state);
218 # endif
219 #else
220 # ifdef STREAMSPTY
221 (void) tcgetattr(ttyfd, &termbuf);
222 # else
223 (void) tcgetattr(pty, &termbuf);
224 # endif
225 #endif
226 termbuf2 = termbuf;
227 }
228
229 #if defined(LINEMODE) && defined(TIOCPKT_IOCTL)
230 void
231 copy_termbuf(cp, len)
232 char *cp;
233 int len;
234 {
235 if (len > sizeof(termbuf))
236 len = sizeof(termbuf);
237 memmove((char *)&termbuf, cp, len);
238 termbuf2 = termbuf;
239 }
240 #endif /* defined(LINEMODE) && defined(TIOCPKT_IOCTL) */
241
242 void
243 set_termbuf()
244 {
245 /*
246 * Only make the necessary changes.
247 */
248 #ifndef USE_TERMIO
249 if (bcmp((char *)&termbuf.sg, (char *)&termbuf2.sg, sizeof(termbuf.sg)))
250 (void) ioctl(pty, TIOCSETN, (char *)&termbuf.sg);
251 if (bcmp((char *)&termbuf.tc, (char *)&termbuf2.tc, sizeof(termbuf.tc)))
252 (void) ioctl(pty, TIOCSETC, (char *)&termbuf.tc);
253 if (bcmp((char *)&termbuf.ltc, (char *)&termbuf2.ltc,
254 sizeof(termbuf.ltc)))
255 (void) ioctl(pty, TIOCSLTC, (char *)&termbuf.ltc);
256 if (termbuf.lflags != termbuf2.lflags)
257 (void) ioctl(pty, TIOCLSET, (char *)&termbuf.lflags);
258 #else /* USE_TERMIO */
259 if (bcmp((char *)&termbuf, (char *)&termbuf2, sizeof(termbuf)))
260 # ifdef STREAMSPTY
261 (void) tcsetattr(ttyfd, TCSANOW, &termbuf);
262 # else
263 (void) tcsetattr(pty, TCSANOW, &termbuf);
264 # endif
265 # if defined(CRAY2) && defined(UNICOS5)
266 needtermstat = 1;
267 # endif
268 #endif /* USE_TERMIO */
269 }
270
271
272 /*
273 * spcset(func, valp, valpp)
274 *
275 * This function takes various special characters (func), and
276 * sets *valp to the current value of that character, and
277 * *valpp to point to where in the "termbuf" structure that
278 * value is kept.
279 *
280 * It returns the SLC_ level of support for this function.
281 */
282
283 #ifndef USE_TERMIO
284 int
285 spcset(func, valp, valpp)
286 int func;
287 cc_t *valp;
288 cc_t **valpp;
289 {
290 switch(func) {
291 case SLC_EOF:
292 *valp = termbuf.tc.t_eofc;
293 *valpp = (cc_t *)&termbuf.tc.t_eofc;
294 return(SLC_VARIABLE);
295 case SLC_EC:
296 *valp = termbuf.sg.sg_erase;
297 *valpp = (cc_t *)&termbuf.sg.sg_erase;
298 return(SLC_VARIABLE);
299 case SLC_EL:
300 *valp = termbuf.sg.sg_kill;
301 *valpp = (cc_t *)&termbuf.sg.sg_kill;
302 return(SLC_VARIABLE);
303 case SLC_IP:
304 *valp = termbuf.tc.t_intrc;
305 *valpp = (cc_t *)&termbuf.tc.t_intrc;
306 return(SLC_VARIABLE|SLC_FLUSHIN|SLC_FLUSHOUT);
307 case SLC_ABORT:
308 *valp = termbuf.tc.t_quitc;
309 *valpp = (cc_t *)&termbuf.tc.t_quitc;
310 return(SLC_VARIABLE|SLC_FLUSHIN|SLC_FLUSHOUT);
311 case SLC_XON:
312 *valp = termbuf.tc.t_startc;
313 *valpp = (cc_t *)&termbuf.tc.t_startc;
314 return(SLC_VARIABLE);
315 case SLC_XOFF:
316 *valp = termbuf.tc.t_stopc;
317 *valpp = (cc_t *)&termbuf.tc.t_stopc;
318 return(SLC_VARIABLE);
319 case SLC_AO:
320 *valp = termbuf.ltc.t_flushc;
321 *valpp = (cc_t *)&termbuf.ltc.t_flushc;
322 return(SLC_VARIABLE);
323 case SLC_SUSP:
324 *valp = termbuf.ltc.t_suspc;
325 *valpp = (cc_t *)&termbuf.ltc.t_suspc;
326 return(SLC_VARIABLE);
327 case SLC_EW:
328 *valp = termbuf.ltc.t_werasc;
329 *valpp = (cc_t *)&termbuf.ltc.t_werasc;
330 return(SLC_VARIABLE);
331 case SLC_RP:
332 *valp = termbuf.ltc.t_rprntc;
333 *valpp = (cc_t *)&termbuf.ltc.t_rprntc;
334 return(SLC_VARIABLE);
335 case SLC_LNEXT:
336 *valp = termbuf.ltc.t_lnextc;
337 *valpp = (cc_t *)&termbuf.ltc.t_lnextc;
338 return(SLC_VARIABLE);
339 case SLC_FORW1:
340 *valp = termbuf.tc.t_brkc;
341 *valpp = (cc_t *)&termbuf.ltc.t_lnextc;
342 return(SLC_VARIABLE);
343 case SLC_BRK:
344 case SLC_SYNCH:
345 case SLC_AYT:
346 case SLC_EOR:
347 *valp = (cc_t)0;
348 *valpp = (cc_t *)0;
349 return(SLC_DEFAULT);
350 default:
351 *valp = (cc_t)0;
352 *valpp = (cc_t *)0;
353 return(SLC_NOSUPPORT);
354 }
355 }
356
357 #else /* USE_TERMIO */
358
359 int
360 spcset(func, valp, valpp)
361 int func;
362 cc_t *valp;
363 cc_t **valpp;
364 {
365
366 #define setval(a, b) *valp = termbuf.c_cc[a]; \
367 *valpp = &termbuf.c_cc[a]; \
368 return(b);
369 #define defval(a) *valp = ((cc_t)a); *valpp = (cc_t *)0; return(SLC_DEFAULT);
370
371 switch(func) {
372 case SLC_EOF:
373 setval(VEOF, SLC_VARIABLE);
374 case SLC_EC:
375 setval(VERASE, SLC_VARIABLE);
376 case SLC_EL:
377 setval(VKILL, SLC_VARIABLE);
378 case SLC_IP:
379 setval(VINTR, SLC_VARIABLE|SLC_FLUSHIN|SLC_FLUSHOUT);
380 case SLC_ABORT:
381 setval(VQUIT, SLC_VARIABLE|SLC_FLUSHIN|SLC_FLUSHOUT);
382 case SLC_XON:
383 #ifdef VSTART
384 setval(VSTART, SLC_VARIABLE);
385 #else
386 defval(0x13);
387 #endif
388 case SLC_XOFF:
389 #ifdef VSTOP
390 setval(VSTOP, SLC_VARIABLE);
391 #else
392 defval(0x11);
393 #endif
394 case SLC_EW:
395 #ifdef VWERASE
396 setval(VWERASE, SLC_VARIABLE);
397 #else
398 defval(0);
399 #endif
400 case SLC_RP:
401 #ifdef VREPRINT
402 setval(VREPRINT, SLC_VARIABLE);
403 #else
404 defval(0);
405 #endif
406 case SLC_LNEXT:
407 #ifdef VLNEXT
408 setval(VLNEXT, SLC_VARIABLE);
409 #else
410 defval(0);
411 #endif
412 case SLC_AO:
413 #if !defined(VDISCARD) && defined(VFLUSHO)
414 # define VDISCARD VFLUSHO
415 #endif
416 #ifdef VDISCARD
417 setval(VDISCARD, SLC_VARIABLE|SLC_FLUSHOUT);
418 #else
419 defval(0);
420 #endif
421 case SLC_SUSP:
422 #ifdef VSUSP
423 setval(VSUSP, SLC_VARIABLE|SLC_FLUSHIN);
424 #else
425 defval(0);
426 #endif
427 #ifdef VEOL
428 case SLC_FORW1:
429 setval(VEOL, SLC_VARIABLE);
430 #endif
431 #ifdef VEOL2
432 case SLC_FORW2:
433 setval(VEOL2, SLC_VARIABLE);
434 #endif
435 case SLC_AYT:
436 #ifdef VSTATUS
437 setval(VSTATUS, SLC_VARIABLE);
438 #else
439 defval(0);
440 #endif
441
442 case SLC_BRK:
443 case SLC_SYNCH:
444 case SLC_EOR:
445 defval(0);
446
447 default:
448 *valp = 0;
449 *valpp = 0;
450 return(SLC_NOSUPPORT);
451 }
452 }
453 #endif /* USE_TERMIO */
454
455 #ifdef CRAY
456 /*
457 * getnpty()
458 *
459 * Return the number of pty's configured into the system.
460 */
461 int
462 getnpty()
463 {
464 #ifdef _SC_CRAY_NPTY
465 int numptys;
466
467 if ((numptys = sysconf(_SC_CRAY_NPTY)) != -1)
468 return numptys;
469 else
470 #endif /* _SC_CRAY_NPTY */
471 return 128;
472 }
473 #endif /* CRAY */
474
475 #ifndef convex
476 /*
477 * getpty()
478 *
479 * Allocate a pty. As a side effect, the external character
480 * array "line" contains the name of the slave side.
481 *
482 * Returns the file descriptor of the opened pty.
483 */
484 #ifdef CRAY
485 char myline[16];
486 #else
487 /*
488 char line[16];
489 */
490 #endif /* CRAY */
491
492 int
493 getpty(ptynum)
494 int *ptynum;
495 {
496 register int p;
497 #ifdef STREAMSPTY
498 int t;
499 char *ptsname();
500
501 p = open("/dev/ptmx", 2);
502 if (p > 0) {
503 grantpt(p);
504 unlockpt(p);
505 strcpy(line, ptsname(p));
506 return(p);
507 }
508
509 #else /* ! STREAMSPTY */
510 #ifndef CRAY
511 register char *cp, *p1, *p2;
512 register int i;
513 #if defined(sun) && defined(TIOCGPGRP) && BSD < 199207
514 int dummy;
515 #endif
516
517 #ifndef __hpux
518 (void) strcpy(line, _PATH_DEV);
519 (void) strcat(line, "ptyXX");
520 p1 = &line[8];
521 p2 = &line[9];
522 #else
523 (void) strcpy(line, "/dev/ptym/ptyXX");
524 p1 = &line[13];
525 p2 = &line[14];
526 #endif
527
528 for (cp = "pqrsPQRS"; *cp; cp++) {
529 struct stat stb;
530
531 *p1 = *cp;
532 *p2 = '0';
533 /*
534 * This stat() check is just to keep us from
535 * looping through all 256 combinations if there
536 * aren't that many ptys available.
537 */
538 if (stat(line, &stb) < 0)
539 break;
540 for (i = 0; i < 32; i++) {
541 *p2 = "0123456789abcdefghijklmnopqrstuv"[i];
542 p = open(line, 2);
543 if (p > 0) {
544 #ifndef __hpux
545 line[5] = 't';
546 #else
547 for (p1 = &line[8]; *p1; p1++)
548 *p1 = *(p1+1);
549 line[9] = 't';
550 #endif
551 chown(line, 0, 0);
552 chmod(line, 0600);
553 #if defined(sun) && defined(TIOCGPGRP) && BSD < 199207
554 if (ioctl(p, TIOCGPGRP, &dummy) == 0
555 || errno != EIO) {
556 chmod(line, 0666);
557 close(p);
558 line[5] = 'p';
559 } else
560 #endif /* defined(sun) && defined(TIOCGPGRP) && BSD < 199207 */
561 return(p);
562 }
563 }
564 }
565 #else /* CRAY */
566 extern lowpty, highpty;
567 struct stat sb;
568
569 for (*ptynum = lowpty; *ptynum <= highpty; (*ptynum)++) {
570 (void) sprintf(myline, "%spty/%03d", _PATH_DEV, *ptynum);
571 p = open(myline, 2);
572 if (p < 0)
573 continue;
574 (void) sprintf(line, "/dev/ttyp%03d", *ptynum);
575 /*
576 * Here are some shenanigans to make sure that there
577 * are no listeners lurking on the line.
578 */
579 if(stat(line, &sb) < 0) {
580 (void) close(p);
581 continue;
582 }
583 if(sb.st_uid || sb.st_gid || sb.st_mode != 0600) {
584 chown(line, 0, 0);
585 chmod(line, 0600);
586 (void)close(p);
587 p = open(myline, 2);
588 if (p < 0)
589 continue;
590 }
591 /*
592 * Now it should be safe...check for accessability.
593 */
594 if (access(line, 6) == 0)
595 return(p);
596 else {
597 /* no tty side to pty so skip it */
598 (void) close(p);
599 }
600 }
601 #endif /* CRAY */
602 #endif /* STREAMSPTY */
603 return(-1);
604 }
605 #endif /* convex */
606
607 #ifdef LINEMODE
608 /*
609 * tty_flowmode() Find out if flow control is enabled or disabled.
610 * tty_linemode() Find out if linemode (external processing) is enabled.
611 * tty_setlinemod(on) Turn on/off linemode.
612 * tty_isecho() Find out if echoing is turned on.
613 * tty_setecho(on) Enable/disable character echoing.
614 * tty_israw() Find out if terminal is in RAW mode.
615 * tty_binaryin(on) Turn on/off BINARY on input.
616 * tty_binaryout(on) Turn on/off BINARY on output.
617 * tty_isediting() Find out if line editing is enabled.
618 * tty_istrapsig() Find out if signal trapping is enabled.
619 * tty_setedit(on) Turn on/off line editing.
620 * tty_setsig(on) Turn on/off signal trapping.
621 * tty_issofttab() Find out if tab expansion is enabled.
622 * tty_setsofttab(on) Turn on/off soft tab expansion.
623 * tty_islitecho() Find out if typed control chars are echoed literally
624 * tty_setlitecho() Turn on/off literal echo of control chars
625 * tty_tspeed(val) Set transmit speed to val.
626 * tty_rspeed(val) Set receive speed to val.
627 */
628
629 #ifdef convex
630 static int linestate;
631 #endif
632
633 int
634 tty_linemode()
635 {
636 #ifndef convex
637 #ifndef USE_TERMIO
638 return(termbuf.state & TS_EXTPROC);
639 #else
640 return(termbuf.c_lflag & EXTPROC);
641 #endif
642 #else
643 return(linestate);
644 #endif
645 }
646
647 void
648 tty_setlinemode(on)
649 int on;
650 {
651 #ifdef TIOCEXT
652 # ifndef convex
653 set_termbuf();
654 # else
655 linestate = on;
656 # endif
657 (void) ioctl(pty, TIOCEXT, (char *)&on);
658 # ifndef convex
659 init_termbuf();
660 # endif
661 #else /* !TIOCEXT */
662 # ifdef EXTPROC
663 if (on)
664 termbuf.c_lflag |= EXTPROC;
665 else
666 termbuf.c_lflag &= ~EXTPROC;
667 # endif
668 #endif /* TIOCEXT */
669 }
670 #endif /* LINEMODE */
671
672 int
673 tty_isecho()
674 {
675 #ifndef USE_TERMIO
676 return (termbuf.sg.sg_flags & ECHO);
677 #else
678 return (termbuf.c_lflag & ECHO);
679 #endif
680 }
681
682 int
683 tty_flowmode()
684 {
685 #ifndef USE_TERMIO
686 return(((termbuf.tc.t_startc) > 0 && (termbuf.tc.t_stopc) > 0) ? 1 : 0);
687 #else
688 return((termbuf.c_iflag & IXON) ? 1 : 0);
689 #endif
690 }
691
692 int
693 tty_restartany()
694 {
695 #ifndef USE_TERMIO
696 # ifdef DECCTQ
697 return((termbuf.lflags & DECCTQ) ? 0 : 1);
698 # else
699 return(-1);
700 # endif
701 #else
702 return((termbuf.c_iflag & IXANY) ? 1 : 0);
703 #endif
704 }
705
706 void
707 tty_setecho(on)
708 int on;
709 {
710 #ifndef USE_TERMIO
711 if (on)
712 termbuf.sg.sg_flags |= ECHO|CRMOD;
713 else
714 termbuf.sg.sg_flags &= ~(ECHO|CRMOD);
715 #else
716 if (on)
717 termbuf.c_lflag |= ECHO;
718 else
719 termbuf.c_lflag &= ~ECHO;
720 #endif
721 }
722
723 int
724 tty_israw()
725 {
726 #ifndef USE_TERMIO
727 return(termbuf.sg.sg_flags & RAW);
728 #else
729 return(!(termbuf.c_lflag & ICANON));
730 #endif
731 }
732
733 #if defined (AUTHENTICATION) && defined(NO_LOGIN_F) && defined(LOGIN_R)
734 int
735 tty_setraw(on)
736 {
737 # ifndef USE_TERMIO
738 if (on)
739 termbuf.sg.sg_flags |= RAW;
740 else
741 termbuf.sg.sg_flags &= ~RAW;
742 # else
743 if (on)
744 termbuf.c_lflag &= ~ICANON;
745 else
746 termbuf.c_lflag |= ICANON;
747 # endif
748 }
749 #endif
750
751 void
752 tty_binaryin(on)
753 int on;
754 {
755 #ifndef USE_TERMIO
756 if (on)
757 termbuf.lflags |= LPASS8;
758 else
759 termbuf.lflags &= ~LPASS8;
760 #else
761 if (on) {
762 termbuf.c_iflag &= ~ISTRIP;
763 } else {
764 termbuf.c_iflag |= ISTRIP;
765 }
766 #endif
767 }
768
769 void
770 tty_binaryout(on)
771 int on;
772 {
773 #ifndef USE_TERMIO
774 if (on)
775 termbuf.lflags |= LLITOUT;
776 else
777 termbuf.lflags &= ~LLITOUT;
778 #else
779 if (on) {
780 termbuf.c_cflag &= ~(CSIZE|PARENB);
781 termbuf.c_cflag |= CS8;
782 termbuf.c_oflag &= ~OPOST;
783 } else {
784 termbuf.c_cflag &= ~CSIZE;
785 termbuf.c_cflag |= CS7|PARENB;
786 termbuf.c_oflag |= OPOST;
787 }
788 #endif
789 }
790
791 int
792 tty_isbinaryin()
793 {
794 #ifndef USE_TERMIO
795 return(termbuf.lflags & LPASS8);
796 #else
797 return(!(termbuf.c_iflag & ISTRIP));
798 #endif
799 }
800
801 int
802 tty_isbinaryout()
803 {
804 #ifndef USE_TERMIO
805 return(termbuf.lflags & LLITOUT);
806 #else
807 return(!(termbuf.c_oflag&OPOST));
808 #endif
809 }
810
811 #ifdef LINEMODE
812 int
813 tty_isediting()
814 {
815 #ifndef USE_TERMIO
816 return(!(termbuf.sg.sg_flags & (CBREAK|RAW)));
817 #else
818 return(termbuf.c_lflag & ICANON);
819 #endif
820 }
821
822 int
823 tty_istrapsig()
824 {
825 #ifndef USE_TERMIO
826 return(!(termbuf.sg.sg_flags&RAW));
827 #else
828 return(termbuf.c_lflag & ISIG);
829 #endif
830 }
831
832 void
833 tty_setedit(on)
834 int on;
835 {
836 #ifndef USE_TERMIO
837 if (on)
838 termbuf.sg.sg_flags &= ~CBREAK;
839 else
840 termbuf.sg.sg_flags |= CBREAK;
841 #else
842 if (on)
843 termbuf.c_lflag |= ICANON;
844 else
845 termbuf.c_lflag &= ~ICANON;
846 #endif
847 }
848
849 void
850 tty_setsig(on)
851 int on;
852 {
853 #ifndef USE_TERMIO
854 if (on)
855 ;
856 #else
857 if (on)
858 termbuf.c_lflag |= ISIG;
859 else
860 termbuf.c_lflag &= ~ISIG;
861 #endif
862 }
863 #endif /* LINEMODE */
864
865 int
866 tty_issofttab()
867 {
868 #ifndef USE_TERMIO
869 return (termbuf.sg.sg_flags & XTABS);
870 #else
871 # ifdef OXTABS
872 return (termbuf.c_oflag & OXTABS);
873 # endif
874 # ifdef TABDLY
875 return ((termbuf.c_oflag & TABDLY) == TAB3);
876 # endif
877 #endif
878 }
879
880 void
881 tty_setsofttab(on)
882 int on;
883 {
884 #ifndef USE_TERMIO
885 if (on)
886 termbuf.sg.sg_flags |= XTABS;
887 else
888 termbuf.sg.sg_flags &= ~XTABS;
889 #else
890 if (on) {
891 # ifdef OXTABS
892 termbuf.c_oflag |= OXTABS;
893 # endif
894 # ifdef TABDLY
895 termbuf.c_oflag &= ~TABDLY;
896 termbuf.c_oflag |= TAB3;
897 # endif
898 } else {
899 # ifdef OXTABS
900 termbuf.c_oflag &= ~OXTABS;
901 # endif
902 # ifdef TABDLY
903 termbuf.c_oflag &= ~TABDLY;
904 termbuf.c_oflag |= TAB0;
905 # endif
906 }
907 #endif
908 }
909
910 int
911 tty_islitecho()
912 {
913 #ifndef USE_TERMIO
914 return (!(termbuf.lflags & LCTLECH));
915 #else
916 # ifdef ECHOCTL
917 return (!(termbuf.c_lflag & ECHOCTL));
918 # endif
919 # ifdef TCTLECH
920 return (!(termbuf.c_lflag & TCTLECH));
921 # endif
922 # if !defined(ECHOCTL) && !defined(TCTLECH)
923 return (0); /* assumes ctl chars are echoed '^x' */
924 # endif
925 #endif
926 }
927
928 void
929 tty_setlitecho(on)
930 int on;
931 {
932 #ifndef USE_TERMIO
933 if (on)
934 termbuf.lflags &= ~LCTLECH;
935 else
936 termbuf.lflags |= LCTLECH;
937 #else
938 # ifdef ECHOCTL
939 if (on)
940 termbuf.c_lflag &= ~ECHOCTL;
941 else
942 termbuf.c_lflag |= ECHOCTL;
943 # endif
944 # ifdef TCTLECH
945 if (on)
946 termbuf.c_lflag &= ~TCTLECH;
947 else
948 termbuf.c_lflag |= TCTLECH;
949 # endif
950 #endif
951 }
952
953 int
954 tty_iscrnl()
955 {
956 #ifndef USE_TERMIO
957 return (termbuf.sg.sg_flags & CRMOD);
958 #else
959 return (termbuf.c_iflag & ICRNL);
960 #endif
961 }
962
963 /*
964 * Try to guess whether speeds are "encoded" (4.2BSD) or just numeric (4.4BSD).
965 */
966 #if B4800 != 4800
967 #define DECODE_BAUD
968 #endif
969
970 #ifdef DECODE_BAUD
971 /*
972 * A table of available terminal speeds
973 */
974 struct termspeeds {
975 int speed;
976 int value;
977 } termspeeds[] = {
978 { 0, B0 }, { 50, B50 }, { 75, B75 },
979 { 110, B110 }, { 134, B134 }, { 150, B150 },
980 { 200, B200 }, { 300, B300 }, { 600, B600 },
981 { 1200, B1200 }, { 1800, B1800 }, { 2400, B2400 },
982 { 4800, B4800 }, { 9600, B9600 }, { 19200, B9600 },
983 { 38400, B9600 }, { -1, B9600 }
984 };
985 #endif /* DECODE_BAUD */
986
987 void
988 tty_tspeed(val)
989 int val;
990 {
991 #ifdef DECODE_BAUD
992 register struct termspeeds *tp;
993
994 for (tp = termspeeds; (tp->speed != -1) && (val > tp->speed); tp++)
995 ;
996 cfsetospeed(&termbuf, tp->value);
997 #else /* DECODE_BAUD */
998 cfsetospeed(&termbuf, val);
999 #endif /* DECODE_BAUD */
1000 }
1001
1002 void
1003 tty_rspeed(val)
1004 int val;
1005 {
1006 #ifdef DECODE_BAUD
1007 register struct termspeeds *tp;
1008
1009 for (tp = termspeeds; (tp->speed != -1) && (val > tp->speed); tp++)
1010 ;
1011 cfsetispeed(&termbuf, tp->value);
1012 #else /* DECODE_BAUD */
1013 cfsetispeed(&termbuf, val);
1014 #endif /* DECODE_BAUD */
1015 }
1016
1017 #if defined(CRAY2) && defined(UNICOS5)
1018 int
1019 tty_isnewmap()
1020 {
1021 return((termbuf.c_oflag & OPOST) && (termbuf.c_oflag & ONLCR) &&
1022 !(termbuf.c_oflag & ONLRET));
1023 }
1024 #endif
1025
1026 #ifdef PARENT_DOES_UTMP
1027 # ifndef NEWINIT
1028 extern struct utmp wtmp;
1029 extern char wtmpf[];
1030 # else /* NEWINIT */
1031 int gotalarm;
1032
1033 /* ARGSUSED */
1034 void
1035 nologinproc(sig)
1036 int sig;
1037 {
1038 gotalarm++;
1039 }
1040 # endif /* NEWINIT */
1041 #endif /* PARENT_DOES_UTMP */
1042
1043 #ifndef NEWINIT
1044 # ifdef PARENT_DOES_UTMP
1045 extern void utmp_sig_init P((void));
1046 extern void utmp_sig_reset P((void));
1047 extern void utmp_sig_wait P((void));
1048 extern void utmp_sig_notify P((int));
1049 # endif /* PARENT_DOES_UTMP */
1050 #endif
1051
1052 /*
1053 * getptyslave()
1054 *
1055 * Open the slave side of the pty, and do any initialization
1056 * that is necessary.
1057 */
1058 void
1059 getptyslave()
1060 {
1061 register int t = -1;
1062 char erase;
1063
1064 #if !defined(CRAY) || !defined(NEWINIT)
1065 # ifdef LINEMODE
1066 int waslm;
1067 # endif
1068 # ifdef TIOCGWINSZ
1069 struct winsize ws;
1070 extern int def_row, def_col;
1071 # endif
1072 extern int def_tspeed, def_rspeed;
1073 /*
1074 * Opening the slave side may cause initilization of the
1075 * kernel tty structure. We need remember the state of
1076 * if linemode was turned on
1077 * terminal window size
1078 * terminal speed
1079 * erase character
1080 * so that we can re-set them if we need to.
1081 */
1082 # ifdef LINEMODE
1083 waslm = tty_linemode();
1084 # endif
1085 erase = termbuf.c_cc[VERASE];
1086
1087 /*
1088 * Make sure that we don't have a controlling tty, and
1089 * that we are the session (process group) leader.
1090 */
1091 # ifdef TIOCNOTTY
1092 t = open(_PATH_TTY, O_RDWR);
1093 if (t >= 0) {
1094 (void) ioctl(t, TIOCNOTTY, (char *)0);
1095 (void) close(t);
1096 }
1097 # endif
1098
1099
1100 # ifdef PARENT_DOES_UTMP
1101 /*
1102 * Wait for our parent to get the utmp stuff to get done.
1103 */
1104 utmp_sig_wait();
1105 # endif
1106
1107 t = cleanopen(line);
1108 if (t < 0)
1109 fatalperror(net, line);
1110
1111 #ifdef STREAMSPTY
1112 #ifdef USE_TERMIO
1113 ttyfd = t;
1114 #endif
1115 if (ioctl(t, I_PUSH, "ptem") < 0)
1116 fatal(net, "I_PUSH ptem");
1117 if (ioctl(t, I_PUSH, "ldterm") < 0)
1118 fatal(net, "I_PUSH ldterm");
1119 if (ioctl(t, I_PUSH, "ttcompat") < 0)
1120 fatal(net, "I_PUSH ttcompat");
1121 if (ioctl(pty, I_PUSH, "pckt") < 0)
1122 fatal(net, "I_PUSH pckt");
1123 #endif
1124
1125 /*
1126 * set up the tty modes as we like them to be.
1127 */
1128 init_termbuf();
1129 # ifdef TIOCGWINSZ
1130 if (def_row || def_col) {
1131 bzero((char *)&ws, sizeof(ws));
1132 ws.ws_col = def_col;
1133 ws.ws_row = def_row;
1134 (void)ioctl(t, TIOCSWINSZ, (char *)&ws);
1135 }
1136 # endif
1137
1138 /*
1139 * Settings for sgtty based systems
1140 */
1141 # ifndef USE_TERMIO
1142 termbuf.sg.sg_flags |= CRMOD|ANYP|ECHO|XTABS;
1143 # endif /* USE_TERMIO */
1144
1145 /*
1146 * Settings for UNICOS (and HPUX)
1147 */
1148 # if defined(CRAY) || defined(__hpux)
1149 termbuf.c_oflag = OPOST|ONLCR|TAB3;
1150 termbuf.c_iflag = IGNPAR|ISTRIP|ICRNL|IXON;
1151 termbuf.c_lflag = ISIG|ICANON|ECHO|ECHOE|ECHOK;
1152 termbuf.c_cflag = EXTB|HUPCL|CS8;
1153 # endif
1154
1155 /*
1156 * Settings for all other termios/termio based
1157 * systems, other than 4.4BSD. In 4.4BSD the
1158 * kernel does the initial terminal setup.
1159 */
1160 # if defined(USE_TERMIO) && !(defined(CRAY) || defined(__hpux)) && (BSD <= 43)
1161 # ifndef OXTABS
1162 # define OXTABS 0
1163 # endif
1164 termbuf.c_lflag |= ECHO;
1165 termbuf.c_oflag |= ONLCR|OXTABS;
1166 termbuf.c_iflag |= ICRNL;
1167 termbuf.c_iflag &= ~IXOFF;
1168 # endif /* defined(USE_TERMIO) && !defined(CRAY) && (BSD <= 43) */
1169 tty_rspeed((def_rspeed > 0) ? def_rspeed : 9600);
1170 tty_tspeed((def_tspeed > 0) ? def_tspeed : 9600);
1171 if (erase)
1172 termbuf.c_cc[VERASE] = erase;
1173 # ifdef LINEMODE
1174 if (waslm)
1175 tty_setlinemode(1);
1176 # endif /* LINEMODE */
1177
1178 /*
1179 * Set the tty modes, and make this our controlling tty.
1180 */
1181 set_termbuf();
1182 if (login_tty(t) == -1)
1183 fatalperror(net, "login_tty");
1184 #endif /* !defined(CRAY) || !defined(NEWINIT) */
1185 if (net > 2)
1186 (void) close(net);
1187 #if defined(AUTHENTICATION) && defined(NO_LOGIN_F) && defined(LOGIN_R)
1188 /*
1189 * Leave the pty open so that we can write out the rlogin
1190 * protocol for /bin/login, if the authentication works.
1191 */
1192 #else
1193 if (pty > 2) {
1194 (void) close(pty);
1195 pty = -1;
1196 }
1197 #endif
1198 }
1199
1200 #if !defined(CRAY) || !defined(NEWINIT)
1201 #ifndef O_NOCTTY
1202 #define O_NOCTTY 0
1203 #endif
1204 /*
1205 * Open the specified slave side of the pty,
1206 * making sure that we have a clean tty.
1207 */
1208 int
1209 cleanopen(line)
1210 char *line;
1211 {
1212 register int t;
1213 #if defined(_SC_CRAY_SECURE_SYS)
1214 struct secstat secbuf;
1215 #endif /* _SC_CRAY_SECURE_SYS */
1216
1217 #ifndef STREAMSPTY
1218 /*
1219 * Make sure that other people can't open the
1220 * slave side of the connection.
1221 */
1222 (void) chown(line, 0, 0);
1223 (void) chmod(line, 0600);
1224 #endif
1225
1226 # if !defined(CRAY) && (BSD > 43)
1227 (void) revoke(line);
1228 # endif
1229 #if defined(_SC_CRAY_SECURE_SYS)
1230 if (secflag) {
1231 if (secstat(line, &secbuf) < 0)
1232 return(-1);
1233 if (setulvl(secbuf.st_slevel) < 0)
1234 return(-1);
1235 if (setucmp(secbuf.st_compart) < 0)
1236 return(-1);
1237 }
1238 #endif /* _SC_CRAY_SECURE_SYS */
1239
1240 t = open(line, O_RDWR|O_NOCTTY);
1241
1242 #if defined(_SC_CRAY_SECURE_SYS)
1243 if (secflag) {
1244 if (setulvl(sysv.sy_minlvl) < 0)
1245 return(-1);
1246 if (setucmp(0) < 0)
1247 return(-1);
1248 }
1249 #endif /* _SC_CRAY_SECURE_SYS */
1250
1251 if (t < 0)
1252 return(-1);
1253
1254 /*
1255 * Hangup anybody else using this ttyp, then reopen it for
1256 * ourselves.
1257 */
1258 # if !(defined(CRAY) || defined(__hpux)) && (BSD <= 43) && !defined(STREAMSPTY)
1259 (void) signal(SIGHUP, SIG_IGN);
1260 vhangup();
1261 (void) signal(SIGHUP, SIG_DFL);
1262 t = open(line, O_RDWR|O_NOCTTY);
1263 if (t < 0)
1264 return(-1);
1265 # endif
1266 # if defined(CRAY) && defined(TCVHUP)
1267 {
1268 register int i;
1269 (void) signal(SIGHUP, SIG_IGN);
1270 (void) ioctl(t, TCVHUP, (char *)0);
1271 (void) signal(SIGHUP, SIG_DFL);
1272 setpgrp();
1273
1274 #if defined(_SC_CRAY_SECURE_SYS)
1275 if (secflag) {
1276 if (secstat(line, &secbuf) < 0)
1277 return(-1);
1278 if (setulvl(secbuf.st_slevel) < 0)
1279 return(-1);
1280 if (setucmp(secbuf.st_compart) < 0)
1281 return(-1);
1282 }
1283 #endif /* _SC_CRAY_SECURE_SYS */
1284
1285 i = open(line, O_RDWR);
1286
1287 #if defined(_SC_CRAY_SECURE_SYS)
1288 if (secflag) {
1289 if (setulvl(sysv.sy_minlvl) < 0)
1290 return(-1);
1291 if (setucmp(0) < 0)
1292 return(-1);
1293 }
1294 #endif /* _SC_CRAY_SECURE_SYS */
1295
1296 if (i < 0)
1297 return(-1);
1298 (void) close(t);
1299 t = i;
1300 }
1301 # endif /* defined(CRAY) && defined(TCVHUP) */
1302 return(t);
1303 }
1304 #endif /* !defined(CRAY) || !defined(NEWINIT) */
1305
1306 #if BSD <= 43
1307
1308 int
1309 login_tty(t)
1310 int t;
1311 {
1312 if (setsid() < 0) {
1313 #ifdef ultrix
1314 /*
1315 * The setsid() may have failed because we
1316 * already have a pgrp == pid. Zero out
1317 * our pgrp and try again...
1318 */
1319 if ((setpgrp(0, 0) < 0) || (setsid() < 0))
1320 #endif
1321 fatalperror(net, "setsid()");
1322 }
1323 # ifdef TIOCSCTTY
1324 if (ioctl(t, TIOCSCTTY, (char *)0) < 0)
1325 fatalperror(net, "ioctl(sctty)");
1326 # if defined(CRAY)
1327 /*
1328 * Close the hard fd to /dev/ttypXXX, and re-open through
1329 * the indirect /dev/tty interface.
1330 */
1331 close(t);
1332 if ((t = open(_PATH_TTY, O_RDWR)) < 0)
1333 fatalperror(net, "open(/dev/tty)");
1334 # endif
1335 # else
1336 /*
1337 * We get our controlling tty assigned as a side-effect
1338 * of opening up a tty device. But on BSD based systems,
1339 * this only happens if our process group is zero. The
1340 * setsid() call above may have set our pgrp, so clear
1341 * it out before opening the tty...
1342 */
1343 (void) setpgrp(0, 0);
1344 close(open(line, O_RDWR));
1345 # endif
1346 if (t != 0)
1347 (void) dup2(t, 0);
1348 if (t != 1)
1349 (void) dup2(t, 1);
1350 if (t != 2)
1351 (void) dup2(t, 2);
1352 if (t > 2)
1353 close(t);
1354 return(0);
1355 }
1356 #endif /* BSD <= 43 */
1357
1358 #ifdef NEWINIT
1359 char *gen_id = "fe";
1360 #endif
1361
1362 /*
1363 * startslave(host)
1364 *
1365 * Given a hostname, do whatever
1366 * is necessary to startup the login process on the slave side of the pty.
1367 */
1368
1369 /* ARGSUSED */
1370 void
1371 startslave(host, autologin, autoname)
1372 char *host;
1373 int autologin;
1374 char *autoname;
1375 {
1376 register int i;
1377 #ifdef NEWINIT
1378 extern char *ptyip;
1379 struct init_request request;
1380 void nologinproc();
1381 register int n;
1382 #endif /* NEWINIT */
1383
1384 #if defined(AUTHENTICATION)
1385 if (!autoname || !autoname[0])
1386 autologin = 0;
1387
1388 if (autologin < auth_level) {
1389 fatal(net, "Authorization failed");
1390 exit(1);
1391 }
1392 #endif
1393
1394 #ifndef NEWINIT
1395 # ifdef PARENT_DOES_UTMP
1396 utmp_sig_init();
1397 # endif /* PARENT_DOES_UTMP */
1398
1399 if ((i = fork()) < 0)
1400 fatalperror(net, "fork");
1401 if (i) {
1402 # ifdef PARENT_DOES_UTMP
1403 /*
1404 * Cray parent will create utmp entry for child and send
1405 * signal to child to tell when done. Child waits for signal
1406 * before doing anything important.
1407 */
1408 register int pid = i;
1409 void sigjob P((int));
1410
1411 setpgrp();
1412 utmp_sig_reset(); /* reset handler to default */
1413 /*
1414 * Create utmp entry for child
1415 */
1416 (void) time(&wtmp.ut_time);
1417 wtmp.ut_type = LOGIN_PROCESS;
1418 wtmp.ut_pid = pid;
1419 SCPYN(wtmp.ut_user, "LOGIN");
1420 SCPYN(wtmp.ut_host, host);
1421 SCPYN(wtmp.ut_line, line + sizeof(_PATH_DEV) - 1);
1422 #ifndef __hpux
1423 SCPYN(wtmp.ut_id, wtmp.ut_line+3);
1424 #else
1425 SCPYN(wtmp.ut_id, wtmp.ut_line+7);
1426 #endif
1427 pututline(&wtmp);
1428 endutent();
1429 if ((i = open(wtmpf, O_WRONLY|O_APPEND)) >= 0) {
1430 (void) write(i, (char *)&wtmp, sizeof(struct utmp));
1431 (void) close(i);
1432 }
1433 #ifdef CRAY
1434 (void) signal(WJSIGNAL, sigjob);
1435 #endif
1436 utmp_sig_notify(pid);
1437 # endif /* PARENT_DOES_UTMP */
1438 } else {
1439 getptyslave(autologin);
1440 start_login(host, autologin, autoname);
1441 /*NOTREACHED*/
1442 }
1443 #else /* NEWINIT */
1444
1445 /*
1446 * Init will start up login process if we ask nicely. We only wait
1447 * for it to start up and begin normal telnet operation.
1448 */
1449 if ((i = open(INIT_FIFO, O_WRONLY)) < 0) {
1450 char tbuf[128];
1451 (void) snprintf(tbuf, sizeof(tbuf), "Can't open %s\n", INIT_FIFO);
1452 fatalperror(net, tbuf);
1453 }
1454 memset((char *)&request, 0, sizeof(request));
1455 request.magic = INIT_MAGIC;
1456 SCPYN(request.gen_id, gen_id);
1457 SCPYN(request.tty_id, &line[8]);
1458 SCPYN(request.host, host);
1459 SCPYN(request.term_type, terminaltype ? terminaltype : "network");
1460 #if !defined(UNICOS5)
1461 request.signal = SIGCLD;
1462 request.pid = getpid();
1463 #endif
1464 #ifdef BFTPDAEMON
1465 /*
1466 * Are we working as the bftp daemon?
1467 */
1468 if (bftpd) {
1469 SCPYN(request.exec_name, BFTPPATH);
1470 }
1471 #endif /* BFTPDAEMON */
1472 if (write(i, (char *)&request, sizeof(request)) < 0) {
1473 char tbuf[128];
1474 (void) snprintf(tbuf, sizeof(tbuf), "Can't write to %s\n", INIT_FIFO);
1475 fatalperror(net, tbuf);
1476 }
1477 (void) close(i);
1478 (void) signal(SIGALRM, nologinproc);
1479 for (i = 0; ; i++) {
1480 char tbuf[128];
1481 alarm(15);
1482 n = read(pty, ptyip, BUFSIZ);
1483 if (i == 3 || n >= 0 || !gotalarm)
1484 break;
1485 gotalarm = 0;
1486 snprintf(tbuf, sizeof(tbuf), "telnetd: waiting for /etc/init to start login process on %s\r\n", line);
1487 (void) write(net, tbuf, strlen(tbuf));
1488 }
1489 if (n < 0 && gotalarm)
1490 fatal(net, "/etc/init didn't start login process");
1491 pcc += n;
1492 alarm(0);
1493 (void) signal(SIGALRM, SIG_DFL);
1494
1495 return;
1496 #endif /* NEWINIT */
1497 }
1498
1499 char *envinit[3];
1500 extern char **environ;
1501
1502 void
1503 init_env()
1504 {
1505 extern char *getenv();
1506 char **envp;
1507
1508 envp = envinit;
1509 if ((*envp = getenv("TZ")))
1510 *envp++ -= 3;
1511 #if defined(CRAY) || defined(__hpux)
1512 else
1513 *envp++ = "TZ=GMT0";
1514 #endif
1515 *envp = 0;
1516 environ = envinit;
1517 }
1518
1519 #ifndef NEWINIT
1520
1521 /*
1522 * start_login(host)
1523 *
1524 * Assuming that we are now running as a child processes, this
1525 * function will turn us into the login process.
1526 */
1527
1528 void
1529 start_login(host, autologin, name)
1530 char *host;
1531 int autologin;
1532 char *name;
1533 {
1534 register char **argv;
1535 char **addarg();
1536 extern char *getenv();
1537 #ifdef UTMPX
1538 register int pid = getpid();
1539 struct utmpx utmpx;
1540 #endif
1541 #ifdef SOLARIS
1542 char *term;
1543 char termbuf[64];
1544 #endif
1545
1546 #ifdef UTMPX
1547 /*
1548 * Create utmp entry for child
1549 */
1550
1551 bzero(&utmpx, sizeof(utmpx));
1552 SCPYN(utmpx.ut_user, ".telnet");
1553 SCPYN(utmpx.ut_line, line + sizeof(_PATH_DEV) - 1);
1554 utmpx.ut_pid = pid;
1555 utmpx.ut_id[0] = 't';
1556 utmpx.ut_id[1] = 'n';
1557 utmpx.ut_id[2] = SC_WILDC;
1558 utmpx.ut_id[3] = SC_WILDC;
1559 utmpx.ut_type = LOGIN_PROCESS;
1560 (void) time(&utmpx.ut_tv.tv_sec);
1561 if (makeutx(&utmpx) == NULL)
1562 fatal(net, "makeutx failed");
1563 #endif
1564
1565 scrub_env();
1566
1567 /*
1568 * -h : pass on name of host.
1569 * WARNING: -h is accepted by login if and only if
1570 * getuid() == 0.
1571 * -p : don't clobber the environment (so terminal type stays set).
1572 *
1573 * -f : force this login, he has already been authenticated
1574 */
1575 argv = addarg(0, "login");
1576
1577 #if !defined(NO_LOGIN_H)
1578
1579 # if defined (AUTHENTICATION) && defined(NO_LOGIN_F) && defined(LOGIN_R)
1580 /*
1581 * Don't add the "-h host" option if we are going
1582 * to be adding the "-r host" option down below...
1583 */
1584 if ((auth_level < 0) || (autologin != AUTH_VALID))
1585 # endif
1586 {
1587 argv = addarg(argv, "-h");
1588 argv = addarg(argv, host);
1589 #ifdef SOLARIS
1590 /*
1591 * SVR4 version of -h takes TERM= as second arg, or -
1592 */
1593 term = getenv("TERM");
1594 if (term == NULL || term[0] == 0) {
1595 term = "-";
1596 } else {
1597 strcpy(termbuf, "TERM=");
1598 strncat(termbuf, term, sizeof(termbuf) - 6);
1599 term = termbuf;
1600 }
1601 argv = addarg(argv, term);
1602 #endif
1603 }
1604 #endif
1605 #if !defined(NO_LOGIN_P)
1606 argv = addarg(argv, "-p");
1607 #endif
1608 #ifdef BFTPDAEMON
1609 /*
1610 * Are we working as the bftp daemon? If so, then ask login
1611 * to start bftp instead of shell.
1612 */
1613 if (bftpd) {
1614 argv = addarg(argv, "-e");
1615 argv = addarg(argv, BFTPPATH);
1616 } else
1617 #endif
1618 #if defined (SecurID)
1619 /*
1620 * don't worry about the -f that might get sent.
1621 * A -s is supposed to override it anyhow.
1622 */
1623 if (require_SecurID)
1624 argv = addarg(argv, "-s");
1625 #endif
1626 #if defined (AUTHENTICATION)
1627 if (auth_level >= 0 && autologin == AUTH_VALID) {
1628 # if !defined(NO_LOGIN_F)
1629 argv = addarg(argv, "-f");
1630 argv = addarg(argv, "--");
1631 argv = addarg(argv, name);
1632 # else
1633 # if defined(LOGIN_R)
1634 /*
1635 * We don't have support for "login -f", but we
1636 * can fool /bin/login into thinking that we are
1637 * rlogind, and allow us to log in without a
1638 * password. The rlogin protocol expects
1639 * local-user\0remote-user\0term/speed\0
1640 */
1641
1642 if (pty > 2) {
1643 register char *cp;
1644 char speed[128];
1645 int isecho, israw, xpty, len;
1646 extern int def_rspeed;
1647 # ifndef LOGIN_HOST
1648 /*
1649 * Tell login that we are coming from "localhost".
1650 * If we passed in the real host name, then the
1651 * user would have to allow .rhost access from
1652 * every machine that they want authenticated
1653 * access to work from, which sort of defeats
1654 * the purpose of an authenticated login...
1655 * So, we tell login that the session is coming
1656 * from "localhost", and the user will only have
1657 * to have "localhost" in their .rhost file.
1658 */
1659 # define LOGIN_HOST "localhost"
1660 # endif
1661 argv = addarg(argv, "-r");
1662 argv = addarg(argv, LOGIN_HOST);
1663
1664 xpty = pty;
1665 # ifndef STREAMSPTY
1666 pty = 0;
1667 # else
1668 ttyfd = 0;
1669 # endif
1670 init_termbuf();
1671 isecho = tty_isecho();
1672 israw = tty_israw();
1673 if (isecho || !israw) {
1674 tty_setecho(0); /* Turn off echo */
1675 tty_setraw(1); /* Turn on raw */
1676 set_termbuf();
1677 }
1678 len = strlen(name)+1;
1679 write(xpty, name, len);
1680 write(xpty, name, len);
1681 snprintf(speed, sizeof(speed),
1682 "%s/%d", (cp = getenv("TERM")) ? cp : "",
1683 (def_rspeed > 0) ? def_rspeed : 9600);
1684 len = strlen(speed)+1;
1685 write(xpty, speed, len);
1686
1687 if (isecho || !israw) {
1688 init_termbuf();
1689 tty_setecho(isecho);
1690 tty_setraw(israw);
1691 set_termbuf();
1692 if (!israw) {
1693 /*
1694 * Write a newline to ensure
1695 * that login will be able to
1696 * read the line...
1697 */
1698 write(xpty, "\n", 1);
1699 }
1700 }
1701 pty = xpty;
1702 }
1703 # else
1704 argv = addarg(argv, "--");
1705 argv = addarg(argv, name);
1706 # endif
1707 # endif
1708 } else
1709 #endif
1710 if (getenv("USER")) {
1711 argv = addarg(argv, "--");
1712 argv = addarg(argv, getenv("USER"));
1713 #if defined(LOGIN_ARGS) && defined(NO_LOGIN_P)
1714 {
1715 register char **cpp;
1716 for (cpp = environ; *cpp; cpp++)
1717 argv = addarg(argv, *cpp);
1718 }
1719 #endif
1720 /*
1721 * Assume that login will set the USER variable
1722 * correctly. For SysV systems, this means that
1723 * USER will no longer be set, just LOGNAME by
1724 * login. (The problem is that if the auto-login
1725 * fails, and the user then specifies a different
1726 * account name, he can get logged in with both
1727 * LOGNAME and USER in his environment, but the
1728 * USER value will be wrong.
1729 */
1730 unsetenv("USER");
1731 }
1732 #if defined(AUTHENTICATION) && defined(NO_LOGIN_F) && defined(LOGIN_R)
1733 if (pty > 2)
1734 close(pty);
1735 #endif
1736 closelog();
1737
1738 if (altlogin == NULL) {
1739 altlogin = _PATH_LOGIN;
1740 }
1741 execv(altlogin, argv);
1742
1743 syslog(LOG_ERR, "%s: %m", altlogin);
1744 fatalperror(net, altlogin);
1745 /*NOTREACHED*/
1746 }
1747
1748 char **
1749 addarg(argv, val)
1750 register char **argv;
1751 register char *val;
1752 {
1753 register char **cpp;
1754
1755 if (argv == NULL) {
1756 /*
1757 * 10 entries, a leading length, and a null
1758 */
1759 argv = (char **)malloc(sizeof(*argv) * 12);
1760 if (argv == NULL)
1761 return(NULL);
1762 *argv++ = (char *)10;
1763 *argv = (char *)0;
1764 }
1765 for (cpp = argv; *cpp; cpp++)
1766 ;
1767 if (cpp == &argv[(long)argv[-1]]) {
1768 --argv;
1769 *argv = (char *)((long)(*argv) + 10);
1770 argv = (char **)realloc(argv, sizeof(*argv) * ((long)(*argv) + 2));
1771 if (argv == NULL)
1772 return(NULL);
1773 argv++;
1774 cpp = &argv[(long)argv[-1] - 10];
1775 }
1776 *cpp++ = val;
1777 *cpp = 0;
1778 return(argv);
1779 }
1780 #endif /* NEWINIT */
1781
1782 /*
1783 * scrub_env()
1784 *
1785 * We only accept the environment variables listed below.
1786 */
1787 void
1788 scrub_env()
1789 {
1790 static const char *reject[] = {
1791 "TERMCAP=/",
1792 NULL
1793 };
1794
1795 static const char *accept[] = {
1796 "XAUTH=", "XAUTHORITY=", "DISPLAY=",
1797 "TERM=",
1798 "EDITOR=",
1799 "PAGER=",
1800 "LOGNAME=",
1801 "POSIXLY_CORRECT=",
1802 "PRINTER=",
1803 NULL
1804 };
1805
1806 char **cpp, **cpp2;
1807 const char **p;
1808
1809 for (cpp2 = cpp = environ; *cpp; cpp++) {
1810 int reject_it = 0;
1811
1812 for(p = reject; *p; p++)
1813 if(strncmp(*cpp, *p, strlen(*p)) == 0) {
1814 reject_it = 1;
1815 break;
1816 }
1817 if (reject_it)
1818 continue;
1819
1820 for(p = accept; *p; p++)
1821 if(strncmp(*cpp, *p, strlen(*p)) == 0)
1822 break;
1823 if(*p != NULL)
1824 *cpp2++ = *cpp;
1825 }
1826 *cpp2 = NULL;
1827 }
1828
1829 /*
1830 * cleanup()
1831 *
1832 * This is the routine to call when we are all through, to
1833 * clean up anything that needs to be cleaned up.
1834 */
1835 /* ARGSUSED */
1836 void
1837 cleanup(sig)
1838 int sig;
1839 {
1840 #ifndef PARENT_DOES_UTMP
1841 # if (BSD > 43) || defined(convex)
1842 char *p;
1843
1844 p = line + sizeof(_PATH_DEV) - 1;
1845 if (logout(p))
1846 logwtmp(p, "", "");
1847 (void)chmod(line, 0666);
1848 (void)chown(line, 0, 0);
1849 *p = 'p';
1850 (void)chmod(line, 0666);
1851 (void)chown(line, 0, 0);
1852 (void) shutdown(net, 2);
1853 exit(1);
1854 # else
1855 void rmut();
1856
1857 rmut();
1858 vhangup(); /* XXX */
1859 (void) shutdown(net, 2);
1860 exit(1);
1861 # endif
1862 #else /* PARENT_DOES_UTMP */
1863 # ifdef NEWINIT
1864 (void) shutdown(net, 2);
1865 exit(1);
1866 # else /* NEWINIT */
1867 # ifdef CRAY
1868 static int incleanup = 0;
1869 register int t;
1870
1871 /*
1872 * 1: Pick up the zombie, if we are being called
1873 * as the signal handler.
1874 * 2: If we are a nested cleanup(), return.
1875 * 3: Try to clean up TMPDIR.
1876 * 4: Fill in utmp with shutdown of process.
1877 * 5: Close down the network and pty connections.
1878 * 6: Finish up the TMPDIR cleanup, if needed.
1879 */
1880 if (sig == SIGCHLD)
1881 while (waitpid(-1, 0, WNOHANG) > 0)
1882 ; /* VOID */
1883 t = sigblock(sigmask(SIGCHLD));
1884 if (incleanup) {
1885 sigsetmask(t);
1886 return;
1887 }
1888 incleanup = 1;
1889 sigsetmask(t);
1890 if (secflag) {
1891 /*
1892 * We need to set ourselves back to a null
1893 * label to clean up.
1894 */
1895
1896 setulvl(sysv.sy_minlvl);
1897 setucmp((long)0);
1898 }
1899
1900 t = cleantmp(&wtmp);
1901 setutent(); /* just to make sure */
1902 # endif /* CRAY */
1903 rmut(line);
1904 close(pty);
1905 (void) shutdown(net, 2);
1906 # ifdef CRAY
1907 if (t == 0)
1908 cleantmp(&wtmp);
1909 # endif /* CRAY */
1910 exit(1);
1911 # endif /* NEWINT */
1912 #endif /* PARENT_DOES_UTMP */
1913 }
1914
1915 #if defined(PARENT_DOES_UTMP) && !defined(NEWINIT)
1916 /*
1917 * _utmp_sig_rcv
1918 * utmp_sig_init
1919 * utmp_sig_wait
1920 * These three functions are used to coordinate the handling of
1921 * the utmp file between the server and the soon-to-be-login shell.
1922 * The server actually creates the utmp structure, the child calls
1923 * utmp_sig_wait(), until the server calls utmp_sig_notify() and
1924 * signals the future-login shell to proceed.
1925 */
1926 static int caught=0; /* NZ when signal intercepted */
1927 static void (*func)(); /* address of previous handler */
1928
1929 void
1930 _utmp_sig_rcv(sig)
1931 int sig;
1932 {
1933 caught = 1;
1934 (void) signal(SIGUSR1, func);
1935 }
1936
1937 void
1938 utmp_sig_init()
1939 {
1940 /*
1941 * register signal handler for UTMP creation
1942 */
1943 if ((int)(func = signal(SIGUSR1, _utmp_sig_rcv)) == -1)
1944 fatalperror(net, "telnetd/signal");
1945 }
1946
1947 void
1948 utmp_sig_reset()
1949 {
1950 (void) signal(SIGUSR1, func); /* reset handler to default */
1951 }
1952
1953 # ifdef __hpux
1954 # define sigoff() /* do nothing */
1955 # define sigon() /* do nothing */
1956 # endif
1957
1958 void
1959 utmp_sig_wait()
1960 {
1961 /*
1962 * Wait for parent to write our utmp entry.
1963 */
1964 sigoff();
1965 while (caught == 0) {
1966 pause(); /* wait until we get a signal (sigon) */
1967 sigoff(); /* turn off signals while we check caught */
1968 }
1969 sigon(); /* turn on signals again */
1970 }
1971
1972 void
1973 utmp_sig_notify(pid)
1974 {
1975 kill(pid, SIGUSR1);
1976 }
1977
1978 # ifdef CRAY
1979 static int gotsigjob = 0;
1980
1981 /*ARGSUSED*/
1982 void
1983 sigjob(sig)
1984 int sig;
1985 {
1986 register int jid;
1987 register struct jobtemp *jp;
1988
1989 while ((jid = waitjob(NULL)) != -1) {
1990 if (jid == 0) {
1991 return;
1992 }
1993 gotsigjob++;
1994 jobend(jid, NULL, NULL);
1995 }
1996 }
1997
1998 /*
1999 * Clean up the TMPDIR that login created.
2000 * The first time this is called we pick up the info
2001 * from the utmp. If the job has already gone away,
2002 * then we'll clean up and be done. If not, then
2003 * when this is called the second time it will wait
2004 * for the signal that the job is done.
2005 */
2006 int
2007 cleantmp(wtp)
2008 register struct utmp *wtp;
2009 {
2010 struct utmp *utp;
2011 static int first = 1;
2012 register int mask, omask, ret;
2013 extern struct utmp *getutid P((const struct utmp *_Id));
2014
2015
2016 mask = sigmask(WJSIGNAL);
2017
2018 if (first == 0) {
2019 omask = sigblock(mask);
2020 while (gotsigjob == 0)
2021 sigpause(omask);
2022 return(1);
2023 }
2024 first = 0;
2025 setutent(); /* just to make sure */
2026
2027 utp = getutid(wtp);
2028 if (utp == 0) {
2029 syslog(LOG_ERR, "can't get /etc/utmp entry to clean TMPDIR");
2030 return(-1);
2031 }
2032 /*
2033 * Nothing to clean up if the user shell was never started.
2034 */
2035 if (utp->ut_type != USER_PROCESS || utp->ut_jid == 0)
2036 return(1);
2037
2038 /*
2039 * Block the WJSIGNAL while we are in jobend().
2040 */
2041 omask = sigblock(mask);
2042 ret = jobend(utp->ut_jid, utp->ut_tpath, utp->ut_user);
2043 sigsetmask(omask);
2044 return(ret);
2045 }
2046
2047 int
2048 jobend(jid, path, user)
2049 register int jid;
2050 register char *path;
2051 register char *user;
2052 {
2053 static int saved_jid = 0;
2054 static char saved_path[sizeof(wtmp.ut_tpath)+1];
2055 static char saved_user[sizeof(wtmp.ut_user)+1];
2056
2057 if (path) {
2058 strncpy(saved_path, path, sizeof(wtmp.ut_tpath));
2059 strncpy(saved_user, user, sizeof(wtmp.ut_user));
2060 saved_path[sizeof(saved_path)] = '\0';
2061 saved_user[sizeof(saved_user)] = '\0';
2062 }
2063 if (saved_jid == 0) {
2064 saved_jid = jid;
2065 return(0);
2066 }
2067 cleantmpdir(jid, saved_path, saved_user);
2068 return(1);
2069 }
2070
2071 /*
2072 * Fork a child process to clean up the TMPDIR
2073 */
2074 cleantmpdir(jid, tpath, user)
2075 register int jid;
2076 register char *tpath;
2077 register char *user;
2078 {
2079 switch(fork()) {
2080 case -1:
2081 syslog(LOG_ERR, "TMPDIR cleanup(%s): fork() failed: %m",
2082 tpath);
2083 break;
2084 case 0:
2085 execl(CLEANTMPCMD, CLEANTMPCMD, user, tpath, (char *)0);
2086 syslog(LOG_ERR, "TMPDIR cleanup(%s): execl(%s) failed: %m",
2087 tpath, CLEANTMPCMD);
2088 exit(1);
2089 default:
2090 /*
2091 * Forget about child. We will exit, and
2092 * /etc/init will pick it up.
2093 */
2094 break;
2095 }
2096 }
2097 # endif /* CRAY */
2098 #endif /* defined(PARENT_DOES_UTMP) && !defined(NEWINIT) */
2099
2100 /*
2101 * rmut()
2102 *
2103 * This is the function called by cleanup() to
2104 * remove the utmp entry for this person.
2105 */
2106
2107 #ifdef UTMPX
2108 void
2109 rmut()
2110 {
2111 register f;
2112 int found = 0;
2113 struct utmp *u, *utmp;
2114 int nutmp;
2115 struct stat statbf;
2116
2117 struct utmpx *utxp, utmpx;
2118
2119 /*
2120 * This updates the utmpx and utmp entries and make a wtmp/x entry
2121 */
2122
2123 SCPYN(utmpx.ut_line, line + sizeof(_PATH_DEV) - 1);
2124 utxp = getutxline(&utmpx);
2125 if (utxp) {
2126 utxp->ut_type = DEAD_PROCESS;
2127 utxp->ut_exit.e_termination = 0;
2128 utxp->ut_exit.e_exit = 0;
2129 (void) time(&utmpx.ut_tv.tv_sec);
2130 utmpx.ut_tv.tv_usec = 0;
2131 modutx(utxp);
2132 }
2133 endutxent();
2134 } /* end of rmut */
2135 #endif
2136
2137 #if !defined(UTMPX) && !(defined(CRAY) || defined(__hpux)) && BSD <= 43
2138 void
2139 rmut()
2140 {
2141 register f;
2142 int found = 0;
2143 struct utmp *u, *utmp;
2144 int nutmp;
2145 struct stat statbf;
2146
2147 f = open(utmpf, O_RDWR);
2148 if (f >= 0) {
2149 (void) fstat(f, &statbf);
2150 utmp = (struct utmp *)malloc((unsigned)statbf.st_size);
2151 if (!utmp)
2152 syslog(LOG_ERR, "utmp malloc failed");
2153 if (statbf.st_size && utmp) {
2154 nutmp = read(f, (char *)utmp, (int)statbf.st_size);
2155 nutmp /= sizeof(struct utmp);
2156
2157 for (u = utmp ; u < &utmp[nutmp] ; u++) {
2158 if (SCMPN(u->ut_line, line+5) ||
2159 u->ut_name[0]==0)
2160 continue;
2161 (void) lseek(f, ((long)u)-((long)utmp), L_SET);
2162 SCPYN(u->ut_name, "");
2163 SCPYN(u->ut_host, "");
2164 (void) time(&u->ut_time);
2165 (void) write(f, (char *)u, sizeof(wtmp));
2166 found++;
2167 }
2168 }
2169 (void) close(f);
2170 }
2171 if (found) {
2172 f = open(wtmpf, O_WRONLY|O_APPEND);
2173 if (f >= 0) {
2174 SCPYN(wtmp.ut_line, line+5);
2175 SCPYN(wtmp.ut_name, "");
2176 SCPYN(wtmp.ut_host, "");
2177 (void) time(&wtmp.ut_time);
2178 (void) write(f, (char *)&wtmp, sizeof(wtmp));
2179 (void) close(f);
2180 }
2181 }
2182 (void) chmod(line, 0666);
2183 (void) chown(line, 0, 0);
2184 line[strlen(_PATH_DEV)] = 'p';
2185 (void) chmod(line, 0666);
2186 (void) chown(line, 0, 0);
2187 } /* end of rmut */
2188 #endif /* CRAY */
2189
2190 #ifdef __hpux
2191 rmut (line)
2192 char *line;
2193 {
2194 struct utmp utmp;
2195 struct utmp *utptr;
2196 int fd; /* for /etc/wtmp */
2197
2198 utmp.ut_type = USER_PROCESS;
2199 (void) strncpy(utmp.ut_id, line+12, sizeof(utmp.ut_id));
2200 (void) setutent();
2201 utptr = getutid(&utmp);
2202 /* write it out only if it exists */
2203 if (utptr) {
2204 utptr->ut_type = DEAD_PROCESS;
2205 utptr->ut_time = time((long *) 0);
2206 (void) pututline(utptr);
2207 /* set wtmp entry if wtmp file exists */
2208 if ((fd = open(wtmpf, O_WRONLY | O_APPEND)) >= 0) {
2209 (void) write(fd, utptr, sizeof(utmp));
2210 (void) close(fd);
2211 }
2212 }
2213 (void) endutent();
2214
2215 (void) chmod(line, 0666);
2216 (void) chown(line, 0, 0);
2217 line[14] = line[13];
2218 line[13] = line[12];
2219 line[8] = 'm';
2220 line[9] = '/';
2221 line[10] = 'p';
2222 line[11] = 't';
2223 line[12] = 'y';
2224 (void) chmod(line, 0666);
2225 (void) chown(line, 0, 0);
2226 }
2227 #endif