445 lines
8.6 KiB
C
445 lines
8.6 KiB
C
/*
|
|
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);
|
|
}
|