#include "expect_cf.h"
#include <stdio.h>
#include <signal.h>
#if defined(SIGCLD) && !defined(SIGCHLD)
#define SIGCHLD SIGCLD
#endif
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#else
extern int fork(), execl(), wait();
#endif
#include <errno.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/ioctl.h>
#include <sys/file.h>
#ifdef HAVE_SYS_FCNTL_H
# include <sys/fcntl.h>
#else
# include <fcntl.h>
#endif
#if defined(HAVE_TERMIOS)
# include <sys/termios.h>
#else
# include <sys/termio.h>
*/
#endif
#if CRAY>=70 && defined(_CRAY2)
#include <sys/session.h>
#endif
#include <sys/pty.h>
#include <pwd.h>
#include <utmp.h>
#include <signal.h>
#include "exp_tty_in.h"
#include "exp_rename.h"
#ifdef HAVE_SYSCONF_H
#include <sys/sysconfig.h>
#endif
void debuglog();
#ifndef TRUE
#define TRUE 1
#define FALSE 0
#endif
#ifndef MAXHOSTNAMELEN
#define MAXHOSTNAMELEN 64
#endif
static char linep[] = "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0";
static char linet[] = "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0";
static int lowpty;
static int highpty;
static int realuid;
static int realgid;
static int *ptys;
static char myname[32];
static char hostname[MAXHOSTNAMELEN];
char *exp_pty_slave_name;
char *exp_pty_error;
static void
pty_stty(s,name)
char *s;
char *name;
{
#define MAX_ARGLIST 10240
char buf[MAX_ARGLIST];
RETSIGTYPE (*old)();
#ifdef STTY_READS_STDOUT
sprintf(buf,"/bin/stty %s > %s",s,name);
#else
sprintf(buf,"/bin/stty %s < %s",s,name);
#endif
old = signal(SIGCHLD, SIG_DFL);
system(buf);
signal(SIGCHLD, old);
}
int exp_dev_tty;
static int knew_dev_tty;
#ifdef TIOCGWINSZ
static struct winsize winsize = {0, 0};
#endif
#if defined(TIOCGSIZE) && !defined(TIOCGWINSZ)
static struct ttysize winsize = {0, 0};
#endif
exp_tty exp_tty_original;
#define GET_TTYTYPE 0
#define SET_TTYTYPE 1
static void
ttytype(request,fd,ttycopy,ttyinit,s)
int request;
int fd;
int ttycopy;
int ttyinit;
char *s;
{
if (request == GET_TTYTYPE) {
if (-1 == ioctl(fd, TCGETA, (char *)&exp_tty_original)) {
knew_dev_tty = FALSE;
exp_dev_tty = -1;
}
#ifdef TIOCGWINSZ
ioctl(fd,TIOCGWINSZ,&winsize);
#endif
#if defined(TIOCGSIZE) && !defined(TIOCGWINSZ)
ioctl(fd,TIOCGSIZE,&winsize);
#endif
} else {
if (ttycopy && knew_dev_tty) {
(void) ioctl(fd, TCSETA, (char *)&exp_tty_current);
#ifdef TIOCSWINSZ
ioctl(fd,TIOCSWINSZ,&winsize);
#endif
#if defined(TIOCSSIZE) && !defined(TIOCSWINSZ)
ioctl(fd,TIOCGSIZE,&winsize);
#endif
}
if (ttyinit) {
pty_stty(DFLT_STTY,linet);
}
if (s) {
pty_stty(s,linet);
}
}
}
void
exp_init_pty()
{
int npty;
char *myline;
lowpty=0;
#ifdef _SC_CRAY_NPTY
highpty=sysconf(_SC_CRAY_NPTY);
#else
highpty=128;
#endif
ptys = (int *) malloc(sizeof(int)*(highpty+1));
if (ptys == NULL) {
fprintf(stderr,"exp_init_pty: couldn't allocate pty array\n");
exit(1);
}
for (npty = lowpty;npty <= highpty;npty++)
ptys[npty] = 0;
realuid=getuid();
realgid=getgid();
exp_dev_tty = open("/dev/tty",O_RDWR);
knew_dev_tty = (exp_dev_tty != -1);
if (knew_dev_tty) ttytype(GET_TTYTYPE,exp_dev_tty,0,0,(char *)0);
(void) cuserid(myname);
(void) gethostname(hostname,sizeof(hostname));
setuid(0);
setreuid(realuid,realuid);
}
int
getptymaster()
{
struct stat sb;
int master;
int npty;
exp_pty_error = 0;
debuglog("getptymaster: lowpty=%d highpty=%d\n",lowpty,highpty);
for (npty = lowpty; npty <= highpty; npty++) {
if (seteuid(0) == -1) {
debuglog("getptymaster: seteuid root errno=%d\n",
errno);
}
(void) sprintf(linep, "/dev/pty/%03d", npty);
master = open(linep, O_RDWR);
if (master < 0) {
debuglog("getptymaster: open linep=%s errno=%d\n",
linep,errno);
continue;
}
(void) sprintf(linet, "/dev/ttyp%03d", npty);
if(stat(linet, &sb) < 0) {
debuglog("getptymaster: stat linet=%s errno=%d\n",
linet,errno);
(void) close(master);
continue;
}
if (sb.st_uid || sb.st_gid || sb.st_mode != 0600) {
if (chown(linet, realuid, realgid) == -1) {
debuglog("getptymaster: chown linet=%s errno=%d\n",
linet,errno);
}
if (chmod(linet, 0600) == -1) {
debuglog("getptymaster: chmod linet=%s errno=%d\n",
linet,errno);
}
(void)close(master);
master = open(linep, 2);
if (master < 0) {
debuglog("getptymaster: reopen linep=%s errno=%d\n",
linep,errno);
continue;
}
}
if (seteuid(realuid) == -1) {
debuglog("getptymaster: seteuid user errno=%d\n",
errno);
}
if (access(linet, R_OK|W_OK) != 0) {
debuglog("getptymaster: access linet=%s errno=%d\n",
linet,errno);
(void) close(master);
continue;
}
debuglog("getptymaster: allocated %s\n",linet);
ptys[npty] = -1;
exp_pty_slave_name = linet;
return(master);
}
if (seteuid(realuid) == -1) {
debuglog("getptymaster: seteuid user errno=%d\n",errno);
}
return(-1);
}
void
exp_slave_control(master,control)
int master;
int control;
{
}
int
getptyslave(ttycopy,ttyinit,stty_args)
int ttycopy;
int ttyinit;
char *stty_args;
{
int slave;
if (0 > (slave = open(linet, O_RDWR))) {
debuglog("getptyslave: open linet=%s errno=%d\n",linet,errno);
return(-1);
}
if (0 != slave) {
debuglog("getptyslave: slave fd not 0\n");
return(slave);
}
if (0 == slave) {
fcntl(0,F_DUPFD,1);
fcntl(0,F_DUPFD,2);
}
ttytype(SET_TTYTYPE,slave,ttycopy,ttyinit,stty_args);
return(slave);
}
setptyutmp()
{
struct utmp utmp;
if (seteuid(0) == -1) {
debuglog("setptyutmp: setuid root errno=%d\n",errno);
return(-1);
}
(void) time(&utmp.ut_time);
utmp.ut_type = USER_PROCESS;
utmp.ut_pid = getpid();
strncpy(utmp.ut_user,myname,sizeof(utmp.ut_user));
strncpy(utmp.ut_host,hostname,sizeof(utmp.ut_host));
strncpy(utmp.ut_line,linet+5,sizeof(utmp.ut_line));
strncpy(utmp.ut_id,linet+8,sizeof(utmp.ut_id));
if (pututline(&utmp) == NULL) {
debuglog("setptyutmp: pututline failed\n");
}
endutent();
if (seteuid(realuid) == -1)
debuglog("setptyutmp: seteuid user errno=%d\n",errno);
return(0);
}
setptypid(pid)
int pid;
{
int npty;
for (npty = lowpty; npty <= highpty; npty++) {
if (ptys[npty] < 0) {
debuglog("setptypid: ttyp%03d pid=%d\n",npty,pid);
ptys[npty] = pid;
break;
}
}
}
ttyp_reset()
{
int npty;
if (seteuid(0) == -1) {
debuglog("ttyp_reset: seteuid root errno=%d\n",errno);
}
for (npty = lowpty; npty <= highpty; npty++) {
if (ptys[npty] <= 0)
continue;
(void) sprintf(linet, "/dev/ttyp%03d", npty);
debuglog("ttyp_reset: resetting %s, killing %d\n",
linet,ptys[npty]);
if (chown(linet,0,0) == -1) {
debuglog("ttyp_reset: chown %s errno=%d\n",linet,errno);
}
if (chmod(linet, 0666) == -1) {
debuglog("ttyp_reset: chmod %s errno=%d\n",linet,errno);
}
resetptyutmp();
if (kill(ptys[npty],SIGKILL) == -1) {
debuglog("ttyp_reset: kill pid=%d errno=%d\n",
ptys[npty],errno);
}
}
if (seteuid(realuid) == -1) {
debuglog("ttyp_reset: seteuid user errno=%d\n",errno);
}
}
void
exp_pty_exit()
{
ttyp_reset();
}
resetptyutmp()
{
struct utmp utmp;
(void) setutent ();
(void) strncpy(utmp.ut_id, linet + strlen(linet) - 4,
sizeof (utmp.ut_id));
utmp.ut_type = USER_PROCESS;
if(getutid(&utmp) == NULL) {
debuglog("resetptyutmp: no utmp entry for %s\n",linet);
return(-1);
}
strncpy(utmp.ut_name,"",sizeof(utmp.ut_name));
strncpy(utmp.ut_host,"",sizeof(utmp.ut_host));
time(&utmp.ut_time);
utmp.ut_type = DEAD_PROCESS;
utmp.ut_exit.e_exit = 0;
pututline(&utmp);
(void) endutent();
return(0);
}