446 lines
		
	
	
		
			8.6 KiB
		
	
	
	
		
			C
		
	
	
		
			Executable File
		
	
	
	
	
			
		
		
	
	
			446 lines
		
	
	
		
			8.6 KiB
		
	
	
	
		
			C
		
	
	
		
			Executable File
		
	
	
	
	
/*
 | 
						|
in.rshd.c
 | 
						|
*/
 | 
						|
 | 
						|
/*
 | 
						|
	main channel:
 | 
						|
 | 
						|
	back channel\0
 | 
						|
	remuser\0
 | 
						|
	locuser\0
 | 
						|
	command\0
 | 
						|
	data
 | 
						|
 | 
						|
	back channel:
 | 
						|
	signal\0
 | 
						|
 | 
						|
*/
 | 
						|
 | 
						|
#include <sys/types.h>
 | 
						|
#include <errno.h>
 | 
						|
#include <fcntl.h>
 | 
						|
#include <limits.h>
 | 
						|
#include <pwd.h>
 | 
						|
#include <grp.h>
 | 
						|
#include <signal.h>
 | 
						|
#include <stdio.h>
 | 
						|
#include <stdlib.h>
 | 
						|
#include <string.h>
 | 
						|
#include <unistd.h>
 | 
						|
#include <sys/ioctl.h>
 | 
						|
#include <net/gen/in.h>
 | 
						|
#include <net/gen/inet.h>
 | 
						|
#include <net/gen/netdb.h>
 | 
						|
#include <net/gen/socket.h>
 | 
						|
#include <net/gen/tcp.h>
 | 
						|
#include <net/gen/tcp_io.h>
 | 
						|
#include <net/hton.h>
 | 
						|
#include <net/netlib.h>
 | 
						|
 | 
						|
#define DEBUG 0
 | 
						|
 | 
						|
#if DEBUG
 | 
						|
#define where() fprintf(stderr, "%s, %d: ", __FILE__, __LINE__)
 | 
						|
#endif
 | 
						|
 | 
						|
char cmdbuf[_POSIX_ARG_MAX+1], locuser[16], remuser[16];
 | 
						|
extern char **environ;
 | 
						|
char username[20]="USER=";
 | 
						|
char homedir[64]="HOME=";
 | 
						|
char shell[64]="SHELL=";
 | 
						|
char tz[1024]="TZ=";
 | 
						|
char *envinit[]= {homedir, shell, username, tz, "PATH=:/bin:/usr/bin", 0};
 | 
						|
char *prog_name;
 | 
						|
char buffer[PIPE_BUF];
 | 
						|
 | 
						|
#if __STDC__
 | 
						|
#define PROTO(func, args) func args
 | 
						|
#else
 | 
						|
#define PROTO(func, args) func ()
 | 
						|
#endif
 | 
						|
 | 
						|
PROTO (int main, (int argc, char *argv[]));
 | 
						|
PROTO (void getstr, (char*buf, int cnt, char *err));
 | 
						|
PROTO (void close_on_exec, (int fd));
 | 
						|
 | 
						|
int main(argc, argv)
 | 
						|
int argc;
 | 
						|
char *argv[];
 | 
						|
{
 | 
						|
	int result, result1;
 | 
						|
	nwio_tcpconf_t tcpconf, err_tcpconf;
 | 
						|
	nwio_tcpcl_t tcpconnopt;
 | 
						|
	nwio_tcpatt_t tcpattachopt;
 | 
						|
	tcpport_t tcpport;
 | 
						|
	tcpport_t err_port;
 | 
						|
	int err_fd, pds[2];
 | 
						|
	pid_t pid, pid1, new_pg;
 | 
						|
#if USEATTACH
 | 
						|
	int err2_fd;
 | 
						|
#endif
 | 
						|
	struct passwd *pwent;
 | 
						|
	char *cp, *buff_ptr, *TZ;
 | 
						|
	char sig;
 | 
						|
 | 
						|
	prog_name= argv[0];
 | 
						|
	if (argc != 1)
 | 
						|
	{
 | 
						|
		fprintf(stderr, "%s: wrong number of arguments (%d)\n",
 | 
						|
			prog_name, argc);
 | 
						|
		exit(1);
 | 
						|
	}
 | 
						|
 | 
						|
	signal(SIGINT, SIG_DFL);
 | 
						|
	signal(SIGQUIT, SIG_DFL);
 | 
						|
	signal(SIGTERM, SIG_DFL);
 | 
						|
 | 
						|
#if DEBUG
 | 
						|
 { where(); fprintf(stderr, "\n"); }
 | 
						|
#endif
 | 
						|
	result= ioctl (0, NWIOGTCPCONF, &tcpconf);
 | 
						|
	if (result<0)
 | 
						|
	{
 | 
						|
		fprintf(stderr, "%s: ioctl(NWIOGTCPCONF)= %d : %s\n", 
 | 
						|
			prog_name, errno, strerror(errno));
 | 
						|
		exit(1);
 | 
						|
	}
 | 
						|
#if DEBUG
 | 
						|
 { where(); fprintf(stderr, "\n"); }
 | 
						|
#endif
 | 
						|
 | 
						|
	tcpport= ntohs(tcpconf.nwtc_remport);
 | 
						|
	if (tcpport >= TCPPORT_RESERVED || tcpport < TCPPORT_RESERVED/2)
 | 
						|
	{
 | 
						|
		printf("\1%s: unprotected port (%d)\n", prog_name, tcpport);
 | 
						|
		exit(1);
 | 
						|
	}
 | 
						|
	alarm(60);
 | 
						|
	err_port= 0;
 | 
						|
	for (;;)
 | 
						|
	{
 | 
						|
		char c;
 | 
						|
		result= read(0, &c, 1);
 | 
						|
		if (result <0)
 | 
						|
		{
 | 
						|
			fprintf(stderr, "%s: read= %d : %s\n", prog_name, 
 | 
						|
				errno, strerror(errno));
 | 
						|
		}
 | 
						|
		if (result<1)
 | 
						|
			exit(1);
 | 
						|
		if (c == 0)
 | 
						|
			break;
 | 
						|
		err_port= err_port*10 + c - '0';
 | 
						|
	}
 | 
						|
	alarm(0);
 | 
						|
	if (err_port != 0)
 | 
						|
	{
 | 
						|
		int n, pid, lport;
 | 
						|
 | 
						|
		pid= getpid();
 | 
						|
		lport= 1;
 | 
						|
		do {
 | 
						|
			lport= (lport << 1) | (pid & 1);
 | 
						|
			pid >>= 1;
 | 
						|
		} while (lport < TCPPORT_RESERVED/2);
 | 
						|
 | 
						|
		n= TCPPORT_RESERVED/2;
 | 
						|
		do
 | 
						|
		{
 | 
						|
			if (--lport < TCPPORT_RESERVED/2)
 | 
						|
				lport= TCPPORT_RESERVED-1;
 | 
						|
			err_fd= open ("/dev/tcp", O_RDWR);
 | 
						|
			if (err_fd<0)
 | 
						|
			{
 | 
						|
				fprintf(stderr, "%s: open= %d : %s\n", 
 | 
						|
					prog_name, errno, strerror(errno));
 | 
						|
				exit(1);
 | 
						|
			}
 | 
						|
			close_on_exec(err_fd);
 | 
						|
			err_tcpconf.nwtc_flags= NWTC_LP_SET | NWTC_SET_RA |
 | 
						|
				NWTC_SET_RP | NWTC_EXCL;
 | 
						|
			err_tcpconf.nwtc_locport= htons(lport);
 | 
						|
			err_tcpconf.nwtc_remport= htons(err_port);
 | 
						|
			err_tcpconf.nwtc_remaddr= tcpconf.nwtc_remaddr;
 | 
						|
 | 
						|
#if DEBUG
 | 
						|
 { where(); fprintf(stderr, "\n"); }
 | 
						|
#endif
 | 
						|
			result= ioctl (err_fd, NWIOSTCPCONF, &err_tcpconf);
 | 
						|
			if (result == 0) break;
 | 
						|
			if (errno != EADDRINUSE)
 | 
						|
			{
 | 
						|
				fprintf(stderr, 
 | 
						|
					"%s: ioctl(NWIOSTCPCONF)= %d : %s\n",
 | 
						|
					prog_name, errno, strerror(errno));
 | 
						|
				exit(1);
 | 
						|
			}
 | 
						|
			close(err_fd);
 | 
						|
		} while (--n > 0);
 | 
						|
		if (n == 0)
 | 
						|
		{
 | 
						|
			printf("\1can't get stderr port\n");
 | 
						|
			exit(1);
 | 
						|
		}
 | 
						|
 | 
						|
		err_tcpconf.nwtc_flags= NWTC_SHARED;
 | 
						|
#if DEBUG
 | 
						|
{ where(); fprintf(stderr, "\n"); }
 | 
						|
#endif
 | 
						|
		result= ioctl (err_fd, NWIOSTCPCONF, &err_tcpconf);
 | 
						|
		if (result<0)
 | 
						|
		{
 | 
						|
			fprintf(stderr, 
 | 
						|
				"%s: ioctl(NWIOSTCPCONF)= %d : %s\n",
 | 
						|
				prog_name, errno, strerror(errno));
 | 
						|
			exit(1);
 | 
						|
		}
 | 
						|
#if DEBUG
 | 
						|
{ where(); fprintf(stderr, "\n"); }
 | 
						|
#endif
 | 
						|
		tcpconnopt.nwtcl_flags= 0;
 | 
						|
 | 
						|
		n= 20;
 | 
						|
		for (;;)
 | 
						|
		{
 | 
						|
#if DEBUG
 | 
						|
{ where(); fprintf(stderr, "\n"); }
 | 
						|
#endif
 | 
						|
			result= ioctl (err_fd, NWIOTCPCONN, &tcpconnopt);
 | 
						|
			if (result == 0) break;
 | 
						|
			if (errno != EAGAIN && errno != ECONNREFUSED)
 | 
						|
			{
 | 
						|
				fprintf(stderr,
 | 
						|
					"%s: ioctl(NWIOTCPCONN)= %d : %s\n",
 | 
						|
					prog_name, errno, strerror(errno));
 | 
						|
				exit(1);
 | 
						|
			}
 | 
						|
			if (--n == 0) break;
 | 
						|
			sleep(1);
 | 
						|
#if DEBUG
 | 
						|
{ where(); fprintf(stderr, "\n"); }
 | 
						|
#endif
 | 
						|
		}
 | 
						|
#if USEATTACH
 | 
						|
		err2_fd= open ("/dev/tcp", O_RDWR);
 | 
						|
		close_on_exec(err2_fd);
 | 
						|
		if (err2_fd<0)
 | 
						|
		{
 | 
						|
			fprintf(stderr, "%s: open= %d : %s\n", errno,
 | 
						|
				prog_name, strerror(errno));
 | 
						|
			exit(1);
 | 
						|
		}
 | 
						|
#if DEBUG
 | 
						|
 { where(); fprintf(stderr, "\n"); }
 | 
						|
#endif
 | 
						|
		result= ioctl (err2_fd, NWIOSTCPCONF, &err_tcpconf);
 | 
						|
		if (result<0)
 | 
						|
		{
 | 
						|
			fprintf(stderr, "%s: ioctl(NWIOSTCPCONF)= %d : %s\n",
 | 
						|
				prog_name, errno, strerror(errno));
 | 
						|
			exit(1);
 | 
						|
		}
 | 
						|
#if DEBUG
 | 
						|
 { where(); fprintf(stderr, "\n"); }
 | 
						|
#endif
 | 
						|
		tcpattachopt.nwta_flags= 0;
 | 
						|
#if DEBUG
 | 
						|
 { where(); fprintf(stderr, "\n"); }
 | 
						|
#endif
 | 
						|
		result= ioctl (err2_fd, NWIOTCPATTACH, &tcpattachopt);
 | 
						|
		if (result<0)
 | 
						|
		{
 | 
						|
			fprintf(stderr, "%s: ioctl(NWIOTCPATTACH)= %d : %s\n",
 | 
						|
				prog_name, errno, strerror(errno));
 | 
						|
			exit(1);
 | 
						|
		}
 | 
						|
#if DEBUG
 | 
						|
 { where(); fprintf(stderr, "\n"); }
 | 
						|
#endif
 | 
						|
#endif
 | 
						|
	}
 | 
						|
	getstr(remuser, sizeof(remuser), "remuser");
 | 
						|
	getstr(locuser, sizeof(locuser), "locuser");
 | 
						|
	getstr(cmdbuf, sizeof(cmdbuf), "cmdbuf");
 | 
						|
	setpwent();
 | 
						|
	pwent= getpwnam(locuser);
 | 
						|
	if (!pwent)
 | 
						|
	{
 | 
						|
		printf("\1Login incorrect.\n");
 | 
						|
		exit(1);
 | 
						|
	}
 | 
						|
	endpwent();
 | 
						|
	if (chdir(pwent->pw_dir) < 0)
 | 
						|
	{
 | 
						|
		chdir("/");
 | 
						|
	}
 | 
						|
#if DEBUG
 | 
						|
 { where(); fprintf(stderr, "calling iruserok(%s, %d, %s, %s)\n", 
 | 
						|
	inet_ntoa(tcpconf.nwtc_remaddr), 0, remuser, locuser); }
 | 
						|
#endif
 | 
						|
	if (iruserok(tcpconf.nwtc_remaddr, 0, remuser, locuser) < 0)
 | 
						|
	{
 | 
						|
		printf("\1Permission denied.\n");
 | 
						|
		exit(1);
 | 
						|
	}
 | 
						|
	if (err_port)
 | 
						|
	{
 | 
						|
		/* Let's go to a different process group. */
 | 
						|
		new_pg= setsid();
 | 
						|
		pid= fork();
 | 
						|
		if (pid<0)
 | 
						|
		{
 | 
						|
			if (errno != EAGAIN)
 | 
						|
			{
 | 
						|
				fprintf(stderr, "%s: fork()= %d : %s\n",
 | 
						|
					prog_name, errno, strerror(errno));
 | 
						|
			}
 | 
						|
			printf("\1Try again.\n");
 | 
						|
			exit(1);
 | 
						|
		}
 | 
						|
		if (pid)
 | 
						|
		{
 | 
						|
			close(0);	/* stdin */
 | 
						|
			close(1);	/* stdout */
 | 
						|
#if USEATTACH
 | 
						|
			close(err_fd);	/* stderr for shell */
 | 
						|
#endif
 | 
						|
			dup2(2,0);
 | 
						|
			dup2(2,1);
 | 
						|
			for (;;)
 | 
						|
			{
 | 
						|
#if !USEATTACH
 | 
						|
				if (read(err_fd, &sig, 1) <= 0)
 | 
						|
#else
 | 
						|
				if (read(err2_fd, &sig, 1) <= 0)
 | 
						|
#endif
 | 
						|
				{
 | 
						|
#if 0
 | 
						|
					printf("read failed: %d\n", errno);
 | 
						|
#endif
 | 
						|
					exit(0);
 | 
						|
				}
 | 
						|
				pid= 0;
 | 
						|
#if 0
 | 
						|
				printf("killing %d with %d\n", -new_pg, sig);
 | 
						|
#endif
 | 
						|
				kill(-new_pg, sig);
 | 
						|
			}
 | 
						|
		}
 | 
						|
#if USEATTACH
 | 
						|
		close(err2_fd);	/* signal channel for parent */
 | 
						|
#endif
 | 
						|
		result= pipe(pds);
 | 
						|
		if (result<0)
 | 
						|
		{
 | 
						|
			printf("\1Can't make pipe\n");
 | 
						|
			kill(getppid(), SIGTERM);
 | 
						|
			exit(1);
 | 
						|
		}
 | 
						|
		pid1= fork();
 | 
						|
		if (pid1<0)
 | 
						|
		{
 | 
						|
			if (errno != EAGAIN)
 | 
						|
			{
 | 
						|
				fprintf(stderr, "%s: fork()= %d : %s\n",
 | 
						|
					prog_name, errno, strerror(errno));
 | 
						|
			}
 | 
						|
			printf("\1Try again.\n");
 | 
						|
			kill(-new_pg, SIGTERM);
 | 
						|
			exit(1);
 | 
						|
		}
 | 
						|
		if (pid1)
 | 
						|
		{
 | 
						|
			close(pds[1]);	/* write side of pipe */
 | 
						|
			for (;;)
 | 
						|
			{
 | 
						|
				result= read(pds[0], buffer, sizeof(buffer));
 | 
						|
				if (result<=0)
 | 
						|
				{
 | 
						|
					kill(pid, SIGTERM);
 | 
						|
					exit(0);
 | 
						|
				}
 | 
						|
				buff_ptr= buffer;
 | 
						|
				while (result>0)
 | 
						|
				{
 | 
						|
					result1= write (err_fd, buff_ptr,
 | 
						|
						result);
 | 
						|
					if (result1 <= 0)
 | 
						|
					{
 | 
						|
						fprintf(stderr, 
 | 
						|
						"%s: write()= %d : %s\n",
 | 
						|
							prog_name, errno,
 | 
						|
							strerror(errno));
 | 
						|
						kill(-new_pg, SIGTERM);
 | 
						|
						exit(1);
 | 
						|
					}
 | 
						|
					result -= result1;
 | 
						|
				}
 | 
						|
			}
 | 
						|
		}
 | 
						|
		close(err_fd);	/* file descriptor for error channel */
 | 
						|
		close (pds[0]);	/* read side of pipe */
 | 
						|
		dup2(pds[1], 2);
 | 
						|
		close (pds[1]);	/* write side of pipe */
 | 
						|
	}
 | 
						|
	if (*pwent->pw_shell == '\0')
 | 
						|
		pwent->pw_shell= "/bin/sh";
 | 
						|
#if __minix_vmd
 | 
						|
	initgroups(pwent->pw_name, pwent->pw_gid);
 | 
						|
#endif
 | 
						|
	setgid(pwent->pw_gid);
 | 
						|
	setuid(pwent->pw_uid);
 | 
						|
	TZ=getenv("TZ");
 | 
						|
	environ= envinit;
 | 
						|
	strncat(homedir, pwent->pw_dir, sizeof(homedir)-6);
 | 
						|
	strncat(shell, pwent->pw_shell, sizeof(shell)-7);
 | 
						|
	strncat(username, pwent->pw_name, sizeof(username)-6);
 | 
						|
	if (TZ)
 | 
						|
		strncat(tz, TZ, sizeof(tz)-4);
 | 
						|
	else
 | 
						|
		envinit[3]= NULL;
 | 
						|
 | 
						|
	cp= strrchr(pwent->pw_shell, '/');
 | 
						|
	if (cp)
 | 
						|
		cp++;
 | 
						|
	else
 | 
						|
		cp= pwent->pw_shell;
 | 
						|
 | 
						|
	if (!err_port)
 | 
						|
		dup2(1, 2);
 | 
						|
	write(1, "\0", 1);
 | 
						|
 | 
						|
	execl(pwent->pw_shell, cp, "-c", cmdbuf, 0);
 | 
						|
	close(2);
 | 
						|
	open("/dev/tty", O_RDWR);
 | 
						|
	fprintf(stderr, "%s: execl(%s, %s, .., %s)= %d : %s\n", prog_name,
 | 
						|
		pwent->pw_shell, cp, cmdbuf, errno, strerror(errno));
 | 
						|
	kill(getppid(), SIGTERM);
 | 
						|
	exit(1);
 | 
						|
}
 | 
						|
 | 
						|
void getstr(buf, cnt, err)
 | 
						|
char *buf;
 | 
						|
int cnt;
 | 
						|
char *err;
 | 
						|
{
 | 
						|
	char c;
 | 
						|
 | 
						|
	do
 | 
						|
	{
 | 
						|
		if (read(0, &c, 1) != 1)
 | 
						|
			exit(1);
 | 
						|
		*buf++ = c;
 | 
						|
		if (--cnt == 0)
 | 
						|
		{
 | 
						|
			printf("\1%s too long", err);
 | 
						|
			exit(1);
 | 
						|
		}
 | 
						|
	} while (c != 0);
 | 
						|
}
 | 
						|
 | 
						|
void close_on_exec(fd)
 | 
						|
int fd;
 | 
						|
{
 | 
						|
	(void) fcntl(fd, F_SETFD, fcntl(fd, F_GETFD) | FD_CLOEXEC);
 | 
						|
}
 |