Commit baee982f authored by Seblu's avatar Seblu
Browse files

Refonde du module d'options

Ajout de l'option daemon et de son traitement
parent 6ea98116
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -2,6 +2,8 @@ bin_PROGRAMS= sld

sld_SOURCES=	src/sld.hh		\
		src/sld.cc		\
		src/options.hh		\
		src/options.cc		\
		src/daemon.hh		\
		src/daemon.cc		\
		src/error.hh		\
+1 −0
Original line number Diff line number Diff line
@@ -5,3 +5,4 @@ port=18136
scriptdir=/tmp/sld
retrydelay=5
verbose=1
daemon=0
+21 −178
Original line number Diff line number Diff line
@@ -29,160 +29,34 @@ SLDaemon &SLDaemon::Instance() {
  return *instance_;
}

void SLDaemon::usage(const char *argv0) const {
  std::cerr << "usage: "
	    << argv0
	    << " [-f conffile] [-d scriptdir] [-h] [-v] [-l login]"
	    << "[-p pass] [-H host] [-P port] [-r] [-V]"
	    << std::endl
	    << "  -f conffile  : read and load conf file (def: /etc/sldrc)." << std::endl
	    << "  -d scriptdir : Scripts directory." << std::endl
	    << "  -h           : Print this usage." << std::endl
	    << "  -v           : Verbose mode." << std::endl
	    << "  -q           : Quiet mode." << std::endl
	    << "  -l host      : Set login to host. (def: check hostname)" << std::endl
	    << "  -p secret    : Set pass to secret." << std::endl
	    << "  -H name      : Set server host to name." << std::endl
	    << "  -P number    : Set server port to number. (def: 18136)" << std::endl
	    << "  -r val       : Set retry delay to val in seconds (def: 60)" << std::endl
	    << "  -V           : Print version and exit." << std::endl;
}

SLDaemon::Options SLDaemon::getoptions(int argc, char *argv[]) const {
  Options opt;

  for (int i = 1; i < argc; ++i) {
    if (!strcmp(argv[i], "-h")) {
      usage(*argv);
      throw Error(ERR_USAGE);
    }
    else if (!strcmp(argv[i], "-v")) {
      opt.verbose = 1;
    }
    else if (!strcmp(argv[i], "-q")) {
      opt.verbose = 0;
    }
    else if (!strcmp(argv[i], "-V")) {
      std::cout << "sl daemon version : " << VERSION << std::endl;
      exit(ERR_OK);
    }
    else if (!strcmp(argv[i], "-H")) {
      if (++i >= argc)
	throw Error(ERR_USAGE, "No enough argument for option -h");
      opt.server = string(argv[i]);
    }
    else if (!strcmp(argv[i], "-P")) {
      if (++i >= argc)
	throw Error(ERR_USAGE, "No enough argument for option -p");
      char *endptr;
      opt.port = strtol(argv[i], &endptr, 10);
      if (!(*argv[i] != '\0' && *endptr == '\0'))
	throw Error(ERR_USAGE, "Unable to convert port to a number");
    }
    else if (!strcmp(argv[i], "-f")) {
      if (++i >= argc)
	throw Error(ERR_USAGE, "No enough argument for option -f");
      opt.conffile = string(argv[i]);
    }
    else if (!strcmp(argv[i], "-d")) {
      if (++i >= argc)
	throw Error(ERR_USAGE, "No enough argument for option -d");
      opt.scriptdir = string(argv[i]);
    }
    else if (!strcmp(argv[i], "-l")) {
      if (++i >= argc)
	throw Error(ERR_USAGE, "No enough argument for option -l");
      opt.login = string(argv[i]);
    }
    else if (!strcmp(argv[i], "-p")) {
      if (++i >= argc)
	throw Error(ERR_USAGE, "No enough argument for option -p");
      opt.pass = string(argv[i]);
    }
    else if (!strcmp(argv[i], "-r")) {
      if (++i >= argc)
	throw Error(ERR_USAGE, "No enough argument for option -r");
      opt.retrydelay = atoi(argv[i]);
    }
    else
      throw Error(ERR_USAGE, (string) "Invalid options : " + argv[i]);
  }
  return opt;
}

SLDaemon::Options SLDaemon::getoptions(const string file) const {
  ifstream fs;
  char line[MAX_CONF_LINE_SIZE];
  int i=0;
  char name[11], value[MAX_CONF_LINE_SIZE - 10 + 1];
  SLDaemon::Options o;

  fs.open(file.c_str(), ifstream::in);

  if (fs.fail())
    throw Error(ERR_FILE, "Unable to open configuration file");

  while (!fs.eof()) {
    fs.getline(line, MAX_CONF_LINE_SIZE);
    if (fs.eof())
      break;
    ++i;
    sscanf(line, "%10[^=]=%2039s\n", name, value); //TODO: fix magic number

    if (!strcasecmp(name, "host"))
      o.login = value;
    else if (!strcasecmp(name, "pass"))
      o.pass = value;
    else if (!strcasecmp(name, "server"))
      o.server = value;
    else if (!strcasecmp(name, "port"))
      o.port = atoi(value);
    else if (!strcasecmp(name, "scriptdir"))
      o.scriptdir = value;
    else if (!strcasecmp(name, "verbose"))
      o.verbose = atoi(value);
    else if (!strcasecmp(name, "retrydelay"))
      o.retrydelay = atoi(value);
    else
      std::cerr << "Invalid line " << i << ": " << line << std::endl;
  }

  fs.close();

  return o;
}

void SLDaemon::applyoptions(const Options &opt) {
  options_.merge(opt);
}

void SLDaemon::check_options() const {

  // Check validy of arguement
  if (options_.server == "")
  if (options.server == "")
    throw Error(ERR_BADPARAM, "No valid server address specified");
  if (options_.port <= 0)
  if (options.port <= 0)
    throw Error(ERR_BADPARAM, "No valid server port specified");
  if (options_.login == "")
  if (options.login == "")
    throw Error(ERR_BADPARAM, "No valid login specified");
  if (options_.pass == "")
  if (options.pass == "")
    throw Error(ERR_BADPARAM, "No valid pass specified");
  if (options_.scriptdir == "")
  if (options.scriptdir == "")
    throw Error(ERR_BADPARAM, "No valid scripts directory specified");
  if (options_.retrydelay < 1)
  if (options.retrydelay < 1)
    throw Error(ERR_BADPARAM, "No valid retry delay specified");

  // Check dir script exist
  if (euidaccess(options_.scriptdir.c_str(), W_OK))
  if (euidaccess(options.scriptdir.c_str(), W_OK))
    throw Error(ERR_BADPARAM, "Unable to write into script directory");
}

void SLDaemon::run() {
  char *line;

  if (verbose())
    options_.print();
    std::cout << options;
  check_options();
  clean_dir(options_.scriptdir);
  clean_dir(options.scriptdir);
 net_connect:
  try {
    connect();
@@ -228,7 +102,7 @@ void SLDaemon::run() {
  catch (const Error &e) {
    if (e.code() != ERR_NET)
      throw;
    sleep(options_.retrydelay);
    sleep(options.retrydelay);
    goto net_connect;
  }
}
@@ -246,7 +120,7 @@ void SLDaemon::connect() {
    disconnect();

  // retrieve remote host info
  h = gethostbyname(options_.server.c_str());
  h = gethostbyname(options.server.c_str());
  if (h == 0)
    throw Error(ERR_NET, hstrerror(h_errno));

@@ -256,13 +130,13 @@ void SLDaemon::connect() {
    throw Error(ERR_NET, strerror(errno));

  daddr.sin_family = AF_INET;
  daddr.sin_port = htons(options_.port);
  daddr.sin_port = htons(options.port);
  daddr.sin_addr = *((struct in_addr *) h->h_addr);
  memset(daddr.sin_zero, '\0', sizeof daddr.sin_zero);

  if (verbose())
    std::cout << "Connecting to " << h->h_name << " (" << inet_ntoa(*(struct in_addr*)h->h_addr)
	      << ") on port " << options_.port << "..." << std::endl;
	      << ") on port " << options.port << "..." << std::endl;

  // connect
  if (::connect(socket_fd_, (struct sockaddr *) &daddr, sizeof daddr) == -1)
@@ -270,7 +144,7 @@ void SLDaemon::connect() {

  if (verbose())
    std::cout << "Connected to " << h->h_name << " (" << inet_ntoa(*(struct in_addr*)h->h_addr)
	      << ") on port " << options_.port << "..." << std::endl;
	      << ") on port " << options.port << "..." << std::endl;

  // initialize socket stream
  if ((socket_fs_ = fdopen(socket_fd_, "r+")) == 0)
@@ -364,7 +238,7 @@ void SLDaemon::auth() {
  BIO *bmem, *b64;
  BUF_MEM *bptr;

  SHA1((const unsigned char *) options_.pass.c_str(), options_.pass.length(), md);
  SHA1((const unsigned char *) options.pass.c_str(), options.pass.length(), md);

  b64 = BIO_new(BIO_f_base64());
  bmem = BIO_new(BIO_s_mem());
@@ -379,7 +253,7 @@ void SLDaemon::auth() {
    buf2[bptr->length-1] = 0;
  }

  snprintf(buf, MAX_LINE_SIZE, "HOST %s", options_.login.c_str());
  snprintf(buf, MAX_LINE_SIZE, "HOST %s", options.login.c_str());
  sendln(buf);

  snprintf(buf, MAX_LINE_SIZE, "PASS %s", buf2);
@@ -416,7 +290,7 @@ void SLDaemon::cmd_exec(const char *line) {
    sendln("EXEC: Syntax error.");
    return;
  }
  string path = options_.scriptdir + "/" +  buf;
  string path = options.scriptdir + "/" +  buf;

  // Check transversal path attack
  if (strchr(buf, '/')) {
@@ -515,7 +389,7 @@ void SLDaemon::cmd_file(const char *line) {
    return;
  }

  string target = options_.scriptdir + "/" + filename;
  string target = options.scriptdir + "/" + filename;

  //get size
  int size;
@@ -661,9 +535,9 @@ void SLDaemon::cmd_update() {
}

void SLDaemon::cmd_list() {
  FILE *fls = popen(string("ls -1A " + options_.scriptdir).c_str(), "r");
  FILE *fls = popen(string("ls -1A " + options.scriptdir).c_str(), "r");
  if (fls == 0) {
    sendln("LIST: Unable to list " + options_.scriptdir + ".");
    sendln("LIST: Unable to list " + options.scriptdir + ".");
    return;
  }

@@ -776,37 +650,6 @@ void SLDaemon::clean_dir(const string &dir) const {
  closedir(ds);
}

//******************************************************************************
// Class Options functions
//******************************************************************************

SLDaemon::Options::Options() {
  port = -1;
  verbose = -1;
  retrydelay = -1;
}

void SLDaemon::Options::merge(const SLDaemon::Options &opt) {
  if (opt.server != "") server = opt.server;
  if (opt.port >= 0) port = opt.port;
  if (opt.login != "") login = opt.login;
  if (opt.pass != "") pass = opt.pass;
  if (opt.verbose >= 0) verbose = opt.verbose;
  if (opt.conffile != "") conffile = opt.conffile;
  if (opt.scriptdir != "") scriptdir = opt.scriptdir;
  if (opt.retrydelay >= 0) retrydelay = opt.retrydelay;
}

void SLDaemon::Options::print() {
  std::cout << "server: " << server << std::endl;
  std::cout << "port: " << port << std::endl;
  std::cout << "host login: " << login << std::endl;
  std::cout << "host pass: " << pass << std::endl;
  std::cout << "script directory: " << scriptdir << std::endl;
  std::cout << "configuration file: " << conffile << std::endl;
  std::cout << "retry delay: " << retrydelay << std::endl;
  std::cout << "verbose level: " << verbose << std::endl;
}

//******************************************************************************
// Class Job functions
+5 −21
Original line number Diff line number Diff line
#ifndef DAEMON_HH
# define DAEMON_HH

# include "options.hh"

typedef std::string string;
typedef std::stringstream sstream;
typedef std::ostream ostream;
@@ -18,20 +20,6 @@ public:

  static SLDaemon &Instance();

  struct Options {
    Options();
    void merge(const Options &);
    void print();
    string server;
    int port; //-1 undef
    string login;
    string pass;
    int verbose; //0=false, 1=true, -1=undef
    string scriptdir;
    string conffile;
    int retrydelay; //-1 undef
  };

  struct Job {
    Job() {}
    Job(int, const string &, time_t);
@@ -41,11 +29,10 @@ public:
    bool operator()(const Job &a, const Job &b);
  };

  inline bool verbose() const { return options_.verbose == 1; }
  inline bool verbose() const { return options.verbose == 1; }

  Options options;

  Options getoptions(int argc, char *argv[]) const;
  Options getoptions(const string file) const;
  void applyoptions(const Options &opt);
  void run();

  // friends functions
@@ -53,8 +40,6 @@ public:
  friend void sigchild(int);

protected:
  // parsed options
  Options options_;

  // current socket
  int socket_fd_;
@@ -65,7 +50,6 @@ protected:
  t_job jobs_;

  // Options functions
  void usage(const char *argv0) const;
  void check_options() const;

  // network functions
+159 −0
Original line number Diff line number Diff line
#include "sld.hh"

Options::Options() {
  port = -1;
  verbose = -1;
  retrydelay = -1;
  daemon = -1;
}

void Options::usage(const char *argv0) const {
  std::cerr << "usage: "
	    << argv0
	    << " [-f conffile] [-d scriptdir] [-h] [-v] [-l login]"
	    << "[-p pass] [-H host] [-P port] [-r] [-V]"
	    << std::endl
	    << "  -f conffile  : read and load conf file (def: /etc/sldrc)." << std::endl
	    << "  -d scriptdir : Scripts directory." << std::endl
	    << "  -h           : Print this usage." << std::endl
	    << "  -v           : Verbose mode." << std::endl
	    << "  -q           : Quiet mode." << std::endl
	    << "  -d           : Daemon mode." << std::endl
	    << "  -l host      : Set login to host (def: check hostname)." << std::endl
	    << "  -p secret    : Set pass to secret." << std::endl
	    << "  -H name      : Set server host to name." << std::endl
	    << "  -P number    : Set server port to number (def: 18136)." << std::endl
	    << "  -r val       : Set retry delay to val in seconds (def: 60)." << std::endl
	    << "  -V           : Print version and exit." << std::endl;
}

void Options::merge(const Options &opt) {
  if (opt.server != "") server = opt.server;
  if (opt.port >= 0) port = opt.port;
  if (opt.login != "") login = opt.login;
  if (opt.pass != "") pass = opt.pass;
  if (opt.verbose >= 0) verbose = opt.verbose;
  if (opt.conffile != "") conffile = opt.conffile;
  if (opt.scriptdir != "") scriptdir = opt.scriptdir;
  if (opt.retrydelay >= 0) retrydelay = opt.retrydelay;
  if (opt.daemon >= 0) daemon = opt.daemon;
}

Options &Options::getoptions(int argc, char *argv[]) {
  for (int i = 1; i < argc; ++i) {
    if (!strcmp(argv[i], "-h")) {
      usage(*argv);
      throw Error(ERR_USAGE);
    }
    else if (!strcmp(argv[i], "-v")) {
      this->verbose = 1;
    }
    else if (!strcmp(argv[i], "-q")) {
      this->verbose = 0;
    }
    else if (!strcmp(argv[i], "-d")) {
      this->daemon = 1;
    }
    else if (!strcmp(argv[i], "-V")) {
      std::cout << "sl daemon version : " << VERSION << std::endl;
      exit(ERR_OK);
    }
    else if (!strcmp(argv[i], "-H")) {
      if (++i >= argc)
	throw Error(ERR_USAGE, "No enough argument for option -h");
      this->server = string(argv[i]);
    }
    else if (!strcmp(argv[i], "-P")) {
      if (++i >= argc)
	throw Error(ERR_USAGE, "No enough argument for option -p");
      char *endptr;
      this->port = strtol(argv[i], &endptr, 10);
      if (!(*argv[i] != '\0' && *endptr == '\0'))
	throw Error(ERR_USAGE, "Unable to convert port to a number");
    }
    else if (!strcmp(argv[i], "-f")) {
      if (++i >= argc)
	throw Error(ERR_USAGE, "No enough argument for option -f");
      this->conffile = string(argv[i]);
    }
    else if (!strcmp(argv[i], "-d")) {
      if (++i >= argc)
	throw Error(ERR_USAGE, "No enough argument for option -d");
      this->scriptdir = string(argv[i]);
    }
    else if (!strcmp(argv[i], "-l")) {
      if (++i >= argc)
	throw Error(ERR_USAGE, "No enough argument for option -l");
      this->login = string(argv[i]);
    }
    else if (!strcmp(argv[i], "-p")) {
      if (++i >= argc)
	throw Error(ERR_USAGE, "No enough argument for option -p");
      this->pass = string(argv[i]);
    }
    else if (!strcmp(argv[i], "-r")) {
      if (++i >= argc)
	throw Error(ERR_USAGE, "No enough argument for option -r");
      this->retrydelay = atoi(argv[i]);
    }
    else
      throw Error(ERR_USAGE, (string) "Invalid options : " + argv[i]);
  }
  return *this;
}

Options Options::getoptions(const string file) {
  ifstream fs;
  char line[MAX_CONF_LINE_SIZE];
  int i=0;
  char name[11], value[MAX_CONF_LINE_SIZE - 10 + 1];

  fs.open(file.c_str(), ifstream::in);

  if (fs.fail())
    throw Error(ERR_FILE, "Unable to open configuration file");

  while (!fs.eof()) {
    fs.getline(line, MAX_CONF_LINE_SIZE);
    if (fs.eof())
      break;
    ++i;
    sscanf(line, "%10[^=]=%2039s\n", name, value); //TODO: fix magic number

    if (!strcasecmp(name, "host"))
      this->login = value;
    else if (!strcasecmp(name, "pass"))
      this->pass = value;
    else if (!strcasecmp(name, "server"))
      this->server = value;
    else if (!strcasecmp(name, "port"))
      this->port = atoi(value);
    else if (!strcasecmp(name, "scriptdir"))
      this->scriptdir = value;
    else if (!strcasecmp(name, "verbose"))
      this->verbose = atoi(value);
    else if (!strcasecmp(name, "retrydelay"))
      this->retrydelay = atoi(value);
    else if (!strcasecmp(name, "daemon"))
      this->daemon = atoi(value);
    else
      std::cerr << "Invalid line " << i << ": " << line << std::endl;
  }

  fs.close();

  return *this;
}

ostream &operator<< (ostream &s, const Options &o) {
  return s << "server: " << o.server << std::endl
	   << "port: " << o.port << std::endl
	   << "host login: " << o.login << std::endl
	   << "host pass: " << o.pass << std::endl
	   << "script directory: " << o.scriptdir << std::endl
	   << "configuration file: " << o.conffile << std::endl
	   << "retry delay: " << o.retrydelay << std::endl
	   << "daemon mode: " << o.daemon << std::endl
	   << "verbose level: " << o.verbose << std::endl;
}
Loading