summaryrefslogtreecommitdiff
path: root/cmd/osspartysh
diff options
context:
space:
mode:
authorIgor Pashev <pashev.igor@gmail.com>2013-05-03 21:08:42 +0400
committerIgor Pashev <pashev.igor@gmail.com>2013-05-03 21:08:42 +0400
commit1058def8e7827e56ce4a70afb4aeacb5dc44148f (patch)
tree4495d23e7b54ab5700e3839081e797c1eafe0db9 /cmd/osspartysh
downloadoss4-1058def8e7827e56ce4a70afb4aeacb5dc44148f.tar.gz
Imported Upstream version 4.2-build2006upstream/4.2-build2006upstream
Diffstat (limited to 'cmd/osspartysh')
-rw-r--r--cmd/osspartysh/.config3
-rw-r--r--cmd/osspartysh/osspartysh.c527
-rw-r--r--cmd/osspartysh/osspartysh.man64
3 files changed, 594 insertions, 0 deletions
diff --git a/cmd/osspartysh/.config b/cmd/osspartysh/.config
new file mode 100644
index 0000000..6659027
--- /dev/null
+++ b/cmd/osspartysh/.config
@@ -0,0 +1,3 @@
+targetos=Linux
+targetos=FreeBSD
+ldflags=-lutil
diff --git a/cmd/osspartysh/osspartysh.c b/cmd/osspartysh/osspartysh.c
new file mode 100644
index 0000000..6c382f8
--- /dev/null
+++ b/cmd/osspartysh/osspartysh.c
@@ -0,0 +1,527 @@
+/*
+ * Purpose: "Reverse telnet" helper utility for OSS technical support
+ *
+ * Description:
+ * The osspartysh program is an utility that permits safe access to the
+ * customer systems by the OSS support staff.
+ *
+ * Unlike usual ssh/telnet access this program works in revewrse way. The
+ * person who gives technical support can establish a termibal server using
+ * osspartysh -d -p <TCP port>. The client can then connect to this
+ * terminal server program by executing osspartysh -h <the support host> -p <port>.
+ * Outgoing TCP connections can easily pass usual firewall and NAT settings
+ * which makes establishing the connection very easy. After the connection is
+ * open both sides can type commands and see what happens in the system. If
+ * the customer thiks the tech suport guy is doing something too dangerous he
+ * can always hit ^C or ^Z and unplug the ethernet connector.
+ */
+/*
+ *
+ * This file is part of Open Sound System.
+ *
+ * Copyright (C) 4Front Technologies 1996-2008.
+ *
+ * This this source file is released under GPL v2 license (no other versions).
+ * See the COPYING file included in the main directory of this source
+ * distribution for the license terms and conditions.
+ *
+ */
+
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/socket.h>
+#include <sys/select.h>
+#include <sys/wait.h>
+#include <netinet/in.h>
+#include <netinet/tcp.h>
+#include <arpa/inet.h>
+#include <netdb.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <termios.h>
+#include <fcntl.h>
+#ifdef __FreeBSD__
+#include <libutil.h>
+#else
+#include <pty.h>
+#include <utmp.h>
+#endif
+#include <errno.h>
+
+#define PARTYSH_MAGIC "ParTySH"
+#define PARTYSH_VERSION "0100" // 1.0
+#define PARTYSH_HDRSIZE 250
+
+int localfd=0;
+int connfd = -1;
+struct termios saved_tc;
+int listenfd=-1;
+int off=0;
+int on=1;
+
+#define max(a, b) ((a>b) ? a : b)
+
+static void
+restore_terminal(void)
+{
+ if (tcsetattr(localfd, 0, &saved_tc) == -1)
+ perror("tcsetattr");
+}
+
+static void
+setup_terminal(void)
+{
+ struct termios tc;
+
+ if (tcgetattr(0, &tc)==-1)
+ {
+ perror("tcgetattr");
+ exit(1);
+ }
+
+ if (tcgetattr(0, &saved_tc)==-1)
+ {
+ perror("tcgetattr");
+ exit(1);
+ }
+
+ atexit(restore_terminal);
+
+ tc.c_lflag &= ~(ICANON|ECHO|ISIG);
+ tc.c_cc[VMIN]=1;
+ tc.c_cc[VTIME]=1;
+
+ if (tcsetattr(0, 0, &tc) == -1)
+ perror("tcsetattr");
+}
+
+int
+wait_connect(void)
+{
+ if (listen(listenfd, 1) == -1)
+ {
+ perror("listen");
+ exit(1);
+ }
+
+ printf("Waiting for a new connection - hit ^C to exit.\n");
+
+ if ((connfd=accept(listenfd, NULL, NULL))==-1)
+ {
+ perror("accept");
+ exit(1);
+ }
+
+ printf("Connected\n\n");fflush(stdout);
+
+ printf("You may need to type ^L after running vi.\n");
+ printf("\n");
+ printf("Hit enter couple of times after exiting the shell so that\n");
+ printf("you can kill the osspartysh program. If the program is left\n");
+ printf("running after a session then new clients can connect the same host/port again.\n");
+ printf("\n");fflush(stdout);
+
+ setsockopt(connfd, IPPROTO_TCP, TCP_NODELAY, &off, sizeof(off));
+
+ return 1;
+}
+
+static void
+terminal_loop(int connfd)
+{
+ fd_set readfds;
+ int n, l;
+ char buf[512];
+
+ while (1)
+ {
+ FD_ZERO(&readfds);
+
+ FD_SET(0, &readfds);
+ FD_SET(connfd, &readfds);
+
+ if ((n=select(connfd+1, &readfds, NULL, NULL, NULL))==-1)
+ {
+ perror("select");
+ return;
+ }
+
+ if (FD_ISSET(0, &readfds))
+ {
+ if ((l=read(0, buf, sizeof(buf)))<0)
+ {
+ perror("read(0)");
+ return;
+ }
+
+ if (write(connfd, buf, l)!=l)
+ {
+ perror("write(conn)");
+ return;
+ }
+ }
+
+ if (FD_ISSET(connfd, &readfds))
+ {
+ if ((l=read(connfd, buf, sizeof(buf)))<0)
+ {
+ perror("read(conn)");
+ exit(0);
+ }
+
+ if (write(1, buf, l)!=l)
+ {
+ perror("write(1)");
+ return;
+ }
+ }
+ }
+}
+
+static void
+shell_loop(int connfd, int infd, int outfd)
+{
+ fd_set readfds;
+ int n, l;
+ char buf[512];
+
+ while (1)
+ {
+ FD_ZERO(&readfds);
+
+ FD_SET(infd, &readfds);
+ if (infd != 0)
+ FD_SET(0, &readfds);
+ FD_SET(connfd, &readfds);
+
+ if ((n=select(max(infd, connfd)+1, &readfds, NULL, NULL, NULL))==-1)
+ {
+ perror("select");
+ return;
+ }
+
+ if (FD_ISSET(infd, &readfds))
+ {
+ if ((l=read(infd, buf, sizeof(buf)))<0)
+ {
+ if (errno == EIO)
+ {
+ printf("Disconnected\n");
+ exit(1);
+ }
+
+ perror("read(infd)");
+ return;
+ }
+
+ if (write(connfd, buf, l)!=l)
+ {
+ perror("write(conn)");
+ return;
+ }
+
+ if (write(1, buf, l)!=l) // Echo to the local terminal
+ exit(1);
+ }
+
+ if (FD_ISSET(connfd, &readfds))
+ {
+ if ((l=read(connfd, buf, sizeof(buf)))<0)
+ {
+ perror("read(conn)");
+ exit(0);
+ }
+
+ if (write(outfd, buf, l)!=l)
+ {
+ perror("write(outfd)");
+ return;
+ }
+
+ // write(1, buf, l); // Echo to the local terminal
+ }
+
+ if (infd != 0 && FD_ISSET(0, &readfds))
+ {
+ if ((l=read(0, buf, sizeof(buf)))<0)
+ {
+ perror("read(0)");
+ exit(0);
+ }
+
+ if (write(outfd, buf, l)!=l)
+ {
+ perror("write(outfd)");
+ return;
+ }
+
+ // write(1, buf, l); // Echo to the local terminal
+ }
+ }
+}
+
+void
+handle_connection(int connfd)
+{
+ char welcomebuf[PARTYSH_HDRSIZE] = {0};
+
+ sprintf(welcomebuf, PARTYSH_MAGIC " " PARTYSH_VERSION " Just testing");
+ if (write(connfd, welcomebuf, PARTYSH_HDRSIZE) != PARTYSH_HDRSIZE)
+ {
+ perror("send welcome");
+ fprintf(stderr, "Cannot send the welcome string\n");
+ exit(1);
+ }
+
+ setup_terminal();
+ localfd=dup(0);
+
+ if (fork())
+ {
+ /* Parent process */
+ close(connfd);
+ wait(NULL);
+ printf("Session closed1\n");fflush(stdout);
+ restore_terminal();
+ }
+ else
+ {
+ terminal_loop(connfd);
+ close(connfd);
+ }
+
+}
+
+int
+run_daemon(int port)
+{
+ struct sockaddr_in servaddr;
+
+ if (port==0)
+ {
+ fprintf(stderr, "Please give a port (-p)\n");
+ exit(1);
+ }
+
+ if ((listenfd = socket(AF_INET, SOCK_STREAM, 0)) == -1)
+ {
+ perror("socket");
+ exit(1);
+ }
+
+ bzero(&servaddr, sizeof(servaddr));
+ servaddr.sin_family = AF_INET;
+ servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
+ servaddr.sin_port = htons(port);
+
+ if (bind(listenfd, (struct sockaddr *)&servaddr, sizeof(servaddr))==-1)
+ {
+ perror("bind");
+ exit(1);
+ }
+
+ while (1)
+ {
+
+ if (!wait_connect())
+ {
+ perror("wait connection");
+ exit(1);
+ }
+
+ handle_connection(connfd);
+ }
+
+ close(listenfd);
+
+ return 0;
+}
+
+void
+pty_session(int connfd)
+{
+ mode_t mode;
+ pid_t pid;
+ int ptyfd, fd;
+ FILE *f;
+ char tmpl[32]="/tmp/osspartyshXXXXXX";
+
+ mode = umask(077);
+ if ((fd = mkstemp(tmpl)) == -1)
+ {
+ perror("mkstemp");
+ exit(-1);
+ }
+ chmod(tmpl, 0700);
+ umask(mode);
+
+ if ((f = fdopen(fd, "w")) != NULL)
+ {
+ fprintf(f, "PS1=\"[SHARED]@\\h:\\w $ \"\n");
+ fprintf(f, "export PS1\n");
+ fclose(f);
+ }
+ else close(fd);
+
+ if ((pid=forkpty(&ptyfd, NULL, NULL, NULL))==-1)
+ {
+ perror("forkpty");
+ exit(1);
+ }
+
+ if (pid != 0)
+ {
+ setup_terminal();
+ sleep(1);
+ unlink(tmpl);
+ shell_loop(connfd, ptyfd, ptyfd);
+ wait(NULL);
+ restore_terminal();
+ }
+ else
+ {
+ execlp("bash", "bash", "--rcfile", tmpl, NULL);
+ }
+}
+
+int
+run_client(char *host, int port)
+{
+
+ struct sockaddr_in sa;
+ struct hostent *he;
+ char *ps1, *p;
+ char welcomebuf[PARTYSH_HDRSIZE];
+
+ int sockfd, connfd;
+
+ if (host == NULL)
+ {
+ fprintf(stderr, "Please give a host (-h)\n");
+ exit(1);
+ }
+
+ if (port==0)
+ {
+ fprintf(stderr, "Please give a port (-p)\n");
+ exit(1);
+ }
+
+ if ((sockfd = socket (PF_INET, SOCK_STREAM, 0)) == -1)
+ {
+ perror ("socket");
+ return 0;
+ }
+
+ printf("Looking for the server\n");
+
+ if ((he = gethostbyname (host)) == NULL)
+ {
+ perror("lookup");
+ fprintf(stderr, "Cannot find the support host\n");
+ return 0;
+ }
+
+ sa.sin_family = AF_INET;
+ sa.sin_port = htons (port);
+
+ printf ("Connecting to the support center at %s:%d\n", host, port);
+
+ memcpy ((void *) &sa.sin_addr, *he->h_addr_list, he->h_length);
+ if ((connfd = connect (sockfd, (void *) &sa, sizeof (sa))) == -1)
+ {
+ perror("connect");
+ fprintf(stderr, "Cannot connect to the support center\n");
+ return 0;
+ }
+
+ if (read(sockfd, welcomebuf, PARTYSH_HDRSIZE) != PARTYSH_HDRSIZE)
+ {
+ perror("receive welcome");
+ exit(1);
+ }
+
+ // printf("Welcome %s\n", welcomebuf);
+
+ if (strncmp(welcomebuf, PARTYSH_MAGIC, strlen(PARTYSH_MAGIC))!=0)
+ {
+ fprintf(stderr, "Didn't receive valid velcome string - abort\n");
+ exit(1);
+ }
+
+ if ((ps1=getenv("PS1")) != NULL)
+ {
+ p = ps1;
+
+ while (*p)
+ {
+ if (*p == '#') *p= '$';
+ if (*p == '>') *p= '<';
+ p++;
+ }
+ //printf("PS1='%s'\n", ps1);
+
+ setenv("PS1", ps1, 1);
+ } else setenv("PS1", "ossremote> ", 1);
+
+ setsockopt(sockfd, IPPROTO_TCP, TCP_NODELAY, &off, sizeof(off));
+ printf("*** Established connection - You are now sharing this session ***\n\n");fflush(stdout);
+ printf("You may need to type ^L after running vi.\n");
+ printf("\n");
+ fflush(stdout);
+
+#if 0
+ close(0);
+ dup(sockfd);
+ close(1);
+ dup(sockfd);
+ close(2);
+ dup(sockfd);
+
+ printf("Now connected to the remote system - Hit ^C to disconnect\n");fflush(stdout);
+
+ execlp("bash", "bash", "-i", NULL);
+ //execlp("sh", "sh", NULL);
+#else
+# if 1
+ pty_session(sockfd);
+# else
+ shell_loop(sockfd, 0, 1);
+# endif
+#endif
+ close(sockfd);
+ close(connfd);
+
+ return 0;
+}
+
+int main(int argc, char *argv[])
+{
+ int i;
+ int daemon_mode=0;
+ int port=0;
+ char *host=NULL;
+
+ while ((i = getopt(argc, argv, "dp:h:")) != EOF)
+ switch (i)
+ {
+ case 'd':
+ daemon_mode=1;
+ break;
+
+ case 'p':
+ port = atoi(optarg);
+ break;
+
+ case 'h':
+ host=optarg;
+ break;
+ }
+
+ if (daemon_mode)
+ exit(run_daemon(port));
+
+ exit(run_client(host, port));
+}
diff --git a/cmd/osspartysh/osspartysh.man b/cmd/osspartysh/osspartysh.man
new file mode 100644
index 0000000..bf1c509
--- /dev/null
+++ b/cmd/osspartysh/osspartysh.man
@@ -0,0 +1,64 @@
+NAME
+osspartysh - reverse "telnet" utility for OSs technical support
+
+SYNOPSIS
+osspartysh -d -p <port> (by the support engineer)
+osspartysh -h <support_host> -p <support_port> (by the customer)
+
+DESCRIPTION
+
+The osspartysh is an utility that makes it possible to a remote suport
+engineer to share the session with a customer. The session runs in customer's
+computer but both the customer and the support engineer can type comands
+and see the output. It is possible to run commands like vi to edit files.
+
+There is limited chat mechanism based on the comments of the shell (bash)
+command language. Both peers can send messages by typing the comment character
+(#) in the beginning of the line.
+
+SECURITY
+
+The osspartysh sessions are established in reverse way when compared to usual
+remote terminal programs like ssh or telnet. This gives improved security
+for both sides. The actual internet connection is not crypted so it
+cannot be used for editing confidential files, etc. However there is no need to
+send passwords over internet since the protocol doesn't rely on them.
+
+ SECURITY FOR THE CUSTOMER
+
+There is no need to open any incoming TCP ports in the firewall or NAT. In
+addition there is no need to reset any passwords to give the support engineer an
+access to the system. In addition the customer can see whatever commands are
+typed and there is good time to hit ^C or ^Z to abort the commands.
+
+Connections opened to the remote terminal server are verified to ensure that
+using wrong port number doesn't feed invalid commands to the local shell.
+Otherwise it would be possible that connecting to a wrong port (say http
+server) sends bad strings to the command interpreter (bash).
+
+ SECURITY FOR THE SUPPORT ENGINEER
+
+The system used as the support terminal needs to have the TCP port opened in
+the firewall and NAT settings. However this doesn't cause any security risks.
+If a possible attacker manages to connect to this port then all he can do is
+sending characters that are (only) shown on the terminal screen.
+
+OPTIONS
+-d Launch the utility in terminal server mode (by default
+ connect to a remote terminal.
+-h <host> Give the IP address or host name of the remote terminal
+ server.
+-p <port> Give the TCP port to use. Must be the same in both sides.
+
+KNOWN BUGS
+
+o Sometimes it's necessary to hit ^L after running vi or some other
+ curses based program. Without this the keyboard will be locked and
+ typed characters will not be shown on the screen
+o When the session is ended (by typing ^D or exit) the terminal (support)
+ side will be hanging until enter is hit twice. After this the
+ terminal server will be ready for a new connection by any client. It is
+ also possible to stop the terminal server by hitting ^C.
+
+AUTHOR
+4Front Technologies