/
wizshell/
wizshell/binsrc/
wizshell/binsrc/elvis-1.7/doc/
wizshell/docs/help/
wizshell/etc/
wizshell/src/util/
#include 	"tcp.h"


/* Function declarations. */
void outa_here(), setup_tty();


extern int childpid, newfd, telnet;
extern int doutmp;
extern char remotehost[];
 

/*
 * Read a stream socket one line at a time, and write each line back
 * to another stream socket.
/*
 * Return when the connection is terminated.
 */

static int at_cr=0;		/* State of telnet input */

sync_rw(sockfd, streamfd)
int	sockfd;    /* network connection file descriptor */
int 	streamfd;  /* pty file descriptor */
{
	extern 	int errno;

	int	n, ttyfd=0;
	char	line[BUFSIZ];
	fd_set	readfds, writefds;
	struct Buf_Len received, *newbuflen;

	/* Zero out fdset for select() */
	FD_ZERO(&readfds); 

#ifdef OLDDEBUG
	char *opt_str, opt_ind[24];
#endif

	/*
 	 * Now do that I/O thang. :)
 	 */

	for ( ; ; )
	{
		FD_SET(sockfd, &readfds);  FD_SET(streamfd, &readfds);
		
		select(10, &readfds, 0, 0, NULL);

		if ( FD_ISSET(sockfd, &readfds) )
		{ 
			if ( (n=read(sockfd, line, BUFSIZ)) <= 0 )
			{
				if (n == 0)
					exit(0);  /* connection terminated */
				else if (n < 0) {
					perror("socket read error");
					exit(3);
				}
			}

			strncpy(received.buffer, line, n);
			received.len=n;

			if ( telnet )
				newbuflen=negotiate(sockfd, &received);
			else
				newbuflen=(&received);

			if ( telnet )
			{  /* Map cr-null, cr-lf to cr */
				int mapped=0, i, j;

				for ( i=0, j=0; i<newbuflen->len; ++i )
				{  
#ifdef DEBUG
					switch (newbuflen->buffer[i])
					{
						case '\r': 
						fprintf(stderr, "CR");
								break;
						case '\n':
						fprintf(stderr, "NL");
								break;
						case '\0':
						fprintf(stderr, "NULL");
								break;
						default: break;
					}
#endif /* DEBUG */
					if ( at_cr )
					{ 
#ifdef DEBUG
						fprintf(stderr, "AT_CR\r\n");
#endif
						at_cr=0;
						switch (newbuflen->buffer[i])
						{
							case '\0':
							case '\n':
#ifdef DEBUG
						fprintf(stderr, "MAP\r\n");
#endif
							mapped=1;
							continue;
							default:  break;
						}
					}
					if ( newbuflen->buffer[i] == '\r' )
						at_cr=1;
					line[j++]=newbuflen->buffer[i];
				}

				/* Only bother re-copying if we mapped a NUL */
				if ( mapped )
				{
					strncpy(newbuflen->buffer, line, j);
					newbuflen->len=j;
					mapped=0;
				}
			}

			if (writen(streamfd, newbuflen->buffer, newbuflen->len)
				 != newbuflen->len)
				return(-1);
		}

		if ( FD_ISSET(streamfd, &readfds) )
		{
			n=read(streamfd, line, BUFSIZ);
			if ( n == 0 )
			{
#ifdef OLDDEBUG
				fprintf(stderr, "stream read returned 0.\r\n");
#endif
				exit(0);
			}
			else if (n < 0)
			{
				if ( errno == EIO )
					continue;
				else {
					perror("pty read error");
					exit(3);
				}
			}

			if (writen(sockfd, line, n) != n) {
				perror("write sockfd error");
				exit(3);
			}
		}
	}
}


/*
 * Initialize a pty, fork a command running under it, and then 
 * return the master file descriptor
 */

int setup(argv, pw)
char *argv[];
struct passwd *pw;
{
	int master_fd, slave_fd;
	int 	n, fd;

	if ( (master_fd=get_pty_master()) < 0 ) {
		perror("get_pty_master()");
		exit(3);
	}

     /* If the program dies before we get to the sync-rw(), we're outahere. */
	signal(SIGCLD, outa_here);

	if ( (childpid=fork()) < 0 ) {
		perror("fork error");
		exit(3);
	} else if ( childpid == 0 )
	{
		dropctty();		/* Lose controlling tty */

		/* Gain slave as controlling tty */
		if ( (slave_fd=get_pty_slave()) < 0 ) {
			perror("get_pty_slave()");
			exit(3);
		}

#if defined(TIOCSCTTY) && !defined(CIBAUD)
		if ( ioctl(slave_fd, TIOCSCTTY, NULL) < 0 )
			perror("TIOCSCTTY error");
#endif  /* BSD */

		/* Rearrange file descriptors */
		close(0); dup(slave_fd);
		close(1); dup(slave_fd);
		close(master_fd); 
		if ( ! netdebug )
			close(2), dup(slave_fd);
		close(slave_fd);

		/* Reset the terminal */
		if ( tty_reset(0) < 0 )
			(void) tty_sane(0);

#ifdef SIGTSTP  /* Prevent non-job-control programs from dying on SIGTSTP */
                signal(SIGTSTP, SIG_IGN);
#endif
		if ( login_exec(argv, pw) < 0 ) {
			perror("login_exec() error");
			exit(255);
		}
		/* NOTREACHED */
	}
	dropctty();		/* Lose controlling tty */
	setup_tty(pw);		/* Change ownership of the tty and log utmp */

	return(master_fd);
}


/* These functions take care of the tty */

extern char tty_name[];		/* from misc.c */
extern int doutmp;		/* from tcpserv.c */

char *logname=NULL;
int ttyowner=0;			/* The owner of the tty */

void setup_tty(pw)
struct passwd *pw;
{
	struct stat sb;
	time_t now;
	int newowner;

	/* Make sure the tty exists */
	if ( stat(tty_name, &sb) < 0 )
		return;
	else
		ttyowner=sb.st_uid;

	if ( doutmp ) 	/* Set up the user to log in utmp */
	{
		if ( pw )
			logname=pw->pw_name;
		else if ( (pw=(struct passwd *)getpwuid(getuid())) != NULL )
			logname=pw->pw_name;
		else
			logname="nobody";
		(void) time(&now);

		(void) utmp(tty_name, logname, remotehost, now, 0);
	}
	if ( pw )
		newowner=pw->pw_uid;
	else if ( (pw=(struct passwd *)getpwuid(getuid())) != NULL )
		newowner=pw->pw_uid;
	else
		newowner=0;	/* chown to root as last resort */

	(void) chmod(tty_name, 0620);
	(void) chown(tty_name, newowner, sb.st_gid);
}


/* Cleanup function */

void outa_here()
{
	struct stat sb;
	time_t now;

	if ( childpid )
		kill(childpid, SIGHUP);

	if ( stat(tty_name, &sb) == 0 )
	{
		if ( doutmp && logname )
		{
			(void) time(&now);
			(void) utmp(tty_name, logname, NULL, now, 1);
		}
		(void) chmod(tty_name, 0666);
		(void) chown(tty_name, ttyowner, sb.st_gid);
	}
	exit(0);
}