Commit a0879ef9 authored by Seblu's avatar Seblu
Browse files

Suppresion de la commande RELOAD de sld

Suppression de memory leaks
update fonctionne
exec fonctionne (suppression race condition d'enregistrement avec le fils)
parent b49c4ad8
Loading
Loading
Loading
Loading
+8 −7
Original line number Diff line number Diff line
bin_PROGRAMS=	sld

sld_SOURCES=	sld.hh			\
		sld.cc			\
		daemon.cc		\
		error.hh		\
		error.cc
sld_SOURCES=	src/sld.hh		\
		src/sld.cc		\
		src/daemon.hh		\
		src/daemon.cc		\
		src/error.hh		\
		src/error.cc

CLEANFILES= *~ '\#*'
CLEANFILES= *~ '\#*' .*.swp .*~

.PHONY: tar re

+2 −2
Original line number Diff line number Diff line
@@ -63,8 +63,8 @@ AC_ARG_WITH([efence],
  [AS_HELP_STRING([--with-efence], [link with lib efence])],
  [dnl action-if-given
       LDFLAGS="$LDFLAGS -lefence"
       test -r "/usr/include/efence.h" &&
       CXXFLAGS="$CXXFLAGS -include stdlib.h -include efence.h"
       #test -r "/usr/include/efencepp.h" &&
       #CXXFLAGS="$CXXFLAGS -include efencepp.h"
  ],
  [dnl action-if-not-given
       true
+155 −160
Original line number Diff line number Diff line
@@ -43,7 +43,7 @@ void SLDaemon::usage(const char *argv0) const {
	    << "  -d scriptdir : Scripts directory." << std::endl
	    << "  -h           : Print this usage." << std::endl
	    << "  -v           : Verbose mode." << std::endl
	    << "  -l name      : Set login to name." << std::endl
	    << "  -l host      : Set login to host." << 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." << std::endl
@@ -158,8 +158,8 @@ void SLDaemon::check_options() const {
  if (options_.scriptdir == "")
    throw Error(ERR_BADPARAM, "No scripts directory specified.");

  // Empty scripts dir
  // TODO
  // TODO: Check dir exist
  // TODO: Empty scripts dir
}
void SLDaemon::run() {
  char *line;
@@ -169,13 +169,10 @@ void SLDaemon::run() {
  auth();
  while (1) {
    line = recvln();
    warn(line, RCV_DATA);
    // call right handler
    try {
      if (!strcmp(line, "EXIT\n"))
	cmd_exit();
      else if (!strcmp(line, "RELOAD\n"))
	cmd_reload();
      else if (!strcmp(line, "VERSION\n"))
	cmd_version();
      else if (!strcmp(line, "STATUS\n"))
@@ -186,21 +183,20 @@ void SLDaemon::run() {
	cmd_killall();
      else if (!strcmp(line, "KILL\n"))
	cmd_kill(line);
      else if (!strncmp(line, "JOB ", 4))
	cmd_job(line);
      else if (!strncmp(line, "EXEC ", 4))
	cmd_exec(line);
      else if (!strncmp(line, "FILE ", 5))
	cmd_file(line);
      else if (!strcmp(line, "UPDATE"))
      else if (!strcmp(line, "UPDATE\n"))
	cmd_update();
      else
	proto_violation();
	sendln("sld: Invalid command.");
    }
    catch (const Error &e) {
      e.print();
      send("!! ");
      send(e.message());
      sendln(e.message());
      std::cerr << "!! " << e.message() << std::endl;
    }
    delete line;
    delete[] line;
  }
}

@@ -265,11 +261,18 @@ void SLDaemon::send(const char *data, size_t len, bool buf) {
    throw Error(ERR_NET, strerror(errno));
}

void SLDaemon::sendln(const string &s) {
  if (!fprintf(socket_fs_, "%s\n", s.c_str()))
    throw Error(ERR_NET, strerror(errno));
  if (verbose())
    std::cout << SND_DATA << s << std::endl;
}

char *SLDaemon::recv(size_t size) {
  char *data = new char[size];

  if (fread(data, 1, size, socket_fs_) != size) {
    delete data;
    delete[] data;
    throw Error(ERR_NET, strerror(errno));
  }
  return data;
@@ -279,20 +282,23 @@ void SLDaemon::recv(size_t size, const string &filename) {
  char *data = recv(size);
  FILE *fs = fopen(filename.c_str(), "w");
  if (fs == 0)
    throw Error(ERR_FILE, (string) "recv: " + strerror(errno));
    throw Error(ERR_FILE, (string) "recv: fopen: " + strerror(errno));
  if (fwrite(data, 1, size, fs) != size)
    throw Error(ERR_FILE, (string) "recv: " + strerror(errno));
    throw Error(ERR_FILE, (string) "recv: fwrite: " + strerror(errno));
  if (fclose(fs))
    throw Error(ERR_FILE, (string) "recv: " + strerror(errno));
    throw Error(ERR_FILE, (string) "recv: fclose: " + strerror(errno));
}

char *SLDaemon::recvln() {
  char *line = new char[MAX_LINE_SIZE];

  if (fgets(line, MAX_LINE_SIZE, socket_fs_) == 0) {
    delete line;
    delete[] line;
    throw Error(ERR_FILE, (string) "recvln: " + strerror(errno));
  }
  if (verbose())
    std::cout << SND_DATA << line;

  return line;
}

@@ -307,6 +313,8 @@ void SLDaemon::flush() {

void SLDaemon::auth() {
  unsigned char md[SHA_DIGEST_LENGTH];
  char buf[MAX_LINE_SIZE];
  char *buf2 = "";
  BIO *bmem, *b64;
  BUF_MEM *bptr;

@@ -319,99 +327,84 @@ void SLDaemon::auth() {
  BIO_flush(b64);
  BIO_get_mem_ptr(b64, &bptr);

  char *buff = new char[bptr->length];
  memcpy(buff, bptr->data, bptr->length-1);
  buff[bptr->length-1] = 0;

  BIO_free_all(b64);

  send("HOST ");
  send(options_.login);
  send("\n");

  send("PASS ");
  send(buff);
  send("\n");

  flush();

  delete buff;

  return;
  if (bptr->length > 0) {
    buf2 = new char[bptr->length];
    memcpy(buf2, bptr->data, bptr->length-1);
    buf2[bptr->length-1] = 0;
  }

void SLDaemon::answer(const string &msg, bool prefix) {
  if (verbose())
    std::cout << (prefix ? SND_DATA : "") << msg;
  send(msg);
}
  snprintf(buf, MAX_LINE_SIZE, "HOST %s", options_.login.c_str());
  sendln(buf);

void SLDaemon::answer(long int i, bool prefix) {
  if (verbose()) std::cout << (prefix ? SND_DATA : "") << i;
  send(i);
}
  snprintf(buf, MAX_LINE_SIZE, "PASS %s", buf2);
  sendln(buf);

void SLDaemon::warn(const string &msg, const string &prefix) {
  if (verbose())
    std::cout << prefix << msg;
}
  if (bptr->length > 0)
    delete[] buf2;

void SLDaemon::warn(long int i, const string &prefix) {
  if (verbose())
    std::cout << prefix << i;
}
  BIO_free_all(b64);

void SLDaemon::proto_violation() {
  answer("sld: Protocol violation.\n");
  return;
}



//******************************************************************************
// command functions
//******************************************************************************

void SLDaemon::cmd_exit() {
  answer("BYE\n");
  sendln("Bye.");
  disconnect();
  exit(ERR_OK);
}

void SLDaemon::cmd_version() {
  answer(VERSION + "\n");
  sendln(VERSION);
}

void SLDaemon::cmd_job(const char *line) {
void SLDaemon::cmd_exec(const char *line) {
  assert(line);

  // build path
  char buf[MAX_LINE_SIZE];
  sscanf(line, "EXEC %512s\n", buf);  //FIXME: Bad static magic number
  if (sscanf(line, "EXEC %512s\n", buf) != 1) {  //FIXME: Bad static magic number
    sendln("EXEC: Syntax error.");
    return;
  }
  string path = options_.scriptdir + "/" +  buf;

  // Check transversal path attack
  if (strchr(buf, '/')) {
    sendln("EXEC: Invalid character in job name.");
    return;
  }

  // Check if file exist
  struct stat st;
  int ret = lstat(path.c_str(), &st);
  if (ret == ENOENT || errno == EACCES) {
    answer((string) "JOB: " + strerror(errno) + ".\n");
  if (ret) {
    char msg[MAX_LINE_SIZE];
    snprintf(msg, MAX_LINE_SIZE, "EXEC: %s: %s.", buf, strerror(errno));
    sendln(msg);
    return;
  }
  // check for exec flag
  if (st.st_mode & S_IXUSR != S_IXUSR) {
    answer("JOB: no exec flag.\n");
    sendln("EXEC: no exec flag.");
    return;
  }
  // check file owner
  if (st.st_uid != getuid()) {
    answer("JOB: Bad file owner.\n");
    sendln("EXEC: Bad file owner.");
    return;
  }

  // Create new process
  // flush before fork
  flush();

  //Create new process
  pid_t pid = fork();
  if (pid == -1) {
    answer((string) "JOB: Unable to fork: " + strerror(errno) + ".\n");
    sendln((string) "EXEC: Unable to fork: " + strerror(errno) + ".");
    return;
  }

@@ -423,12 +416,26 @@ void SLDaemon::cmd_job(const char *line) {

    // send job info
    snprintf(buf, MAX_LINE_SIZE,
	     "JOB: %s, pid: %d, start at: %ld.\n",
	     "EXEC: %s, pid: %d, start at: %ld.",
	     j.name.c_str(), j.pid, j.start_time);
    answer(buf);
    sendln(buf);

    // allow sun to start
    if (kill(pid, SIGCONT)) {
      perror("sld: cmd_exec");
      jobs_.erase(j);
    }
  }
  // Son job
  else if (pid == 0) {
    // Wait father registration stuff before doing something else
    // so we suspend execution
    if (kill(getpid(), SIGSTOP)) {
      perror("sld: cmd_exec");
      return;
    }

    // try to run job
    if (dup2(socket_fd_, STDOUT_FILENO) == -1) {
      perror(">> dup2");
      exit(ERR_UNKNOWN);
@@ -452,30 +459,35 @@ void SLDaemon::cmd_file(const char *line) {
  // get filename
  char filename[MAX_LINE_SIZE];
  if (sscanf(line, "FILE %512s\n", filename) != 1) { //FIXME: bad magic size
    proto_violation();
    sendln("FILE: Syntax error.");
    return;
  }

  // Check transversal path attack
  if (strchr(filename, '/')) {
    sendln("FILE: Invalid character in filename.");
    return;
  }

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

  //get size
  int size;
  buf = recvln();
  warn(buf);
  ret = sscanf(buf, "SIZE %i\n", &size);
  delete buf;
  delete[] buf;
  if (ret != 1) {
    answer("FILE: Invalid size parameter.\n"); 
    sendln("FILE: Invalid size parameter.");
    return;
  }

  //get md5
  char md5[MAX_LINE_SIZE];
  buf = recvln();
  warn(buf);
  ret = sscanf(buf, "MD5 %512s\n", md5); //FIXME: bad magic size
  delete buf;
  delete[] buf;
  if (ret != 1) {
    answer("FILE: Invalid md5 parameter.\n");
    sendln("FILE: Invalid md5 parameter.");
    return;
  }

@@ -485,7 +497,7 @@ void SLDaemon::cmd_file(const char *line) {
  }
  catch (const Error &err) {
    if (err.code() == ERR_FILE) {
      answer("FILE: Data transfer error.\n");
      sendln("FILE: Data transfer error.");
      return;
    }
    throw;
@@ -493,26 +505,26 @@ void SLDaemon::cmd_file(const char *line) {

  // check MD5
  if (SLDaemon::md5(target) != string(md5)) {
    answer("FILE: file " + target + ": Invalid MD5.\n");
    sendln("FILE: file " + target + ": Invalid MD5.");
    unlink(target.c_str());
    return;
 }

  // proceed chown
  if (chown(target.c_str(), getuid(), getgid())) {
    answer("FILE: chown of " + target + ": Unable to chown.\n");
    sendln("FILE: chown of " + target + ": Unable to chown.");
    unlink(target.c_str());
    return;
  }

  // proceed chmod
  if (chmod(target.c_str(), S_IRUSR | S_IWUSR | S_IXUSR)) {
    answer("FILE: chmod of " + target + ": Unable to chmod.\n");
    sendln("FILE: chmod of " + target + ": Unable to chmod.");
    unlink(target.c_str());
    return;
  }

  answer("FILE: Transfer of " + target + ": OK.\n"); 
  sendln("FILE: Transfer of " + target + ": OK.");
}

void SLDaemon::cmd_update() {
@@ -520,70 +532,92 @@ void SLDaemon::cmd_update() {
  int ret;

  // get filename
  const string &target = binpath;
  const string &target = getbinpath();

  //get size
  int size;
  buf = recvln();
  warn(buf);
  ret = sscanf(buf, "SIZE %i\n", &size);
  delete buf;
  delete[] buf;
  if (ret != 1) {
    answer("UPDATE: Invalid size parameter.\n"); 
    sendln("UPDATE: Syntax error.");
    return;
  }

  //get md5
  char md5[MAX_LINE_SIZE];
  buf = recvln();
  warn(buf);
  ret = sscanf(buf, "MD5 %512s\n", md5); //FIXME: bad magic size
  delete buf;
  delete[] buf;
  if (ret != 1) {
    answer("UPDATE: Invalid md5 parameter.\n");
    sendln("UPDATE: Invalid md5 parameter.");
    return;
  }

  // find tempory filename
  char tempsld[PATH_MAX] = "/tmp/sldXXXXXX";
  int tempsld_fd = mkstemp(tempsld);

  if (tempsld_fd == 0) {
    sendln((string) "UPDATE: mkstemp: " + strerror(errno) + ".");
    return;
  }
  close(tempsld_fd);

  //get data
  try {
    recv(size, target);
    recv(size, tempsld);
  }
  catch (const Error &err) {
    if (err.code() == ERR_FILE) {
      answer("UPDATE: Data transfer error.\n");
      sendln("UPDATE: " + err.message() + ".");
      unlink(tempsld);
      return;
    }
    throw;
  }

  // check MD5
  if (SLDaemon::md5(target) != string(md5)) {
    answer("UPDATE: file " + target + ": Invalid MD5.\n");
  if (SLDaemon::md5(tempsld) != string(md5)) {
    sendln("UPDATE: file " + tempsld + ": Invalid MD5.");
    unlink(tempsld);
    return;
 }

  // copy file to its right destination
  unlink(target.c_str());
  cp(tempsld, target.c_str());


  // check MD5
  if (SLDaemon::md5(target.c_str()) != string(md5)) {
    sendln("UPDATE: file " + target + ": Invalid MD5.");
    unlink(tempsld);
    return;
 }


  // proceed chown
  if (chown(target.c_str(), getuid(), getgid())) {
    answer("FILE: chown of " + target + ": Unable to chown.\n");
    sendln("FILE: chown of " + target + ": Unable to chown.");
    unlink(target.c_str());
    return;
  }

  // proceed chmod
  if (chmod(target.c_str(), S_IRUSR | S_IWUSR | S_IXUSR)) {
    answer("FILE: chmod of " + target + ": Unable to chmod.\n");
    sendln("FILE: chmod of " + target + ": Unable to chmod.");
    unlink(target.c_str());
    return;
  }

  answer("UPDATE: Transfer of " + target + ": OK.\n"); 
  sendln("UPDATE: Transfer of " + target + ": OK.");
}

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

@@ -592,8 +626,7 @@ void SLDaemon::cmd_list() {
  try {
    while ((len = fread(buf, 1, 255, fls)) > 0)
      send(buf, len);
    flush();
    warn("LIST: data send.\n");
    sendln("LIST: data send.");
  }
  catch (...) {
    pclose(fls);
@@ -606,14 +639,16 @@ void SLDaemon::cmd_status() {
  time_t t = time(0);
  char buf[MAX_LINE_SIZE];

  answer("STATUS of \n");
  if (jobs_.size() == 0)
    return;

  sendln("STATUS of");
  for (i = jobs_.begin(); i != jobs_.end(); ++i) {
    snprintf(buf, MAX_LINE_SIZE,
	     " job: %s, pid: %d, start at: %ld, since: %ld seconds.\n",
	     " job: %s, pid: %d, start at: %ld, since: %ld seconds.",
	     i->name.c_str(), i->pid, i->start_time,t - i->start_time);
    answer(buf);
    sendln(buf);
  }
  flush();
}

void SLDaemon::cmd_kill(const char *line) {
@@ -623,18 +658,17 @@ void SLDaemon::cmd_kill(const char *line) {
  // retrieve pid
  int pid;
  if (sscanf(line, "KILL %i\n", &pid) != 1) {
    proto_violation();
    sendln("KILL: Syntax error.");
    return;
  }

  for (i = jobs_.begin(); i != jobs_.end(); ++i)
    if (pid == i->pid) {
      int ret = kill(i->pid, SIGKILL);
      snprintf(buf, MAX_LINE_SIZE, "KILL: kill -SIGKILL %d (%s), return %d (%s).\n",
      snprintf(buf, MAX_LINE_SIZE, "KILL: kill -SIGKILL %d (%s), return %d (%s).",
	       i->pid, i->name.c_str(), ret, ((ret == -1) ? strerror(errno) : "OK" ));
      answer(buf);
      sendln(buf);
    }
  flush();
}

void SLDaemon::cmd_killall() {
@@ -643,48 +677,9 @@ void SLDaemon::cmd_killall() {

  for (i = jobs_.begin(); i != jobs_.end(); ++i) {
    int ret = kill(i->pid, SIGKILL);
    snprintf(buf, MAX_LINE_SIZE, "KILL: kill -SIGKILL %d (%s), return %d (%s).\n",
    snprintf(buf, MAX_LINE_SIZE, "KILL: kill -SIGKILL %d (%s), return %d (%s).",
	     i->pid, i->name.c_str(), ret, ((ret == -1) ? strerror(errno) : "OK" ));
    answer(buf);
  }
  flush();
}

void SLDaemon::cmd_reload() {
  const string &path = binpath;

  if (path == "") {
    answer("RELOAD: Unable to locate sld binary.\n");
    return;
  }
  
  // Get bin info
  struct stat st;
  if (lstat(path.c_str(), &st)) {
    answer((string)"RELOAD: lstat: " + strerror(errno) + ".\n");
    return;
  }
  
  // FIXME: check re run right (exec + file owner)

  answer((string) "RELOAD: Trying to reload `" + path.c_str() + "'.\n");
  
  int pid = fork();
  if (pid == -1) {
    answer((string)"RELOAD: fork: " + strerror(errno) + ".\n");
    return;
  }
  // father process
  if (pid) {
    disconnect();
    exit(0);
  }
  // son process
  else {
    execl(path.c_str(), path.c_str());
    answer((string) "RELOAD: execl: " + strerror(errno) + ".\n");
    flush();
    exit(ERR_UNKNOWN);
    sendln(buf);
  }
}

+4 −49
Original line number Diff line number Diff line

#ifndef SLD_HH
# define SLD_HH

# include <cassert>
# include <ios>
# include <iostream>
# include <fstream>
# include <sstream>
# include <map>
# include <time.h>
# include <set>

# include "error.hh"
#ifndef DAEMON_HH
# define DAEMON_HH

typedef std::string string;
typedef std::stringstream sstream;
typedef std::ostream ostream;
typedef std::ifstream ifstream;

enum {
  ERR_OK = 0,
  ERR_USAGE = 1,
  ERR_BADPARAM = 2,
  ERR_FILE = 3,
  ERR_NET = 4,
  ERR_PROTO = 5,
  ERR_AUTH = 6,
  ERR_NOMEM = 41,
  ERR_UNKNOWN = 42
};

// -----------------------------------------------------------------------------
// Gonstant
// -----------------------------------------------------------------------------

static const string VERSION = "1";
static const int MAX_LINE_SIZE = 512;
static const string RCV_DATA = "<< ";
static const string SND_DATA = ">> ";

extern string binpath;
string getbinpath(const char *argv0);

void sigchild(int);

// -----------------------------------------------------------------------------
// SLDAEMON CLASS
// -----------------------------------------------------------------------------
@@ -109,6 +71,7 @@ protected:
  void send(const char *data, size_t len, bool buf = true);
  void send(const string str, bool buf = true);
  void send(long int i);
  void sendln(const string &s);
  char *recv(size_t size);
  void recv(size_t size, const string &filename);
  char *recvln();
@@ -116,21 +79,15 @@ protected:

  // protocol functions
  void auth();
  void answer(const string &, bool = true);
  void answer(long int, bool = true);
  void warn(const string &, const string & = "");
  void warn(long int, const string & = "");
  void proto_violation();

  // commmand functions
  void cmd_exit();
  void cmd_version();
  void cmd_list();
  void cmd_reload();
  void cmd_status();
  void cmd_killall();
  void cmd_kill(const char *line);
  void cmd_job(const char *line);
  void cmd_exec(const char *line);
  void cmd_update();
  void cmd_file(const char *line);

@@ -146,6 +103,4 @@ private:
  SLDaemon &operator=(const SLDaemon &) { assert(true); return *instance_; }
};



#endif
+0 −0

File moved.

Loading