]>
git.saurik.com Git - apple/network_cmds.git/blob - telnetd.tproj/sys_term.c
2 * Copyright (c) 1989, 1993
3 * The Regents of the University of California. All rights reserved.
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
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.
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
36 static const char sccsid
[] = "@(#)sys_term.c 8.2 (Berkeley) 12/15/93";
38 static const char rcsid
[] =
39 "$FreeBSD: src/libexec/telnetd/sys_term.c,v 1.31 2001/07/09 09:23:42 brian Exp $";
44 #include "pathnames.h"
46 #if defined(AUTHENTICATION)
47 #include <libtelnet/auth.h>
50 extern char *altlogin
;
52 #if defined(CRAY) || defined(__hpux)
53 # define PARENT_DOES_UTMP
67 # ifndef PARENT_DOES_UTMP
69 char wtmpf
[] = _PATH_WTMP
;
71 char wtmpf
[] = "/usr/adm/wtmp";
74 char utmpf
[] = _PATH_UTMP
;
76 char utmpf
[] = "/etc/utmp";
78 # else /* PARENT_DOES_UTMP */
79 char wtmpf
[] = "/etc/wtmp";
80 # endif /* PARENT_DOES_UTMP */
85 # if defined(_SC_CRAY_SECURE_SYS) && !defined(SCM_SECURITY)
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.
91 # undef _SC_CRAY_SECURE_SYS
94 # if defined(_SC_CRAY_SECURE_SYS)
96 #include <sys/secstat.h>
98 extern struct sysv sysv
;
99 # endif /* _SC_CRAY_SECURE_SYS */
105 #include <sys/stropts.h>
108 #define SCPYN(a, b) (void) strncpy(a, b, sizeof(a))
109 #define SCMPN(a, b) strncmp(a, b, sizeof(a))
112 #include <sys/stream.h>
115 #include <sys/resource.h>
116 #include <sys/proc.h>
136 #if defined(UNICOS5) && defined(CRAY2) && !defined(EXTPROC)
137 # define EXTPROC 0400
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 */
154 # define termios termio
158 # define TCSANOW TCSETS
159 # define TCSADRAIN TCSETSW
160 # define tcgetattr(f, t) ioctl(f, TCGETS, (char *)t)
163 # define TCSANOW TCSETA
164 # define TCSADRAIN TCSETAW
165 # define tcgetattr(f, t) ioctl(f, TCGETA, (char *)t)
167 # define TCSANOW TIOCSETA
168 # define TCSADRAIN TIOCSETAW
169 # define tcgetattr(f, t) ioctl(f, TIOCGETA, (char *)t)
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)
177 # define cfsetispeed(tp, val) (tp)->c_cflag &= ~CIBAUD; \
178 (tp)->c_cflag |= ((val)<<IBSHIFT)
179 # define cfgetispeed(tp) (((tp)->c_cflag & CIBAUD)>>IBSHIFT)
181 # define cfsetispeed(tp, val) (tp)->c_cflag &= ~CBAUD; \
182 (tp)->c_cflag |= (val)
183 # define cfgetispeed(tp) ((tp)->c_cflag & CBAUD)
185 # endif /* TCSANOW */
186 struct termios termbuf
, termbuf2
; /* pty control structure */
190 #endif /* USE_TERMIO */
192 #include <sys/types.h>
195 int cleanopen
__P((char *));
196 void scrub_env
__P((void));
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.
213 (void) ioctl(pty
, TIOCGETP
, (char *)&termbuf
.sg
);
214 (void) ioctl(pty
, TIOCGETC
, (char *)&termbuf
.tc
);
215 (void) ioctl(pty
, TIOCGLTC
, (char *)&termbuf
.ltc
);
217 (void) ioctl(pty
, TIOCGSTATE
, (char *)&termbuf
.state
);
221 (void) tcgetattr(ttyfd
, &termbuf
);
223 (void) tcgetattr(pty
, &termbuf
);
229 #if defined(LINEMODE) && defined(TIOCPKT_IOCTL)
231 copy_termbuf(cp
, len
)
235 if (len
> sizeof(termbuf
))
236 len
= sizeof(termbuf
);
237 memmove((char *)&termbuf
, cp
, len
);
240 #endif /* defined(LINEMODE) && defined(TIOCPKT_IOCTL) */
246 * Only make the necessary changes.
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
)))
261 (void) tcsetattr(ttyfd
, TCSANOW
, &termbuf
);
263 (void) tcsetattr(pty
, TCSANOW
, &termbuf
);
265 # if defined(CRAY2) && defined(UNICOS5)
268 #endif /* USE_TERMIO */
273 * spcset(func, valp, valpp)
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
280 * It returns the SLC_ level of support for this function.
285 spcset(func
, valp
, valpp
)
292 *valp
= termbuf
.tc
.t_eofc
;
293 *valpp
= (cc_t
*)&termbuf
.tc
.t_eofc
;
294 return(SLC_VARIABLE
);
296 *valp
= termbuf
.sg
.sg_erase
;
297 *valpp
= (cc_t
*)&termbuf
.sg
.sg_erase
;
298 return(SLC_VARIABLE
);
300 *valp
= termbuf
.sg
.sg_kill
;
301 *valpp
= (cc_t
*)&termbuf
.sg
.sg_kill
;
302 return(SLC_VARIABLE
);
304 *valp
= termbuf
.tc
.t_intrc
;
305 *valpp
= (cc_t
*)&termbuf
.tc
.t_intrc
;
306 return(SLC_VARIABLE
|SLC_FLUSHIN
|SLC_FLUSHOUT
);
308 *valp
= termbuf
.tc
.t_quitc
;
309 *valpp
= (cc_t
*)&termbuf
.tc
.t_quitc
;
310 return(SLC_VARIABLE
|SLC_FLUSHIN
|SLC_FLUSHOUT
);
312 *valp
= termbuf
.tc
.t_startc
;
313 *valpp
= (cc_t
*)&termbuf
.tc
.t_startc
;
314 return(SLC_VARIABLE
);
316 *valp
= termbuf
.tc
.t_stopc
;
317 *valpp
= (cc_t
*)&termbuf
.tc
.t_stopc
;
318 return(SLC_VARIABLE
);
320 *valp
= termbuf
.ltc
.t_flushc
;
321 *valpp
= (cc_t
*)&termbuf
.ltc
.t_flushc
;
322 return(SLC_VARIABLE
);
324 *valp
= termbuf
.ltc
.t_suspc
;
325 *valpp
= (cc_t
*)&termbuf
.ltc
.t_suspc
;
326 return(SLC_VARIABLE
);
328 *valp
= termbuf
.ltc
.t_werasc
;
329 *valpp
= (cc_t
*)&termbuf
.ltc
.t_werasc
;
330 return(SLC_VARIABLE
);
332 *valp
= termbuf
.ltc
.t_rprntc
;
333 *valpp
= (cc_t
*)&termbuf
.ltc
.t_rprntc
;
334 return(SLC_VARIABLE
);
336 *valp
= termbuf
.ltc
.t_lnextc
;
337 *valpp
= (cc_t
*)&termbuf
.ltc
.t_lnextc
;
338 return(SLC_VARIABLE
);
340 *valp
= termbuf
.tc
.t_brkc
;
341 *valpp
= (cc_t
*)&termbuf
.ltc
.t_lnextc
;
342 return(SLC_VARIABLE
);
353 return(SLC_NOSUPPORT
);
357 #else /* USE_TERMIO */
360 spcset(func
, valp
, valpp
)
366 #define setval(a, b) *valp = termbuf.c_cc[a]; \
367 *valpp = &termbuf.c_cc[a]; \
369 #define defval(a) *valp = ((cc_t)a); *valpp = (cc_t *)0; return(SLC_DEFAULT);
373 setval(VEOF
, SLC_VARIABLE
);
375 setval(VERASE
, SLC_VARIABLE
);
377 setval(VKILL
, SLC_VARIABLE
);
379 setval(VINTR
, SLC_VARIABLE
|SLC_FLUSHIN
|SLC_FLUSHOUT
);
381 setval(VQUIT
, SLC_VARIABLE
|SLC_FLUSHIN
|SLC_FLUSHOUT
);
384 setval(VSTART
, SLC_VARIABLE
);
390 setval(VSTOP
, SLC_VARIABLE
);
396 setval(VWERASE
, SLC_VARIABLE
);
402 setval(VREPRINT
, SLC_VARIABLE
);
408 setval(VLNEXT
, SLC_VARIABLE
);
413 #if !defined(VDISCARD) && defined(VFLUSHO)
414 # define VDISCARD VFLUSHO
417 setval(VDISCARD
, SLC_VARIABLE
|SLC_FLUSHOUT
);
423 setval(VSUSP
, SLC_VARIABLE
|SLC_FLUSHIN
);
429 setval(VEOL
, SLC_VARIABLE
);
433 setval(VEOL2
, SLC_VARIABLE
);
437 setval(VSTATUS
, SLC_VARIABLE
);
450 return(SLC_NOSUPPORT
);
453 #endif /* USE_TERMIO */
459 * Return the number of pty's configured into the system.
467 if ((numptys
= sysconf(_SC_CRAY_NPTY
)) != -1)
470 #endif /* _SC_CRAY_NPTY */
479 * Allocate a pty. As a side effect, the external character
480 * array "line" contains the name of the slave side.
482 * Returns the file descriptor of the opened pty.
501 p
= open("/dev/ptmx", 2);
505 strcpy(line
, ptsname(p
));
509 #else /* ! STREAMSPTY */
511 register char *cp
, *p1
, *p2
;
513 #if defined(sun) && defined(TIOCGPGRP) && BSD < 199207
518 (void) strcpy(line
, _PATH_DEV
);
519 (void) strcat(line
, "ptyXX");
523 (void) strcpy(line
, "/dev/ptym/ptyXX");
528 for (cp
= "pqrsPQRS"; *cp
; cp
++) {
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.
538 if (stat(line
, &stb
) < 0)
540 for (i
= 0; i
< 32; i
++) {
541 *p2
= "0123456789abcdefghijklmnopqrstuv"[i
];
547 for (p1
= &line
[8]; *p1
; p1
++)
553 #if defined(sun) && defined(TIOCGPGRP) && BSD < 199207
554 if (ioctl(p
, TIOCGPGRP
, &dummy
) == 0
560 #endif /* defined(sun) && defined(TIOCGPGRP) && BSD < 199207 */
566 extern lowpty
, highpty
;
569 for (*ptynum
= lowpty
; *ptynum
<= highpty
; (*ptynum
)++) {
570 (void) sprintf(myline
, "%spty/%03d", _PATH_DEV
, *ptynum
);
574 (void) sprintf(line
, "/dev/ttyp%03d", *ptynum
);
576 * Here are some shenanigans to make sure that there
577 * are no listeners lurking on the line.
579 if(stat(line
, &sb
) < 0) {
583 if(sb
.st_uid
|| sb
.st_gid
|| sb
.st_mode
!= 0600) {
592 * Now it should be safe...check for accessability.
594 if (access(line
, 6) == 0)
597 /* no tty side to pty so skip it */
602 #endif /* STREAMSPTY */
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.
630 static int linestate
;
638 return(termbuf
.state
& TS_EXTPROC
);
640 return(termbuf
.c_lflag
& EXTPROC
);
657 (void) ioctl(pty
, TIOCEXT
, (char *)&on
);
664 termbuf
.c_lflag
|= EXTPROC
;
666 termbuf
.c_lflag
&= ~EXTPROC
;
670 #endif /* LINEMODE */
676 return (termbuf
.sg
.sg_flags
& ECHO
);
678 return (termbuf
.c_lflag
& ECHO
);
686 return(((termbuf
.tc
.t_startc
) > 0 && (termbuf
.tc
.t_stopc
) > 0) ? 1 : 0);
688 return((termbuf
.c_iflag
& IXON
) ? 1 : 0);
697 return((termbuf
.lflags
& DECCTQ
) ? 0 : 1);
702 return((termbuf
.c_iflag
& IXANY
) ? 1 : 0);
712 termbuf
.sg
.sg_flags
|= ECHO
|CRMOD
;
714 termbuf
.sg
.sg_flags
&= ~(ECHO
|CRMOD
);
717 termbuf
.c_lflag
|= ECHO
;
719 termbuf
.c_lflag
&= ~ECHO
;
727 return(termbuf
.sg
.sg_flags
& RAW
);
729 return(!(termbuf
.c_lflag
& ICANON
));
733 #if defined (AUTHENTICATION) && defined(NO_LOGIN_F) && defined(LOGIN_R)
739 termbuf
.sg
.sg_flags
|= RAW
;
741 termbuf
.sg
.sg_flags
&= ~RAW
;
744 termbuf
.c_lflag
&= ~ICANON
;
746 termbuf
.c_lflag
|= ICANON
;
757 termbuf
.lflags
|= LPASS8
;
759 termbuf
.lflags
&= ~LPASS8
;
762 termbuf
.c_iflag
&= ~ISTRIP
;
764 termbuf
.c_iflag
|= ISTRIP
;
775 termbuf
.lflags
|= LLITOUT
;
777 termbuf
.lflags
&= ~LLITOUT
;
780 termbuf
.c_cflag
&= ~(CSIZE
|PARENB
);
781 termbuf
.c_cflag
|= CS8
;
782 termbuf
.c_oflag
&= ~OPOST
;
784 termbuf
.c_cflag
&= ~CSIZE
;
785 termbuf
.c_cflag
|= CS7
|PARENB
;
786 termbuf
.c_oflag
|= OPOST
;
795 return(termbuf
.lflags
& LPASS8
);
797 return(!(termbuf
.c_iflag
& ISTRIP
));
805 return(termbuf
.lflags
& LLITOUT
);
807 return(!(termbuf
.c_oflag
&OPOST
));
816 return(!(termbuf
.sg
.sg_flags
& (CBREAK
|RAW
)));
818 return(termbuf
.c_lflag
& ICANON
);
826 return(!(termbuf
.sg
.sg_flags
&RAW
));
828 return(termbuf
.c_lflag
& ISIG
);
838 termbuf
.sg
.sg_flags
&= ~CBREAK
;
840 termbuf
.sg
.sg_flags
|= CBREAK
;
843 termbuf
.c_lflag
|= ICANON
;
845 termbuf
.c_lflag
&= ~ICANON
;
858 termbuf
.c_lflag
|= ISIG
;
860 termbuf
.c_lflag
&= ~ISIG
;
863 #endif /* LINEMODE */
869 return (termbuf
.sg
.sg_flags
& XTABS
);
872 return (termbuf
.c_oflag
& OXTABS
);
875 return ((termbuf
.c_oflag
& TABDLY
) == TAB3
);
886 termbuf
.sg
.sg_flags
|= XTABS
;
888 termbuf
.sg
.sg_flags
&= ~XTABS
;
892 termbuf
.c_oflag
|= OXTABS
;
895 termbuf
.c_oflag
&= ~TABDLY
;
896 termbuf
.c_oflag
|= TAB3
;
900 termbuf
.c_oflag
&= ~OXTABS
;
903 termbuf
.c_oflag
&= ~TABDLY
;
904 termbuf
.c_oflag
|= TAB0
;
914 return (!(termbuf
.lflags
& LCTLECH
));
917 return (!(termbuf
.c_lflag
& ECHOCTL
));
920 return (!(termbuf
.c_lflag
& TCTLECH
));
922 # if !defined(ECHOCTL) && !defined(TCTLECH)
923 return (0); /* assumes ctl chars are echoed '^x' */
934 termbuf
.lflags
&= ~LCTLECH
;
936 termbuf
.lflags
|= LCTLECH
;
940 termbuf
.c_lflag
&= ~ECHOCTL
;
942 termbuf
.c_lflag
|= ECHOCTL
;
946 termbuf
.c_lflag
&= ~TCTLECH
;
948 termbuf
.c_lflag
|= TCTLECH
;
957 return (termbuf
.sg
.sg_flags
& CRMOD
);
959 return (termbuf
.c_iflag
& ICRNL
);
964 * Try to guess whether speeds are "encoded" (4.2BSD) or just numeric (4.4BSD).
972 * A table of available terminal speeds
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
}
985 #endif /* DECODE_BAUD */
992 register struct termspeeds
*tp
;
994 for (tp
= termspeeds
; (tp
->speed
!= -1) && (val
> tp
->speed
); tp
++)
996 cfsetospeed(&termbuf
, tp
->value
);
997 #else /* DECODE_BAUD */
998 cfsetospeed(&termbuf
, val
);
999 #endif /* DECODE_BAUD */
1007 register struct termspeeds
*tp
;
1009 for (tp
= termspeeds
; (tp
->speed
!= -1) && (val
> tp
->speed
); tp
++)
1011 cfsetispeed(&termbuf
, tp
->value
);
1012 #else /* DECODE_BAUD */
1013 cfsetispeed(&termbuf
, val
);
1014 #endif /* DECODE_BAUD */
1017 #if defined(CRAY2) && defined(UNICOS5)
1021 return((termbuf
.c_oflag
& OPOST
) && (termbuf
.c_oflag
& ONLCR
) &&
1022 !(termbuf
.c_oflag
& ONLRET
));
1026 #ifdef PARENT_DOES_UTMP
1028 extern struct utmp wtmp
;
1029 extern char wtmpf
[];
1030 # else /* NEWINIT */
1040 # endif /* NEWINIT */
1041 #endif /* PARENT_DOES_UTMP */
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 */
1055 * Open the slave side of the pty, and do any initialization
1056 * that is necessary.
1061 register int t
= -1;
1064 #if !defined(CRAY) || !defined(NEWINIT)
1070 extern int def_row
, def_col
;
1072 extern int def_tspeed
, def_rspeed
;
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
1080 * so that we can re-set them if we need to.
1083 waslm
= tty_linemode();
1085 erase
= termbuf
.c_cc
[VERASE
];
1088 * Make sure that we don't have a controlling tty, and
1089 * that we are the session (process group) leader.
1092 t
= open(_PATH_TTY
, O_RDWR
);
1094 (void) ioctl(t
, TIOCNOTTY
, (char *)0);
1100 # ifdef PARENT_DOES_UTMP
1102 * Wait for our parent to get the utmp stuff to get done.
1107 t
= cleanopen(line
);
1109 fatalperror(net
, line
);
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");
1126 * set up the tty modes as we like them to be.
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
);
1139 * Settings for sgtty based systems
1142 termbuf
.sg
.sg_flags
|= CRMOD
|ANYP
|ECHO
|XTABS
;
1143 # endif /* USE_TERMIO */
1146 * Settings for UNICOS (and HPUX)
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
;
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.
1160 # if defined(USE_TERMIO) && !(defined(CRAY) || defined(__hpux)) && (BSD <= 43)
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);
1172 termbuf
.c_cc
[VERASE
] = erase
;
1176 # endif /* LINEMODE */
1179 * Set the tty modes, and make this our controlling tty.
1182 if (login_tty(t
) == -1)
1183 fatalperror(net
, "login_tty");
1184 #endif /* !defined(CRAY) || !defined(NEWINIT) */
1187 #if defined(AUTHENTICATION) && defined(NO_LOGIN_F) && defined(LOGIN_R)
1189 * Leave the pty open so that we can write out the rlogin
1190 * protocol for /bin/login, if the authentication works.
1200 #if !defined(CRAY) || !defined(NEWINIT)
1205 * Open the specified slave side of the pty,
1206 * making sure that we have a clean tty.
1213 #if defined(_SC_CRAY_SECURE_SYS)
1214 struct secstat secbuf
;
1215 #endif /* _SC_CRAY_SECURE_SYS */
1219 * Make sure that other people can't open the
1220 * slave side of the connection.
1222 (void) chown(line
, 0, 0);
1223 (void) chmod(line
, 0600);
1226 # if !defined(CRAY) && (BSD > 43)
1227 (void) revoke(line
);
1229 #if defined(_SC_CRAY_SECURE_SYS)
1231 if (secstat(line
, &secbuf
) < 0)
1233 if (setulvl(secbuf
.st_slevel
) < 0)
1235 if (setucmp(secbuf
.st_compart
) < 0)
1238 #endif /* _SC_CRAY_SECURE_SYS */
1240 t
= open(line
, O_RDWR
|O_NOCTTY
);
1242 #if defined(_SC_CRAY_SECURE_SYS)
1244 if (setulvl(sysv
.sy_minlvl
) < 0)
1249 #endif /* _SC_CRAY_SECURE_SYS */
1255 * Hangup anybody else using this ttyp, then reopen it for
1258 # if !(defined(CRAY) || defined(__hpux)) && (BSD <= 43) && !defined(STREAMSPTY)
1259 (void) signal(SIGHUP
, SIG_IGN
);
1261 (void) signal(SIGHUP
, SIG_DFL
);
1262 t
= open(line
, O_RDWR
|O_NOCTTY
);
1266 # if defined(CRAY) && defined(TCVHUP)
1269 (void) signal(SIGHUP
, SIG_IGN
);
1270 (void) ioctl(t
, TCVHUP
, (char *)0);
1271 (void) signal(SIGHUP
, SIG_DFL
);
1274 #if defined(_SC_CRAY_SECURE_SYS)
1276 if (secstat(line
, &secbuf
) < 0)
1278 if (setulvl(secbuf
.st_slevel
) < 0)
1280 if (setucmp(secbuf
.st_compart
) < 0)
1283 #endif /* _SC_CRAY_SECURE_SYS */
1285 i
= open(line
, O_RDWR
);
1287 #if defined(_SC_CRAY_SECURE_SYS)
1289 if (setulvl(sysv
.sy_minlvl
) < 0)
1294 #endif /* _SC_CRAY_SECURE_SYS */
1301 # endif /* defined(CRAY) && defined(TCVHUP) */
1304 #endif /* !defined(CRAY) || !defined(NEWINIT) */
1315 * The setsid() may have failed because we
1316 * already have a pgrp == pid. Zero out
1317 * our pgrp and try again...
1319 if ((setpgrp(0, 0) < 0) || (setsid() < 0))
1321 fatalperror(net
, "setsid()");
1324 if (ioctl(t
, TIOCSCTTY
, (char *)0) < 0)
1325 fatalperror(net
, "ioctl(sctty)");
1328 * Close the hard fd to /dev/ttypXXX, and re-open through
1329 * the indirect /dev/tty interface.
1332 if ((t
= open(_PATH_TTY
, O_RDWR
)) < 0)
1333 fatalperror(net
, "open(/dev/tty)");
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...
1343 (void) setpgrp(0, 0);
1344 close(open(line
, O_RDWR
));
1356 #endif /* BSD <= 43 */
1359 char *gen_id
= "fe";
1365 * Given a hostname, do whatever
1366 * is necessary to startup the login process on the slave side of the pty.
1371 startslave(host
, autologin
, autoname
)
1379 struct init_request request
;
1382 #endif /* NEWINIT */
1384 #if defined(AUTHENTICATION)
1385 if (!autoname
|| !autoname
[0])
1388 if (autologin
< auth_level
) {
1389 fatal(net
, "Authorization failed");
1395 # ifdef PARENT_DOES_UTMP
1397 # endif /* PARENT_DOES_UTMP */
1399 if ((i
= fork()) < 0)
1400 fatalperror(net
, "fork");
1402 # ifdef PARENT_DOES_UTMP
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.
1408 register int pid
= i
;
1409 void sigjob
P((int));
1412 utmp_sig_reset(); /* reset handler to default */
1414 * Create utmp entry for child
1416 (void) time(&wtmp
.ut_time
);
1417 wtmp
.ut_type
= LOGIN_PROCESS
;
1419 SCPYN(wtmp
.ut_user
, "LOGIN");
1420 SCPYN(wtmp
.ut_host
, host
);
1421 SCPYN(wtmp
.ut_line
, line
+ sizeof(_PATH_DEV
) - 1);
1423 SCPYN(wtmp
.ut_id
, wtmp
.ut_line
+3);
1425 SCPYN(wtmp
.ut_id
, wtmp
.ut_line
+7);
1429 if ((i
= open(wtmpf
, O_WRONLY
|O_APPEND
)) >= 0) {
1430 (void) write(i
, (char *)&wtmp
, sizeof(struct utmp
));
1434 (void) signal(WJSIGNAL
, sigjob
);
1436 utmp_sig_notify(pid
);
1437 # endif /* PARENT_DOES_UTMP */
1439 getptyslave(autologin
);
1440 start_login(host
, autologin
, autoname
);
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.
1449 if ((i
= open(INIT_FIFO
, O_WRONLY
)) < 0) {
1451 (void) snprintf(tbuf
, sizeof(tbuf
), "Can't open %s\n", INIT_FIFO
);
1452 fatalperror(net
, tbuf
);
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();
1466 * Are we working as the bftp daemon?
1469 SCPYN(request
.exec_name
, BFTPPATH
);
1471 #endif /* BFTPDAEMON */
1472 if (write(i
, (char *)&request
, sizeof(request
)) < 0) {
1474 (void) snprintf(tbuf
, sizeof(tbuf
), "Can't write to %s\n", INIT_FIFO
);
1475 fatalperror(net
, tbuf
);
1478 (void) signal(SIGALRM
, nologinproc
);
1479 for (i
= 0; ; i
++) {
1482 n
= read(pty
, ptyip
, BUFSIZ
);
1483 if (i
== 3 || n
>= 0 || !gotalarm
)
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
));
1489 if (n
< 0 && gotalarm
)
1490 fatal(net
, "/etc/init didn't start login process");
1493 (void) signal(SIGALRM
, SIG_DFL
);
1496 #endif /* NEWINIT */
1500 extern char **environ
;
1505 extern char *getenv();
1509 if ((*envp
= getenv("TZ")))
1511 #if defined(CRAY) || defined(__hpux)
1513 *envp
++ = "TZ=GMT0";
1524 * Assuming that we are now running as a child processes, this
1525 * function will turn us into the login process.
1529 start_login(host
, autologin
, name
)
1534 register char **argv
;
1536 extern char *getenv();
1538 register int pid
= getpid();
1548 * Create utmp entry for child
1551 bzero(&utmpx
, sizeof(utmpx
));
1552 SCPYN(utmpx
.ut_user
, ".telnet");
1553 SCPYN(utmpx
.ut_line
, line
+ sizeof(_PATH_DEV
) - 1);
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");
1568 * -h : pass on name of host.
1569 * WARNING: -h is accepted by login if and only if
1571 * -p : don't clobber the environment (so terminal type stays set).
1573 * -f : force this login, he has already been authenticated
1575 argv
= addarg(0, "login");
1577 #if !defined(NO_LOGIN_H)
1579 # if defined (AUTHENTICATION) && defined(NO_LOGIN_F) && defined(LOGIN_R)
1581 * Don't add the "-h host" option if we are going
1582 * to be adding the "-r host" option down below...
1584 if ((auth_level
< 0) || (autologin
!= AUTH_VALID
))
1587 argv
= addarg(argv
, "-h");
1588 argv
= addarg(argv
, host
);
1591 * SVR4 version of -h takes TERM= as second arg, or -
1593 term
= getenv("TERM");
1594 if (term
== NULL
|| term
[0] == 0) {
1597 strcpy(termbuf
, "TERM=");
1598 strncat(termbuf
, term
, sizeof(termbuf
) - 6);
1601 argv
= addarg(argv
, term
);
1605 #if !defined(NO_LOGIN_P)
1606 argv
= addarg(argv
, "-p");
1610 * Are we working as the bftp daemon? If so, then ask login
1611 * to start bftp instead of shell.
1614 argv
= addarg(argv
, "-e");
1615 argv
= addarg(argv
, BFTPPATH
);
1618 #if defined (SecurID)
1620 * don't worry about the -f that might get sent.
1621 * A -s is supposed to override it anyhow.
1623 if (require_SecurID
)
1624 argv
= addarg(argv
, "-s");
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
);
1633 # if defined(LOGIN_R)
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
1645 int isecho
, israw
, xpty
, len
;
1646 extern int def_rspeed
;
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.
1659 # define LOGIN_HOST "localhost"
1661 argv
= addarg(argv
, "-r");
1662 argv
= addarg(argv
, LOGIN_HOST
);
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 */
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
);
1687 if (isecho
|| !israw
) {
1689 tty_setecho(isecho
);
1694 * Write a newline to ensure
1695 * that login will be able to
1698 write(xpty
, "\n", 1);
1704 argv
= addarg(argv
, "--");
1705 argv
= addarg(argv
, name
);
1710 if (getenv("USER")) {
1711 argv
= addarg(argv
, "--");
1712 argv
= addarg(argv
, getenv("USER"));
1713 #if defined(LOGIN_ARGS) && defined(NO_LOGIN_P)
1715 register char **cpp
;
1716 for (cpp
= environ
; *cpp
; cpp
++)
1717 argv
= addarg(argv
, *cpp
);
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.
1732 #if defined(AUTHENTICATION) && defined(NO_LOGIN_F) && defined(LOGIN_R)
1738 if (altlogin
== NULL
) {
1739 altlogin
= _PATH_LOGIN
;
1741 execv(altlogin
, argv
);
1743 syslog(LOG_ERR
, "%s: %m", altlogin
);
1744 fatalperror(net
, altlogin
);
1750 register char **argv
;
1753 register char **cpp
;
1757 * 10 entries, a leading length, and a null
1759 argv
= (char **)malloc(sizeof(*argv
) * 12);
1762 *argv
++ = (char *)10;
1765 for (cpp
= argv
; *cpp
; cpp
++)
1767 if (cpp
== &argv
[(long)argv
[-1]]) {
1769 *argv
= (char *)((long)(*argv
) + 10);
1770 argv
= (char **)realloc(argv
, sizeof(*argv
) * ((long)(*argv
) + 2));
1774 cpp
= &argv
[(long)argv
[-1] - 10];
1780 #endif /* NEWINIT */
1785 * We only accept the environment variables listed below.
1790 static const char *reject
[] = {
1795 static const char *accept
[] = {
1796 "XAUTH=", "XAUTHORITY=", "DISPLAY=",
1809 for (cpp2
= cpp
= environ
; *cpp
; cpp
++) {
1812 for(p
= reject
; *p
; p
++)
1813 if(strncmp(*cpp
, *p
, strlen(*p
)) == 0) {
1820 for(p
= accept
; *p
; p
++)
1821 if(strncmp(*cpp
, *p
, strlen(*p
)) == 0)
1832 * This is the routine to call when we are all through, to
1833 * clean up anything that needs to be cleaned up.
1840 #ifndef PARENT_DOES_UTMP
1841 # if (BSD > 43) || defined(convex)
1844 p
= line
+ sizeof(_PATH_DEV
) - 1;
1847 (void)chmod(line
, 0666);
1848 (void)chown(line
, 0, 0);
1850 (void)chmod(line
, 0666);
1851 (void)chown(line
, 0, 0);
1852 (void) shutdown(net
, 2);
1858 vhangup(); /* XXX */
1859 (void) shutdown(net
, 2);
1862 #else /* PARENT_DOES_UTMP */
1864 (void) shutdown(net
, 2);
1866 # else /* NEWINIT */
1868 static int incleanup
= 0;
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.
1881 while (waitpid(-1, 0, WNOHANG
) > 0)
1883 t
= sigblock(sigmask(SIGCHLD
));
1892 * We need to set ourselves back to a null
1893 * label to clean up.
1896 setulvl(sysv
.sy_minlvl
);
1900 t
= cleantmp(&wtmp
);
1901 setutent(); /* just to make sure */
1905 (void) shutdown(net
, 2);
1911 # endif /* NEWINT */
1912 #endif /* PARENT_DOES_UTMP */
1915 #if defined(PARENT_DOES_UTMP) && !defined(NEWINIT)
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.
1926 static int caught
=0; /* NZ when signal intercepted */
1927 static void (*func
)(); /* address of previous handler */
1934 (void) signal(SIGUSR1
, func
);
1941 * register signal handler for UTMP creation
1943 if ((int)(func
= signal(SIGUSR1
, _utmp_sig_rcv
)) == -1)
1944 fatalperror(net
, "telnetd/signal");
1950 (void) signal(SIGUSR1
, func
); /* reset handler to default */
1954 # define sigoff() /* do nothing */
1955 # define sigon() /* do nothing */
1962 * Wait for parent to write our utmp entry.
1965 while (caught
== 0) {
1966 pause(); /* wait until we get a signal (sigon) */
1967 sigoff(); /* turn off signals while we check caught */
1969 sigon(); /* turn on signals again */
1973 utmp_sig_notify(pid
)
1979 static int gotsigjob
= 0;
1987 register struct jobtemp
*jp
;
1989 while ((jid
= waitjob(NULL
)) != -1) {
1994 jobend(jid
, NULL
, NULL
);
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.
2008 register struct utmp
*wtp
;
2011 static int first
= 1;
2012 register int mask
, omask
, ret
;
2013 extern struct utmp
*getutid
P((const struct utmp
*_Id
));
2016 mask
= sigmask(WJSIGNAL
);
2019 omask
= sigblock(mask
);
2020 while (gotsigjob
== 0)
2025 setutent(); /* just to make sure */
2029 syslog(LOG_ERR
, "can't get /etc/utmp entry to clean TMPDIR");
2033 * Nothing to clean up if the user shell was never started.
2035 if (utp
->ut_type
!= USER_PROCESS
|| utp
->ut_jid
== 0)
2039 * Block the WJSIGNAL while we are in jobend().
2041 omask
= sigblock(mask
);
2042 ret
= jobend(utp
->ut_jid
, utp
->ut_tpath
, utp
->ut_user
);
2048 jobend(jid
, path
, user
)
2050 register char *path
;
2051 register char *user
;
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];
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';
2063 if (saved_jid
== 0) {
2067 cleantmpdir(jid
, saved_path
, saved_user
);
2072 * Fork a child process to clean up the TMPDIR
2074 cleantmpdir(jid
, tpath
, user
)
2076 register char *tpath
;
2077 register char *user
;
2081 syslog(LOG_ERR
, "TMPDIR cleanup(%s): fork() failed: %m",
2085 execl(CLEANTMPCMD
, CLEANTMPCMD
, user
, tpath
, (char *)0);
2086 syslog(LOG_ERR
, "TMPDIR cleanup(%s): execl(%s) failed: %m",
2087 tpath
, CLEANTMPCMD
);
2091 * Forget about child. We will exit, and
2092 * /etc/init will pick it up.
2098 #endif /* defined(PARENT_DOES_UTMP) && !defined(NEWINIT) */
2103 * This is the function called by cleanup() to
2104 * remove the utmp entry for this person.
2113 struct utmp
*u
, *utmp
;
2117 struct utmpx
*utxp
, utmpx
;
2120 * This updates the utmpx and utmp entries and make a wtmp/x entry
2123 SCPYN(utmpx
.ut_line
, line
+ sizeof(_PATH_DEV
) - 1);
2124 utxp
= getutxline(&utmpx
);
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;
2137 #if !defined(UTMPX) && !(defined(CRAY) || defined(__hpux)) && BSD <= 43
2143 struct utmp
*u
, *utmp
;
2147 f
= open(utmpf
, O_RDWR
);
2149 (void) fstat(f
, &statbf
);
2150 utmp
= (struct utmp
*)malloc((unsigned)statbf
.st_size
);
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
);
2157 for (u
= utmp
; u
< &utmp
[nutmp
] ; u
++) {
2158 if (SCMPN(u
->ut_line
, line
+5) ||
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
));
2172 f
= open(wtmpf
, O_WRONLY
|O_APPEND
);
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
));
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);
2196 int fd
; /* for /etc/wtmp */
2198 utmp
.ut_type
= USER_PROCESS
;
2199 (void) strncpy(utmp
.ut_id
, line
+12, sizeof(utmp
.ut_id
));
2201 utptr
= getutid(&utmp
);
2202 /* write it out only if it exists */
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
));
2215 (void) chmod(line
, 0666);
2216 (void) chown(line
, 0, 0);
2217 line
[14] = line
[13];
2218 line
[13] = line
[12];
2224 (void) chmod(line
, 0666);
2225 (void) chown(line
, 0, 0);