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