mirror of
https://github.com/samba-team/samba.git
synced 2024-12-28 07:21:54 +03:00
cef59090bb
Jeremy (jallison@whistle.com)
(This used to be commit e7eb1f044d
)
491 lines
8.0 KiB
C
491 lines
8.0 KiB
C
/* vt_mode.c */
|
|
/*
|
|
support vtp-sessions
|
|
|
|
written by Christian A. Lademann <cal@zls.com>
|
|
*/
|
|
|
|
/*
|
|
02.05.95:cal:ported to samba-1.9.13
|
|
*/
|
|
|
|
#define __vt_mode_c__
|
|
|
|
|
|
/* #include <stdio.h> */
|
|
/* #include <fcntl.h> */
|
|
/* #include <sys/types.h> */
|
|
/* #include <unistd.h> */
|
|
/* #include <signal.h> */
|
|
/* #include <errno.h> */
|
|
/* #include <ctype.h> */
|
|
/* #include <utmp.h> */
|
|
/* #include <sys/param.h> */
|
|
/* #include <sys/ioctl.h> */
|
|
/* #include <stdlib.h> */
|
|
/* #include <string.h> */
|
|
|
|
#include "includes.h"
|
|
#include "vt_mode.h"
|
|
#include <utmp.h>
|
|
|
|
#ifdef SCO
|
|
extern char *strdup();
|
|
#endif
|
|
|
|
extern int Client;
|
|
|
|
#ifdef LINUX
|
|
# define HAS_VTY
|
|
#endif
|
|
|
|
#ifdef SCO
|
|
# define HAS_PTY
|
|
# define HAS_VTY
|
|
|
|
# include <sys/tty.h>
|
|
#endif
|
|
|
|
extern int DEBUGLEVEL;
|
|
extern char *InBuffer, *OutBuffer;
|
|
extern int done_become_user;
|
|
|
|
char master_name [64], slave_name [64];
|
|
int master, slave, i, o, e;
|
|
|
|
int ms_type = MS_NONE,
|
|
ms_poll = 0;
|
|
|
|
|
|
/*
|
|
VT_Check: test incoming packet for "vtp" or "iVT1\0"
|
|
*/
|
|
int VT_Check(char *buffer)
|
|
{
|
|
DEBUG(3,("Checking packet: <%10s...>\n", buffer+4));
|
|
if((strncmp(buffer+4, "vtp", 3) == 0 && smb_len(buffer) == 3) || (strncmp(buffer+4, "iVT1\0", 5) == 0 && smb_len(buffer) == 5))
|
|
return(1);
|
|
else
|
|
return(0);
|
|
}
|
|
|
|
|
|
/*
|
|
VT_Start_utmp: prepare /etc/utmp for /bin/login
|
|
*/
|
|
int VT_Start_utmp(void)
|
|
{
|
|
struct utmp u, *v;
|
|
char *tt;
|
|
|
|
|
|
setutent();
|
|
|
|
fstrcpy(u.ut_line, VT_Line);
|
|
|
|
if((v = getutline(&u)) == NULL) {
|
|
if(strncmp(VT_Line, "tty", 3) == 0)
|
|
tt = VT_Line + 3;
|
|
else if(strlen(VT_Line) > 4)
|
|
tt = VT_Line + strlen(VT_Line) - 4;
|
|
else
|
|
tt = VT_Line;
|
|
|
|
fstrcpy(u.ut_id, tt);
|
|
u.ut_time = time((time_t*)0);
|
|
}
|
|
|
|
fstrcpy(u.ut_user, "LOGIN");
|
|
fstrcpy(u.ut_line, VT_Line);
|
|
u.ut_pid = getpid();
|
|
u.ut_type = LOGIN_PROCESS;
|
|
pututline(&u);
|
|
|
|
endutent();
|
|
|
|
return(0);
|
|
}
|
|
|
|
|
|
/*
|
|
VT_Stop_utmp: prepare /etc/utmp for other processes
|
|
*/
|
|
int VT_Stop_utmp(void)
|
|
{
|
|
struct utmp u, *v;
|
|
|
|
|
|
if(VT_Line != NULL) {
|
|
setutent();
|
|
|
|
fstrcpy(u.ut_line, VT_Line);
|
|
|
|
if((v = getutline(&u)) != NULL) {
|
|
fstrcpy(v->ut_user, "");
|
|
v->ut_type = DEAD_PROCESS;
|
|
v->ut_time = time((time_t*)0);
|
|
pututline(v);
|
|
}
|
|
|
|
endutent();
|
|
}
|
|
|
|
return(0);
|
|
}
|
|
|
|
|
|
/*
|
|
VT_AtExit: Things to do when the program exits
|
|
*/
|
|
void VT_AtExit(void)
|
|
{
|
|
if(VT_ChildPID > 0) {
|
|
kill(VT_ChildPID, SIGHUP);
|
|
(void)wait(NULL);
|
|
}
|
|
|
|
VT_Stop_utmp();
|
|
}
|
|
|
|
|
|
/*
|
|
VT_SigCLD: signalhandler for SIGCLD: set flag if child-process died
|
|
*/
|
|
void VT_SigCLD(int sig)
|
|
{
|
|
if(wait(NULL) == VT_ChildPID)
|
|
VT_ChildDied = True;
|
|
else
|
|
signal(SIGCLD, VT_SigCLD);
|
|
}
|
|
|
|
|
|
/*
|
|
VT_SigEXIT: signalhandler for signals that cause the process to exit
|
|
*/
|
|
void VT_SigEXIT(int sig)
|
|
{
|
|
VT_AtExit();
|
|
|
|
exit(1);
|
|
}
|
|
|
|
|
|
/*
|
|
VT_Start: initialize vt-specific data, alloc pty, spawn shell and send ACK
|
|
*/
|
|
int VT_Start(void)
|
|
{
|
|
char OutBuf [64], *X, *Y;
|
|
|
|
|
|
ms_type = MS_NONE;
|
|
master = slave = -1;
|
|
|
|
#ifdef HAS_VTY
|
|
#ifdef LINUX
|
|
# define MASTER_TMPL "/dev/pty "
|
|
# define SLAVE_TMPL "/dev/tty "
|
|
# define LETTER1 "pqrs"
|
|
# define POS1 8
|
|
# define LETTER2 "0123456789abcdef"
|
|
# define POS2 9
|
|
#endif
|
|
|
|
#ifdef SCO
|
|
# define MASTER_TMPL "/dev/ptyp_ "
|
|
# define SLAVE_TMPL "/dev/ttyp_ "
|
|
# define LETTER1 "0123456"
|
|
# define POS1 10
|
|
# define LETTER2 "0123456789abcdef"
|
|
# define POS2 11
|
|
#endif
|
|
|
|
if(ms_poll == MS_VTY || ms_poll == 0) {
|
|
strcpy(master_name, MASTER_TMPL);
|
|
strcpy(slave_name, SLAVE_TMPL);
|
|
|
|
for(X = LETTER1; *X && master < 0; X++)
|
|
for(Y = LETTER2; *Y && master < 0; Y++) {
|
|
master_name [POS1] = *X;
|
|
master_name [POS2] = *Y;
|
|
if((master = open(master_name, O_RDWR)) >= 0) {
|
|
slave_name [POS1] = *X;
|
|
slave_name [POS2] = *Y;
|
|
if((slave = open(slave_name, O_RDWR)) < 0)
|
|
close(master);
|
|
}
|
|
}
|
|
|
|
if(master >= 0 && slave >= 0)
|
|
ms_type = MS_VTY;
|
|
}
|
|
|
|
# undef MASTER_TMPL
|
|
# undef SLAVE_TMPL
|
|
# undef LETTER1
|
|
# undef LETTER2
|
|
# undef POS1
|
|
# undef POS2
|
|
#endif
|
|
|
|
|
|
#ifdef HAS_PTY
|
|
#ifdef SCO
|
|
# define MASTER_TMPL "/dev/ptyp%d"
|
|
# define SLAVE_TMPL "/dev/ttyp%d"
|
|
# define MIN_I 0
|
|
# define MAX_I 63
|
|
#endif
|
|
|
|
if(ms_poll == MS_PTY || ms_poll == 0) {
|
|
int i;
|
|
|
|
for(i = MIN_I; i <= MAX_I && master < 0; i++) {
|
|
sprintf(master_name, MASTER_TMPL, i);
|
|
if((master = open(master_name, O_RDWR)) >= 0) {
|
|
sprintf(slave_name, SLAVE_TMPL, i);
|
|
if((slave = open(slave_name, O_RDWR)) < 0)
|
|
close(master);
|
|
}
|
|
}
|
|
|
|
if(master >= 0 && slave >= 0)
|
|
ms_type = MS_PTY;
|
|
}
|
|
|
|
# undef MASTER_TMPL
|
|
# undef SLAVE_TMPL
|
|
# undef MIN_I
|
|
# undef MAX_I
|
|
#endif
|
|
|
|
|
|
if(! ms_type)
|
|
return(-1);
|
|
|
|
VT_Line = strdup(strrchr(slave_name, '/') + 1);
|
|
|
|
switch((VT_ChildPID = fork())) {
|
|
case -1:
|
|
return(-1);
|
|
break;
|
|
|
|
case 0:
|
|
#ifdef SCO
|
|
setsid();
|
|
#endif
|
|
close(0);
|
|
close(1);
|
|
close(2);
|
|
|
|
i = open(slave_name, O_RDWR);
|
|
o = open(slave_name, O_RDWR);
|
|
e = open(slave_name, O_RDWR);
|
|
|
|
#ifdef LINUX
|
|
setsid();
|
|
if (ioctl(slave, TIOCSCTTY, (char *)NULL) == -1)
|
|
exit(1);
|
|
#endif
|
|
#ifdef SCO
|
|
tcsetpgrp(0, getpid());
|
|
#endif
|
|
|
|
VT_Start_utmp();
|
|
|
|
system("stty sane");
|
|
execlp("/bin/login", "login", "-c", (char*)0);
|
|
exit(1);
|
|
break;
|
|
|
|
default:
|
|
VT_Mode = True;
|
|
VT_Status = VT_OPEN;
|
|
VT_ChildDied = False;
|
|
VT_Fd = master;
|
|
|
|
signal(SIGCLD, VT_SigCLD);
|
|
|
|
signal(SIGHUP, VT_SigEXIT);
|
|
signal(SIGTERM, VT_SigEXIT);
|
|
signal(SIGINT, VT_SigEXIT);
|
|
signal(SIGQUIT, VT_SigEXIT);
|
|
|
|
memset(OutBuf, 0, sizeof(OutBuf));
|
|
OutBuf [4] = 0x06;
|
|
_smb_setlen(OutBuf, 1);
|
|
|
|
send_smb(Client,OutBuf);
|
|
|
|
return(0);
|
|
break;
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
VT_Output: transport data from socket to pty
|
|
*/
|
|
int VT_Output(char *Buffer)
|
|
{
|
|
int i, len, nb;
|
|
|
|
|
|
if(VT_Status != VT_OPEN)
|
|
return(-1);
|
|
|
|
len = smb_len(Buffer);
|
|
|
|
nb = write(VT_Fd, Buffer + 4, len);
|
|
|
|
return((nb == len) ? 0 : -1);
|
|
}
|
|
|
|
|
|
/*
|
|
VT_Input: transport data from pty to socket
|
|
*/
|
|
int VT_Input(char *Buffer,int Size)
|
|
{
|
|
int len;
|
|
|
|
|
|
if(VT_Status != VT_OPEN)
|
|
return(-1);
|
|
|
|
memset(Buffer, 0, Size);
|
|
len = read(VT_Fd, Buffer + 4, MIN(VT_MAXREAD, Size));
|
|
|
|
_smb_setlen(Buffer, len);
|
|
|
|
return(len + 4);
|
|
}
|
|
|
|
|
|
/*
|
|
VT_Process: main loop while in vt-mode
|
|
*/
|
|
void VT_Process(void)
|
|
{
|
|
static int trans_num = 0;
|
|
extern int Client;
|
|
int nread;
|
|
|
|
|
|
VT_Start();
|
|
|
|
atexit(VT_AtExit);
|
|
|
|
while (True) {
|
|
int32 len;
|
|
int msg_type;
|
|
int msg_flags;
|
|
int counter;
|
|
int last_keepalive=0;
|
|
struct fd_set si;
|
|
struct timeval to, *top;
|
|
int n, ret, t;
|
|
|
|
|
|
errno = 0;
|
|
t = SMBD_SELECT_LOOP*1000;
|
|
|
|
|
|
FD_ZERO(&si);
|
|
FD_SET(Client, &si);
|
|
|
|
FD_SET(VT_Fd, &si);
|
|
|
|
if(t >= 0) {
|
|
to.tv_sec = t / 1000;
|
|
to.tv_usec = t - (to.tv_sec * 1000);
|
|
|
|
top = &to;
|
|
} else
|
|
top = NULL;
|
|
|
|
if(VT_ChildDied)
|
|
goto leave_VT_Process;
|
|
|
|
n = select(MAX(VT_Fd, Client) + 1, &si, NULL, NULL, top);
|
|
|
|
if(VT_ChildDied)
|
|
goto leave_VT_Process;
|
|
|
|
if(n == 0) {
|
|
int i;
|
|
time_t t;
|
|
BOOL allidle = True;
|
|
extern int keepalive;
|
|
|
|
counter += SMBD_SELECT_LOOP;
|
|
|
|
t = time(NULL);
|
|
|
|
if (keepalive && (counter-last_keepalive)>keepalive) {
|
|
if (!send_keepalive(Client))
|
|
goto leave_VT_Process;
|
|
last_keepalive = counter;
|
|
}
|
|
} else if(n > 0) {
|
|
counter = 0;
|
|
|
|
if(FD_ISSET(VT_Fd, &si)) {
|
|
/* got input from vt */
|
|
nread = VT_Input(OutBuffer, MIN(BUFFER_SIZE,lp_maxxmit()));
|
|
|
|
if(nread > 0)
|
|
send_smb(Client,OutBuffer);
|
|
}
|
|
|
|
if(FD_ISSET(Client, &si)) {
|
|
/* got input from socket */
|
|
|
|
if(receive_smb(Client,InBuffer, 0)) {
|
|
msg_type = CVAL(InBuffer,0);
|
|
msg_flags = CVAL(InBuffer,1);
|
|
|
|
len = smb_len(InBuffer);
|
|
|
|
DEBUG(6,("got message type 0x%x of len 0x%x\n",msg_type,len));
|
|
|
|
nread = len + 4;
|
|
|
|
DEBUG(3,("%s Transaction %d of length %d\n",timestring(),trans_num,nread));
|
|
|
|
if(msg_type == 0)
|
|
VT_Output(InBuffer);
|
|
else {
|
|
nread = construct_reply(InBuffer,OutBuffer,nread,MIN(BUFFER_SIZE,lp_maxxmit()));
|
|
|
|
if(nread > 0) {
|
|
if (nread != smb_len(OutBuffer) + 4) {
|
|
DEBUG(0,("ERROR: Invalid message response size! %d %d\n",
|
|
nread,
|
|
smb_len(OutBuffer)));
|
|
} else
|
|
send_smb(Client,OutBuffer);
|
|
}
|
|
}
|
|
} else
|
|
if(errno == EBADF)
|
|
goto leave_VT_Process;
|
|
}
|
|
}
|
|
|
|
trans_num++;
|
|
}
|
|
|
|
leave_VT_Process:
|
|
/*
|
|
if(VT_ChildPID > 0)
|
|
kill(VT_ChildPID, SIGHUP);
|
|
|
|
VT_Stop_utmp(VT_Line);
|
|
return;
|
|
*/
|
|
close_sockets();
|
|
exit(0);
|
|
}
|