summaryrefslogtreecommitdiff
path: root/source/smbd/vt_mode.c
diff options
context:
space:
mode:
Diffstat (limited to 'source/smbd/vt_mode.c')
-rw-r--r--source/smbd/vt_mode.c496
1 files changed, 496 insertions, 0 deletions
diff --git a/source/smbd/vt_mode.c b/source/smbd/vt_mode.c
new file mode 100644
index 00000000000..83b62a38ac2
--- /dev/null
+++ b/source/smbd/vt_mode.c
@@ -0,0 +1,496 @@
+/* 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(buffer)
+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
+*/
+VT_Start_utmp()
+{
+ struct utmp u, *v;
+ char *tt;
+
+
+ setutent();
+
+ strcpy(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;
+
+ strcpy(u.ut_id, tt);
+ u.ut_time = time((time_t*)0);
+ }
+
+ strcpy(u.ut_user, "LOGIN");
+ strcpy(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
+*/
+VT_Stop_utmp()
+{
+ struct utmp u, *v;
+
+
+ if(VT_Line != NULL) {
+ setutent();
+
+ strcpy(u.ut_line, VT_Line);
+
+ if((v = getutline(&u)) != NULL) {
+ strcpy(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()
+{
+ 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(sig)
+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(sig)
+int sig;
+{
+ VT_AtExit();
+
+ exit(1);
+}
+
+
+/*
+VT_Start: initialize vt-specific data, alloc pty, spawn shell and send ACK
+*/
+int VT_Start()
+{
+ 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(Buffer)
+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(Buffer, Size)
+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()
+{
+ 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);
+}