* Copyright (c) 1989 Regents of the University of California.
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the University of
* California, Berkeley and its contributors.
* 4. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
static char sccsid
[] = "@(#)sys_term.c 5.16 (Berkeley) 3/22/91";
#if defined(AUTHENTICATE)
#include <libtelnet/auth.h>
char wtmpf
[] = "/usr/adm/wtmp";
char utmpf
[] = "/etc/utmp";
char wtmpf
[] = "/etc/wtmp";
#define SCPYN(a, b) (void) strncpy(a, b, sizeof(a))
#define SCMPN(a, b) strncmp(a, b, sizeof(a))
#if defined(UNICOS5) && defined(CRAY2) && !defined(EXTPROC)
# define cfsetospeed(tp, val) (tp)->sg.sg_ospeed = (val)
# define cfsetispeed(tp, val) (tp)->sg.sg_ispeed = (val)
# define cfgetospeed(tp) (tp)->sg.sg_ospeed
# define cfgetispeed(tp) (tp)->sg.sg_ispeed
# define TCSADRAIN TCSETSW
# define tcgetattr(f, t) ioctl(f, TCGETS, (char *)t)
# define TCSADRAIN TCSETAW
# define tcgetattr(f, t) ioctl(f, TCGETA, (char *)t)
# define TCSANOW TIOCSETA
# define TCSADRAIN TIOCSETAW
# define tcgetattr(f, t) ioctl(f, TIOCGETA, (char *)t)
# define tcsetattr(f, a, t) ioctl(f, a, t)
# define cfsetospeed(tp, val) (tp)->c_cflag &= ~CBAUD; \
# define cfgetospeed(tp) ((tp)->c_cflag & CBAUD)
# define cfsetispeed(tp, val) (tp)->c_cflag &= ~CIBAUD; \
(tp)->c_cflag |= ((val)<<IBSHIFT)
# define cfgetispeed(tp) (((tp)->c_cflag & CIBAUD)>>IBSHIFT)
# define cfsetispeed(tp, val) (tp)->c_cflag &= ~CBAUD; \
# define cfgetispeed(tp) ((tp)->c_cflag & CBAUD)
struct termios termbuf
, termbuf2
; /* pty control structure */
* These three routines are used to get and set the "termbuf" structure
* to and from the kernel. init_termbuf() gets the current settings.
* copy_termbuf() hands in a new "termbuf" to write to the kernel, and
* set_termbuf() writes the structure into the kernel.
(void) ioctl(pty
, TIOCGETP
, (char *)&termbuf
.sg
);
(void) ioctl(pty
, TIOCGETC
, (char *)&termbuf
.tc
);
(void) ioctl(pty
, TIOCGLTC
, (char *)&termbuf
.ltc
);
(void) ioctl(pty
, TIOCGSTATE
, (char *)&termbuf
.state
);
(void) tcgetattr(pty
, &termbuf
);
#if defined(LINEMODE) && defined(TIOCPKT_IOCTL)
if (len
> sizeof(termbuf
))
bcopy(cp
, (char *)&termbuf
, len
);
#endif /* defined(LINEMODE) && defined(TIOCPKT_IOCTL) */
* Only make the necessary changes.
if (bcmp((char *)&termbuf
.sg
, (char *)&termbuf2
.sg
, sizeof(termbuf
.sg
)))
(void) ioctl(pty
, TIOCSETN
, (char *)&termbuf
.sg
);
if (bcmp((char *)&termbuf
.tc
, (char *)&termbuf2
.tc
, sizeof(termbuf
.tc
)))
(void) ioctl(pty
, TIOCSETC
, (char *)&termbuf
.tc
);
if (bcmp((char *)&termbuf
.ltc
, (char *)&termbuf2
.ltc
,
(void) ioctl(pty
, TIOCSLTC
, (char *)&termbuf
.ltc
);
if (termbuf
.lflags
!= termbuf2
.lflags
)
(void) ioctl(pty
, TIOCLSET
, (char *)&termbuf
.lflags
);
if (bcmp((char *)&termbuf
, (char *)&termbuf2
, sizeof(termbuf
)))
(void) tcsetattr(pty
, TCSANOW
, &termbuf
);
# if defined(CRAY2) && defined(UNCIOS5)
* spcset(func, valp, valpp)
* This function takes various special characters (func), and
* sets *valp to the current value of that character, and
* *valpp to point to where in the "termbuf" structure that
* It returns the SLC_ level of support for this function.
spcset(func
, valp
, valpp
)
*valp
= termbuf
.tc
.t_eofc
;
*valpp
= (cc_t
*)&termbuf
.tc
.t_eofc
;
*valp
= termbuf
.sg
.sg_erase
;
*valpp
= (cc_t
*)&termbuf
.sg
.sg_erase
;
*valp
= termbuf
.sg
.sg_kill
;
*valpp
= (cc_t
*)&termbuf
.sg
.sg_kill
;
*valp
= termbuf
.tc
.t_intrc
;
*valpp
= (cc_t
*)&termbuf
.tc
.t_intrc
;
return(SLC_VARIABLE
|SLC_FLUSHIN
|SLC_FLUSHOUT
);
*valp
= termbuf
.tc
.t_quitc
;
*valpp
= (cc_t
*)&termbuf
.tc
.t_quitc
;
return(SLC_VARIABLE
|SLC_FLUSHIN
|SLC_FLUSHOUT
);
*valp
= termbuf
.tc
.t_startc
;
*valpp
= (cc_t
*)&termbuf
.tc
.t_startc
;
*valp
= termbuf
.tc
.t_stopc
;
*valpp
= (cc_t
*)&termbuf
.tc
.t_stopc
;
*valp
= termbuf
.ltc
.t_flushc
;
*valpp
= (cc_t
*)&termbuf
.ltc
.t_flushc
;
*valp
= termbuf
.ltc
.t_suspc
;
*valpp
= (cc_t
*)&termbuf
.ltc
.t_suspc
;
*valp
= termbuf
.ltc
.t_werasc
;
*valpp
= (cc_t
*)&termbuf
.ltc
.t_werasc
;
*valp
= termbuf
.ltc
.t_rprntc
;
*valpp
= (cc_t
*)&termbuf
.ltc
.t_rprntc
;
*valp
= termbuf
.ltc
.t_lnextc
;
*valpp
= (cc_t
*)&termbuf
.ltc
.t_lnextc
;
*valp
= termbuf
.tc
.t_brkc
;
*valpp
= (cc_t
*)&termbuf
.ltc
.t_lnextc
;
spcset(func
, valp
, valpp
)
#define setval(a, b) *valp = termbuf.c_cc[a]; \
*valpp = &termbuf.c_cc[a]; \
#define defval(a) *valp = ((cc_t)a); *valpp = (cc_t *)0; return(SLC_DEFAULT);
setval(VEOF
, SLC_VARIABLE
);
setval(VERASE
, SLC_VARIABLE
);
setval(VKILL
, SLC_VARIABLE
);
setval(VINTR
, SLC_VARIABLE
|SLC_FLUSHIN
|SLC_FLUSHOUT
);
setval(VQUIT
, SLC_VARIABLE
|SLC_FLUSHIN
|SLC_FLUSHOUT
);
setval(VSTART
, SLC_VARIABLE
);
setval(VSTOP
, SLC_VARIABLE
);
setval(VWERASE
, SLC_VARIABLE
);
setval(VREPRINT
, SLC_VARIABLE
);
setval(VLNEXT
, SLC_VARIABLE
);
#if !defined(VDISCARD) && defined(VFLUSHO)
# define VDISCARD VFLUSHO
setval(VDISCARD
, SLC_VARIABLE
|SLC_FLUSHOUT
);
setval(VSUSP
, SLC_VARIABLE
|SLC_FLUSHIN
);
setval(VEOL
, SLC_VARIABLE
);
setval(VEOL2
, SLC_VARIABLE
);
setval(VSTATUS
, SLC_VARIABLE
);
* Return the number of pty's configured into the system.
if ((numptys
= sysconf(_SC_CRAY_NPTY
)) != -1)
#endif /* _SC_CRAY_NPTY */
* Allocate a pty. As a side effect, the external character
* array "line" contains the name of the slave side.
* Returns the file descriptor of the opened pty.
char *line
= "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0";
static char Xline
[] = "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0";
char *myline
= "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0";
register char c
, *p1
, *p2
;
(void) sprintf(line
, "/dev/ptyXX");
for (c
= 'p'; c
<= 's'; c
++) {
if (stat(line
, &stb
) < 0)
for (i
= 0; i
< 16; i
++) {
*p2
= "0123456789abcdef"[i
];
for (npty
= lowpty
; npty
<= highpty
; npty
++) {
(void) sprintf(myline
, "/dev/pty/%03d", npty
);
(void) sprintf(line
, "/dev/ttyp%03d", npty
);
* Here are some shenanigans to make sure that there
* are no listeners lurking on the line.
if(stat(line
, &sb
) < 0) {
if(sb
.st_uid
|| sb
.st_gid
|| sb
.st_mode
!= 0600) {
* Now it should be safe...check for accessability.
if (access(line
, 6) == 0)
/* no tty side to pty so skip it */
* tty_flowmode() Find out if flow control is enabled or disabled.
* tty_linemode() Find out if linemode (external processing) is enabled.
* tty_setlinemod(on) Turn on/off linemode.
* tty_isecho() Find out if echoing is turned on.
* tty_setecho(on) Enable/disable character echoing.
* tty_israw() Find out if terminal is in RAW mode.
* tty_binaryin(on) Turn on/off BINARY on input.
* tty_binaryout(on) Turn on/off BINARY on output.
* tty_isediting() Find out if line editing is enabled.
* tty_istrapsig() Find out if signal trapping is enabled.
* tty_setedit(on) Turn on/off line editing.
* tty_setsig(on) Turn on/off signal trapping.
* tty_issofttab() Find out if tab expansion is enabled.
* tty_setsofttab(on) Turn on/off soft tab expansion.
* tty_islitecho() Find out if typed control chars are echoed literally
* tty_setlitecho() Turn on/off literal echo of control chars
* tty_tspeed(val) Set transmit speed to val.
* tty_rspeed(val) Set receive speed to val.
return(((termbuf
.tc
.t_startc
) > 0 && (termbuf
.tc
.t_stopc
) > 0) ? 1 : 0);
return(termbuf
.c_iflag
& IXON
? 1 : 0);
return(termbuf
.state
& TS_EXTPROC
);
return(termbuf
.c_lflag
& EXTPROC
);
(void) ioctl(pty
, TIOCEXT
, (char *)&on
);
termbuf
.c_lflag
|= EXTPROC
;
termbuf
.c_lflag
&= ~EXTPROC
;
return (termbuf
.sg
.sg_flags
& ECHO
);
return (termbuf
.c_lflag
& ECHO
);
termbuf
.sg
.sg_flags
|= ECHO
|CRMOD
;
termbuf
.sg
.sg_flags
&= ~(ECHO
|CRMOD
);
termbuf
.c_lflag
&= ~ECHO
;
#if defined(LINEMODE) && defined(KLUDGELINEMODE)
return(termbuf
.sg
.sg_flags
& RAW
);
return(!(termbuf
.c_lflag
& ICANON
));
#endif /* defined(LINEMODE) && defined(KLUDGELINEMODE) */
termbuf
.lflags
|= LPASS8
;
termbuf
.lflags
&= ~LPASS8
;
termbuf
.c_iflag
&= ~ISTRIP
;
termbuf
.c_iflag
|= ISTRIP
;
termbuf
.lflags
|= LLITOUT
;
termbuf
.lflags
&= ~LLITOUT
;
termbuf
.c_cflag
&= ~(CSIZE
|PARENB
);
termbuf
.c_oflag
&= ~OPOST
;
termbuf
.c_cflag
&= ~CSIZE
;
termbuf
.c_cflag
|= CS7
|PARENB
;
termbuf
.c_oflag
|= OPOST
;
return(termbuf
.lflags
& LPASS8
);
return(!(termbuf
.c_iflag
& ISTRIP
));
return(termbuf
.lflags
& LLITOUT
);
return(!(termbuf
.c_oflag
&OPOST
));
return(!(termbuf
.sg
.sg_flags
& (CBREAK
|RAW
)));
return(termbuf
.c_lflag
& ICANON
);
return(!(termbuf
.sg
.sg_flags
&RAW
));
return(termbuf
.c_lflag
& ISIG
);
termbuf
.sg
.sg_flags
&= ~CBREAK
;
termbuf
.sg
.sg_flags
|= CBREAK
;
termbuf
.c_lflag
|= ICANON
;
termbuf
.c_lflag
&= ~ICANON
;
termbuf
.c_lflag
&= ~ISIG
;
return (termbuf
.sg
.sg_flags
& XTABS
);
return (termbuf
.c_oflag
& OXTABS
);
return ((termbuf
.c_oflag
& TABDLY
) == TAB3
);
termbuf
.sg
.sg_flags
|= XTABS
;
termbuf
.sg
.sg_flags
&= ~XTABS
;
termbuf
.c_oflag
|= OXTABS
;
termbuf
.c_oflag
&= ~TABDLY
;
termbuf
.c_oflag
&= ~OXTABS
;
termbuf
.c_oflag
&= ~TABDLY
;
return (!(termbuf
.lflags
& LCTLECH
));
return (!(termbuf
.c_lflag
& ECHOCTL
));
return (!(termbuf
.c_lflag
& TCTLECH
));
# if !defined(ECHOCTL) && !defined(TCTLECH)
return (0); /* assumes ctl chars are echoed '^x' */
termbuf
.lflags
&= ~LCTLECH
;
termbuf
.lflags
|= LCTLECH
;
termbuf
.c_lflag
&= ~ECHOCTL
;
termbuf
.c_lflag
|= ECHOCTL
;
termbuf
.c_lflag
&= ~TCTLECH
;
termbuf
.c_lflag
|= TCTLECH
;
return (termbuf
.sg
.sg_flags
& CRMOD
);
return (termbuf
.c_iflag
& ICRNL
);
* A table of available terminal speeds
{ 0, B0
}, { 50, B50
}, { 75, B75
},
{ 110, B110
}, { 134, B134
}, { 150, B150
},
{ 200, B200
}, { 300, B300
}, { 600, B600
},
{ 1200, B1200
}, { 1800, B1800
}, { 2400, B2400
},
{ 4800, B4800
}, { 9600, B9600
}, { 19200, B9600
},
{ 38400, B9600
}, { -1, B9600
}
register struct termspeeds
*tp
;
for (tp
= termspeeds
; (tp
->speed
!= -1) && (val
> tp
->speed
); tp
++)
cfsetospeed(&termbuf
, tp
->value
);
register struct termspeeds
*tp
;
for (tp
= termspeeds
; (tp
->speed
!= -1) && (val
> tp
->speed
); tp
++)
cfsetispeed(&termbuf
, tp
->value
);
#if defined(CRAY2) && defined(UNICOS5)
return((termbuf
.c_oflag
& OPOST
) && (termbuf
.c_oflag
& ONLCR
) &&
!(termbuf
.c_oflag
& ONLRET
));
extern void utmp_sig_init
P((void));
extern void utmp_sig_reset
P((void));
extern void utmp_sig_wait
P((void));
extern void utmp_sig_notify
P((int));
* Open the slave side of the pty, and do any initialization
* that is necessary. The return value is a file descriptor
#if !defined(CRAY) || !defined(NEWINIT)
extern int def_row
, def_col
;
extern int def_tspeed
, def_rspeed
;
* Opening the slave side may cause initilization of the
* kernel tty structure. We need remember the state of
* if linemode was turned on
* so that we can re-set them if we need to.
* Make sure that we don't have a controlling tty, and
* that we are the session (process group) leader.
t
= open(_PATH_TTY
, O_RDWR
);
(void) ioctl(t
, TIOCNOTTY
, (char *)0);
* Wait for our parent to get the utmp stuff to get done.
* set up the tty modes as we like them to be.
if (def_row
|| def_col
) {
bzero((char *)&ws
, sizeof(ws
));
(void)ioctl(t
, TIOCSWINSZ
, (char *)&ws
);
* Settings for sgtty based systems
termbuf
.sg
.sg_flags
|= CRMOD
|ANYP
|ECHO
|XTABS
;
termbuf
.c_oflag
= OPOST
|ONLCR
|TAB3
;
termbuf
.c_iflag
= IGNPAR
|ISTRIP
|ICRNL
|IXON
;
termbuf
.c_lflag
= ISIG
|ICANON
|ECHO
|ECHOE
|ECHOK
;
termbuf
.c_cflag
= EXTB
|HUPCL
|CS8
;
* Settings for all other termios/termio based
* systems, other than 4.4BSD. In 4.4BSD the
* kernel does the initial terminal setup.
# if defined(USE_TERMIO) && !defined(CRAY) && (BSD <= 43)
termbuf
.c_oflag
|= ONLCR
|OXTABS
;
termbuf
.c_iflag
|= ICRNL
;
termbuf
.c_iflag
&= ~IXOFF
;
# endif /* defined(USE_TERMIO) && !defined(CRAY) && (BSD <= 43) */
tty_rspeed((def_rspeed
> 0) ? def_rspeed
: 9600);
tty_tspeed((def_tspeed
> 0) ? def_tspeed
: 9600);
* Set the tty modes, and make this our controlling tty.
fatalperror(net
, "login_tty");
#endif /* !defined(CRAY) || !defined(NEWINIT) */
#if !defined(CRAY) || !defined(NEWINIT)
* Open the specified slave side of the pty,
* making sure that we have a clean tty.
* Make sure that other people can't open the
* slave side of the connection.
(void) chown(line
, 0, 0);
(void) chmod(line
, 0600);
# if !defined(CRAY) && (BSD > 43)
t
= open(line
, O_RDWR
|O_NOCTTY
);
* Hangup anybody else using this ttyp, then reopen it for
# if !defined(CRAY) && (BSD <= 43)
(void) signal(SIGHUP
, SIG_IGN
);
(void) signal(SIGHUP
, SIG_DFL
);
t
= open(line
, O_RDWR
|O_NOCTTY
);
# if defined(CRAY) && defined(TCVHUP)
(void) signal(SIGHUP
, SIG_IGN
);
(void) ioctl(t
, TCVHUP
, (char *)0);
(void) signal(SIGHUP
, SIG_DFL
);
# endif /* defined(CRAY) && defined(TCVHUP) */
#endif /* !defined(CRAY) || !defined(NEWINIT) */
fatalperror(net
, "setsid()");
if (ioctl(t
, TIOCSCTTY
, (char *)0) < 0)
fatalperror(net
, "ioctl(sctty)");
# if defined(CRAY) && defined(SESS_CTTY) /* SESS_CTTY is in param.h */
* Close the hard fd to /dev/ttypXXX, and re-open through
* the indirect /dev/tty interface.
if ((t
= open("/dev/tty", O_RDWR
)) < 0)
fatalperror(net
, "open(/dev/tty)");
close(open(line
, O_RDWR
));
* Given a hostname, do whatever
* is necessary to startup the login process on the slave side of the pty.
startslave(host
, autologin
, autoname
)
struct init_request request
;
#if defined(AUTHENTICATE)
if (!autoname
|| !autoname
[0])
if (autologin
< auth_level
) {
fatal(net
, "Authorization failed");
fatalperror(net
, "fork");
* Cray parent will create utmp entry for child and send
* signal to child to tell when done. Child waits for signal
* before doing anything important.
utmp_sig_reset(); /* reset handler to default */
* Create utmp entry for child
(void) time(&wtmp
.ut_time
);
wtmp
.ut_type
= LOGIN_PROCESS
;
SCPYN(wtmp
.ut_user
, "LOGIN");
SCPYN(wtmp
.ut_host
, host
);
SCPYN(wtmp
.ut_line
, line
+ sizeof("/dev/") - 1);
SCPYN(wtmp
.ut_id
, wtmp
.ut_line
+3);
if ((i
= open(wtmpf
, O_WRONLY
|O_APPEND
)) >= 0) {
(void) write(i
, (char *)&wtmp
, sizeof(struct utmp
));
(void) signal(WJSIGNAL
, sigjob
);
start_login(host
, autologin
, autoname
);
* Init will start up login process if we ask nicely. We only wait
* for it to start up and begin normal telnet operation.
if ((i
= open(INIT_FIFO
, O_WRONLY
)) < 0) {
(void) sprintf(tbuf
, "Can't open %s\n", INIT_FIFO
);
memset((char *)&request
, 0, sizeof(request
));
request
.magic
= INIT_MAGIC
;
SCPYN(request
.gen_id
, gen_id
);
SCPYN(request
.tty_id
, &line
[8]);
SCPYN(request
.host
, host
);
SCPYN(request
.term_type
, terminaltype
? terminaltype
: "network");
* Are we working as the bftp daemon?
SCPYN(request
.exec_name
, BFTPPATH
);
if (write(i
, (char *)&request
, sizeof(request
)) < 0) {
(void) sprintf(tbuf
, "Can't write to %s\n", INIT_FIFO
);
(void) signal(SIGALRM
, nologinproc
);
n
= read(pty
, ptyip
, BUFSIZ
);
if (i
== 3 || n
>= 0 || !gotalarm
)
sprintf(tbuf
, "telnetd: waiting for /etc/init to start login process on %s\r\n", line
);
(void) write(net
, tbuf
, strlen(tbuf
));
fatal(net
, "/etc/init didn't start login process");
(void) signal(SIGALRM
, SIG_DFL
);
if (*envp
= getenv("TZ"))
* Assuming that we are now running as a child processes, this
* function will turn us into the login process.
start_login(host
, autologin
, name
)
* -h : pass on name of host.
* WARNING: -h is accepted by login if and only if
* -p : don't clobber the environment (so terminal type stays set).
* -f : force this login, he has already been authenticated
argv
= addarg(0, "login");
argv
= addarg(argv
, "-h");
argv
= addarg(argv
, host
);
argv
= addarg(argv
, "-p");
* Are we working as the bftp daemon? If so, then ask login
* to start bftp instead of shell.
argv
= addarg(argv
, "-e");
argv
= addarg(argv
, BFTPPATH
);
* don't worry about the -f that might get sent.
* A -s is supposed to override it anyhow.
argv
= addarg(argv
, "-s");
#if defined (AUTHENTICATE)
if (auth_level
>= 0 && autologin
== AUTH_VALID
) {
# if !defined(NO_LOGIN_F)
argv
= addarg(argv
, "-f");
argv
= addarg(argv
, name
);
argv
= addarg(argv
, getenv("USER"));
#if defined(CRAY) && defined(NO_LOGIN_P)
for (cpp
= environ
; *cpp
; cpp
++)
argv
= addarg(argv
, *cpp
);
execv(_PATH_LOGIN
, argv
);
syslog(LOG_ERR
, "%s: %m\n", _PATH_LOGIN
);
fatalperror(net
, _PATH_LOGIN
);
* 10 entries, a leading length, and a null
argv
= (char **)malloc(sizeof(*argv
) * 12);
for (cpp
= argv
; *cpp
; cpp
++)
if (cpp
== &argv
[(int)argv
[-1]]) {
*argv
= (char *)((int)(*argv
) + 10);
argv
= (char **)realloc(argv
, (int)(*argv
) + 2);
cpp
= &argv
[(int)argv
[-1] - 10];
* This is the routine to call when we are all through, to
* clean up anything that needs to be cleaned up.
# if (BSD > 43) || defined(convex)
p
= line
+ sizeof("/dev/") - 1;
static int incleanup
= 0;
* 1: Pick up the zombie, if we are being called
* 2: If we are a nested cleanup(), return.
* 3: Try to clean up TMPDIR.
* 4: Fill in utmp with shutdown of process.
* 5: Close down the network and pty connections.
* 6: Finish up the TMPDIR cleanup, if needed.
while (waitpid(-1, 0, WNOHANG
) > 0)
t
= sigblock(sigmask(SIGCHLD
));
setutent(); /* just to make sure */
#if defined(CRAY) && !defined(NEWINIT)
* These three functions are used to coordinate the handling of
* the utmp file between the server and the soon-to-be-login shell.
* The server actually creates the utmp structure, the child calls
* utmp_sig_wait(), until the server calls utmp_sig_notify() and
* signals the future-login shell to proceed.
static int caught
=0; /* NZ when signal intercepted */
static void (*func
)(); /* address of previous handler */
(void) signal(SIGUSR1
, func
);
* register signal handler for UTMP creation
if ((int)(func
= signal(SIGUSR1
, _utmp_sig_rcv
)) == -1)
fatalperror(net
, "telnetd/signal");
(void) signal(SIGUSR1
, func
); /* reset handler to default */
* Wait for parent to write our utmp entry.
pause(); /* wait until we get a signal (sigon) */
sigoff(); /* turn off signals while we check caught */
sigon(); /* turn on signals again */
static int gotsigjob
= 0;
register struct jobtemp
*jp
;
while ((jid
= waitjob(NULL
)) != -1) {
* Clean up the TMPDIR that login created.
* The first time this is called we pick up the info
* from the utmp. If the job has already gone away,
* then we'll clean up and be done. If not, then
* when this is called the second time it will wait
* for the signal that the job is done.
register struct utmp
*wtp
;
register int mask
, omask
, ret
;
extern struct utmp
*getutid
P((struct utmp
*));
mask
= sigmask(WJSIGNAL
);
setutent(); /* just to make sure */
syslog(LOG_ERR
, "Can't get /etc/utmp entry to clean TMPDIR");
* Nothing to clean up if the user shell was never started.
if (utp
->ut_type
!= USER_PROCESS
|| utp
->ut_jid
== 0)
* Block the WJSIGNAL while we are in jobend().
ret
= jobend(utp
->ut_jid
, utp
->ut_tpath
, utp
->ut_user
);
static int saved_jid
= 0;
static char saved_path
[sizeof(wtmp
.ut_tpath
)+1];
static char saved_user
[sizeof(wtmp
.ut_user
)+1];
strncpy(saved_path
, path
, sizeof(wtmp
.ut_tpath
));
strncpy(saved_user
, user
, sizeof(wtmp
.ut_user
));
saved_path
[sizeof(saved_path
)] = '\0';
saved_user
[sizeof(saved_user
)] = '\0';
cleantmpdir(jid
, saved_path
, saved_user
);
* Fork a child process to clean up the TMPDIR
cleantmpdir(jid
, tpath
, user
)
syslog(LOG_ERR
, "TMPDIR cleanup(%s): fork() failed: %m\n",
execl(CLEANTMPCMD
, CLEANTMPCMD
, user
, tpath
, 0);
syslog(LOG_ERR
, "TMPDIR cleanup(%s): execl(%s) failed: %m\n",
* Forget about child. We will exit, and
* /etc/init will pick it up.
#endif /* defined(CRAY) && !defined(NEWINIT) */
* This is the function called by cleanup() to
* remove the utmp entry for this person.
#if !defined(CRAY) && BSD <= 43
(void) fstat(f
, &statbf
);
utmp
= (struct utmp
*)malloc((unsigned)statbf
.st_size
);
syslog(LOG_ERR
, "utmp malloc failed");
if (statbf
.st_size
&& utmp
) {
nutmp
= read(f
, (char *)utmp
, (int)statbf
.st_size
);
nutmp
/= sizeof(struct utmp
);
for (u
= utmp
; u
< &utmp
[nutmp
] ; u
++) {
if (SCMPN(u
->ut_line
, line
+5) ||
(void) lseek(f
, ((long)u
)-((long)utmp
), L_SET
);
(void) time(&u
->ut_time
);
(void) write(f
, (char *)u
, sizeof(wtmp
));
f
= open(wtmpf
, O_WRONLY
|O_APPEND
);
SCPYN(wtmp
.ut_line
, line
+5);
(void) time(&wtmp
.ut_time
);
(void) write(f
, (char *)&wtmp
, sizeof(wtmp
));
(void) chmod(line
, 0666);
(void) chown(line
, 0, 0);
line
[strlen("/dev/")] = 'p';
(void) chmod(line
, 0666);
(void) chown(line
, 0, 0);