Commit be270a29 authored by Seblu's avatar Seblu
Browse files

Avancer sur le daemon.

La partie auth est bonne.
L'execution de script est faite
Il reste la mise a jour et l'envoie de fichier.
Il faut debugger le recv (le getline)
parent 99d1689d
Loading
Loading
Loading
Loading

src/sld/Makefile.am

0 → 100644
+15 −0
Original line number Diff line number Diff line
bin_PROGRAMS=sld

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

CLEANFILES= *~ '\#*'

.PHONY: tar re

tar: distcheck

re: clean all

src/sld/bootstrap

0 → 100755
+21 −0
Original line number Diff line number Diff line
#!/bin/sh
## bootstrap for 42sh in /home/seblu/devel/c/42sh
##
## Made by Seblu
## Login   <seblu@epita.fr>
##
## Started on  Sun Jul 16 19:43:53 2006 Seblu
## Last update Sun Jul 16 19:44:01 2006 Seblu
##

# Failures do matter.
set -e

# See what i'am doing
set -x

# install the GNU Build System.
autoreconf -i -f -v

# FIXME: autoheader does not obey --force.
find . -name 'config.h.in' | xargs touch
 No newline at end of file

src/sld/configure.ac

0 → 100644
+89 −0
Original line number Diff line number Diff line
# Require a recent version of autotools
AC_PREREQ(2.59)

# Auto conf init
AC_INIT([sld],[1.0],[seblu@seblu.net],[sld])

# Define configure generator directory
AC_CONFIG_AUX_DIR([build])

# Auto Make init
AM_INIT_AUTOMAKE([foreign dist-bzip2 no-dist-gzip])

# Check platform
AC_CANONICAL_HOST

CXXFLAGS='-Wall -W -ansi -pedantic -D_XOPEN_SOURCE=600'

# Check for C++ compiler
AC_LANG([C++])
AC_PROG_CXX

# Check for Make
AC_PROG_MAKE_SET

# check for ranlib
AC_PROG_RANLIB

# Check for lib efence
AC_CHECK_LIB([efence], [malloc], [EFENCELIB=-lefence])
AC_SUBST([EFENCELIB])

# Checks for library functions.

# Checks for typedefs, structures, and compiler characteristics.

# Check for headers

dnl Memo:
dnl AC ARG WITH(package, help-string, [action-if-given], [action-if-not-given])


AC_ARG_WITH([noerror],
  [AS_HELP_STRING([--with-noerror], [Warning dont create compilation error])],
  [dnl action-if-given
       true
  ],
  [dnl action-if-not-given
       CXXFLAGS="$CXXFLAGS -Werror"
  ]
)

AC_ARG_WITH([debug],
  [AS_HELP_STRING([--with-debug], [use -g and don't use -DNDEBUG -O3])],
  [dnl action-if-given
       CXXFLAGS="$CXXFLAGS -g"
  ],
  [dnl action-if-not-given
      CXXFLAGS="$CXXFLAGS -DNDEBUG -O3"
  ]
)

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"
  ],
  [dnl action-if-not-given
       true
  ]
)

LDFLAGS="$LDFLAGS -lssl"

AC_SUBST([CXXFLAGS])
AC_SUBST([LDFLAGS])

AC_HEADER_STDC

AC_CONFIG_HEADERS([config.h])
AC_CHECK_HEADERS([stdlib.h])

# define Autoconf config files
AC_CONFIG_FILES([
	Makefile
])

AC_OUTPUT

src/sld/daemon.cc

0 → 100644
+359 −0
Original line number Diff line number Diff line

#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <unistd.h>
#include <sys/wait.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <openssl/sha.h>
#include <openssl/bio.h>
#include <openssl/buffer.h>
#include <openssl/evp.h>

#include "sld.hh"

SLDaemon::options::options() {
  this->port = 0;
  this->verbose = 3;
}

void SLDaemon::usage(const char *argv0) const {
  std::cerr << "usage: " 
	    << argv0
	    << " [-f conffile] [-d scriptdir] [-h] [-v] [-u user]"
	    << "[-p pass] [-H host] [-P port] [-V]"
	    << std::endl
	    << "  -f conffile  : read and load conf file." << std::endl
	    << "  -d scriptdir : Scripts directory." << std::endl
	    << "  -h           : Print this usage." << std::endl
	    << "  -v           : Verbose mode." << std::endl
	    << "  -u name      : Set user to name." << 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
	    << "  -V           : Print version and exit." << std::endl;

}

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

  if (argc == 1) {
    usage(*argv);
    throw Error(EXIT_USAGE);
  }

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

SLDaemon::options *SLDaemon::getoptions(const string file) const {
  if (file == "")
    throw Error(EXIT_BADPARAM, "Conf file not implemented");
  throw Error(EXIT_BADPARAM, "Conf file not implemented");
  return NULL;
}

void SLDaemon::applyoptions(const options *opt) {
  assert(opt);
  if (opt->host != "") options_.host = opt->host;
  if (opt->port != 0) options_.port = opt->port;
  if (opt->user != "") options_.user = opt->user;
  if (opt->pass != "") options_.pass = opt->pass;
  if (opt->verbose != 3) options_.verbose = opt->verbose;
  if (opt->conffile != "") options_.conffile = opt->conffile;
  if (opt->scriptdir != "") options_.scriptdir = opt->scriptdir;
}

void SLDaemon::check_options() const {
  // print info in verbose mode
  if (verbose()) {
    std::cout << "Server host is : " << options_.host << "." << std::endl;
    std::cout << "Server port is : " << options_.port << "." << std::endl;
    std::cout << "Daemon user is : " << options_.user << "." << std::endl;
    std::cout << "Daemon pass is : " << options_.pass << "." << std::endl;
    std::cout << "Daemon scripts directory is : " << options_.scriptdir << "." << std::endl;
    std::cout << "Verbose mode : " << verbose() << "." << std::endl;
  }

  // Check validy of arguement
  if (options_.host == "")
    throw Error(EXIT_BADPARAM, "No server address specified.");
  if (options_.port == 0)
    throw Error(EXIT_BADPARAM, "No server port specified.");
  if (options_.port < 1 || options_.port > 65535)
    throw Error(EXIT_BADPARAM, "Bad server port number (1 - 65535).");
  if (options_.user == "")
    throw Error(EXIT_BADPARAM, "No user specified.");
  if (options_.pass == "")
    throw Error(EXIT_BADPARAM, "No pass specified.");
  if (options_.scriptdir == "")
    throw Error(EXIT_BADPARAM, "No scripts directory specified.");

  // Empty scripts dir
  // TODO
}

void SLDaemon::connect() {
  struct sockaddr_in daddr;
  struct hostent *h;

  h = gethostbyname(options_.host.c_str());
  if (h == NULL)
    throw Error(EXIT_NET, hstrerror(h_errno));

  socket_ = socket(PF_INET, SOCK_STREAM, 0);
  if (socket_ == -1)
    throw Error(EXIT_NET, strerror(errno));

  daddr.sin_family = AF_INET;
  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 (::connect(socket_, (struct sockaddr *) &daddr, sizeof daddr) == -1)
    throw Error(EXIT_NET, strerror(errno));

  recv_offset_ = 0;
  recv_size_ = 0;
}

void SLDaemon::send(const string str) {
  if (str.length() == 0)
    return;
  if (write(socket_, str.c_str(), str.length()) <= 0)
    throw Error(EXIT_NET, strerror(errno));
}

void SLDaemon::send(const char *data, size_t len) {
  if (len == 0)
    return;
  if (write(socket_, data, len) <= 0)
    throw Error(EXIT_NET, strerror(errno));
}

char *SLDaemon::recv() {
  char *stringbuffer = NULL;
  ssize_t ret;

  do {
    for (size_t i = recv_offset_; i < recv_size_; ++i) {
      if (recv_buf_[i] == '\n') {
	bufferize(&stringbuffer, (const char*) recv_buf_ + recv_offset_, i - recv_offset_);
	recv_offset_ = i + 1;
	return stringbuffer;
      }
    }
    if (recv_size_ > recv_offset_)
      bufferize(&stringbuffer, (const char*) recv_buf_ + recv_offset_, recv_size_ - recv_offset_);
    recv_offset_ = 0;
    ret = read(socket_, recv_buf_, RECV_BUF_SIZE);
    if (ret == 0)
      throw Error(EXIT_NET, "Connexion closed.");
    if (ret < 0)
      throw Error(EXIT_NET, (string) "SLDaemon::recv: " + strerror(errno));
    recv_size_ = ret;
  }
  while (recv_size_ > 0);
  return stringbuffer;
}

void	SLDaemon::bufferize(char **str, const char *append, size_t n)
{
  size_t	ln;
  size_t	i;
  size_t	j;

  ln = (*str == NULL) ? 0 : strlen(*str);
  if ((*str = (char *) realloc(*str, (ln + n + 1) * sizeof (char))) == NULL)
    throw Error(EXIT_NOMEM, strerror(errno));
  for (i = ln, j = 0; i < ln + n; i++, j++)
    (*str)[i] = append[j];
  (*str)[ln + n] = 0;
}

void SLDaemon::protocol_violation() {
  std::cerr << "Protocol Violation." << std::endl;
  send("Protocol Violation.\n");  
}

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

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

  b64 = BIO_new(BIO_f_base64());
  bmem = BIO_new(BIO_s_mem());
  b64 = BIO_push(b64, bmem);
  BIO_write(b64, md, SHA_DIGEST_LENGTH);
  BIO_flush(b64);
  BIO_get_mem_ptr(b64, &bptr);

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

  BIO_free_all(b64);

  send(options_.user);
  send(":");
  send(buff);
  send("\n");

  free(buff);

  return;
}

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

  check_options();
  connect();
  auth();
  while (1) {
    line = recv();
    // call right handler
    try {
      if (!strncmp(line, "EXIT", 4))
	cmd_exit();
      else if (!strncmp(line, "VERSION", 7))
	cmd_version();
      else if (!strncmp(line, "EXEC ", 5))
	cmd_exec(line);
      else if (!strncmp(line, "FILE ", 5))
	cmd_file(line);
      else if (!strncmp(line, "UPDATE", 6))
	cmd_update();
      else
	protocol_violation();
    }
    catch (const Error &e) {
      e.print();
      send("!! ");
      send(e.message());
    }
  }
}

void SLDaemon::cmd_version() {
  if (verbose())
    std::cout << ">> Version requested." << std::endl;
  send(VERSION);
}

void SLDaemon::cmd_exit() {
  if (verbose())
    std::cout << ">> Exit requested." << std::endl;
  send("Bye", 3);
  exit(0);
}

void SLDaemon::cmd_exec(const char *line) {
  assert(line);
  char *p = strchr(line, ' ');
  if (p == NULL) {
    protocol_violation();
    return;
  }
  string path = options_.scriptdir + "/" +  string(p + 1);
  send(">> EXEC " + path + "\n");
  if (verbose())
    std::cout << ">> EXEC " << path << std::endl;

  // fork
  pid_t pid = fork();
  if (pid == -1)
    throw Error(EXIT_NET, "Unable to fork");

  if (pid > 0) {
    int status;
    char buf[10];
    waitpid(pid, &status, 0);
    status = WEXITSTATUS(status);
    snprintf(buf, 10, "%d", status);    
    send((string) ">> EXEC return " + buf + "\n");
  }
  else if (pid == 0) {
    if (dup2(socket_, STDOUT_FILENO) == -1) {
      perror(">> dup2");
      exit(EXIT_UNKNOWN);
    }
    if (dup2(socket_, STDERR_FILENO) == -1) {
      perror(">> dup2");
      exit(EXIT_UNKNOWN);
    }
    if (execl(path.c_str(), path.c_str(), NULL) == -1) {
      perror(">> execl");
      exit(EXIT_UNKNOWN);
    }
  }
}

void SLDaemon::cmd_file(const char *line) {
  assert(line);
    if (verbose())
    std::cout << "FILE transfer : " << std::endl;
}

void SLDaemon::cmd_update() {
  std::cout << "UPDATE detected" << std::endl;
}

src/sld/error.cc

0 → 100644
+69 −0
Original line number Diff line number Diff line
#include "error.hh"

Error::Error(int i, const string s)
{
  val_ = i;
  msg_ << s;
}

Error::Error(const Error &e)
{
  val_ = e.val_;
  msg_ << e.msg_.str();
}

void Error::print() const
{
  if (msg_.str() != "")
    std::cerr << msg_.str() << std::endl;
}

string Error::message() const
{
  return msg_.str();
}

int Error::code() const
{
  return val_;
}

void Error::code(int v)
{
  val_ = v;
}

Error &Error::operator=(const Error &rhs)
{
  val_ = rhs.val_;
  msg_.str("");
  msg_ << rhs.msg_.str();
  return *this;
}

ostream &operator<<(ostream &o, const Error &e)
{
  o << e.msg_.str();
  return o;
}

Error &operator<<(Error &e, int val)
{
  e.msg_ << val;
  return e;
}

Error &operator<<(Error &e, const string &s)
{
  e.msg_ << s;
  return e;
}

Error &operator>>(Error &e, const string &s)
{
  string buf = s + e.msg_.str();

  e.msg_.str("");
  e.msg_ << buf;
  return e;
}
Loading