Модераторы: xvr
  

Поиск:

Ответ в темуСоздание новой темы Создание опроса
> simple-telnetd демон, пример демона на С/С++ 
:(
    Опции темы
d2s1
Дата 5.3.2010, 10:43 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 2
Регистрация: 1.3.2010

Репутация: нет
Всего: нет



Написал пример демона simple-telnetd, он позволяет удаленно запускать некоторое ограниченное подмножество команд и выводить пользователю результат их выполнения.

1) simple-telnetd запускает только разрешенные программы, перечисленные в файле /etc/simple-telnetd.conf (пример конфигурационного файла прилагается). Демон перечитывает конфигурационный файл по сигналу SIGHUP.
Примечание: в конфиг заносятся корректные команды с путем и без параметров. Пустые строки в конфиг лучше не заносить.

2) запускаемые пользовтелем команды могут иметь параметры командной строки, интерактивное взаимодействие не поддерживается.

3) обработка спец. символов не производится

4) через параметр командной строки демону может передаваться таймаут выполнения одной команды. Параметр задается в секундах, значение по умолчанию - 1 секунда.

5) работоспособность демона проверена на Linux, Mac, FreeBSD.

6) реализовано журналирование с уровнями важности DEBUG, INFO, и ERR от имени средства daemon.

Для запуска:

0) создать конфигурационный файл (пример ниже) в
/etc/simple-telnetd.conf

1) компиляция
c++ stelnetd.cpp

2) запуск без параметров:
./a.out

запуск с указанием таймаута в секундах:
./a.out 2

3) для подключения к демону используется telnet:
telnet localhost 6023

4) в сессии telnet можно вводить команды, например:
/bin/ls
/bin/ls -l /
/bin/pwd

5) для перезагрузки конфигурационного файла демону послается сигнал HUP:
killall -s SIGHUP a.out

6) для остановки демона послается сигнал TERM или KILL
killall -s SIGKILL a.out

Пример конфига:
Код

/bin/ls
/bin/pwd


Код демона:
Код

////////////////////////////
// Simple telnetd daemon 
//        by d2s1        
///////////////////////////

/*
* configuration file: /etc/simple-telnetd.conf
* SIGHUP - reload configuration file
* default socket: 0.0.0.0:6023
*/

#include <stdio.h>
#include <syslog.h>

#include <stdarg.h>

#include <signal.h>
#include <sys/types.h>
#include <sys/param.h>
#include <sys/resource.h>

#include <sys/socket.h>
#include <netinet/in.h>

#include <fstream>
#include <iostream>

#include <errno.h>
#include <sys/stat.h> // umask
#include <fcntl.h>  // open
#include <sys/ioctl.h>

#include <string.h>
#include <stdlib.h>

using namespace std;

//
// return values (error codes)
//
const int NO_ERROR = 0;
const int CONFIG_ERROR = 1;
const int SOCKET_ERROR = 2;
const int BIND_ERROR = 3;
const int ACCEPT_ERROR = 4;
const int PIPE_ERROR = 5;
const int WRITE_ERROR = 6;
const int READ_ERROR = 7;
const int SETSID_ERROR = 8;
const int CHDIR_ERROR = 9;
const int OPEN_ERROR = 10;

//
// globals
//
char valid_command_list[255][255];  // 255 commands
int list_length=0;  // actual number of commands
bool finalize=false;  // termination flag
int pio[2]; // pipes for std io: 0 - input, 1 - output & error
int timeout=1;  // command execution timeout (sec)
int sock,newsock;

// load conf file
static bool load_conf()
{
  char par[255];  // filename maximum length in HFS+ and ext3
  ifstream conf("/etc/simple-telnetd.conf");
  if (!conf)
  {
    syslog(LOG_ERR, "can not access config file: /etc/simple-telnetd.conf");
    return false;
  }
  int line=0;
  list_length=0;
  memset(valid_command_list, 0, 255 * 255);
  while((!conf.eof()) && (line < 255))
  {
    conf.getline(par, 255);
    size_t cmd_len = strcspn(par, "\r\n\t ");   // space symbols (delimiters)
    memcpy(valid_command_list[line], par, cmd_len);
    syslog(LOG_INFO, "loaded command %s", valid_command_list[line]);
    line++;
  }
  list_length=line;
  syslog(LOG_INFO, "configuration loaded.");
  return true;
}

// sighup handler - reload conf
static void sighup_handler(int signo)
{
  signal(SIGHUP, sighup_handler);
  close(sock);
  close(newsock);
  load_conf();
}

// sigterm handler - finalize
static void sigterm_handler(int signo)
{
   syslog(LOG_INFO, "terminated by SIGTERM.");
   finalize=true;
}

// server logic
static int server(int port)
{
     // constants
     const int BUF_SIZE = 1024;
     //locals
     int clen, readed_data_lenght;
     char buf[BUF_SIZE];
     struct sockaddr_in serv_addr, cli_addr;
     struct timeval tv;
     tv.tv_sec=240;
     tv.tv_usec=0;
     // socket connect
     sock = socket(AF_INET, SOCK_STREAM, 0);
     if (sock < 0) 
     {
       syslog(LOG_ERR, "can not create socket. %d %s", errno, strerror(errno));
       return SOCKET_ERROR;
     }
     setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv));
     memset((char *) &serv_addr, 0, sizeof(serv_addr));
     serv_addr.sin_family = AF_INET;
     serv_addr.sin_addr.s_addr = INADDR_ANY;
     serv_addr.sin_port = htons(port);
     if (bind(sock, (struct sockaddr *) &serv_addr, sizeof(serv_addr)) < 0)
     {
       syslog(LOG_ERR, "can not bind socket. %d %s", errno, strerror(errno));
       close(sock);
       return BIND_ERROR;
     }
     while(!finalize)
     {
         listen(sock, 1);
         clen = sizeof(cli_addr);
         newsock = accept(sock, (struct sockaddr *) &cli_addr, (socklen_t *) &clen);
         if (newsock < 0) 
         {
           syslog(LOG_ERR, "can not accept connection. %d %s", errno, strerror(errno));
           close(sock);
           return ACCEPT_ERROR;
         }
         syslog(LOG_INFO, "connection open from %a", &cli_addr.sin_addr);
         //data read 
         while(!finalize)
         {
             memset(buf, 0, BUF_SIZE);
             readed_data_lenght = read(newsock, buf, BUF_SIZE-1);
             if(readed_data_lenght < 0)
             {
                if(errno == EWOULDBLOCK)
                {
                  syslog(LOG_ERR, "socket timeout.");
                }
                else
                {
                  syslog(LOG_ERR, "read error. %d %s", errno, strerror(errno));
                }
             }  
             else if (readed_data_lenght > 0)
             {
                size_t cmd_len = strcspn(buf, "\r\n\t ");   // space symbols (delimiters)
                char buffer[cmd_len+1];
                buffer[cmd_len] = 0;
                memcpy(buffer, buf, cmd_len);
                bool cmd_valid = false;
                for (int cmd=0; cmd < list_length; cmd++)
                {
//                  syslog(LOG_DEBUG, "compare:%svs%s", buffer, valid_command_list[cmd]);
                  if (strcmp(buffer, valid_command_list[cmd]) == 0)
                  {
                    cmd_valid = true;
                    break;
                  }
                }
                if (!cmd_valid)
                {
                    syslog(LOG_ERR, "invalid cmd: %s", buf);
                    // todo or not todo: send error message to user?
                }
                else
                {
                  syslog(LOG_INFO, "cmd valid: %s", buf);
                  char *arg[10];  // max possible arguments: 0..9 
                  int num = 1;
                  arg[0] = new char(strlen(buffer));
                  strcpy(arg[0], buffer);
                  char *p = strtok(buf, "\r\n\t ");
                  do 
                  {
                    p = strtok(NULL, "\r\n\t ");
                    if(p)
                    {
                      arg[num] = new char(strlen(p));
                      strcpy(arg[num],p);
                      syslog(LOG_DEBUG, "arg[%d]=%s", num, arg[num]);
                      num++;
                    }
                  } while(p);
                  char *ar[num+1];  // actual number of arguments
                  ar[num] = NULL;
                  for (int i = 0; i < num; i++)
                  {
                    ar[i] = new char(strlen(arg[i]));
                    strcpy(ar[i],arg[i]);
                    syslog(LOG_DEBUG, "ar[%d]=%s", i, ar[i]);
                  }
                  char answer[4096];
                  memset(answer, 0, 4096);
                  int pid = fork();
                  if (pid == 0)
                  {
                    // child
                   int execvretcode = 0;
                   if (num == 1)
                  {
                    syslog(LOG_DEBUG, "execv with NULL");
                    execvretcode = execv(buffer, NULL);
                  }
                  else
                  {
                       syslog(LOG_DEBUG, "execv %s with argv", buffer);
                       for (int ii=0; ii<num; ii++)
                       {
                         syslog(LOG_DEBUG, "ar[%d]=%s", ii, ar[ii]);
                       }
                       execvretcode = execv(buffer, ar);
                   }
                    if (execvretcode < 0)
                    {
                      syslog(LOG_ERR, "execv error. %d %s", errno, strerror(errno));
                      cerr<<strerror(errno)<<'\n';
                    }
                    else
                    {
                      // we are another process now
                    }
                  }
                  else
                  {
                    // parent
                    sleep(timeout);
                    int bytes = -1;
//                    cout<<"output\n";
                    syslog(LOG_DEBUG, "ioctl");
                    if (ioctl (pio[0], FIONREAD, &bytes) != 0)
                    {
                      syslog(LOG_ERR, "ioctl error. %d %s", errno, strerror(errno));
                      bytes = -1;
                    }
                    if (bytes > 0)
                    {
                      syslog(LOG_DEBUG, "read");
                      if (read(pio[0], answer, 4096) < 0)
                      {
                        syslog(LOG_ERR, "read error. %d %s", errno, strerror(errno));
                      }
                    }
                    syslog(LOG_DEBUG, "kill");
                    kill(pid, SIGKILL);
                  }
    
                  syslog(LOG_DEBUG, "send");
                  if (send(newsock, answer, strlen(answer), 0) != strlen(answer))
                  {
                    syslog(LOG_ERR, "send error: %d %s", errno, strerror(errno));
                  }
                }
    
             }
             else // readed_data_lenght == 0
             {
                syslog(LOG_INFO, "connection closed by remote host.");
                break;
             }
         }
     }    
     close(newsock);
     close(sock);
     return NO_ERROR;
}

// entry point
int main (int argc, char *argv[])
{
  int fd;
  int oldfd[3];
  struct rlimit flim;
  // open syslog using daemon facility
  openlog("Simple telnetd", LOG_PID | LOG_CONS, LOG_DAEMON);
  syslog(LOG_INFO, "starting...");
  // ignore terminal's signals
  if (getppid() != 1)
  {
    signal(SIGTTOU, SIG_IGN);
    signal(SIGTTIN, SIG_IGN);
    signal(SIGTSTP, SIG_IGN); 
  }
  // handle SIGHUP todo use sigset_t
  signal(SIGHUP, sighup_handler);
  signal(SIGTERM, sigterm_handler); // for soft termination
  // check command line parameters
  if (argc > 1)
  {
    syslog(LOG_DEBUG, "argv[1]=%s", argv[1]);
    int to = atoi(argv[1]);
    if (to > 0)
    {
      syslog(LOG_INFO, "set timeout %d", to);
      timeout = to;
    }
  }
  // allocate pipes
  if (pipe(pio) < 0)
  {
    syslog(LOG_ERR, "can not allocate i/o pipes. %d %s", errno, strerror(errno));
    return PIPE_ERROR;
  }
  // switch std io to pipes
  oldfd[0]=dup(STDIN_FILENO);
  oldfd[1]=dup(STDOUT_FILENO);
  oldfd[2]=dup(STDERR_FILENO);
  dup2(pio[1], STDOUT_FILENO);
  dup2(pio[0], STDIN_FILENO);
  dup2(pio[1], STDERR_FILENO);
  // create new group and session leader
  if (fork() != 0)
  {
    return 0;
  }
  umask(0);
  if (setsid() < 0) // todo BSD - create group, open terminal and ioctl TIOCNOTTY
  {
    syslog(LOG_ERR, "setsid error: %d %s", errno, strerror(errno));
    return SETSID_ERROR;
  }
//  getrlimit(RLIMIT_NOFILE, &flim);
  //for (fd = 0; fd < flim.rlim_max; fd++)
  //{
    //if ((fd != STDIN_FILENO) && (fd != STDOUT_FILENO) && (fd != STDERR_FILENO))
    //close(fd);
  //  }

  // set current dir to root
  if (chdir("/") < 0)
  {
    syslog(LOG_ERR, "chdir error: %d %s", errno, strerror(errno));
    return CHDIR_ERROR;
  }
  if (!load_conf())
  {
    closelog();
    return CONFIG_ERROR;
  }
  syslog(LOG_INFO, "started.");

  int result_code = 0;
  while (!finalize)
  {
    result_code = server(6023);
  }

  // restore std io
  dup2(oldfd[0], STDIN_FILENO);
  dup2(oldfd[1], STDOUT_FILENO);
  dup2(oldfd[2], STDERR_FILENO);
  syslog(LOG_INFO, "stoped.");
  closelog();
  return result_code;
}


Примечания:
- демон однопоточный, одновременно с ним может работать не более 1 клиента;
- есть небольшие утечки памяти в функции server (3 new и 0 delete) smile ;
- закомментированный участок в функции main не работает под Mac'ом (потому и закоменчен) smile

Это сообщение отредактировал(а) d2s1 - 5.3.2010, 10:49
PM MAIL   Вверх
GrayCardinal
Дата 8.3.2010, 16:57 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Фигасе
****


Профиль
Группа: Завсегдатай
Сообщений: 3039
Регистрация: 9.11.2003

Репутация: 8
Всего: 58



Вроде не заказывали smile


--------------------
PM MAIL WWW   Вверх
azesmcar
Дата 8.3.2010, 17:06 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


uploading...
****


Профиль
Группа: Участник Клуба
Сообщений: 6291
Регистрация: 12.11.2004
Где: Армения

Репутация: 1
Всего: 211



Цитата(GrayCardinal @  8.3.2010,  16:57 Найти цитируемый пост)
Вроде не заказывали 

Поздно спохватились, придется платить smile 

PM   Вверх
d2s1
Дата 8.3.2010, 17:07 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 2
Регистрация: 1.3.2010

Репутация: нет
Всего: нет



Вдруг кому-нибудь да пригодится smile
PM MAIL   Вверх
GrayCardinal
Дата 8.3.2010, 17:07 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Фигасе
****


Профиль
Группа: Завсегдатай
Сообщений: 3039
Регистрация: 9.11.2003

Репутация: 8
Всего: 58



azesmcar, 
smile


--------------------
PM MAIL WWW   Вверх
Devourer
Дата 13.3.2010, 01:58 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 95
Регистрация: 23.8.2008

Репутация: нет
Всего: нет



d2s1, уже ))) СПС ))))
PM MAIL ICQ   Вверх
  
Ответ в темуСоздание новой темы Создание опроса
Правила форума "С/С++: Программирование под Unix/Linux"
xvr
  • Проставьте несколько ключевых слов темы, чтобы её можно было легче найти.
  • Не забывайте пользоваться кнопкой "Код".
  • Вопросы мобильной разработки тут
  • Телепатов на форуме нет! Задавайте чёткий, конкретный и полный вопрос. Указывайте полностью ошибки компилятора и компоновщика.
  • Новое сообщение должно иметь прямое отношение к разделу форума. Флуд, флейм, оффтопик запрещены.
  • Категорически запрещается обсуждение вареза, "кряков", взлома программ и т.д.

Если Вам понравилась атмосфера форума, заходите к нам чаще! С уважением, xvr.

 
 
0 Пользователей читают эту тему (0 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | C/C++: Программирование под Unix/Linux | Следующая тема »


 




[ Время генерации скрипта: 0.0559 ]   [ Использовано запросов: 22 ]   [ GZIP включён ]


Реклама на сайте     Информационное спонсорство

 
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности     Powered by Invision Power Board(R) 1.3 © 2003  IPS, Inc.