Loading src/sld/README 0 → 100644 +1 −0 Original line number Diff line number Diff line Max command line size = 512 src/sld/TODO 0 → 100644 +9 −0 Original line number Diff line number Diff line Improvments Commande exec avec execution en // command clean command status command reload command update BUG: la commande file est buggé suremetn dans le MD5 src/sld/daemon.cc +332 −134 Original line number Diff line number Diff line Loading @@ -3,9 +3,11 @@ #include <errno.h> #include <string.h> #include <unistd.h> #include <stdio.h> #include <sys/wait.h> #include <sys/types.h> #include <sys/socket.h> #include <sys/stat.h> #include <netinet/in.h> #include <arpa/inet.h> #include <netdb.h> Loading @@ -13,9 +15,12 @@ #include <openssl/bio.h> #include <openssl/buffer.h> #include <openssl/evp.h> #include <openssl/md5.h> #include "sld.hh" SLDaemon::SLDaemon() : socket_fs_(NULL) {} SLDaemon::options::options() { this->port = 0; this->verbose = 3; Loading @@ -24,14 +29,14 @@ SLDaemon::options::options() { void SLDaemon::usage(const char *argv0) const { std::cerr << "usage: " << argv0 << " [-f conffile] [-d scriptdir] [-h] [-v] [-u user]" << " [-f conffile] [-d scriptdir] [-h] [-v] [-l login]" << "[-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 << " -l name : Set login 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 Loading @@ -44,56 +49,56 @@ SLDaemon::options *SLDaemon::getoptions(int argc, char *argv[]) const { if (argc == 1) { usage(*argv); throw Error(EXIT_USAGE); throw Error(ERR_USAGE); } for (int i = 1; i < argc; ++i) { if (!strcmp(argv[i], "-h")) { usage(*argv); throw Error(EXIT_USAGE); throw Error(ERR_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); exit(ERR_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]); 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(EXIT_USAGE, "No enough argument for option -p."); 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(EXIT_USAGE, "Unable to convert port to a number."); throw Error(ERR_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."); 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(EXIT_USAGE, "No enough argument for option -d."); throw Error(ERR_USAGE, "No enough argument for option -d."); opt.scriptdir = string(argv[i]); } else if (!strcmp(argv[i], "-u")) { else if (!strcmp(argv[i], "-l")) { if (++i >= argc) throw Error(EXIT_USAGE, "No enough argument for option -u."); opt.user = string(argv[i]); 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(EXIT_USAGE, "No enough argument for option -s."); throw Error(ERR_USAGE, "No enough argument for option -p."); opt.pass = string(argv[i]); } else { Error *err = new Error(EXIT_USAGE); Error *err = new Error(ERR_USAGE); *err << "Invalid options : " << string(argv[i]) << "."; throw *err; } Loading @@ -105,16 +110,16 @@ SLDaemon::options *SLDaemon::getoptions(int argc, char *argv[]) const { 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"); throw Error(ERR_BADPARAM, "Conf file not implemented"); throw Error(ERR_BADPARAM, "Conf file not implemented"); return NULL; } void SLDaemon::applyoptions(const options *opt) { assert(opt); if (opt->host != "") options_.host = opt->host; if (opt->server != "") options_.server = opt->server; if (opt->port != 0) options_.port = opt->port; if (opt->user != "") options_.user = opt->user; if (opt->login != "") options_.login = opt->login; if (opt->pass != "") options_.pass = opt->pass; if (opt->verbose != 3) options_.verbose = opt->verbose; if (opt->conffile != "") options_.conffile = opt->conffile; Loading @@ -124,115 +129,166 @@ void SLDaemon::applyoptions(const options *opt) { void SLDaemon::check_options() const { // print info in verbose mode if (verbose()) { std::cout << "Server host is : " << options_.host << "." << std::endl; std::cout << "Server host is : " << options_.server << "." << std::endl; std::cout << "Server port is : " << options_.port << "." << std::endl; std::cout << "Daemon user is : " << options_.user << "." << std::endl; std::cout << "Daemon login is : " << options_.login << "." << 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_.server == "") throw Error(ERR_BADPARAM, "No server address specified."); if (options_.port == 0) throw Error(EXIT_BADPARAM, "No server port specified."); throw Error(ERR_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."); throw Error(ERR_BADPARAM, "Bad server port number (1 - 65535)."); if (options_.login == "") throw Error(ERR_BADPARAM, "No login specified."); if (options_.pass == "") throw Error(EXIT_BADPARAM, "No pass specified."); throw Error(ERR_BADPARAM, "No pass specified."); if (options_.scriptdir == "") throw Error(EXIT_BADPARAM, "No scripts directory specified."); throw Error(ERR_BADPARAM, "No scripts directory specified."); // Empty scripts dir // TODO } void SLDaemon::run() { char *line; check_options(); connect(); auth(); while (1) { line = recvln(); // 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, "CLEAN\n")) cmd_clean(); else if (!strcmp(line, "LIST\n")) cmd_list(); 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(line); else proto_violation(); } catch (const Error &e) { e.print(); send("!! "); send(e.message()); } delete line; } } //****************************************************************************** // network functions //****************************************************************************** void SLDaemon::connect() { struct sockaddr_in daddr; struct hostent *h; h = gethostbyname(options_.host.c_str()); // close existing connexion if (socket_fs_ == NULL) disconnect(); // retrieve remote host info h = gethostbyname(options_.server.c_str()); if (h == NULL) throw Error(EXIT_NET, hstrerror(h_errno)); throw Error(ERR_NET, hstrerror(h_errno)); socket_ = socket(PF_INET, SOCK_STREAM, 0); if (socket_ == -1) throw Error(EXIT_NET, strerror(errno)); // create socket socket_fd_ = socket(PF_INET, SOCK_STREAM, 0); if (socket_fd_ == -1) throw Error(ERR_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)); // connect if (::connect(socket_fd_, (struct sockaddr *) &daddr, sizeof daddr) == -1) throw Error(ERR_NET, strerror(errno)); recv_offset_ = 0; recv_size_ = 0; // initialize socket stream if ((socket_fs_ = fdopen(socket_fd_, "r+")) == NULL) throw Error(ERR_NET, strerror(errno)); } void SLDaemon::send(const string str) { if (str.length() == 0) void SLDaemon::disconnect() { if (socket_fs_ == NULL) return; if (write(socket_, str.c_str(), str.length()) <= 0) throw Error(EXIT_NET, strerror(errno)); if (fclose(socket_fs_)) throw Error(ERR_NET, strerror(errno)); socket_fs_ = NULL; } void SLDaemon::send(const string str, bool buf) { send(str.c_str(), str.length(), buf); } void SLDaemon::send(const char *data, size_t len) { void SLDaemon::send(const char *data, size_t len, bool buf) { if (len == 0) return; if (write(socket_, data, len) <= 0) throw Error(EXIT_NET, strerror(errno)); if (fwrite(data, 1, len, socket_fs_) != len) throw Error(ERR_NET, strerror(errno)); if (!buf && fflush(socket_fs_)) throw Error(ERR_NET, strerror(errno)); } char *SLDaemon::recv() { char *stringbuffer = NULL; ssize_t ret; char *SLDaemon::recv(size_t size) { char *data = new char[size]; 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 (fread(data, 1, size, socket_fs_) != size) { delete data; throw Error(ERR_NET, strerror(errno)); } return data; } 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::recv(size_t size, const string filename) { char *data = recv(size); FILE *fs = fopen(filename.c_str(), "w"); if (fs == NULL) throw Error(ERR_FILE, strerror(errno)); if (fwrite(data, 1, size, fs) != size) throw Error(ERR_FILE, strerror(errno)); if (fclose(fs)) throw Error(ERR_FILE, strerror(errno)); } void SLDaemon::bufferize(char **str, const char *append, size_t n) { size_t ln; size_t i; size_t j; char *SLDaemon::recvln() { char *line = new char[MAX_LINE_SIZE]; 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; if (fgets(line, MAX_LINE_SIZE, socket_fs_) == NULL) { delete line; throw Error(ERR_FILE, strerror(errno)); } return line; } void SLDaemon::protocol_violation() { std::cerr << "Protocol Violation." << std::endl; send("Protocol Violation.\n"); void SLDaemon::flush() { if (fflush(socket_fs_)) throw Error(ERR_NET, strerror(errno)); } //****************************************************************************** // protocol functions //****************************************************************************** void SLDaemon::auth() { unsigned char md[SHA_DIGEST_LENGTH]; BIO *bmem, *b64; Loading @@ -247,71 +303,78 @@ void SLDaemon::auth() { BIO_flush(b64); BIO_get_mem_ptr(b64, &bptr); char *buff = (char *) malloc(bptr->length); char *buff = new char[bptr->length]; memcpy(buff, bptr->data, bptr->length-1); buff[bptr->length-1] = 0; BIO_free_all(b64); send(options_.user); send(":"); send("USER "); send(options_.login); send("\n"); send("PASS "); send(buff); send("\n"); free(buff); flush(); delete buff; char *line = recvln(); if (strcmp(line, "OK\n")) { delete line; throw Error(ERR_AUTH, "Authentification failed !"); } delete line; 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(); void SLDaemon::tee(const string msg) { if (verbose()) std::cout << msg << std::endl; send(msg); send("\n"); } catch (const Error &e) { e.print(); send("!! "); send(e.message()); void SLDaemon::proto_ok() { send("OK\n"); } void SLDaemon::proto_ko() { send("KO\n"); } void SLDaemon::proto_violation() { std::cerr << "Protocol Violation." << std::endl; send((string) "Protocol Violation.\n", false); } void SLDaemon::cmd_version() { //****************************************************************************** // command functions //****************************************************************************** void SLDaemon::cmd_exit() { if (verbose()) std::cout << ">> Version requested." << std::endl; send(VERSION); std::cout << "EXIT requested." << std::endl; send("Bye.\n"); exit(ERR_OK); } void SLDaemon::cmd_exit() { void SLDaemon::cmd_version() { if (verbose()) std::cout << ">> Exit requested." << std::endl; send("Bye", 3); exit(0); std::cout << "VERSION requested." << std::endl; send(VERSION); send("\n"); } void SLDaemon::cmd_exec(const char *line) { assert(line); char *p = strchr(line, ' '); if (p == NULL) { protocol_violation(); proto_violation(); return; } string path = options_.scriptdir + "/" + string(p + 1); Loading @@ -322,7 +385,7 @@ void SLDaemon::cmd_exec(const char *line) { // fork pid_t pid = fork(); if (pid == -1) throw Error(EXIT_NET, "Unable to fork"); throw Error(ERR_NET, "Unable to fork"); if (pid > 0) { int status; Loading @@ -333,27 +396,162 @@ void SLDaemon::cmd_exec(const char *line) { send((string) ">> EXEC return " + buf + "\n"); } else if (pid == 0) { if (dup2(socket_, STDOUT_FILENO) == -1) { if (dup2(socket_fd_, STDOUT_FILENO) == -1) { perror(">> dup2"); exit(EXIT_UNKNOWN); exit(ERR_UNKNOWN); } if (dup2(socket_, STDERR_FILENO) == -1) { if (dup2(socket_fd_, STDERR_FILENO) == -1) { perror(">> dup2"); exit(EXIT_UNKNOWN); exit(ERR_UNKNOWN); } if (execl(path.c_str(), path.c_str(), NULL) == -1) { perror(">> execl"); exit(EXIT_UNKNOWN); exit(ERR_UNKNOWN); } } } void SLDaemon::cmd_file(const char *line) { char *buf; int ret; assert(line); // get filename char filename[512]; //FIXME: bad magic size if (sscanf(line, "FILE %512s\n", filename) != 1) { proto_violation(); return; } string target = options_.scriptdir + "/" + filename; //get size int size; buf = recvln(); ret = sscanf(buf, "SIZE %i\n", &size); delete buf; if (ret != 1) { tee("Invalid size parameter."); return; } //get md5 char *md5; buf = recvln(); ret = sscanf(buf, "MD5 %s\n", md5); delete buf; if (ret != 1) { tee("Invalid md5 parameter."); return; } // show verbose if (verbose()) std::cout << "FILE transfer requested: " << "to=" << target << ", size=" << size << ", md5=" << md5 << "." << std::endl; //get data try { recv(size, target); } catch (const Error &err) { if (err.code() == ERR_FILE) { tee("Data transfer error."); return; } throw; } // check MD5 std::cout << SLDaemon::md5(target) <<std::endl;; if (SLDaemon::md5(target) != string(md5)) { tee("Transfer of " + target + ": FAILED."); unlink(target.c_str()); return; } // proceed chown if (chown(target.c_str(), getuid(), getgid())) { tee("chown of " + target + ": FAILED."); unlink(target.c_str()); return; } // proceed chmod if (chmod(target.c_str(), S_IRUSR | S_IWUSR | S_IXUSR)) { tee("chmod of " + target + ": FAILED."); unlink(target.c_str()); return; } tee("Transfer of " + target + ": OK."); } void SLDaemon::cmd_update(const char *line) { assert(line); if (verbose()) std::cout << "FILE transfer : " << std::endl; std::cout << "UPDATE requested." << std::endl; } void SLDaemon::cmd_list() { if (verbose()) std::cout << "LIST requested." << std::endl; FILE *fls = popen(string("ls -1A " + options_.scriptdir).c_str(), "r"); if (fls == NULL) { tee("Unable to list " + options_.scriptdir + "."); return; } void SLDaemon::cmd_update() { std::cout << "UPDATE detected" << std::endl; char buf[255]; size_t len; try { while ((len = fread(buf, 1, 255, fls)) > 0) send(buf, len); flush(); } catch (...) { pclose(fls); throw; } } void SLDaemon::cmd_clean() { if (verbose()) std::cout << "CLEAN requested." << std::endl; } void SLDaemon::cmd_reload() { if (verbose()) std::cout << "RELOAD requested." << std::endl; } //****************************************************************************** // others functions //****************************************************************************** string SLDaemon::md5(const string file) const { MD5_CTX ctx; FILE *fs; size_t len; char buf[512]; char md[MD5_DIGEST_LENGTH]; char digest[MD5_DIGEST_LENGTH * 2 + 1]; if (!MD5_Init(&ctx)) return ""; if ((fs = fopen(file.c_str(), "r")) == NULL) return ""; while ((len = fread(buf, 1, 512, fs)) > 0) if (!MD5_Update(&ctx, buf, len)) break; if (!MD5_Final((unsigned char*)md, &ctx)) return ""; for(len = 0; len < MD5_DIGEST_LENGTH; ++len) { sprintf(digest + (len * 2), "%02x", (unsigned char) md[len]); } digest[MD5_DIGEST_LENGTH * 2] = 0; return string(digest); } src/sld/sld.cc +1 −1 Original line number Diff line number Diff line Loading @@ -45,5 +45,5 @@ int main(int argc, char *argv[]) std::cerr <<"sld: error: " << e.message() << std::endl; return e.code(); } return EXIT_UNKNOWN; return ERR_UNKNOWN; } src/sld/sld.hh +45 −29 Original line number Diff line number Diff line Loading @@ -17,14 +17,16 @@ typedef std::ostream ostream; typedef std::ifstream ifstream; enum { EXIT_OK = 0, EXIT_USAGE = 1, EXIT_BADPARAM = 2, EXIT_FILE = 3, EXIT_NET = 4, EXIT_PROTO = 5, EXIT_NOMEM = 41, EXIT_UNKNOWN = 42 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 }; // ----------------------------------------------------------------------------- Loading @@ -32,7 +34,7 @@ enum { // ----------------------------------------------------------------------------- const string VERSION = "1"; const int RECV_BUF_SIZE = 512; const int MAX_LINE_SIZE = 512; // ----------------------------------------------------------------------------- // SLDAEMON CLASS Loading @@ -44,17 +46,21 @@ public: static const string version; SLDaemon(); struct options { options(); string host; string server; int port; string user; string login; string pass; int verbose; //0=false, 1=true, 3=undef string scriptdir; string conffile; }; inline bool verbose() const { return options_.verbose == 1; } options *getoptions(int argc, char *argv[]) const; options *getoptions(const string file) const; void applyoptions(const options *opt); Loading @@ -64,32 +70,42 @@ protected: options options_; // current socket int socket_; // receive buffer int recv_buf_[RECV_BUF_SIZE]; char *recv_line_; size_t recv_offset_; size_t recv_size_; int socket_fd_; FILE* socket_fs_; // functions // Options functions void usage(const char *argv0) const; void check_options() const; // network functions void connect(); void send(const char *data, size_t len); void send(const string str); char *recv(); void bufferize(char **str, const char *append, size_t n); void protocol_violation(); void disconnect(); void send(const char *data, size_t len, bool buf = true); void send(const string str, bool buf = true); char *recv(size_t size); void recv(size_t size, const string filename); char *recvln(); void flush(); // protocol functions void auth(); void tee(const string msg); void proto_ok(); void proto_ko(); void proto_violation(); inline bool verbose() const { return options_.verbose == 1; } void cmd_version(); // commmand functions void cmd_exit(); void cmd_update(); void cmd_version(); void cmd_clean(); void cmd_list(); void cmd_reload(); void cmd_update(const char *line); void cmd_exec(const char *line); void cmd_file(const char *line); // others functions string md5(const string file) const; }; #endif Loading
src/sld/README 0 → 100644 +1 −0 Original line number Diff line number Diff line Max command line size = 512
src/sld/TODO 0 → 100644 +9 −0 Original line number Diff line number Diff line Improvments Commande exec avec execution en // command clean command status command reload command update BUG: la commande file est buggé suremetn dans le MD5
src/sld/daemon.cc +332 −134 Original line number Diff line number Diff line Loading @@ -3,9 +3,11 @@ #include <errno.h> #include <string.h> #include <unistd.h> #include <stdio.h> #include <sys/wait.h> #include <sys/types.h> #include <sys/socket.h> #include <sys/stat.h> #include <netinet/in.h> #include <arpa/inet.h> #include <netdb.h> Loading @@ -13,9 +15,12 @@ #include <openssl/bio.h> #include <openssl/buffer.h> #include <openssl/evp.h> #include <openssl/md5.h> #include "sld.hh" SLDaemon::SLDaemon() : socket_fs_(NULL) {} SLDaemon::options::options() { this->port = 0; this->verbose = 3; Loading @@ -24,14 +29,14 @@ SLDaemon::options::options() { void SLDaemon::usage(const char *argv0) const { std::cerr << "usage: " << argv0 << " [-f conffile] [-d scriptdir] [-h] [-v] [-u user]" << " [-f conffile] [-d scriptdir] [-h] [-v] [-l login]" << "[-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 << " -l name : Set login 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 Loading @@ -44,56 +49,56 @@ SLDaemon::options *SLDaemon::getoptions(int argc, char *argv[]) const { if (argc == 1) { usage(*argv); throw Error(EXIT_USAGE); throw Error(ERR_USAGE); } for (int i = 1; i < argc; ++i) { if (!strcmp(argv[i], "-h")) { usage(*argv); throw Error(EXIT_USAGE); throw Error(ERR_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); exit(ERR_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]); 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(EXIT_USAGE, "No enough argument for option -p."); 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(EXIT_USAGE, "Unable to convert port to a number."); throw Error(ERR_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."); 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(EXIT_USAGE, "No enough argument for option -d."); throw Error(ERR_USAGE, "No enough argument for option -d."); opt.scriptdir = string(argv[i]); } else if (!strcmp(argv[i], "-u")) { else if (!strcmp(argv[i], "-l")) { if (++i >= argc) throw Error(EXIT_USAGE, "No enough argument for option -u."); opt.user = string(argv[i]); 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(EXIT_USAGE, "No enough argument for option -s."); throw Error(ERR_USAGE, "No enough argument for option -p."); opt.pass = string(argv[i]); } else { Error *err = new Error(EXIT_USAGE); Error *err = new Error(ERR_USAGE); *err << "Invalid options : " << string(argv[i]) << "."; throw *err; } Loading @@ -105,16 +110,16 @@ SLDaemon::options *SLDaemon::getoptions(int argc, char *argv[]) const { 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"); throw Error(ERR_BADPARAM, "Conf file not implemented"); throw Error(ERR_BADPARAM, "Conf file not implemented"); return NULL; } void SLDaemon::applyoptions(const options *opt) { assert(opt); if (opt->host != "") options_.host = opt->host; if (opt->server != "") options_.server = opt->server; if (opt->port != 0) options_.port = opt->port; if (opt->user != "") options_.user = opt->user; if (opt->login != "") options_.login = opt->login; if (opt->pass != "") options_.pass = opt->pass; if (opt->verbose != 3) options_.verbose = opt->verbose; if (opt->conffile != "") options_.conffile = opt->conffile; Loading @@ -124,115 +129,166 @@ void SLDaemon::applyoptions(const options *opt) { void SLDaemon::check_options() const { // print info in verbose mode if (verbose()) { std::cout << "Server host is : " << options_.host << "." << std::endl; std::cout << "Server host is : " << options_.server << "." << std::endl; std::cout << "Server port is : " << options_.port << "." << std::endl; std::cout << "Daemon user is : " << options_.user << "." << std::endl; std::cout << "Daemon login is : " << options_.login << "." << 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_.server == "") throw Error(ERR_BADPARAM, "No server address specified."); if (options_.port == 0) throw Error(EXIT_BADPARAM, "No server port specified."); throw Error(ERR_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."); throw Error(ERR_BADPARAM, "Bad server port number (1 - 65535)."); if (options_.login == "") throw Error(ERR_BADPARAM, "No login specified."); if (options_.pass == "") throw Error(EXIT_BADPARAM, "No pass specified."); throw Error(ERR_BADPARAM, "No pass specified."); if (options_.scriptdir == "") throw Error(EXIT_BADPARAM, "No scripts directory specified."); throw Error(ERR_BADPARAM, "No scripts directory specified."); // Empty scripts dir // TODO } void SLDaemon::run() { char *line; check_options(); connect(); auth(); while (1) { line = recvln(); // 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, "CLEAN\n")) cmd_clean(); else if (!strcmp(line, "LIST\n")) cmd_list(); 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(line); else proto_violation(); } catch (const Error &e) { e.print(); send("!! "); send(e.message()); } delete line; } } //****************************************************************************** // network functions //****************************************************************************** void SLDaemon::connect() { struct sockaddr_in daddr; struct hostent *h; h = gethostbyname(options_.host.c_str()); // close existing connexion if (socket_fs_ == NULL) disconnect(); // retrieve remote host info h = gethostbyname(options_.server.c_str()); if (h == NULL) throw Error(EXIT_NET, hstrerror(h_errno)); throw Error(ERR_NET, hstrerror(h_errno)); socket_ = socket(PF_INET, SOCK_STREAM, 0); if (socket_ == -1) throw Error(EXIT_NET, strerror(errno)); // create socket socket_fd_ = socket(PF_INET, SOCK_STREAM, 0); if (socket_fd_ == -1) throw Error(ERR_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)); // connect if (::connect(socket_fd_, (struct sockaddr *) &daddr, sizeof daddr) == -1) throw Error(ERR_NET, strerror(errno)); recv_offset_ = 0; recv_size_ = 0; // initialize socket stream if ((socket_fs_ = fdopen(socket_fd_, "r+")) == NULL) throw Error(ERR_NET, strerror(errno)); } void SLDaemon::send(const string str) { if (str.length() == 0) void SLDaemon::disconnect() { if (socket_fs_ == NULL) return; if (write(socket_, str.c_str(), str.length()) <= 0) throw Error(EXIT_NET, strerror(errno)); if (fclose(socket_fs_)) throw Error(ERR_NET, strerror(errno)); socket_fs_ = NULL; } void SLDaemon::send(const string str, bool buf) { send(str.c_str(), str.length(), buf); } void SLDaemon::send(const char *data, size_t len) { void SLDaemon::send(const char *data, size_t len, bool buf) { if (len == 0) return; if (write(socket_, data, len) <= 0) throw Error(EXIT_NET, strerror(errno)); if (fwrite(data, 1, len, socket_fs_) != len) throw Error(ERR_NET, strerror(errno)); if (!buf && fflush(socket_fs_)) throw Error(ERR_NET, strerror(errno)); } char *SLDaemon::recv() { char *stringbuffer = NULL; ssize_t ret; char *SLDaemon::recv(size_t size) { char *data = new char[size]; 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 (fread(data, 1, size, socket_fs_) != size) { delete data; throw Error(ERR_NET, strerror(errno)); } return data; } 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::recv(size_t size, const string filename) { char *data = recv(size); FILE *fs = fopen(filename.c_str(), "w"); if (fs == NULL) throw Error(ERR_FILE, strerror(errno)); if (fwrite(data, 1, size, fs) != size) throw Error(ERR_FILE, strerror(errno)); if (fclose(fs)) throw Error(ERR_FILE, strerror(errno)); } void SLDaemon::bufferize(char **str, const char *append, size_t n) { size_t ln; size_t i; size_t j; char *SLDaemon::recvln() { char *line = new char[MAX_LINE_SIZE]; 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; if (fgets(line, MAX_LINE_SIZE, socket_fs_) == NULL) { delete line; throw Error(ERR_FILE, strerror(errno)); } return line; } void SLDaemon::protocol_violation() { std::cerr << "Protocol Violation." << std::endl; send("Protocol Violation.\n"); void SLDaemon::flush() { if (fflush(socket_fs_)) throw Error(ERR_NET, strerror(errno)); } //****************************************************************************** // protocol functions //****************************************************************************** void SLDaemon::auth() { unsigned char md[SHA_DIGEST_LENGTH]; BIO *bmem, *b64; Loading @@ -247,71 +303,78 @@ void SLDaemon::auth() { BIO_flush(b64); BIO_get_mem_ptr(b64, &bptr); char *buff = (char *) malloc(bptr->length); char *buff = new char[bptr->length]; memcpy(buff, bptr->data, bptr->length-1); buff[bptr->length-1] = 0; BIO_free_all(b64); send(options_.user); send(":"); send("USER "); send(options_.login); send("\n"); send("PASS "); send(buff); send("\n"); free(buff); flush(); delete buff; char *line = recvln(); if (strcmp(line, "OK\n")) { delete line; throw Error(ERR_AUTH, "Authentification failed !"); } delete line; 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(); void SLDaemon::tee(const string msg) { if (verbose()) std::cout << msg << std::endl; send(msg); send("\n"); } catch (const Error &e) { e.print(); send("!! "); send(e.message()); void SLDaemon::proto_ok() { send("OK\n"); } void SLDaemon::proto_ko() { send("KO\n"); } void SLDaemon::proto_violation() { std::cerr << "Protocol Violation." << std::endl; send((string) "Protocol Violation.\n", false); } void SLDaemon::cmd_version() { //****************************************************************************** // command functions //****************************************************************************** void SLDaemon::cmd_exit() { if (verbose()) std::cout << ">> Version requested." << std::endl; send(VERSION); std::cout << "EXIT requested." << std::endl; send("Bye.\n"); exit(ERR_OK); } void SLDaemon::cmd_exit() { void SLDaemon::cmd_version() { if (verbose()) std::cout << ">> Exit requested." << std::endl; send("Bye", 3); exit(0); std::cout << "VERSION requested." << std::endl; send(VERSION); send("\n"); } void SLDaemon::cmd_exec(const char *line) { assert(line); char *p = strchr(line, ' '); if (p == NULL) { protocol_violation(); proto_violation(); return; } string path = options_.scriptdir + "/" + string(p + 1); Loading @@ -322,7 +385,7 @@ void SLDaemon::cmd_exec(const char *line) { // fork pid_t pid = fork(); if (pid == -1) throw Error(EXIT_NET, "Unable to fork"); throw Error(ERR_NET, "Unable to fork"); if (pid > 0) { int status; Loading @@ -333,27 +396,162 @@ void SLDaemon::cmd_exec(const char *line) { send((string) ">> EXEC return " + buf + "\n"); } else if (pid == 0) { if (dup2(socket_, STDOUT_FILENO) == -1) { if (dup2(socket_fd_, STDOUT_FILENO) == -1) { perror(">> dup2"); exit(EXIT_UNKNOWN); exit(ERR_UNKNOWN); } if (dup2(socket_, STDERR_FILENO) == -1) { if (dup2(socket_fd_, STDERR_FILENO) == -1) { perror(">> dup2"); exit(EXIT_UNKNOWN); exit(ERR_UNKNOWN); } if (execl(path.c_str(), path.c_str(), NULL) == -1) { perror(">> execl"); exit(EXIT_UNKNOWN); exit(ERR_UNKNOWN); } } } void SLDaemon::cmd_file(const char *line) { char *buf; int ret; assert(line); // get filename char filename[512]; //FIXME: bad magic size if (sscanf(line, "FILE %512s\n", filename) != 1) { proto_violation(); return; } string target = options_.scriptdir + "/" + filename; //get size int size; buf = recvln(); ret = sscanf(buf, "SIZE %i\n", &size); delete buf; if (ret != 1) { tee("Invalid size parameter."); return; } //get md5 char *md5; buf = recvln(); ret = sscanf(buf, "MD5 %s\n", md5); delete buf; if (ret != 1) { tee("Invalid md5 parameter."); return; } // show verbose if (verbose()) std::cout << "FILE transfer requested: " << "to=" << target << ", size=" << size << ", md5=" << md5 << "." << std::endl; //get data try { recv(size, target); } catch (const Error &err) { if (err.code() == ERR_FILE) { tee("Data transfer error."); return; } throw; } // check MD5 std::cout << SLDaemon::md5(target) <<std::endl;; if (SLDaemon::md5(target) != string(md5)) { tee("Transfer of " + target + ": FAILED."); unlink(target.c_str()); return; } // proceed chown if (chown(target.c_str(), getuid(), getgid())) { tee("chown of " + target + ": FAILED."); unlink(target.c_str()); return; } // proceed chmod if (chmod(target.c_str(), S_IRUSR | S_IWUSR | S_IXUSR)) { tee("chmod of " + target + ": FAILED."); unlink(target.c_str()); return; } tee("Transfer of " + target + ": OK."); } void SLDaemon::cmd_update(const char *line) { assert(line); if (verbose()) std::cout << "FILE transfer : " << std::endl; std::cout << "UPDATE requested." << std::endl; } void SLDaemon::cmd_list() { if (verbose()) std::cout << "LIST requested." << std::endl; FILE *fls = popen(string("ls -1A " + options_.scriptdir).c_str(), "r"); if (fls == NULL) { tee("Unable to list " + options_.scriptdir + "."); return; } void SLDaemon::cmd_update() { std::cout << "UPDATE detected" << std::endl; char buf[255]; size_t len; try { while ((len = fread(buf, 1, 255, fls)) > 0) send(buf, len); flush(); } catch (...) { pclose(fls); throw; } } void SLDaemon::cmd_clean() { if (verbose()) std::cout << "CLEAN requested." << std::endl; } void SLDaemon::cmd_reload() { if (verbose()) std::cout << "RELOAD requested." << std::endl; } //****************************************************************************** // others functions //****************************************************************************** string SLDaemon::md5(const string file) const { MD5_CTX ctx; FILE *fs; size_t len; char buf[512]; char md[MD5_DIGEST_LENGTH]; char digest[MD5_DIGEST_LENGTH * 2 + 1]; if (!MD5_Init(&ctx)) return ""; if ((fs = fopen(file.c_str(), "r")) == NULL) return ""; while ((len = fread(buf, 1, 512, fs)) > 0) if (!MD5_Update(&ctx, buf, len)) break; if (!MD5_Final((unsigned char*)md, &ctx)) return ""; for(len = 0; len < MD5_DIGEST_LENGTH; ++len) { sprintf(digest + (len * 2), "%02x", (unsigned char) md[len]); } digest[MD5_DIGEST_LENGTH * 2] = 0; return string(digest); }
src/sld/sld.cc +1 −1 Original line number Diff line number Diff line Loading @@ -45,5 +45,5 @@ int main(int argc, char *argv[]) std::cerr <<"sld: error: " << e.message() << std::endl; return e.code(); } return EXIT_UNKNOWN; return ERR_UNKNOWN; }
src/sld/sld.hh +45 −29 Original line number Diff line number Diff line Loading @@ -17,14 +17,16 @@ typedef std::ostream ostream; typedef std::ifstream ifstream; enum { EXIT_OK = 0, EXIT_USAGE = 1, EXIT_BADPARAM = 2, EXIT_FILE = 3, EXIT_NET = 4, EXIT_PROTO = 5, EXIT_NOMEM = 41, EXIT_UNKNOWN = 42 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 }; // ----------------------------------------------------------------------------- Loading @@ -32,7 +34,7 @@ enum { // ----------------------------------------------------------------------------- const string VERSION = "1"; const int RECV_BUF_SIZE = 512; const int MAX_LINE_SIZE = 512; // ----------------------------------------------------------------------------- // SLDAEMON CLASS Loading @@ -44,17 +46,21 @@ public: static const string version; SLDaemon(); struct options { options(); string host; string server; int port; string user; string login; string pass; int verbose; //0=false, 1=true, 3=undef string scriptdir; string conffile; }; inline bool verbose() const { return options_.verbose == 1; } options *getoptions(int argc, char *argv[]) const; options *getoptions(const string file) const; void applyoptions(const options *opt); Loading @@ -64,32 +70,42 @@ protected: options options_; // current socket int socket_; // receive buffer int recv_buf_[RECV_BUF_SIZE]; char *recv_line_; size_t recv_offset_; size_t recv_size_; int socket_fd_; FILE* socket_fs_; // functions // Options functions void usage(const char *argv0) const; void check_options() const; // network functions void connect(); void send(const char *data, size_t len); void send(const string str); char *recv(); void bufferize(char **str, const char *append, size_t n); void protocol_violation(); void disconnect(); void send(const char *data, size_t len, bool buf = true); void send(const string str, bool buf = true); char *recv(size_t size); void recv(size_t size, const string filename); char *recvln(); void flush(); // protocol functions void auth(); void tee(const string msg); void proto_ok(); void proto_ko(); void proto_violation(); inline bool verbose() const { return options_.verbose == 1; } void cmd_version(); // commmand functions void cmd_exit(); void cmd_update(); void cmd_version(); void cmd_clean(); void cmd_list(); void cmd_reload(); void cmd_update(const char *line); void cmd_exec(const char *line); void cmd_file(const char *line); // others functions string md5(const string file) const; }; #endif