From mboxrd@z Thu Jan 1 00:00:00 1970 From: rmccabe@sourceware.org Date: 30 Aug 2007 17:07:21 -0000 Subject: [Cluster-devel] conga/ricci/ricci Auth.cpp Auth.h ClientInstan ... Message-ID: <20070830170721.29694.qmail@sourceware.org> List-Id: To: cluster-devel.redhat.com MIME-Version: 1.0 Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7bit CVSROOT: /cvs/cluster Module name: conga Changes by: rmccabe at sourceware.org 2007-08-30 17:07:16 Modified files: ricci/ricci : Auth.cpp Auth.h ClientInstance.cpp ClientInstance.h DBusController.cpp DBusController.h Makefile QueueLocker.cpp QueueLocker.h RebootModule.cpp RebootModule.h Ricci.cpp Ricci.h RicciWorker.cpp RicciWorker.h SSLInstance.cpp SSLInstance.h Server.cpp Server.h dbus_test.cpp main.cpp ricci_defines.h Log message: - cleanup for readability and maintainability - fix a handful of minor problems Patches: http://sourceware.org/cgi-bin/cvsweb.cgi/conga/ricci/ricci/Auth.cpp.diff?cvsroot=cluster&r1=1.5&r2=1.6 http://sourceware.org/cgi-bin/cvsweb.cgi/conga/ricci/ricci/Auth.h.diff?cvsroot=cluster&r1=1.3&r2=1.4 http://sourceware.org/cgi-bin/cvsweb.cgi/conga/ricci/ricci/ClientInstance.cpp.diff?cvsroot=cluster&r1=1.7&r2=1.8 http://sourceware.org/cgi-bin/cvsweb.cgi/conga/ricci/ricci/ClientInstance.h.diff?cvsroot=cluster&r1=1.2&r2=1.3 http://sourceware.org/cgi-bin/cvsweb.cgi/conga/ricci/ricci/DBusController.cpp.diff?cvsroot=cluster&r1=1.15&r2=1.16 http://sourceware.org/cgi-bin/cvsweb.cgi/conga/ricci/ricci/DBusController.h.diff?cvsroot=cluster&r1=1.6&r2=1.7 http://sourceware.org/cgi-bin/cvsweb.cgi/conga/ricci/ricci/Makefile.diff?cvsroot=cluster&r1=1.19&r2=1.20 http://sourceware.org/cgi-bin/cvsweb.cgi/conga/ricci/ricci/QueueLocker.cpp.diff?cvsroot=cluster&r1=1.3&r2=1.4 http://sourceware.org/cgi-bin/cvsweb.cgi/conga/ricci/ricci/QueueLocker.h.diff?cvsroot=cluster&r1=1.1&r2=1.2 http://sourceware.org/cgi-bin/cvsweb.cgi/conga/ricci/ricci/RebootModule.cpp.diff?cvsroot=cluster&r1=1.1&r2=1.2 http://sourceware.org/cgi-bin/cvsweb.cgi/conga/ricci/ricci/RebootModule.h.diff?cvsroot=cluster&r1=1.1&r2=1.2 http://sourceware.org/cgi-bin/cvsweb.cgi/conga/ricci/ricci/Ricci.cpp.diff?cvsroot=cluster&r1=1.25&r2=1.26 http://sourceware.org/cgi-bin/cvsweb.cgi/conga/ricci/ricci/Ricci.h.diff?cvsroot=cluster&r1=1.8&r2=1.9 http://sourceware.org/cgi-bin/cvsweb.cgi/conga/ricci/ricci/RicciWorker.cpp.diff?cvsroot=cluster&r1=1.11&r2=1.12 http://sourceware.org/cgi-bin/cvsweb.cgi/conga/ricci/ricci/RicciWorker.h.diff?cvsroot=cluster&r1=1.6&r2=1.7 http://sourceware.org/cgi-bin/cvsweb.cgi/conga/ricci/ricci/SSLInstance.cpp.diff?cvsroot=cluster&r1=1.8&r2=1.9 http://sourceware.org/cgi-bin/cvsweb.cgi/conga/ricci/ricci/SSLInstance.h.diff?cvsroot=cluster&r1=1.5&r2=1.6 http://sourceware.org/cgi-bin/cvsweb.cgi/conga/ricci/ricci/Server.cpp.diff?cvsroot=cluster&r1=1.6&r2=1.7 http://sourceware.org/cgi-bin/cvsweb.cgi/conga/ricci/ricci/Server.h.diff?cvsroot=cluster&r1=1.2&r2=1.3 http://sourceware.org/cgi-bin/cvsweb.cgi/conga/ricci/ricci/dbus_test.cpp.diff?cvsroot=cluster&r1=1.4&r2=1.5 http://sourceware.org/cgi-bin/cvsweb.cgi/conga/ricci/ricci/main.cpp.diff?cvsroot=cluster&r1=1.4&r2=1.5 http://sourceware.org/cgi-bin/cvsweb.cgi/conga/ricci/ricci/ricci_defines.h.diff?cvsroot=cluster&r1=1.8&r2=1.9 --- conga/ricci/ricci/Auth.cpp 2006/10/24 21:54:29 1.5 +++ conga/ricci/ricci/Auth.cpp 2007/08/30 17:07:14 1.6 @@ -1,5 +1,5 @@ /* - Copyright Red Hat, Inc. 2005 + Copyright Red Hat, Inc. 2005-2007 This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the @@ -13,7 +13,7 @@ You should have received a copy of the GNU General Public License along with this program; see the file COPYING. If not, write to the - Free Software Foundation, Inc., 675 Mass Ave, Cambridge, + Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ /* @@ -25,121 +25,115 @@ #include "Mutex.h" #include +static int +sasl_getopts_callback( void* context, + const char *plugin_name, + const char *option, + const char **result, + unsigned int *len); +static Mutex mutex; // global sasl_lib protection mutex +static bool inited = false; // sasl_lib initialized? -static int -sasl_getopts_callback(void* context, - const char* plugin_name, - const char* option, - const char** result, - unsigned int* len); - - -static Mutex mutex; // global sasl_lib protection mutex -static bool inited = false; // sasl_lib initialized? -const static +const static sasl_callback_t callbacks[] = { - {SASL_CB_GETOPT, (int (*)()) sasl_getopts_callback, NULL}, - {SASL_CB_LIST_END, NULL, NULL}, + { SASL_CB_GETOPT, (int (*)()) sasl_getopts_callback, NULL }, + { SASL_CB_LIST_END, NULL, NULL }, }; - - Auth::Auth() { - if (!initialize_auth_system()) - throw String("Failed to initialize authentication engine"); + if (!initialize_auth_system()) + throw String("Failed to initialize authentication engine"); } Auth::~Auth() {} -bool +bool Auth::authenticate(const String& passwd) const { - MutexLocker l(mutex); - - sasl_conn_t *conn = 0; - try { - bool success = false; - - int ret = sasl_server_new("ricci", // servicename - NULL, // hostname - NULL, // realm - NULL, // local ip:port - NULL, // remote ip:port - callbacks, - 0, // connection flags - &conn); - if (ret != SASL_OK) - throw String("authentication engine error"); - - ret = sasl_checkpass(conn, - "root", 4, - passwd.c_str(), passwd.size()); - if (ret == SASL_OK) - success = true; - else - if (ret != SASL_BADAUTH) - throw String("authentication engine error"); - - sasl_dispose(&conn); conn = 0; - return success; - } catch ( ... ) { - if (conn) { - sasl_dispose(&conn); - conn = 0; - } - throw; - } -} - + MutexLocker l(mutex); + sasl_conn_t *conn = NULL; + try { + bool success = false; + int ret = sasl_server_new("ricci", // servicename + NULL, // hostname + NULL, // realm + NULL, // local ip:port + NULL, // remote ip:port + callbacks, + 0, // connection flags + &conn); + + if (ret != SASL_OK) + throw String("authentication engine error"); + + ret = sasl_checkpass(conn, "root", 4, passwd.c_str(), passwd.size()); + if (ret == SASL_OK) + success = true; + else { + if (ret != SASL_BADAUTH) + throw String("authentication engine error"); + } + + sasl_dispose(&conn); + conn = NULL; + return success; + } catch ( ... ) { + if (conn) { + sasl_dispose(&conn); + conn = NULL; + } + throw; + } +} bool Auth::initialize_auth_system() { - MutexLocker l(mutex); - - if (!inited) { - int ret = sasl_server_init(callbacks, "ricci"); - inited = (ret == SASL_OK); - } - return inited; + MutexLocker l(mutex); + + if (!inited) { + int ret = sasl_server_init(callbacks, "ricci"); + inited = (ret == SASL_OK); + } + return inited; } -int -sasl_getopts_callback(void* context, - const char* plugin_name, - const char* option, - const char** result, - unsigned * len) +int +sasl_getopts_callback( void *context, + const char *plugin_name, + const char *option, + const char **result, + unsigned *len) { - try { - static const char authd_option[] = "pwcheck_method"; - static const char authd_result[] = "saslauthd"; - - static const char authd_version_option[] = "saslauthd_version"; - static const char authd_version_result[] = "2"; - - - if (result) { - *result = 0; - if (strcmp(option, authd_option) == 0) - *result = authd_result; - else if (strcmp(option, authd_version_option) == 0) - *result = authd_version_result; - else { - // modify more options we'd like to use - } - } - if (len) - *len = 0; - - return SASL_OK; - } catch ( ... ) { - return SASL_FAIL; - } + + try { + static const char authd_option[] = "pwcheck_method"; + static const char authd_result[] = "saslauthd"; + static const char authd_version_option[] = "saslauthd_version"; + static const char authd_version_result[] = "2"; + + if (result) { + *result = 0; + if (!strcmp(option, authd_option)) + *result = authd_result; + else if (!strcmp(option, authd_version_option)) + *result = authd_version_result; + else { + // modify more options we'd like to use + } + } + + if (len) + *len = 0; + + return SASL_OK; + } catch ( ... ) { + return SASL_FAIL; + } } --- conga/ricci/ricci/Auth.h 2006/10/24 21:54:29 1.3 +++ conga/ricci/ricci/Auth.h 2007/08/30 17:07:14 1.4 @@ -1,5 +1,5 @@ /* - Copyright Red Hat, Inc. 2005 + Copyright Red Hat, Inc. 2005-2007 This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the @@ -13,7 +13,7 @@ You should have received a copy of the GNU General Public License along with this program; see the file COPYING. If not, write to the - Free Software Foundation, Inc., 675 Mass Ave, Cambridge, + Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ /* @@ -29,20 +29,15 @@ // thread safe - class Auth { - public: - Auth(); - virtual ~Auth(); - - bool authenticate(const String& passwd) const; - - - static bool initialize_auth_system(); // to be called at start-up (not required) - - -}; + public: + Auth(); + virtual ~Auth(); + bool authenticate(const String& passwd) const; + // to be called at start-up (not required) + static bool initialize_auth_system(); +}; -#endif // Auth_h +#endif // Auth_h --- conga/ricci/ricci/ClientInstance.cpp 2006/08/10 22:53:09 1.7 +++ conga/ricci/ricci/ClientInstance.cpp 2007/08/30 17:07:14 1.8 @@ -1,5 +1,5 @@ /* - Copyright Red Hat, Inc. 2005 + Copyright Red Hat, Inc. 2005-2007 This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the @@ -13,7 +13,7 @@ You should have received a copy of the GNU General Public License along with this program; see the file COPYING. If not, write to the - Free Software Foundation, Inc., 675 Mass Ave, Cambridge, + Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ /* @@ -33,194 +33,202 @@ using namespace std; - - -#define ACCEPT_TIMEOUT 30 // seconds -#define SEND_TIMEOUT 120 // seconds -#define RECEIVE_TIMEOUT 120 // seconds - - - -#define MAXIMUM_CLIENTS 10 -static int counter = 0; -static Mutex counter_mutex; - - - -ClientInstance::ClientInstance(ClientSocket sock, - DBusController& dbus_controller) : - _ssl(sock), - _dbus_controller(dbus_controller), - _done(false) -{ - bool max_reached = false; - if (true) { - MutexLocker l(counter_mutex); - if (counter > MAXIMUM_CLIENTS) - max_reached = true; - else { - max_reached = false; - counter++; - } - } - if (max_reached) { - // socket is non-blocking, couple bytes should be able to go out, if not, who cares - sock.send("overload - come back later"); - throw String("maximum number of clients reached"); - } +#define ACCEPT_TIMEOUT 30 // seconds +#define SEND_TIMEOUT 120 // seconds +#define RECEIVE_TIMEOUT 120 // seconds + +#define MAXIMUM_CLIENTS 10 + +static int counter = 0; +static Mutex counter_mutex; + + +ClientInstance::ClientInstance( ClientSocket sock, + DBusController& dbus_controller) : + _ssl(sock), + _dbus_controller(dbus_controller), + _done(false) +{ + bool max_reached = false; + + if (true) { + MutexLocker l(counter_mutex); + if (counter > MAXIMUM_CLIENTS) + max_reached = true; + else { + max_reached = false; + counter++; + } + } + + if (max_reached) { + // socket is non-blocking, couple bytes should be able + // to go out, if not, who cares + sock.send("overload - come back later"); + throw String("maximum number of clients reached"); + } } ClientInstance::~ClientInstance() { - if (true) { - MutexLocker l(counter_mutex); - counter--; - } - - stop(); // stop the thread, if running + if (true) { + MutexLocker l(counter_mutex); + counter--; + } + + stop(); // stop the thread, if running } -bool +bool ClientInstance::done() { - MutexLocker l(_mutex); - return _done; + MutexLocker l(_mutex); + return _done; } -void +void ClientInstance::run() { - int beg_mil = int(time_mil()); - try { - // get dispatcher - Ricci ricci(_dbus_controller); - - // begin encryption - encrypt_begin(); - - // client needs to present certificate - if (!_ssl.client_has_cert()) { - try { - send(XMLObject("Clients_SSL_certificate_required")); - } catch ( ... ) {} - throw String("client hasn't presented certificate"); - } - - bool authed = _ssl.client_cert_authed(); - - // send hello - send(ricci.hello(authed)); - - // process requests - bool done = false; - while (!done && !shouldStop()) { - bool save_cert = false; - bool remove_cert = false; - XMLObject request; - try { - request = receive(); - } catch ( ... ) { + int beg_mil = int(time_mil()); try { - String out = "Timeout_reached_without_valid_XML_request"; - send(XMLObject(out)); - } catch ( ... ) {} - throw; - } - XMLObject response = ricci.request(request, - authed, - save_cert, - remove_cert, - done); - if (!authed && save_cert) { - _ssl.save_client_cert(); - authed = true; - } - if (authed && remove_cert) { - _ssl.remove_client_cert(); - authed = false; - } - send(response); - } - send(XMLObject("bye")); - } catch ( String e ) { - cout << "exception: " << e << endl; - } catch ( ... ) { - cout << "unknown exception" << endl; - } - - cout << "request completed in " << time_mil() - beg_mil << " milliseconds" << endl; - - { - MutexLocker l(_mutex); - _done = true; - } + // get dispatcher + Ricci ricci(_dbus_controller); + + // begin encryption + encrypt_begin(); + + // client needs to present certificate + if (!_ssl.client_has_cert()) { + try { + send(XMLObject("Clients_SSL_certificate_required")); + } catch ( ... ) {} + throw String("client hasn't presented certificate"); + } + + bool authed = _ssl.client_cert_authed(); + + // send hello + send(ricci.hello(authed)); + + // process requests + bool done = false; + while (!done && !shouldStop()) { + bool save_cert = false; + bool remove_cert = false; + XMLObject request; + + try { + request = receive(); + } catch ( ... ) { + try { + String out = "Timeout_reached_without_valid_XML_request"; + send(XMLObject(out)); + } catch ( ... ) {} + throw; + } + + XMLObject response = ricci.request(request, authed, + save_cert, remove_cert, done); + + if (!authed && save_cert) { + _ssl.save_client_cert(); + authed = true; + } + + if (authed && remove_cert) { + _ssl.remove_client_cert(); + authed = false; + } + send(response); + } + send(XMLObject("bye")); + } catch ( String e ) { + cout << "exception: " << e << endl; + } catch ( ... ) { + cout << "unknown exception" << endl; + } + + cout << "request completed in " << time_mil() - beg_mil + << " milliseconds" << endl; + + { + MutexLocker l(_mutex); + _done = true; + } } -XMLObject +XMLObject ClientInstance::receive() { - int beg = int(time_sec()); - String xml_in; - while (true) { - if (shouldStop()) - throw String("thread exiting"); - else if (int(time_sec()) > beg + RECEIVE_TIMEOUT) - throw String("Receive timeout"); - else - xml_in += _ssl.recv(500); - try { - return parseXML(xml_in); - } catch ( ... ) {} - } + int beg = int(time_sec()); + String xml_in; + + while (true) { + if (shouldStop()) + throw String("thread exiting"); + else if (int(time_sec()) > beg + RECEIVE_TIMEOUT) + throw String("Receive timeout"); + else + xml_in += _ssl.recv(500); + + try { + return parseXML(xml_in); + } catch ( ... ) {} + } } -void +void ClientInstance::send(const XMLObject& msg) { - int beg = int(time_sec()); - String out(generateXML(msg)); - while (true) { - if (shouldStop()) - throw String("thread exiting"); - else if (int(time_sec()) > beg + SEND_TIMEOUT) - throw String("Send timeout"); - else - if ((out = _ssl.send(out, 500)).empty()) - break; - } + int beg = int(time_sec()); + String out(generateXML(msg)); + + while (true) { + if (shouldStop()) + throw String("thread exiting"); + else if (int(time_sec()) > beg + SEND_TIMEOUT) + throw String("Send timeout"); + else + if ((out = _ssl.send(out, 500)).empty()) + break; + } } void ClientInstance::encrypt_begin() { - try { - int beg = int(time_sec()); - while (true) { - if (shouldStop()) - throw String("thread exiting"); - else if (int(time_sec()) > beg + ACCEPT_TIMEOUT) - throw String("Accept timeout"); - else - if (_ssl.accept(500)) - break; - } - } catch ( ... ) { - int beg = int(time_sec()); - String out(generateXML(XMLObject("SSL_required"))); - while (true) { - if (shouldStop()) - throw String("thread exiting"); - else if (int(time_sec()) > beg + SEND_TIMEOUT) - throw String("Send timeout"); - else { - bool read = false, write = true; - _ssl.socket().ready(read, write, 500); - if (write) - if ((out = _ssl.socket().send(out)).empty()) - break; - } - } - throw; - } + try { + int beg = int(time_sec()); + while (true) { + if (shouldStop()) + throw String("thread exiting"); + else if (int(time_sec()) > beg + ACCEPT_TIMEOUT) + throw String("Accept timeout"); + else { + if (_ssl.accept(500)) + break; + } + } + } catch ( ... ) { + int beg = int(time_sec()); + String out(generateXML(XMLObject("SSL_required"))); + + while (true) { + if (shouldStop()) + throw String("thread exiting"); + else if (int(time_sec()) > beg + SEND_TIMEOUT) + throw String("Send timeout"); + else { + bool read = false, write = true; + + _ssl.socket().ready(read, write, 500); + if (write) { + if ((out = _ssl.socket().send(out)).empty()) + break; + } + } + } + throw; + } } --- conga/ricci/ricci/ClientInstance.h 2006/04/03 14:50:57 1.2 +++ conga/ricci/ricci/ClientInstance.h 2007/08/30 17:07:14 1.3 @@ -1,5 +1,5 @@ /* - Copyright Red Hat, Inc. 2005 + Copyright Red Hat, Inc. 2005-2007 This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the @@ -13,7 +13,7 @@ You should have received a copy of the GNU General Public License along with this program; see the file COPYING. If not, write to the - Free Software Foundation, Inc., 675 Mass Ave, Cambridge, + Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ /* @@ -31,36 +31,25 @@ #include "SSLInstance.h" #include "XML.h" - class ClientInstance : public Thread { - public: - ClientInstance(ClientSocket sock, - DBusController& dbus_controller); - virtual ~ClientInstance(); - - virtual bool done(); - - - protected: - virtual void run(); - - private: - - SSLInstance _ssl; - - DBusController& _dbus_controller; - - Mutex _mutex; - bool _done; - - - XMLObject receive(); - void send(const XMLObject& msg); - - void encrypt_begin(); - + public: + ClientInstance(ClientSocket sock, DBusController& dbus_controller); + virtual ~ClientInstance(); + virtual bool done(); + + protected: + virtual void run(); + + private: + SSLInstance _ssl; + DBusController& _dbus_controller; + Mutex _mutex; + bool _done; + + XMLObject receive(); + void send(const XMLObject& msg); + void encrypt_begin(); }; - -#endif // ClientInstance_h +#endif // ClientInstance_h --- conga/ricci/ricci/DBusController.cpp 2006/08/10 22:53:09 1.15 +++ conga/ricci/ricci/DBusController.cpp 2007/08/30 17:07:14 1.16 @@ -1,5 +1,5 @@ /* - Copyright Red Hat, Inc. 2005 + Copyright Red Hat, Inc. 2005-2007 This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the @@ -13,7 +13,7 @@ You should have received a copy of the GNU General Public License along with this program; see the file COPYING. If not, write to the - Free Software Foundation, Inc., 675 Mass Ave, Cambridge, + Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ /* @@ -28,7 +28,6 @@ #include "String.h" #include - #define DBUS_API_SUBJECT_TO_CHANGE #include @@ -36,160 +35,156 @@ using namespace std; -#define DBUS_TIMEOUT 2147483647 // milliseconds - - - -static DBusConnection* _dbus_conn = 0; -static Mutex _dbus_mutex; -static int _object_counter = 0; - +#define DBUS_TIMEOUT 2147483647 // milliseconds +static DBusConnection *_dbus_conn = NULL; +static Mutex _dbus_mutex; +static int _object_counter = 0; DBusController::DBusController() { - // TODO: dynamically determine, - // currently, rpm requires storage and cluster modules - _mod_map["storage"] = "modstorage_rw"; - _mod_map["cluster"] = "modcluster_rw"; - _mod_map["rpm"] = "modrpm_rw"; - _mod_map["log"] = "modlog_rw"; - _mod_map["service"] = "modservice_rw"; - _mod_map["reboot"] = "reboot"; - - - MutexLocker lock(_dbus_mutex); - if (_dbus_conn == 0) { - DBusError error; - dbus_error_init (&error); - _dbus_conn = dbus_bus_get(DBUS_BUS_SYSTEM, - &error); - if (dbus_error_is_set(&error) || !_dbus_conn) { - dbus_error_free(&error); - _dbus_conn = 0; - throw String("failed to get system bus connection"); - } else - dbus_error_free(&error); - } - - _object_counter++; - + // TODO: dynamically determine, + // currently, rpm requires storage and cluster modules + _mod_map["storage"] = "modstorage_rw"; + _mod_map["cluster"] = "modcluster_rw"; + _mod_map["rpm"] = "modrpm_rw"; + _mod_map["log"] = "modlog_rw"; + _mod_map["service"] = "modservice_rw"; + _mod_map["reboot"] = "reboot"; + + MutexLocker lock(_dbus_mutex); + if (_dbus_conn == NULL) { + DBusError error; + dbus_error_init(&error); + _dbus_conn = dbus_bus_get(DBUS_BUS_SYSTEM, &error); + if (dbus_error_is_set(&error) || !_dbus_conn) { + dbus_error_free(&error); + _dbus_conn = NULL; + throw String("failed to get system bus connection"); + } else + dbus_error_free(&error); + } + _object_counter++; } DBusController::~DBusController() { - MutexLocker lock(_dbus_mutex); - - if (--_object_counter == 0) { + MutexLocker lock(_dbus_mutex); + + if (--_object_counter == 0) { #if (DBUS_MAJOR_VERSION == 1) || (DBUS_MAJOR_VERSION == 0 && DBUS_MINOR_VERSION >= 90) - dbus_connection_close(_dbus_conn); + dbus_connection_close(_dbus_conn); #elif DBUS_MAJOR_VERSION == 0 && DBUS_MINOR_VERSION < 90 - dbus_connection_disconnect(_dbus_conn); + dbus_connection_disconnect(_dbus_conn); #else -#error "unrecognized major DBUS number" +# error "unrecognized major DBUS number" #endif - dbus_connection_unref(_dbus_conn); - _dbus_conn = 0; - } + dbus_connection_unref(_dbus_conn); + _dbus_conn = NULL; + } } - static String remove_chars(const String& str, char c) { - String s(str); - String::size_type pos; - while ((pos = s.find(c)) != s.npos) - s.erase(pos, 1); - return s; + String s(str); + + String::size_type pos; + while ((pos = s.find(c)) != s.npos) + s.erase(pos, 1); + return s; } String -DBusController::process(const String& message, - const String& module_name) +DBusController::process(const String& message, const String& module_name) { - MutexLocker l(_dbus_mutex); - - if (_mod_map.find(module_name) == _mod_map.end()) - throw String("module not supported"); - - // prepare msg - DBusMessage* msg = dbus_message_new_method_call("com.redhat.ricci", - "/com/redhat/ricci", - "com.redhat.ricci", - _mod_map[module_name].c_str()); - if (!msg) - throw String("not enough memory to create message"); - if (message.size()) { - String msg_clean(remove_chars(message, '\n')); - const char* msg_clean_c_str = msg_clean.c_str(); - - const void* message_dbus_ready = 0; + MutexLocker l(_dbus_mutex); + + if (_mod_map.find(module_name) == _mod_map.end()) + throw String("module not supported"); + + // prepare msg + DBusMessage *msg = dbus_message_new_method_call("com.redhat.ricci", + "/com/redhat/ricci", + "com.redhat.ricci", + _mod_map[module_name].c_str()); + + if (!msg) + throw String("not enough memory to create message"); + + if (message.size()) { + String msg_clean(remove_chars(message, '\n')); + const char *msg_clean_c_str = msg_clean.c_str(); + const void *message_dbus_ready = NULL; #if (DBUS_MAJOR_VERSION == 1) || (DBUS_MAJOR_VERSION == 0 && DBUS_MINOR_VERSION >= 60) - message_dbus_ready = &msg_clean_c_str; + message_dbus_ready = &msg_clean_c_str; #elif DBUS_MAJOR_VERSION == 0 && DBUS_MINOR_VERSION < 60 - message_dbus_ready = msg_clean_c_str; + message_dbus_ready = msg_clean_c_str; #else -#error "unrecognized major DBUS number" +# error "unrecognized major DBUS number" #endif - - if (!dbus_message_append_args(msg, - DBUS_TYPE_STRING, message_dbus_ready, - DBUS_TYPE_INVALID)) - throw String("error appending argument to message"); - } - - - DBusError error; - dbus_error_init (&error); - DBusMessage *resp = dbus_connection_send_with_reply_and_block(_dbus_conn, - msg, - DBUS_TIMEOUT, - &error); - dbus_message_unref(msg); - - // process response - if (resp) { - try { - dbus_error_free(&error); - - int status; - char* out; - char* err; - dbus_message_get_args(resp, - NULL, - DBUS_TYPE_INT32, &status, - DBUS_TYPE_STRING, &out, - DBUS_TYPE_STRING, &err, - DBUS_TYPE_INVALID); - - if (status) { - String e("module returned error code: "); - e += err; - throw e; - } - String ret(out); - dbus_message_unref(resp); - return ret; - } catch ( ... ) { - dbus_message_unref(resp); - throw; - } - } else { - String error_msg(error.message); - dbus_error_free(&error); - throw String("response msg error: ") + error_msg; - } + + if (!dbus_message_append_args(msg, + DBUS_TYPE_STRING, + message_dbus_ready, + DBUS_TYPE_INVALID)) + { + throw String("error appending argument to message"); + } + } + + DBusError error; + dbus_error_init(&error); + + DBusMessage *resp = dbus_connection_send_with_reply_and_block(_dbus_conn, + msg, + DBUS_TIMEOUT, + &error); + dbus_message_unref(msg); + + // process response + if (resp) { + try { + dbus_error_free(&error); + + int status; + char *out; + char *err; + + dbus_message_get_args(resp, NULL, + DBUS_TYPE_INT32, &status, + DBUS_TYPE_STRING, &out, + DBUS_TYPE_STRING, &err, + DBUS_TYPE_INVALID); + + if (status) + throw String("module returned error code: ") + String(err); + String ret(out); + dbus_message_unref(resp); + return ret; + } catch ( ... ) { + dbus_message_unref(resp); + throw; + } + } else { + String error_msg(error.message); + dbus_error_free(&error); + throw String("system bus response msg error: ") + error_msg; + } } -list +list DBusController::modules() { - list mods; - for (map::const_iterator iter = _mod_map.begin(); - iter != _mod_map.end(); - iter++) - mods.push_back(iter->first); - return mods; + list mods; + + for (map::const_iterator + iter = _mod_map.begin() ; + iter != _mod_map.end() ; + iter++) + { + mods.push_back(iter->first); + } + return mods; } --- conga/ricci/ricci/DBusController.h 2006/08/10 22:53:09 1.6 +++ conga/ricci/ricci/DBusController.h 2007/08/30 17:07:14 1.7 @@ -1,5 +1,5 @@ /* - Copyright Red Hat, Inc. 2005 + Copyright Red Hat, Inc. 2005-2007 This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the @@ -13,7 +13,7 @@ You should have received a copy of the GNU General Public License along with this program; see the file COPYING. If not, write to the - Free Software Foundation, Inc., 675 Mass Ave, Cambridge, + Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ /* @@ -27,28 +27,21 @@ #include "XML.h" #include "String.h" - // thread safe // currently: requests, waiting for response, are serialized per PROCESS // FIXME: d-bus supports processing of multiple messages at the same time - class DBusController { - public: - DBusController(); - virtual ~DBusController(); - - String process(const String& message, - const String& module_name); - - std::list modules(); // available modules - - private: - std::map _mod_map; - -}; + public: + DBusController(); + virtual ~DBusController(); + String process(const String& message, const String& module_name); + std::list modules(); // available modules + private: + std::map _mod_map; +}; -#endif // DBusController_h +#endif // DBusController_h --- conga/ricci/ricci/Makefile 2007/01/04 00:20:42 1.19 +++ conga/ricci/ricci/Makefile 2007/08/30 17:07:14 1.20 @@ -1,6 +1,6 @@ ################################################################################################################################################################ ## -## Copyright (C) 2005 Red Hat, Inc. All rights reserved. +## Copyright (C) 2005-2007 Red Hat, Inc. All rights reserved. ## ## This copyrighted material is made available to anyone wishing to use, ## modify, copy, or redistribute it subject to the terms and conditions @@ -14,7 +14,6 @@ include ${top_srcdir}/make/defines.mk TARGET = ricci -TARGET_AUTH = ricci-auth TARGET_WORKER = ricci-worker OBJECTS = main.o \ @@ -26,8 +25,6 @@ Auth.o \ QueueLocker.o -TARGET_AUTH_OBJECTS = auth_helper.o - TARGET_WORKER_OBJECTS = RicciWorker.o \ DBusController.o \ QueueLocker.o \ @@ -38,30 +35,28 @@ #OBJECTS = ssl_test.o -INCLUDE += `pkg-config --cflags dbus-1` -CFLAGS += -CXXFLAGS += -DDBUS_MAJOR_VERSION="${dbus_major_version}" -DDBUS_MINOR_VERSION="${dbus_minor_version}" -LDFLAGS += `pkg-config --libs dbus-1` +INCLUDE += `pkg-config --cflags dbus-1` +CFLAGS += -O2 -Wall -Wextra +CXXFLAGS += -DDBUS_MAJOR_VERSION="${dbus_major_version}" -DDBUS_MINOR_VERSION="${dbus_minor_version}" -O2 -Wall -Wextra +LDFLAGS += `pkg-config --libs dbus-1` -#all: ${TARGET} ${TARGET_AUTH} ${TARGET_WORKER} all: ${TARGET} ${TARGET_WORKER} *.o: *.h ../include/*.h install: - $(INSTALL_DIR) ${sbindir} - $(INSTALL_BIN) ${TARGET} ${sbindir} - $(INSTALL_DIR) ${libexecdir}/ricci - #install -m 4755 ${TARGET_AUTH} ${libexecdir}/ricci - $(INSTALL_BIN) ${TARGET_WORKER} ${libexecdir}/ricci - $(INSTALL_DIR) ${localstatedir}/lib/ricci/queue - $(INSTALL_DIR) ${localstatedir}/lib/ricci/certs + $(INSTALL_DIR) ${sbindir} + $(INSTALL_BIN) ${TARGET} ${sbindir} + $(INSTALL_DIR) ${libexecdir}/ricci + $(INSTALL_BIN) ${TARGET_WORKER} ${libexecdir}/ricci + $(INSTALL_DIR) ${localstatedir}/lib/ricci/queue + $(INSTALL_DIR) ${localstatedir}/lib/ricci/certs $(INSTALL_FILE) cacert.config ${localstatedir}/lib/ricci/certs/ - $(INSTALL_DIR) ${localstatedir}/lib/ricci/certs/clients - $(INSTALL_DIR) ${sysconfdir}/oddjobd.conf.d + $(INSTALL_DIR) ${localstatedir}/lib/ricci/certs/clients + $(INSTALL_DIR) ${sysconfdir}/oddjobd.conf.d $(INSTALL_FILE) d-bus/ricci.oddjob.conf ${sysconfdir}/oddjobd.conf.d - $(INSTALL_DIR) ${sysconfdir}/dbus-1/system.d + $(INSTALL_DIR) ${sysconfdir}/dbus-1/system.d $(INSTALL_FILE) d-bus/ricci.systembus.conf ${sysconfdir}/dbus-1/system.d @@ -69,23 +64,14 @@ clean: rm -f $(TARGET) $(OBJECTS) - rm -f $(TARGET_AUTH) $(TARGET_AUTH_OBJECTS) rm -f $(TARGET_WORKER) $(TARGET_WORKER_OBJECTS) check: rebuild: clean all - $(TARGET): $(OBJECTS) $(CXX) -o $(TARGET) $(OBJECTS) $(LDFLAGS) -lsasl2 -${TARGET_AUTH}: $(TARGET_AUTH_OBJECTS) - $(CXX) -o ${TARGET_AUTH} $(TARGET_AUTH_OBJECTS) ${LDFLAGS} -lpam - ${TARGET_WORKER}: ${TARGET_WORKER_OBJECTS} $(CXX) -o ${TARGET_WORKER} ${TARGET_WORKER_OBJECTS} ${LDFLAGS} - - -Auth_test: Auth_test.o Auth.o - $(CXX) -o Auth_test Auth_test.o Auth.o ${LDFLAGS} -lsasl2 --- conga/ricci/ricci/QueueLocker.cpp 2006/08/10 22:53:09 1.3 +++ conga/ricci/ricci/QueueLocker.cpp 2007/08/30 17:07:14 1.4 @@ -1,5 +1,5 @@ /* - Copyright Red Hat, Inc. 2005 + Copyright Red Hat, Inc. 2005-2007 This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the @@ -13,7 +13,7 @@ You should have received a copy of the GNU General Public License along with this program; see the file COPYING. If not, write to the - Free Software Foundation, Inc., 675 Mass Ave, Cambridge, + Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ /* @@ -37,47 +37,54 @@ static int q_counter = 0; static int fd; - QueueLocker::QueueLocker() : - MutexLocker(q_lock) + MutexLocker(q_lock) { - if (q_counter++) - return; - - try { - fd = open(QUEUE_LOCK_PATH, - O_RDONLY|O_CREAT, - S_IRUSR|S_IWUSR|S_IRGRP); - - if (fd == -1) - throw String("unable to open queue lock file"); - - // acquire flock - int res; - while ((res = flock(fd, LOCK_EX))) - if (errno != EINTR) { - while ((res = close(fd))) - if (errno != EINTR) - throw String("unable to close the queue lock file"); - throw String("unable to lock the queue"); - } - } catch ( ... ) { - q_counter--; - throw; - } + if (q_counter++) + return; + + try { + fd = open(QUEUE_LOCK_PATH, O_RDONLY | O_CREAT, 0640); + if (fd == -1) { + throw String("unable to open queue lock file: ") + + String(strerror(errno)); + } + + // acquire flock + int res; + while ((res = flock(fd, LOCK_EX))) { + if (errno != EINTR) { + int err = errno; + while ((res = close(fd))) { + if (errno != EINTR) { + throw String("unable to close the queue lock file: ") + + String(strerror(errno)); + } + } + throw String("unable to lock the queue: ") + + String(strerror(err)); + } + } + } catch ( ... ) { + q_counter--; + throw; + } } QueueLocker::~QueueLocker() { - if (!--q_counter) { - // release flock - int res; - while ((res = close(fd))) - if (errno != EINTR) { - while ((res = flock(fd, LOCK_UN))) - if (errno != EINTR) - break; // throw String("unable to unlock the queue"); - break; // throw String("unable to close the queue lock file"); - } - } + if (!--q_counter) { + // release flock + + int res; + while ((res = close(fd))) { + if (errno != EINTR) { + while ((res = flock(fd, LOCK_UN))) { + if (errno != EINTR) + break; // throw String("unable to unlock the queue"); + break; // throw String("unable to close the queue lock file"); + } + } + } + } } --- conga/ricci/ricci/QueueLocker.h 2006/03/23 16:29:37 1.1 +++ conga/ricci/ricci/QueueLocker.h 2007/08/30 17:07:14 1.2 @@ -1,5 +1,5 @@ /* - Copyright Red Hat, Inc. 2005 + Copyright Red Hat, Inc. 2005-2007 This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the @@ -13,7 +13,7 @@ You should have received a copy of the GNU General Public License along with this program; see the file COPYING. If not, write to the - Free Software Foundation, Inc., 675 Mass Ave, Cambridge, + Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ /* @@ -29,10 +29,10 @@ class QueueLocker : public MutexLocker { -public: - QueueLocker(); - virtual ~QueueLocker(); + public: + QueueLocker(); + virtual ~QueueLocker(); }; -#endif // QueueLocker_h +#endif // QueueLocker_h --- conga/ricci/ricci/RebootModule.cpp 2006/04/12 15:47:09 1.1 +++ conga/ricci/ricci/RebootModule.cpp 2007/08/30 17:07:14 1.2 @@ -1,5 +1,5 @@ /* - Copyright Red Hat, Inc. 2006 + Copyright Red Hat, Inc. 2006-2007 This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the @@ -13,7 +13,7 @@ You should have received a copy of the GNU General Public License along with this program; see the file COPYING. If not, write to the - Free Software Foundation, Inc., 675 Mass Ave, Cambridge, + Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ /* @@ -26,9 +26,8 @@ using namespace std; - // potential bug, if there are two different dbuss in use -static DBusController* dbus = 0; +static DBusController* dbus = NULL; static bool block = false; @@ -38,48 +37,44 @@ RebootModule::RebootModule(DBusController& dbus) : - Module(build_fcn_map()), - _dbus(dbus) + Module(build_fcn_map()), + _dbus(dbus) { - ::dbus = &_dbus; + ::dbus = &_dbus; } RebootModule::~RebootModule() {} - -XMLObject +XMLObject RebootModule::process(const XMLObject& request) { - return this->Module::process(request); + return this->Module::process(request); } bool RebootModule::block() { - return ::block; + return ::block; } - ApiFcnMap build_fcn_map() { - FcnMap api_1_0; - api_1_0["reboot_now"] = reboot; - - ApiFcnMap api_fcn_map; - api_fcn_map["1.0"] = api_1_0; - - return api_fcn_map; -} + FcnMap api_1_0; + api_1_0["reboot_now"] = reboot; + ApiFcnMap api_fcn_map; + api_fcn_map["1.0"] = api_1_0; -VarMap + return api_fcn_map; +} + +VarMap reboot(const VarMap& args) { - dbus->process("", "reboot"); - - block = true; - - return VarMap(); + dbus->process("", "reboot"); + block = true; + + return VarMap(); } --- conga/ricci/ricci/RebootModule.h 2006/04/12 15:47:09 1.1 +++ conga/ricci/ricci/RebootModule.h 2007/08/30 17:07:14 1.2 @@ -1,5 +1,5 @@ /* - Copyright Red Hat, Inc. 2006 + Copyright Red Hat, Inc. 2006-2007 This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the @@ -13,7 +13,7 @@ You should have received a copy of the GNU General Public License along with this program; see the file COPYING. If not, write to the - Free Software Foundation, Inc., 675 Mass Ave, Cambridge, + Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ /* @@ -30,18 +30,15 @@ class RebootModule : public Module { - public: - RebootModule(DBusController& dbus); - virtual ~RebootModule(); - - virtual XMLObject process(const XMLObject& request); - - bool block(); - - private: - DBusController& _dbus; - + public: + RebootModule(DBusController& dbus); + virtual ~RebootModule(); + virtual XMLObject process(const XMLObject& request); + bool block(); + + private: + DBusController& _dbus; }; -#endif // RebootModule_h +#endif // RebootModule_h --- conga/ricci/ricci/Ricci.cpp 2007/03/23 17:25:13 1.25 +++ conga/ricci/ricci/Ricci.cpp 2007/08/30 17:07:14 1.26 @@ -1,5 +1,5 @@ /* - Copyright Red Hat, Inc. 2005 + Copyright Red Hat, Inc. 2005-2007 This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the @@ -13,7 +13,7 @@ You should have received a copy of the GNU General Public License along with this program; see the file COPYING. If not, write to the - Free Software Foundation, Inc., 675 Mass Ave, Cambridge, + Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ /* @@ -43,464 +43,450 @@ #include using namespace std; - static bool dom0(); static pair clusterinfo(); static String os_release(); - +extern bool advertise_cluster; Ricci::Ricci(DBusController& dbus) : - _dbus(dbus), - _fail_auth_attempt(0) + _dbus(dbus), + _fail_auth_attempt(0) {} Ricci::~Ricci() {} - -XMLObject +XMLObject Ricci::ricci_header(bool authed, bool full) const { - XMLObject header("ricci"); - header.set_attr("version", "1.0"); - if (authed) - header.set_attr("authenticated", "true"); - else - header.set_attr("authenticated", "false"); - - if (full) { - String name = Network::localhost(); - if (name.size()) - header.set_attr("hostname", name); - - pair c_info = clusterinfo(); - if (c_info.first.size()) - header.set_attr("clustername", c_info.first); - if (c_info.second.size()) - header.set_attr("clusteralias", c_info.second); - - if (authed) { - String os = os_release(); - if (os.size()) - header.set_attr("os", os); - - header.set_attr("xen_host", - dom0() ? "true" : "false"); - } - } - - return header; + XMLObject header("ricci"); + header.set_attr("version", "1.0"); + + if (authed) + header.set_attr("authenticated", "true"); + else + header.set_attr("authenticated", "false"); + + if (full || advertise_cluster) { + String name = Network::localhost(); + if (name.size()) + header.set_attr("hostname", name); + + pair c_info = clusterinfo(); + if (c_info.first.size()) + header.set_attr("clustername", c_info.first); + if (c_info.second.size()) + header.set_attr("clusteralias", c_info.second); + + if (authed) { + String os = os_release(); + if (os.size()) + header.set_attr("os", os); + + header.set_attr("xen_host", dom0() ? "true" : "false"); + } + } + + return header; } -XMLObject +XMLObject Ricci::hello(bool authed) const { - return ricci_header(authed, true); + return ricci_header(authed, true); } - XMLObject -Ricci::request(const XMLObject& req, - bool authenticated, - bool& save_cert, - bool& remove_cert, - bool& done) -{ - save_cert = false; - remove_cert = false; - done = false; - - if (req.tag() != "ricci") { - done = true; - return XMLObject("not_ricci_message"); - } - - XMLObject resp = ricci_header(authenticated); - - // version check - String version = req.get_attr("version"); - if (version.empty()) { - resp.set_attr("success", utils::to_string(RRC_MISSING_VERSION)); - return resp; - } else if (req.get_attr("version") != "1.0") { - resp.set_attr("success", utils::to_string(RRC_MISSING_VERSION)); - return resp; - } - - - RicciRetCode success = RRC_INTERNAL_ERROR; - String function = req.get_attr("function"); - if (function == "") { - success = RRC_MISSING_FUNCTION; - } else if (function == "authenticate") { - String passwd = req.get_attr("password"); - bool passwd_ok = false; - if (passwd.size()) { - try { - passwd_ok = Auth().authenticate(passwd); - } catch ( ... ) {} - } - - if (passwd_ok) { - resp = ricci_header(true, true); - success = RRC_SUCCESS; - save_cert = true; - } else { - if (_fail_auth_attempt++ == 3) - done = true; - success = RRC_AUTH_FAIL; - } - - } else if (function == "unauthenticate") { - if (!authenticated) { - // not authenticated - // success = RRC_NEED_AUTH; - // unauthenticate should always succeed - success = RRC_SUCCESS; - } else { - // authenticated - resp = ricci_header(false); - success = RRC_SUCCESS; - remove_cert = true; - } - - } else if (function == "list_modules") { - // available modules - if (!authenticated) { - // not authenticated - success = RRC_NEED_AUTH; - } else { - // authenticated - list modules = _dbus.modules(); - for (list::const_iterator iter = modules.begin(); - iter != modules.end(); - iter++) { - XMLObject x("module"); - x.set_attr("name", *iter); - resp.add_child(x); - } - success = RRC_SUCCESS; - } - - } else if (function == "process_batch") { - - if (!authenticated) { - // not authenticated - success = RRC_NEED_AUTH; - } else { - // authenticated - - bool async = (req.get_attr("async") == "true"); - - const XMLObject* batch_xml = NULL; - for (list::const_iterator iter = req.children().begin(); - iter != req.children().end(); - iter++) - if (iter->tag() == "batch") { - batch_xml = &(*iter); - break; +Ricci::request( const XMLObject& req, + bool& authenticated, + bool& save_cert, + bool& remove_cert, + bool& done) +{ + save_cert = false; + remove_cert = false; + done = false; + + if (req.tag() != "ricci") { + done = true; + return XMLObject("not_ricci_message"); } - if (batch_xml) { - try { - long long id; - if (true) { - Batch batch(*batch_xml); - id = batch.id(); - if (async) { - resp.add_child(batch.report()); - success = RRC_SUCCESS; - } - } - if (!async) { - bool batch_done; - do { - sleep_mil(100); - Batch batch(id); - if (batch_done = batch.done()) { - resp.add_child(batch.report()); - success = RRC_SUCCESS; - } - } while (!batch_done); - } - } catch ( ... ) { - success = RRC_INTERNAL_ERROR; - } - } else - success = RRC_MISSING_BATCH; - } - - } else if (function == "batch_report") { - // get report - - if (!authenticated) { - // not authenticated - success = RRC_NEED_AUTH; - } else { - // authenticated - - long long id = utils::to_long(req.get_attr("batch_id")); - if (id == 0) - success = RRC_INVALID_BATCH_ID; - else { - try { - Batch batch(id); - resp.add_child(batch.report()); - success = RRC_SUCCESS; - } catch ( ... ) { - success = RRC_INVALID_BATCH_ID; - } - } - } - - } else { - // invalid function name - success = RRC_INVALID_FUNCTION; - } - - resp.set_attr("success", utils::to_string(success)); - return resp; -} + XMLObject resp = ricci_header(authenticated); + // version check + String version = req.get_attr("version"); + if (version.empty()) { + resp.set_attr("success", utils::to_string(RRC_MISSING_VERSION)); + return resp; + } else if (req.get_attr("version") != "1.0") { + resp.set_attr("success", utils::to_string(RRC_MISSING_VERSION)); + return resp; + } + RicciRetCode success = RRC_INTERNAL_ERROR; + String function = req.get_attr("function"); + if (function == "") { + success = RRC_MISSING_FUNCTION; + } else if (function == "authenticate") { + String passwd = req.get_attr("password"); + bool passwd_ok = false; + if (passwd.size()) { + try { + passwd_ok = Auth().authenticate(passwd); + } catch ( ... ) {} + } + + if (passwd_ok) { + resp = ricci_header(true, true); + success = RRC_SUCCESS; + save_cert = true; + authenticated = true; + } else { + if (_fail_auth_attempt++ == 3) + done = true; + success = RRC_AUTH_FAIL; + } + } else if (function == "unauthenticate") { + if (!authenticated) { + success = RRC_SUCCESS; + } else { + resp = ricci_header(false); + success = RRC_SUCCESS; + remove_cert = true; + } + } else if (function == "list_modules") { + // available modules + if (!authenticated) { + success = RRC_NEED_AUTH; + } else { + list modules = _dbus.modules(); + for (list::const_iterator + iter = modules.begin() ; + iter != modules.end() ; + iter++) + { + XMLObject x("module"); + x.set_attr("name", *iter); + resp.add_child(x); + } + success = RRC_SUCCESS; + } + } else if (function == "process_batch") { + if (!authenticated) { + success = RRC_NEED_AUTH; + } else { + bool async = (req.get_attr("async") == "true"); + + const XMLObject* batch_xml = NULL; + for (list::const_iterator + iter = req.children().begin() ; + iter != req.children().end() ; + iter++) + { + if (iter->tag() == "batch") { + batch_xml = &(*iter); + break; + } + } + + if (batch_xml) { + try { + long long id; + + if (true) { + Batch batch(*batch_xml); + id = batch.id(); + + if (async) { + resp.add_child(batch.report()); + success = RRC_SUCCESS; + } + } + + if (!async) { + bool batch_done; + do { + sleep_mil(100); + Batch batch(id); + if (batch_done = batch.done()) { + resp.add_child(batch.report()); + success = RRC_SUCCESS; + } + } while (!batch_done); + } + } catch ( ... ) { + success = RRC_INTERNAL_ERROR; + } + } else + success = RRC_MISSING_BATCH; + } + } else if (function == "batch_report") { + // get report + if (!authenticated) { + success = RRC_NEED_AUTH; + } else { + long long id = utils::to_long(req.get_attr("batch_id")); + if (id == 0) + success = RRC_INVALID_BATCH_ID; + else { + try { + Batch batch(id); + resp.add_child(batch.report()); + success = RRC_SUCCESS; + } catch ( ... ) { + success = RRC_INVALID_BATCH_ID; + } + } + } + } else { + // invalid function name + success = RRC_INVALID_FUNCTION; + } + resp.set_attr("success", utils::to_string(success)); + return resp; +} Batch::Batch(const XMLObject& xml) : - _report(xml.tag()), - _state(ProcessWorker::st_sched) + _report(xml.tag()), + _state(ProcessWorker::st_sched) { - QueueLocker lock; - - // id - String path_tmp; - do { - _id = random_generator(1, 2147483647); - _path = String(QUEUE_DIR_PATH) + utils::to_string(_id); - path_tmp = _path + ".tmp"; - if (access(_path.c_str(), F_OK)) - break; - } while (true); - - // generate request - for (map::const_iterator iter = xml.attrs().begin(); - iter != xml.attrs().end(); - iter++) - _report.set_attr(iter->first, iter->second); - _report.set_attr("batch_id", utils::to_string(_id)); - _report.set_attr("status", utils::to_string(_state)); - for (list::const_iterator iter = xml.children().begin(); - iter != xml.children().end(); - iter++) { - XMLObject child(*iter); - if (iter->tag() == "module") - child.set_attr("status", utils::to_string(_state)); - _report.add_child(child); - } - - // create file - int res, fd = open(path_tmp.c_str(), - O_RDONLY|O_CREAT, - S_IRUSR|S_IWUSR|S_IRGRP); - if (fd == -1) - throw String("unable to create batch file"); - while ((res = close(fd))) - if (errno != EINTR) - throw String("unable to close batch fd"); - - // write file - FILE* file = fopen(path_tmp.c_str(), "w+"); - if (!file) - throw String("unable to open batch file"); - try { - // save request - String xml_str(generateXML(_report)); - if (fwrite(xml_str.c_str(), - xml_str.size(), - 1, - file) != 1) - throw String("unable to write batch request"); - fclose(file); - if (rename(path_tmp.c_str(), _path.c_str())) - throw String("failed to rename batch file"); - } catch ( ... ) { - fclose(file); - unlink(path_tmp.c_str()); - throw; - } - - try { - start_worker(_path); - } catch ( ... ) { - unlink(_path.c_str()); - throw; - } + QueueLocker lock; + + // id + String path_tmp; + do { + _id = random_generator(1, 2147483647); + _path = String(QUEUE_DIR_PATH) + utils::to_string(_id); + path_tmp = _path + ".tmp"; + if (access(_path.c_str(), F_OK)) + break; + } while (true); + + // generate request + for (map::const_iterator + iter = xml.attrs().begin() ; + iter != xml.attrs().end() ; + iter++) + { + _report.set_attr(iter->first, iter->second); + } + + _report.set_attr("batch_id", utils::to_string(_id)); + _report.set_attr("status", utils::to_string(_state)); + + for (list::const_iterator + iter = xml.children().begin() ; + iter != xml.children().end() ; + iter++) + { + XMLObject child(*iter); + + if (iter->tag() == "module") + child.set_attr("status", utils::to_string(_state)); + _report.add_child(child); + } + + // create file + int fd = open(path_tmp.c_str(), O_RDONLY | O_CREAT | O_EXCL, 0640); + if (fd == -1) + throw String("unable to create batch file: ") + String(strerror(errno)); + + // write file + FILE *file = fdopen(fd, "w+"); + if (!file) + throw String("unable to open batch file: ") + String(strerror(errno)); + + try { + // save request + String xml_str(generateXML(_report)); + if (fwrite(xml_str.c_str(), xml_str.size(), 1, file) != 1) { + throw String("unable to write batch request: ") + + String(strerror(errno)); + } + fclose(file); + if (rename(path_tmp.c_str(), _path.c_str())) { + throw String("failed to rename batch file: ") + + String(strerror(errno)); + } + } catch ( ... ) { + fclose(file); + unlink(path_tmp.c_str()); + throw; + } + + try { + start_worker(_path); + } catch ( ... ) { + unlink(_path.c_str()); + throw; + } } Batch::Batch(long long id) : - _id(id) + _id(id) { - QueueLocker lock; - - String batch; - - // read file - _path = String(QUEUE_DIR_PATH) + utils::to_string(_id); - FILE* file = fopen(_path.c_str(), "r"); - if (!file) - throw String("unable to open batch file, either invalid ID or access denied"); - try { - do { - char buff[1024]; - unsigned int res = fread(buff, 1, sizeof(buff), file); - batch.append(buff, res); - shred(buff, sizeof(buff)); - if (res < sizeof(buff)) { - if (ferror(file)) - throw String("unable to read batch file"); - else - break; - } - } while (true); - fclose(file); - } catch ( ... ) { - fclose(file); - throw; - } - - _report = parseXML(batch); - if (utils::to_long(_report.get_attr("batch_id")) != _id) - throw String("ID doesn't match"); - _state = utils::to_long(_report.get_attr("status")); + QueueLocker lock; + String batch; + + // read file + _path = String(QUEUE_DIR_PATH) + utils::to_string(_id); + FILE *file = fopen(_path.c_str(), "r"); + if (!file) + throw String("unable to open batch file: ") + String(strerror(errno)); + + try { + do { + char buff[4096]; + size_t res = fread(buff, 1, sizeof(buff), file); + int err = errno; + batch.append(buff, res); + shred(buff, sizeof(buff)); + + if (res < sizeof(buff)) { + if (ferror(file)) { + throw String("unable to read batch file: ") + + String(strerror(err)); + } else + break; + } + } while (true); + fclose(file); + } catch ( ... ) { + fclose(file); + throw; + } + + _report = parseXML(batch); + if (utils::to_long(_report.get_attr("batch_id")) != _id) + throw String("ID doesn't match"); + _state = utils::to_long(_report.get_attr("status")); } Batch::~Batch() { - QueueLocker lock; - if (_state != ProcessWorker::st_sched && - _state != ProcessWorker::st_prog) { - try { - File f(File::open(_path, true)); - f.shred(); - f.unlink(); - } catch ( ... ) {} - } + QueueLocker lock; + + if (_state != ProcessWorker::st_sched && + _state != ProcessWorker::st_prog) + { + try { + File f(File::open(_path, true)); + f.shred(); + f.unlink(); + } catch ( ... ) {} + } } long long Batch::id() const { - return _id; + return _id; } bool Batch::done() const { - bool done = ((_state != ProcessWorker::st_sched) && - (_state != ProcessWorker::st_prog)); - return done; + bool done = ((_state != ProcessWorker::st_sched) && + (_state != ProcessWorker::st_prog)); + return done; } -XMLObject +XMLObject Batch::report() const { - if (done()) - return _report; - - XMLObject rep = _report; - - // TODO: clean-up modules if st_sched || st_prog - - return rep; -} + if (done()) + return _report; + XMLObject rep = _report; -void -Batch::start_worker(const String& path) -{ - String out, err; - int status; - vector args; - args.push_back("-f"); - args.push_back(path); - if (utils::execute(RICCI_WORKER_PATH, - args, - out, - err, - status, - false)) - throw command_not_found_error_msg(RICCI_WORKER_PATH); - if (status) - throw String("execution of ricci-worker failed"); + // TODO: clean-up modules if st_sched || st_prog + return rep; } -void -Batch::restart_batches() +void +Batch::start_worker(const String& path) { - QueueLocker lock; - DIR* dir = opendir(QUEUE_DIR_PATH); - if (!dir) - throw String("unable to open queue directory"); - struct dirent* file_entry; - while ((file_entry = readdir(dir))) - try { - String name(file_entry->d_name); - // check name - if (name.find_first_not_of("0123456789") == name.npos) - // start worker - start_worker(String(QUEUE_DIR_PATH) + name); - } catch ( ... ) {} - closedir(dir); -} + String out, err; + int status; + vector args; + args.push_back("-f"); + args.push_back(path); + if (utils::execute(RICCI_WORKER_PATH, args, out, err, status, false)) + throw command_not_found_error_msg(RICCI_WORKER_PATH); + if (status) + throw String("execution of ricci-worker failed: " + err); +} +void +Batch::restart_batches() +{ + QueueLocker lock; + DIR *dir = opendir(QUEUE_DIR_PATH); + if (!dir) { + throw String("unable to open queue directory: ") + + String(strerror(errno)); + } + struct dirent *file_entry; + while ((file_entry = readdir(dir))) { + try { + String name(file_entry->d_name); + // check name + if (name.find_first_not_of("0123456789") == name.npos) { + // start worker + start_worker(String(QUEUE_DIR_PATH) + name); + } + } catch ( ... ) {} + } + closedir(dir); +} -pair +pair clusterinfo() { - try { - XMLObject xml(readXML("/etc/cluster/cluster.conf")); - String name = xml.get_attr("name"); - String alias = xml.get_attr("alias"); - if (utils::strip(alias).empty()) - alias = name; - return pair(name, alias); - } catch ( ... ) { - return pair("", ""); - } + try { + XMLObject xml(readXML("/etc/cluster/cluster.conf")); + String name = xml.get_attr("name"); + String alias = xml.get_attr("alias"); + + if (utils::strip(alias).empty()) + alias = name; + return pair(name, alias); + } catch ( ... ) { + return pair("", ""); + } } -String +String os_release() { - try { - return utils::strip(File::open("/etc/redhat-release")); - } catch ( ... ) { - return ""; - } + try { + return utils::strip(File::open("/etc/redhat-release")); + } catch ( ... ) { + return ""; + } } -bool +bool dom0() { - try { - String out, err; - int status; - vector args; - args.push_back("nodeinfo"); - if (utils::execute("/usr/bin/virsh", - args, - out, - err, - status, - false)) - throw command_not_found_error_msg("/usr/bin/virsh"); - if (status == 0) - return true; - } catch ( ... ) {} - - return false; + try { + String out, err; + int status; + vector args; + + args.push_back("nodeinfo"); + if (utils::execute("/usr/bin/virsh", args, out, err, status, false)) + throw command_not_found_error_msg("/usr/bin/virsh"); + if (status == 0) + return true; + } catch ( ... ) {} + + return false; } --- conga/ricci/ricci/Ricci.h 2006/08/10 22:53:09 1.8 +++ conga/ricci/ricci/Ricci.h 2007/08/30 17:07:14 1.9 @@ -1,5 +1,5 @@ /* - Copyright Red Hat, Inc. 2005 + Copyright Red Hat, Inc. 2005-2007 This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the @@ -13,7 +13,7 @@ You should have received a copy of the GNU General Public License along with this program; see the file COPYING. If not, write to the - Free Software Foundation, Inc., 675 Mass Ave, Cambridge, + Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ /* @@ -27,82 +27,64 @@ #include "DBusController.h" #include "XML.h" - -enum RicciRetCode {RRC_SUCCESS = 0, - - RRC_MISSING_VERSION = 1, - RRC_UNSUPPORTED_VERSION = 2, - - RRC_MISSING_FUNCTION = 3, - RRC_INVALID_FUNCTION = 4, - - RRC_NEED_AUTH = 5, - - RRC_INTERNAL_ERROR = 6, - - RRC_AUTH_FAIL = 10, - - RRC_MISSING_BATCH = 11, - RRC_INVALID_BATCH_ID = 12, - - RRC_MISSING_MODULE = 13, // remove - RRC_MODULE_FAILURE = 14}; // remove - +enum RicciRetCode { + RRC_SUCCESS = 0, + RRC_MISSING_VERSION = 1, + RRC_UNSUPPORTED_VERSION = 2, + RRC_MISSING_FUNCTION = 3, + RRC_INVALID_FUNCTION = 4, + RRC_NEED_AUTH = 5, + RRC_INTERNAL_ERROR = 6, + RRC_AUTH_FAIL = 10, + RRC_MISSING_BATCH = 11, + RRC_INVALID_BATCH_ID = 12, + RRC_MISSING_MODULE = 13, // remove + RRC_MODULE_FAILURE = 14 // remove +}; class Ricci { - public: - Ricci(DBusController& dbus); - virtual ~Ricci(); - - XMLObject hello(bool authed) const; - - XMLObject request(const XMLObject& req, - bool authenticated, - bool& save_cert, - bool& remove_cert, - bool& done); - - private: - DBusController& _dbus; - - int _fail_auth_attempt; - - XMLObject ricci_header(bool authed, bool full=false) const; - -}; // class Ricci + public: + Ricci(DBusController& dbus); + virtual ~Ricci(); + XMLObject hello(bool authed) const; + + XMLObject request(const XMLObject& req, + bool& authenticated, + bool& save_cert, + bool& remove_cert, + bool& done); + + private: + DBusController& _dbus; + int _fail_auth_attempt; + XMLObject ricci_header(bool authed, bool full=false) const; +}; // class Ricci class Batch { - public: - Batch(const XMLObject&); - Batch(long long id); - virtual ~Batch(); - - virtual long long id() const; - - virtual bool done() const; - - virtual XMLObject report() const; - - static void restart_batches(); // start workers on existing batch files - - private: - - XMLObject _report; - - String _path; - - long long _id; - long long _state; - - static void start_worker(const String& path); - - Batch(const Batch&); - Batch& operator=(const Batch&); - -}; // class Batch - + public: + Batch(const XMLObject&); + Batch(long long id); + + virtual ~Batch(); + virtual long long id() const; + virtual bool done() const; + virtual XMLObject report() const; + + static void restart_batches(); // start workers on existing batch files + + private: + XMLObject _report; + String _path; + long long _id; + long long _state; + + static void start_worker(const String& path); + + Batch(const Batch&); + Batch& operator=(const Batch&); +}; // class Batch -#endif // Ricci_h +#endif // Ricci_h --- conga/ricci/ricci/RicciWorker.cpp 2006/09/26 04:56:52 1.11 +++ conga/ricci/ricci/RicciWorker.cpp 2007/08/30 17:07:14 1.12 @@ -1,5 +1,5 @@ /* - Copyright Red Hat, Inc. 2005 + Copyright Red Hat, Inc. 2005-2007 This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the @@ -13,7 +13,7 @@ You should have received a copy of the GNU General Public License along with this program; see the file COPYING. If not, write to the - Free Software Foundation, Inc., 675 Mass Ave, Cambridge, + Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ /* @@ -41,378 +41,402 @@ void -usage() +usage(const char *progname) { - cout << "invalid usage" << endl; + cerr << "Usage: " << progname << " -f " << endl; } - -int -main(int argc, char** argv) +int +main(int argc, char **argv) { - if (argc != 3) { - usage(); - return 1; - } - if (String(argv[1]) != "-f") { - usage(); - return 1; - } - String path(argv[2]); - - if (daemon(0, 0)) { - cout << "daemon() failed" << endl; - return 1; - } - - try { - DBusController dbus; - BatchWorker batch(dbus, path); - batch.process(); - return 0; - } catch (String e) { - cout << "exception: " << e << endl; - } catch ( ... ) { - cout << "unknown exception" << endl; - } - return 2; -} + if (argc != 3) { + usage(argv[0]); + exit(1); + } + if (String(argv[1]) != "-f") { + usage(argv[0]); + exit(1); + } + String path(argv[2]); + if (daemon(0, 0)) { + cerr << "daemon() failed" << endl; + exit(1); + } + try { + DBusController dbus; + BatchWorker batch(dbus, path); + batch.process(); + exit(0); + } catch (String e) { + cout << "exception: " << e << endl; + } catch ( ... ) { + cout << "unknown exception" << endl; + } + exit(2); +} // ############ ProcessWorker ############## - - - -ProcessWorker::ProcessWorker(DBusController& dbus, - const XMLObject& xml, - BatchWorker& batch, - RebootModule& rm) : - _dbus(dbus), - _rm(rm), - _report(xml), - _batch(batch) -{ - String state_str = _report.get_attr("status"); - if (state_str.empty()) - _state = st_sched; - else - _state = (state) utils::to_long(state_str); +ProcessWorker::ProcessWorker( DBusController& dbus, + const XMLObject& xml, + BatchWorker& batch, + RebootModule& rm) : + _dbus(dbus), + _rm(rm), + _report(xml), + _batch(batch) +{ + String state_str = _report.get_attr("status"); + if (state_str.empty()) + _state = st_sched; + else + _state = (state) utils::to_long(state_str); } ProcessWorker::~ProcessWorker() {} -bool +bool ProcessWorker::scheduled() const { - return _state == st_sched; + return _state == st_sched; } -bool +bool ProcessWorker::in_progress() const { - return _state == st_prog; + return _state == st_prog; } -bool +bool ProcessWorker::done() const { - return _state == st_done; + return _state == st_done; } -bool +bool ProcessWorker::completed() const { - return (_state != st_sched && _state != st_prog); + return (_state != st_sched && _state != st_prog); } -bool +bool ProcessWorker::failed() const { - return _state == st_req_fail || _state == st_mod_fail; + return _state == st_req_fail || _state == st_mod_fail; } -bool +bool ProcessWorker::removed() const { - return _state == st_removed; + return _state == st_removed; } -void +void ProcessWorker::remove() { - if (_state == st_sched) - _state = st_removed; + if (_state == st_sched) + _state = st_removed; } -XMLObject +XMLObject ProcessWorker::report() const { - _report.set_attr("status", utils::to_string(_state)); - return _report; + _report.set_attr("status", utils::to_string(_state)); + return _report; } void ProcessWorker::process() { - if (completed()) - return; - else - _state = st_prog; - - if (_report.children().empty()) { - _state = st_done; - return; - } - - String module_name(_report.get_attr("name")); - - XMLObject module_header("module"); - module_header.set_attr("name", module_name); - try { - XMLObject request = _report.children().front(); - XMLObject mod_resp; - - if (module_name == "reboot") { - mod_resp = _rm.process(request); - if (_rm.block() && check_response(mod_resp)) { - if (mod_resp.tag() == "internal_error") - throw int(); - module_header.add_child(mod_resp); + if (completed()) + return; + else + _state = st_prog; + + if (_report.children().empty()) { + _state = st_done; + return; + } + + String module_name(_report.get_attr("name")); + XMLObject module_header("module"); + module_header.set_attr("name", module_name); + + try { + XMLObject request = _report.children().front(); + XMLObject mod_resp; + + if (module_name == "reboot") { + mod_resp = _rm.process(request); + if (_rm.block() && check_response(mod_resp)) { + if (mod_resp.tag() == "internal_error") + throw int(); + module_header.add_child(mod_resp); + _report = module_header; + _state = st_done; + _batch.save(); + + // sleep while the machine reboots + // ricci will start a new worker thread after the reboot + // that will pickup where it left off + select(0, NULL, NULL, NULL, NULL); + return; + } + } else { + String message = generateXML(request); + String ret = _dbus.process(message, module_name); + mod_resp = parseXML(ret); + } + + if (mod_resp.tag() == "internal_error") + throw int(); + module_header.add_child(mod_resp); + } catch ( ... ) { + _state = st_mod_fail; + return; + } + + // check status within response + bool funcs_succeeded = check_response(module_header.children().front()); + + if (funcs_succeeded) + _state = st_done; + else + _state = st_req_fail; _report = module_header; - _state = st_done; - _batch.save(); - // wait until rebooted, - // ricci will start new worker (after reboot) to pickup where I left - while (true) - sleep_sec(255); - return; - } - } else { - String message = generateXML(request); - String ret = _dbus.process(message, module_name); - mod_resp = parseXML(ret); - } - if (mod_resp.tag() == "internal_error") - throw int(); - module_header.add_child(mod_resp); - } catch ( ... ) { - _state = st_mod_fail; - return; - } - - // check status within response - bool funcs_succeeded = check_response(module_header.children().front()); - - if (funcs_succeeded) - _state = st_done; - else - _state = st_req_fail; - _report = module_header; } -bool +bool ProcessWorker::check_response(const XMLObject& resp) { - bool funcs_succeeded = true; - if (resp.tag() == "API_error") - funcs_succeeded = false; - else { - for (list::const_iterator func_iter = resp.children().begin(); - func_iter != resp.children().end(); - func_iter++) { - const XMLObject& func = *func_iter; - if (func.tag() == FUNC_RESPONSE_TAG) { - for (list::const_iterator var_iter = func.children().begin(); - var_iter != func.children().end(); - var_iter++) { - const XMLObject& var = *var_iter; - if (var.tag() == VARIABLE_TAG) - if (var.get_attr("name") == "success" && - var.get_attr("value") == "false") - funcs_succeeded = false; - } - } - } - } - return funcs_succeeded; -} - - - - + bool funcs_succeeded = true; + if (resp.tag() == "API_error") + funcs_succeeded = false; + else { + for (list::const_iterator + func_iter = resp.children().begin() ; + func_iter != resp.children().end() ; + func_iter++) + { + const XMLObject& func = *func_iter; + if (func.tag() == FUNC_RESPONSE_TAG) { + for (list::const_iterator + var_iter = func.children().begin() ; + var_iter != func.children().end() ; + var_iter++) + { + const XMLObject& var = *var_iter; + if (var.tag() == VARIABLE_TAG) { + if (var.get_attr("name") == "success" && + var.get_attr("value") == "false") + { + funcs_succeeded = false; + } + } + } + } + } + } + return funcs_succeeded; +} // ############ BatchWorker ############## - - - - - -BatchWorker::BatchWorker(DBusController& dbus, - const String& path) : - _rm(dbus), - _path(path) -{ - QueueLocker lock; - - _fd = open(_path.c_str(), O_RDONLY); - if (_fd == -1) - throw String("unable to open batch file"); - try { - // lock file - while (flock(_fd, LOCK_EX|LOCK_NB)) { - if (errno == EINTR) - continue; - else if (errno == EWOULDBLOCK) - throw String("file is in use by other worker"); - else - throw String("unable to acquire flock"); - } - - // read file - String xml_str; - char buff[1024]; - int res; - while ((res = read(_fd, buff, sizeof(buff))) != 0) { - if (res > 0) - xml_str.append(buff, res); - else - if (errno != EINTR) - throw String("failure reading batch file"); - } - shred(buff, sizeof(buff)); - - // _xml - _xml = parseXML(xml_str); - if (_xml.tag() != "batch") - throw String("not a batch file"); - String state_str = _xml.get_attr("status"); - if (state_str.empty()) - throw String("missing status attr"); - _state = (ProcessWorker::state) utils::to_long(state_str); - - // parse xml and generate subprocesses - for (list::const_iterator iter = _xml.children().begin(); - iter != _xml.children().end(); - iter++) - if (iter->tag() == "module") - _procs.push_back(counting_auto_ptr(new ProcessWorker(dbus, *iter, *this, _rm))); - } catch ( ... ) { - close_fd(_fd); - throw; - } +BatchWorker::BatchWorker(DBusController& dbus, const String& path) : + _rm(dbus), + _path(path) +{ + QueueLocker lock; + + _fd = open(_path.c_str(), O_RDONLY); + if (_fd == -1) + throw String("unable to open batch file: ") + String(strerror(errno)); + + try { + // lock file + while (flock(_fd, LOCK_EX | LOCK_NB)) { + if (errno == EINTR) + continue; + else if (errno == EWOULDBLOCK) + throw String("file is in use by other worker"); + else { + throw String("unable to acquire flock: ") + + String(strerror(errno)); + } + } + + // read file + String xml_str; + char buff[4096]; + int res; + + while ((res = read(_fd, buff, sizeof(buff))) != 0) { + if (res > 0) + xml_str.append(buff, res); + else { + if (errno != EINTR) { + throw String("failure reading batch file: ") + + String(strerror(errno)); + } + } + } + shred(buff, sizeof(buff)); + + // _xml + _xml = parseXML(xml_str); + if (_xml.tag() != "batch") + throw String("not a batch file: opening tag is ") + _xml.tag(); + + String state_str = _xml.get_attr("status"); + if (state_str.empty()) + throw String("missing status attr"); + _state = (ProcessWorker::state) utils::to_long(state_str); + + // parse xml and generate subprocesses + for (list::const_iterator + iter = _xml.children().begin() ; + iter != _xml.children().end() ; + iter++) + { + if (iter->tag() == "module") + _procs.push_back(counting_auto_ptr(new ProcessWorker(dbus, *iter, *this, _rm))); + } + } catch ( ... ) { + close_fd(_fd); + throw; + } } BatchWorker::~BatchWorker() { - QueueLocker lock; - - close_fd(_fd); -} + QueueLocker lock; + close_fd(_fd); +} void BatchWorker::close_fd(int fd) { - if (fd) - while (close(fd)) - if (errno != EINTR) - break; + if (fd >= 0) { + while (close(fd)) { + if (errno != EINTR) + break; + } + } } -void +void BatchWorker::process() { - if (_state == ProcessWorker::st_sched || _state == ProcessWorker::st_prog) - _state = ProcessWorker::st_prog; - else - return; - - // process subprocesses - for (list >::iterator iter = _procs.begin(); - iter != _procs.end(); - iter++) { - save(); - ProcessWorker& proc = **iter; - proc.process(); - if (proc.failed()) { - for (iter++; - iter != _procs.end(); - iter++) - (*iter)->remove(); - _state = ProcessWorker::st_req_fail; - save(); - return; - } - } - _state = ProcessWorker::st_done; - save(); + if (_state == ProcessWorker::st_sched || _state == ProcessWorker::st_prog) + _state = ProcessWorker::st_prog; + else + return; + + // process subprocesses + for (list >::iterator + iter = _procs.begin() ; + iter != _procs.end() ; + iter++) + { + save(); + + ProcessWorker& proc = **iter; + proc.process(); + + if (proc.failed()) { + for (iter++ ; iter != _procs.end() ; iter++) + (*iter)->remove(); + _state = ProcessWorker::st_req_fail; + save(); + return; + } + } + + _state = ProcessWorker::st_done; + save(); } -XMLObject +XMLObject BatchWorker::report() const { - XMLObject result(_xml.tag()); - for (map::const_iterator iter = _xml.attrs().begin(); - iter != _xml.attrs().end(); - iter++) - result.set_attr(iter->first, iter->second); - for (list >::const_iterator iter = _procs.begin(); - iter != _procs.end(); - iter++) - result.add_child((*iter)->report()); - result.set_attr("status", utils::to_string(_state)); - return result; + XMLObject result(_xml.tag()); + + for (map::const_iterator + iter = _xml.attrs().begin() ; + iter != _xml.attrs().end() ; + iter++) + { + result.set_attr(iter->first, iter->second); + } + + for (list >::const_iterator + iter = _procs.begin() ; + iter != _procs.end() ; + iter++) + { + result.add_child((*iter)->report()); + } + + result.set_attr("status", utils::to_string(_state)); + return result; } void BatchWorker::save() { - QueueLocker lock; - - String path_tmp(_path + ".tmp"); - int fd_tmp = open(path_tmp.c_str(), - O_WRONLY|O_CREAT, - S_IRUSR|S_IWUSR|S_IRGRP); - if (fd_tmp == -1) - throw String("unable to create tmp batch file"); - - try { - // lock path_tmp - while (flock(fd_tmp, LOCK_EX)) - if (errno != EINTR) - throw String("unable to lock the tmp batch file"); - - // write to tmp file - String out(generateXML(report())); - do { - int res = write(fd_tmp, out.c_str(), out.size()); - if (res == -1) { - if (errno != EINTR) - throw String("unable to write batch file"); - } else - out = out.substr(res); - } while (out.size()); - - // rename path_tmp to _path - if (rename(path_tmp.c_str(), _path.c_str())) - throw String("unable to rename batch file"); - - // close _fd, and replace it with fd_tmp - close_fd(_fd); - _fd = fd_tmp; - } catch ( ... ) { - close_fd(fd_tmp); - unlink(path_tmp.c_str()); - throw; - } + QueueLocker lock; + + String path_tmp(_path + ".tmp"); + int fd_tmp = open(path_tmp.c_str(), O_WRONLY | O_CREAT | O_EXCL, 0640); + if (fd_tmp == -1) { + throw String("unable to create tmp batch file: ") + + String(strerror(errno)); + } + + try { + // lock path_tmp + while (flock(fd_tmp, LOCK_EX)) { + if (errno != EINTR) { + throw String("unable to lock the tmp batch file: ") + + String(strerror(errno)); + } + } + + // write to tmp file + String out(generateXML(report())); + do { + int res = write(fd_tmp, out.c_str(), out.size()); + if (res == -1) { + if (errno != EINTR) { + throw String("unable to write batch file: ") + + String(strerror(errno)); + } + } else + out = out.substr(res); + } while (out.size()); + + // rename path_tmp to _path + if (rename(path_tmp.c_str(), _path.c_str())) { + throw String("unable to rename batch file: ") + + String(strerror(errno)); + } + + // close _fd, and replace it with fd_tmp + close_fd(_fd); + _fd = fd_tmp; + } catch ( ... ) { + close_fd(fd_tmp); + unlink(path_tmp.c_str()); + throw; + } } --- conga/ricci/ricci/RicciWorker.h 2006/08/10 22:53:09 1.6 +++ conga/ricci/ricci/RicciWorker.h 2007/08/30 17:07:14 1.7 @@ -1,5 +1,5 @@ /* - Copyright Red Hat, Inc. 2005 + Copyright Red Hat, Inc. 2005-2007 This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the @@ -13,7 +13,7 @@ You should have received a copy of the GNU General Public License along with this program; see the file COPYING. If not, write to the - Free Software Foundation, Inc., 675 Mass Ave, Cambridge, + Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ /* @@ -35,86 +35,73 @@ class ProcessWorker { - public: - ProcessWorker(DBusController& dbus, - const XMLObject&, - BatchWorker& batch, - RebootModule& rm); - virtual ~ProcessWorker(); - - virtual bool done() const; - virtual bool completed() const; - virtual bool scheduled() const; - virtual bool in_progress() const; - virtual bool failed() const; - virtual bool removed() const; - virtual void remove(); - - virtual XMLObject report() const; - - virtual void process(); - - - enum state {st_done = 0, // completed successfully - st_sched = 1, // scheduled - st_prog = 2, // in progress - st_mod_fail = 3, // module failure - st_req_fail = 4, // request failure, module succeeded - st_removed = 5}; // removed from scheduler - - - protected: - - DBusController& _dbus; - RebootModule& _rm; - - mutable XMLObject _report; - - state _state; - - BatchWorker& _batch; - - private: - bool check_response(const XMLObject& resp); - - ProcessWorker(const ProcessWorker&); - ProcessWorker& operator=(const ProcessWorker&); - -}; + public: + ProcessWorker( DBusController& dbus, + const XMLObject&, + BatchWorker& batch, + RebootModule& rm); + virtual ~ProcessWorker(); + + virtual bool done() const; + virtual bool completed() const; + virtual bool scheduled() const; + virtual bool in_progress() const; + virtual bool failed() const; + virtual bool removed() const; + virtual void remove(); + + virtual XMLObject report() const; + + virtual void process(); + + enum state { + st_done = 0, // completed successfully + st_sched = 1, // scheduled + st_prog = 2, // in progress + st_mod_fail = 3, // module failure + st_req_fail = 4, // request failure, module succeeded + st_removed = 5 // removed from scheduler + }; + + protected: + DBusController& _dbus; + RebootModule& _rm; + mutable XMLObject _report; + state _state; + BatchWorker& _batch; + private: + bool check_response(const XMLObject& resp); + ProcessWorker(const ProcessWorker&); + ProcessWorker& operator=(const ProcessWorker&); +}; class BatchWorker { - public: - BatchWorker(DBusController& dbus, - const String& path); - virtual ~BatchWorker(); - - virtual XMLObject report() const; - - virtual void process(); - - private: - - RebootModule _rm; - - std::list > _procs; - - XMLObject _xml; - ProcessWorker::state _state; - String _path; - - int _fd; - void close_fd(int fd); - void save(); - - BatchWorker(const BatchWorker&); - BatchWorker& operator=(const BatchWorker&); - - friend class ProcessWorker; - -}; + public: + BatchWorker(DBusController& dbus, const String& path); + virtual ~BatchWorker(); + + virtual XMLObject report() const; + virtual void process(); + + private: + RebootModule _rm; + std::list > _procs; + XMLObject _xml; + ProcessWorker::state _state; + String _path; + + int _fd; + void close_fd(int fd); + void save(); + + BatchWorker(const BatchWorker&); + BatchWorker& operator=(const BatchWorker&); + + friend class ProcessWorker; +}; -#endif // RicciWorker_h +#endif // RicciWorker_h --- conga/ricci/ricci/SSLInstance.cpp 2007/06/25 16:03:44 1.8 +++ conga/ricci/ricci/SSLInstance.cpp 2007/08/30 17:07:14 1.9 @@ -13,7 +13,7 @@ You should have received a copy of the GNU General Public License along with this program; see the file COPYING. If not, write to the - Free Software Foundation, Inc., 675 Mass Ave, Cambridge, + Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ /* @@ -51,426 +51,453 @@ class file_cert { -public: - file_cert(const String& file, const String& cert) : - file(file), - cert(cert) {} - - String file; - String cert; -}; -static list authorized_certs; - + public: + file_cert(const String& file, const String& cert) : + file(file), + cert(cert) {} + String file; + String cert; +}; +static list authorized_certs; -static int +static int verify_cert_callback(int preverify_ok, X509_STORE_CTX *ctx) { - return 1; + return 1; } -static void + +static void load_client_certs() { - MutexLocker l(global_lock); - - // load authorized CAs - if (!SSL_CTX_load_verify_locations(ctx, CLIENT_AUTH_CAs_PATH, NULL)) - cout << "failed to load authorized CAs" << endl; - - STACK_OF(X509_NAME) *cert_names = - SSL_load_client_CA_file(CLIENT_AUTH_CAs_PATH); - if (cert_names) - SSL_CTX_set_client_CA_list(ctx, cert_names); - else - cout << "failed to load authorized CAs" << endl; - - // load saved certs - - set files; - String dir_path(CLIENT_CERTS_DIR_PATH); - DIR* d = opendir(dir_path.c_str()); - if (d == NULL) - throw String("unable to open directory ") + dir_path; - try { - while (true) { - struct dirent* ent = readdir(d); - if (ent == NULL) { - closedir(d); - break; - } - String kid_path = ent->d_name; - if (kid_path == "." || kid_path == "..") - continue; - kid_path = dir_path + "/" + kid_path; - struct stat st; - if (stat(kid_path.c_str(), &st)) - continue; - if (S_ISREG(st.st_mode)) - files.insert(kid_path); - } - } catch ( ... ) { - closedir(d); - throw; - } - - authorized_certs.clear(); - - for (set::const_iterator iter = files.begin(); - iter != files.end(); - iter++) { - try { - String cert(File::open(*iter).read()); - if (cert.size() && cert.size() < 10 * 1024) - authorized_certs.push_back(file_cert(*iter, cert)); - } catch ( ... ) {} - } -} -static void -ssl_mutex_callback(int mode, - int n, - const char *file, - int line) -{ - if (mode & CRYPTO_LOCK) - ssl_locks[n]->lock(); - else - ssl_locks[n]->unlock(); + MutexLocker l(global_lock); + + // load authorized CAs + if (!SSL_CTX_load_verify_locations(ctx, CLIENT_AUTH_CAs_PATH, NULL)) + cerr << "failed to load authorized CAs" << endl; + + STACK_OF(X509_NAME) *cert_names = + SSL_load_client_CA_file(CLIENT_AUTH_CAs_PATH); + + if (cert_names) + SSL_CTX_set_client_CA_list(ctx, cert_names); + else + cerr << "failed to load authorized CAs" << endl; + + // load saved certs + + set files; + String dir_path(CLIENT_CERTS_DIR_PATH); + DIR* d = opendir(dir_path.c_str()); + if (d == NULL) + throw String("unable to open directory ") + dir_path; + try { + while (true) { + struct dirent* ent = readdir(d); + if (ent == NULL) { + closedir(d); + break; + } + + String kid_path = ent->d_name; + if (kid_path == "." || kid_path == "..") + continue; + kid_path = dir_path + "/" + kid_path; + + struct stat st; + if (stat(kid_path.c_str(), &st)) + continue; + if (S_ISREG(st.st_mode)) + files.insert(kid_path); + } + } catch ( ... ) { + closedir(d); + throw; + } + + authorized_certs.clear(); + + for (set::const_iterator + iter = files.begin() ; + iter != files.end() ; + iter++) + { + try { + String cert(File::open(*iter).read()); + if (cert.size() && cert.size() < 10 * 1024) + authorized_certs.push_back(file_cert(*iter, cert)); + } catch ( ... ) {} + } } + +static void +ssl_mutex_callback(int mode, int n, const char *file, int line) +{ + if (mode & CRYPTO_LOCK) + ssl_locks[n]->lock(); + else + ssl_locks[n]->unlock(); +} + static pthread_t ssl_id_callback(void) { - return pthread_self(); + return pthread_self(); } - - - // ##### class SSLInstance ##### SSLInstance::SSLInstance(ClientSocket sock) : - _sock(sock), - _accepted(false) + _sock(sock), + _accepted(false) { - { - MutexLocker l(global_lock); - if (!ssl_inited) { - // init library - - SSL_library_init(); - // TODO: random number generator, - // not on systems with /dev/urandom (eg. Linux) - - // thread support - ssl_locks.clear(); - for (int i=0; i(new Mutex())); - CRYPTO_set_locking_callback(ssl_mutex_callback); - CRYPTO_set_id_callback(ssl_id_callback); - - // create context - if (!ctx) - ctx = SSL_CTX_new(SSLv23_server_method()); - if (!ctx) - throw String("SSL context creation failed"); - // set verify_callback() function - SSL_CTX_set_verify(ctx, - SSL_VERIFY_PEER|SSL_VERIFY_CLIENT_ONCE, - verify_cert_callback); - // set mode - SSL_CTX_set_mode(ctx, SSL_MODE_ENABLE_PARTIAL_WRITE); - SSL_CTX_set_mode(ctx, SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER); - - // load key - if (!SSL_CTX_use_PrivateKey_file(ctx, - SERVER_KEY_PATH, - SSL_FILETYPE_PEM)) - throw String("error importing server's cert key file"); - // load server cert - if (!SSL_CTX_use_certificate_file(ctx, - SERVER_CERT_PATH, - SSL_FILETYPE_PEM)) - throw String("error importing server's cert file"); - // load client certs - load_client_certs(); - - ssl_inited = true; - } - - // create SSL object, giving it context - _ssl = SSL_new(ctx); - if (!_ssl) - throw String("creation of ssl object failed"); - } - - // make socket non-blocking - try { - _sock.nonblocking(true); - } catch ( ... ) { - SSL_free(_ssl); - throw; - } - - // assign fd to _ssl - if (!SSL_set_fd(_ssl, _sock.get_sock())) { - SSL_free(_ssl); - throw String("fd assignment to ssl_obj failed"); - } + { + MutexLocker l(global_lock); + if (!ssl_inited) { + // init library + + SSL_library_init(); + // TODO: random number generator, + // not on systems with /dev/urandom (eg. Linux) + + // thread support + ssl_locks.clear(); + for (int i = 0; i < CRYPTO_num_locks() + 1 ; i++) + ssl_locks.push_back(counting_auto_ptr(new Mutex())); + + CRYPTO_set_locking_callback(ssl_mutex_callback); + CRYPTO_set_id_callback(ssl_id_callback); + + // create context + if (!ctx) + ctx = SSL_CTX_new(SSLv23_server_method()); + if (!ctx) + throw String("SSL context creation failed"); + + // set verify_callback() function + SSL_CTX_set_verify(ctx, + SSL_VERIFY_PEER | SSL_VERIFY_CLIENT_ONCE, + verify_cert_callback); + + // set mode + SSL_CTX_set_mode(ctx, SSL_MODE_ENABLE_PARTIAL_WRITE); + SSL_CTX_set_mode(ctx, SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER); + + // load key + if (!SSL_CTX_use_PrivateKey_file(ctx, + SERVER_KEY_PATH, SSL_FILETYPE_PEM)) + { + throw String("error importing server's cert key file"); + } + + // load server cert + if (!SSL_CTX_use_certificate_file(ctx, + SERVER_CERT_PATH, SSL_FILETYPE_PEM)) + { + throw String("error importing server's cert file"); + } + + // load client certs + load_client_certs(); + + ssl_inited = true; + } + + // create SSL object, giving it context + _ssl = SSL_new(ctx); + if (!_ssl) + throw String("creation of ssl object failed"); + } + + // make socket non-blocking + try { + _sock.nonblocking(true); + } catch ( ... ) { + SSL_free(_ssl); + throw; + } + + // assign fd to _ssl + if (!SSL_set_fd(_ssl, _sock.get_sock())) { + SSL_free(_ssl); + throw String("fd assignment to ssl_obj failed"); + } } SSLInstance::~SSLInstance() { - SSL_shutdown(_ssl); - SSL_free(_ssl); + SSL_shutdown(_ssl); + SSL_free(_ssl); } - -bool +bool SSLInstance::accept(unsigned int timeout) { - if (_accepted) - return _accepted; - - unsigned int beg = time_mil(); - while (time_mil() < beg + timeout) { - int ret = SSL_accept(_ssl); - if (ret == 1) { - _accepted = true; - break; - } else { - bool want_read, want_write; - check_error(ret, want_read, want_write); - socket().ready(want_read, want_write, 250); - } - } - - return _accepted; -} - -String -SSLInstance::send(const String& msg, - unsigned int timeout) -{ - if (!_accepted) - throw String("cannot send, yet: SSL connection not accepted"); - - if (msg.empty()) - return msg; - - unsigned int beg = time_mil(); - while (time_mil() < beg + timeout) { - int ret = SSL_write(_ssl, msg.c_str(), msg.size()); - if (ret > 0) { - return msg.substr(ret); - } else { - bool want_read, want_write; - check_error(ret, want_read, want_write); - socket().ready(want_read, want_write, 250); - } - } - - return msg; + if (_accepted) + return _accepted; + + unsigned int beg = time_mil(); + while (time_mil() < beg + timeout) { + int ret = SSL_accept(_ssl); + if (ret == 1) { + _accepted = true; + break; + } else { + bool want_read, want_write; + check_error(ret, want_read, want_write); + socket().ready(want_read, want_write, 250); + } + } + + return _accepted; +} + +String +SSLInstance::send(const String& msg, unsigned int timeout) +{ + if (!_accepted) + throw String("cannot send, yet: SSL connection not accepted"); + + if (msg.empty()) + return msg; + + unsigned int beg = time_mil(); + while (time_mil() < beg + timeout) { + int ret = SSL_write(_ssl, msg.c_str(), msg.size()); + if (ret > 0) { + return msg.substr(ret); + } else { + bool want_read, want_write; + check_error(ret, want_read, want_write); + socket().ready(want_read, want_write, 250); + } + } + + return msg; } -String +String SSLInstance::recv(unsigned int timeout) { - if (!_accepted) - throw String("cannot receive, yet: SSL connection not accepted"); - - char buff[4096]; - - unsigned int beg = time_mil(); - while (time_mil() < beg + timeout) { - int ret = SSL_read(_ssl, buff, sizeof(buff)); - if (ret > 0) { - String data(buff, ret); - shred(buff, sizeof(buff)); - return data; - } else { - bool want_read, want_write; - check_error(ret, want_read, want_write); - socket().ready(want_read, want_write, 250); - } - } - - return ""; + if (!_accepted) + throw String("cannot receive, yet: SSL connection not accepted"); + + char buff[4096]; + unsigned int beg = time_mil(); + while (time_mil() < beg + timeout) { + int ret = SSL_read(_ssl, buff, sizeof(buff)); + if (ret > 0) { + String data(buff, ret); + shred(buff, sizeof(buff)); + return data; + } else { + bool want_read, want_write; + check_error(ret, want_read, want_write); + socket().ready(want_read, want_write, 250); + } + } + + return ""; } -bool +bool SSLInstance::client_has_cert() { - if (!_accepted) - throw String("cannot determine if client has certificate: SSL connection not accepted"); - - if (_cert_pem.size()) - return true; - - X509* cert = SSL_get_peer_certificate(_ssl); - if (!cert) - return false; - - // load cert into _cert_pem - FILE* f = NULL; - try { - if (!(f = tmpfile())) - throw String("unable to open temp file"); - if (!PEM_write_X509(f, cert)) - throw String("unable to write cert to tmp file"); - X509_free(cert); cert = NULL; - - // read cert - rewind(f); - while (true) { - char buff[1024]; - size_t i = fread(buff, sizeof(char), sizeof(buff), f); - _cert_pem.append(buff, i); - if (i == 0) { - if (feof(f)) - break; - else - throw String("error while reading certificate from temp file"); - } - } - fclose(f); f = NULL; - } catch ( ... ) { - if (cert) - X509_free(cert); - if (f) - fclose(f); - _cert_pem.clear(); - throw; - } - - return true; + if (!_accepted) + throw String("cannot determine if client has certificate: SSL connection not accepted"); + + if (_cert_pem.size()) + return true; + + X509 *cert = SSL_get_peer_certificate(_ssl); + if (!cert) + return false; + + // load cert into _cert_pem + FILE* f = NULL; + try { + if (!(f = tmpfile())) + throw String("unable to open temp file"); + + if (!PEM_write_X509(f, cert)) + throw String("unable to write cert to tmp file"); + X509_free(cert); + cert = NULL; + + // read cert + rewind(f); + + while (true) { + /* + ** By default, certificate files are usually about 1400 bytes long. + */ + char buff[2048]; + + size_t i = fread(buff, sizeof(char), sizeof(buff), f); + _cert_pem.append(buff, i); + if (i == 0) { + if (feof(f)) + break; + else + throw String("error while reading certificate from temp file"); + } + } + fclose(f); + f = NULL; + } catch ( ... ) { + if (cert) + X509_free(cert); + + if (f) + fclose(f); + _cert_pem.clear(); + throw; + } + + return true; } -bool +bool SSLInstance::client_cert_authed() { - // signed by authorized CAs? - X509* cert = SSL_get_peer_certificate(_ssl); - if (!cert) - return false; - X509_free(cert); - if (SSL_get_verify_result(_ssl) == X509_V_OK) - return true; - - // cert present among saved certs? - client_has_cert(); // make sure cert is saved in _cert_pem - MutexLocker l(global_lock); - for (list::const_iterator iter = authorized_certs.begin(); - iter != authorized_certs.end(); - iter++) - if (iter->cert == _cert_pem) - return true; - return false; + // signed by authorized CAs? + X509* cert = SSL_get_peer_certificate(_ssl); + if (!cert) + return false; + + X509_free(cert); + if (SSL_get_verify_result(_ssl) == X509_V_OK) + return true; + + // cert present among saved certs? + client_has_cert(); // make sure cert is saved in _cert_pem + MutexLocker l(global_lock); + for (list::const_iterator + iter = authorized_certs.begin() ; + iter != authorized_certs.end() ; + iter++) + { + if (iter->cert == _cert_pem) + return true; + } + + return false; } -bool +bool SSLInstance::save_client_cert() { - MutexLocker l(global_lock); - - if (!client_has_cert()) - throw String("client did not present cert"); - - String f_name(CLIENT_CERTS_DIR_PATH); - f_name += "/client_cert_XXXXXX"; - int fd = -1; - char* buff = new char[f_name.size() + 1]; - try { - // pick a filename - strcpy(buff, f_name.c_str()); - if ((fd = mkstemp(buff)) == -1) - throw String("unable to generate random file"); - f_name = buff; - delete[] buff; buff = 0; - - String data(_cert_pem); - while (data.size()) { - ssize_t i = write(fd, data.c_str(), data.size()); - if (i == -1) { - if (errno != EINTR) - throw String("error writing certificate"); - } else - data = data.substr(i); - } - while (close(fd) && errno == EINTR) - ; - } catch ( ... ) { - delete[] buff; - if (fd != -1) - while (close(fd) && errno == EINTR) - ; - unlink(f_name.c_str()); - return false; - } - - load_client_certs(); - - return true; + MutexLocker l(global_lock); + + if (!client_has_cert()) + throw String("client did not present cert"); + + String f_name(CLIENT_CERTS_DIR_PATH); + f_name += "/client_cert_XXXXXX"; + + int fd = -1; + char* buff = new char[f_name.size() + 1]; + + try { + // pick a filename + strcpy(buff, f_name.c_str()); + if ((fd = mkstemp(buff)) == -1) + throw String("unable to generate random file"); + f_name = buff; + + delete[] buff; + buff = NULL; + + String data(_cert_pem); + while (data.size()) { + ssize_t i = write(fd, data.c_str(), data.size()); + if (i == -1) { + if (errno != EINTR) + throw String("error writing certificate"); + } else + data = data.substr(i); + } + while (close(fd) && errno == EINTR) + ; + } catch ( ... ) { + if (buff) + delete[] buff; + + if (fd != -1) { + while (close(fd) && errno == EINTR) + ; + } + unlink(f_name.c_str()); + return false; + } + + load_client_certs(); + return true; } -bool +bool SSLInstance::remove_client_cert() { - MutexLocker l(global_lock); - - if (!client_has_cert()) - throw String("client did not present cert"); - - for (list::const_iterator iter = authorized_certs.begin(); - iter != authorized_certs.end(); - iter++) - if (iter->cert == _cert_pem) - unlink(iter->file.c_str()); - - load_client_certs(); - return true; + MutexLocker l(global_lock); + + if (!client_has_cert()) + throw String("client did not present cert"); + + for (list::const_iterator + iter = authorized_certs.begin() ; + iter != authorized_certs.end() ; + iter++) + { + if (iter->cert == _cert_pem) + unlink(iter->file.c_str()); + } + + load_client_certs(); + return true; } ClientSocket& SSLInstance::socket() { - return _sock; + return _sock; } void SSLInstance::check_error(int value, bool& want_read, bool& want_write) { - want_read = want_write = false; - - String e; - switch (SSL_get_error(_ssl, value)) { - case SSL_ERROR_NONE: - e = "SSL_ERROR_NONE"; - break; - case SSL_ERROR_ZERO_RETURN: - e = "SSL_ERROR_ZERO_RETURN"; - break; - case SSL_ERROR_WANT_READ: - want_read = true; - return; - case SSL_ERROR_WANT_WRITE: - want_write = true; - return; - case SSL_ERROR_WANT_CONNECT: - e = "SSL_ERROR_WANT_CONNECT"; - break; - case SSL_ERROR_WANT_ACCEPT: - e = "SSL_ERROR_WANT_ACCEPT"; - break; - case SSL_ERROR_WANT_X509_LOOKUP: - e = "SSL_ERROR_WANT_X509_LOOKUP"; - break; - case SSL_ERROR_SYSCALL: - e = "SSL_ERROR_SYSCALL"; - break; - case SSL_ERROR_SSL: - e = "SSL_ERROR_SSL"; - break; - } - throw String("SSL_read() error: ") + e; + want_read = want_write = false; + + String e; + switch (SSL_get_error(_ssl, value)) { + case SSL_ERROR_NONE: + e = "SSL_ERROR_NONE"; + break; + case SSL_ERROR_ZERO_RETURN: + e = "SSL_ERROR_ZERO_RETURN"; + break; + case SSL_ERROR_WANT_READ: + want_read = true; + return; + case SSL_ERROR_WANT_WRITE: + want_write = true; + return; + case SSL_ERROR_WANT_CONNECT: + e = "SSL_ERROR_WANT_CONNECT"; + break; + case SSL_ERROR_WANT_ACCEPT: + e = "SSL_ERROR_WANT_ACCEPT"; + break; + case SSL_ERROR_WANT_X509_LOOKUP: + e = "SSL_ERROR_WANT_X509_LOOKUP"; + break; + case SSL_ERROR_SYSCALL: + e = "SSL_ERROR_SYSCALL"; + break; + case SSL_ERROR_SSL: + e = "SSL_ERROR_SSL"; + break; + } + throw String("SSL_read() error: ") + e; } --- conga/ricci/ricci/SSLInstance.h 2006/08/10 22:53:09 1.5 +++ conga/ricci/ricci/SSLInstance.h 2007/08/30 17:07:14 1.6 @@ -1,5 +1,5 @@ /* - Copyright Red Hat, Inc. 2005 + Copyright Red Hat, Inc. 2005-2007 This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the @@ -13,7 +13,7 @@ You should have received a copy of the GNU General Public License along with this program; see the file COPYING. If not, write to the - Free Software Foundation, Inc., 675 Mass Ave, Cambridge, + Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ /* @@ -35,38 +35,35 @@ class SSLInstance { - public: - SSLInstance(ClientSocket sock); - virtual ~SSLInstance(); - - bool accept(unsigned int timeout); - - String send(const String& msg, unsigned int timeout); - String recv(unsigned int timeout); - - - bool client_has_cert(); - bool client_cert_authed(); // return true if peer's cert authenticated (either thru CA chain, or cert present) - - bool save_client_cert(); - bool remove_client_cert(); - - ClientSocket& socket(); - - private: - SSLInstance(const SSLInstance&); - SSLInstance operator=(const SSLInstance&); - - ClientSocket _sock; - SSL* _ssl; - String _cert_pem; - - bool _accepted; - - void check_error(int value, bool& want_read, bool& want_write); - - -}; // class SSLInstance + public: + SSLInstance(ClientSocket sock); + virtual ~SSLInstance(); + bool accept(unsigned int timeout); -#endif // SSLInstance_h + String send(const String& msg, unsigned int timeout); + String recv(unsigned int timeout); + + // return true if peer's cert authenticated + // (either thru CA chain, or cert present) + bool client_cert_authed(); + + bool client_has_cert(); + bool save_client_cert(); + bool remove_client_cert(); + + ClientSocket& socket(); + + private: + SSLInstance(const SSLInstance&); + SSLInstance operator=(const SSLInstance&); + + ClientSocket _sock; + SSL *_ssl; + String _cert_pem; + + bool _accepted; + void check_error(int value, bool& want_read, bool& want_write); +}; // class SSLInstance + +#endif // SSLInstance_h --- conga/ricci/ricci/Server.cpp 2007/08/21 21:26:49 1.6 +++ conga/ricci/ricci/Server.cpp 2007/08/30 17:07:14 1.7 @@ -1,5 +1,5 @@ /* - Copyright Red Hat, Inc. 2005 + Copyright Red Hat, Inc. 2005-2007 This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the @@ -13,7 +13,7 @@ You should have received a copy of the GNU General Public License along with this program; see the file COPYING. If not, write to the - Free Software Foundation, Inc., 675 Mass Ave, Cambridge, + Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ /* @@ -43,102 +43,100 @@ #include #include - using namespace std; - - static time_t last_purge = 0; static bool shutdown_pending = false; static void shutdown(int); - - - - Server::Server(const ServerSocket& serv_sock) : - _server(serv_sock) + _server(serv_sock) { - _server.nonblocking(true); + _server.nonblocking(true); } Server::~Server() {} - -void +void Server::run() { - // restart unfinished jobs - Batch::restart_batches(); - - // handle clients - list > clients; - - setup_signal(SIGINT, shutdown); - setup_signal(SIGTERM, shutdown); - setup_signal(SIGPIPE, SIG_IGN); - unblock_signal(SIGSEGV); - - while (!shutdown_pending) { - poll_fd poll_data; - poll_data.fd = _server.get_sock(); - poll_data.events = POLLIN; - poll_data.revents = 0; - - // wait for events - int ret = poll(&poll_data, 1, 1000); - time_t cur_time = time(NULL); - if (ret == 0 || cur_time - last_purge >= 2) { - last_purge = cur_time; - // clean up clients - list >::iterator> remove_us; - for (list >::iterator iter = clients.begin(); - iter != clients.end(); - iter++) - if ((*iter)->done()) - remove_us.push_back(iter); - for (list >::iterator>::iterator - iter = remove_us.begin(); - iter != remove_us.end(); - iter++) { - clients.erase(*iter); - cout << "client removed" << endl; - } - } - - if (ret == 0) { - // continue waiting - continue; - } else if (ret == -1) { - if (errno == EINTR) - continue; - else - throw String("poll() error: " + String(strerror(errno))); - } - - // process events - if (poll_data.revents & POLLIN) { - try { - ClientSocket sock = _server.accept(); - counting_auto_ptr - client(new ClientInstance(sock, _dbus_controller)); - client->start(); - clients.push_back(client); - cout << "client added" << endl; - } catch ( String e ) { - cout << "exception: " << e << endl; - } catch ( ... ) {} - } - if (poll_data.revents & (POLLERR | POLLHUP | POLLNVAL)) - throw String("server socket error????"); - - } // while -} + // restart unfinished jobs + Batch::restart_batches(); + + // handle clients + list > clients; + setup_signal(SIGINT, shutdown); + setup_signal(SIGTERM, shutdown); + setup_signal(SIGPIPE, SIG_IGN); + unblock_signal(SIGSEGV); + + while (!shutdown_pending) { + poll_fd poll_data; + poll_data.fd = _server.get_sock(); + poll_data.events = POLLIN; + poll_data.revents = 0; + + // wait for events + int ret = poll(&poll_data, 1, 1000); + time_t cur_time = time(NULL); + + if (ret == 0 || cur_time - last_purge >= 2) { + last_purge = cur_time; + // clean up clients + + list >::iterator> remove_us; + for (list >::iterator + iter = clients.begin() ; + iter != clients.end() ; + iter++) + { + if ((*iter)->done()) + remove_us.push_back(iter); + } + + for (list >::iterator>::iterator + iter = remove_us.begin() ; + iter != remove_us.end() ; + iter++) + { + clients.erase(*iter); + cerr << "client removed" << endl; + } + } + + if (ret == 0) { + // continue waiting + continue; + } else if (ret == -1) { + if (errno == EINTR) + continue; + else + throw String("poll() error: " + String(strerror(errno))); + } + + // process events + if (poll_data.revents & POLLIN) { + try { + ClientSocket sock = _server.accept(); + counting_auto_ptr client(new ClientInstance(sock, _dbus_controller)); + + client->start(); + clients.push_back(client); + cerr << "client added" << endl; + } catch ( String e ) { + cerr << "exception: " << e << endl; + } catch ( ... ) {} + } + + if (poll_data.revents & (POLLERR | POLLHUP | POLLNVAL)) + throw String("server socket error????"); + } // while +} void shutdown(int) { - shutdown_pending = true; + shutdown_pending = true; } --- conga/ricci/ricci/Server.h 2006/04/03 14:45:41 1.2 +++ conga/ricci/ricci/Server.h 2007/08/30 17:07:14 1.3 @@ -1,5 +1,5 @@ /* - Copyright Red Hat, Inc. 2005 + Copyright Red Hat, Inc. 2005-2007 This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the @@ -13,7 +13,7 @@ You should have received a copy of the GNU General Public License along with this program; see the file COPYING. If not, write to the - Free Software Foundation, Inc., 675 Mass Ave, Cambridge, + Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ /* @@ -27,20 +27,17 @@ #include "Socket.h" #include "DBusController.h" - class Server { - public: - Server(const ServerSocket& serv_sock); - virtual ~Server(); - - void run(); - - private: - ServerSocket _server; - DBusController _dbus_controller; - + public: + Server(const ServerSocket& serv_sock); + virtual ~Server(); + + void run(); + + private: + ServerSocket _server; + DBusController _dbus_controller; }; - -#endif // Server_h +#endif // Server_h --- conga/ricci/ricci/dbus_test.cpp 2006/08/10 22:53:09 1.4 +++ conga/ricci/ricci/dbus_test.cpp 2007/08/30 17:07:14 1.5 @@ -10,27 +10,27 @@ int main(int argc, char **argv) { - DBusConnection* conn = dbus_bus_get(DBUS_BUS_SYSTEM, + DBusConnection* conn = dbus_bus_get(DBUS_BUS_SYSTEM, NULL); - + DBusMessage* msg = dbus_message_new_method_call("com.redhat.ricci", - "/com/redhat/ricci", - "com.redhat.ricci", + "/com/redhat/ricci", + "com.redhat.ricci", "modlog_rw"); - + cout << "max msg size: " << dbus_connection_get_max_message_size(conn) << endl; - + // construct xml request String xml = ""; xml += ""; xml += ""; xml += ""; xml += ""; - + dbus_message_append_args(msg, DBUS_TYPE_STRING, xml.c_str(), DBUS_TYPE_INVALID); - + DBusError error; dbus_error_init (&error); DBusMessage *resp = dbus_connection_send_with_reply_and_block(conn, @@ -38,24 +38,24 @@ 100000, &error); dbus_message_unref(msg); - + if (resp) { int status; char* out; char* err; dbus_message_get_args(resp, NULL, - DBUS_TYPE_INT32, &status, - DBUS_TYPE_STRING, &out, + DBUS_TYPE_INT32, &status, + DBUS_TYPE_STRING, &out, DBUS_TYPE_STRING, &err); - + cout << "status: " << status << endl; cout << "out: " << out << endl; cout << "out size: " << String(out).size() << endl; cout << "err: " << err << endl; - + dbus_message_unref(resp); - } else + } else cout << "error: " << error.message << endl; - + } --- conga/ricci/ricci/main.cpp 2006/08/10 22:53:09 1.4 +++ conga/ricci/ricci/main.cpp 2007/08/30 17:07:14 1.5 @@ -1,5 +1,5 @@ /* - Copyright Red Hat, Inc. 2005 + Copyright Red Hat, Inc. 2005-2007 This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the @@ -13,7 +13,7 @@ You should have received a copy of the GNU General Public License along with this program; see the file COPYING. If not, write to the - Free Software Foundation, Inc., 675 Mass Ave, Cambridge, + Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ /* @@ -24,64 +24,104 @@ #include "Server.h" #include "ricci_defines.h" -#include +#include #include +#include +#include +#include + extern "C" { - void daemon_init(char *prog); + void daemon_init(char *prog); } - - #include using namespace std; +bool foreground = false; +bool debug = false; +bool advertise_cluster = false; int main(int argc, char** argv) { - bool foreground=false, debug=false; - unsigned int uid = 0; - - int rv; - while ((rv = getopt(argc, argv, "fdu:")) != EOF) - switch (rv) { - case 'd': - debug = true; - break; - case 'f': - foreground = true; - break; - case 'u': - sscanf(optarg, "%d", &uid); - break; - default: - break; - } - - if (geteuid() != 0) { - cout << "Only root can run this" << endl; - return 1; - } - - try { - ServerSocket serv_sock(RICCI_SERVER_PORT); - - if (!foreground) - daemon_init(argv[0]); - - if (uid != 0) - // change user - if (setreuid(uid, uid)) { - cout << "unable to change uid to " << uid << endl; - return 1; - } - - Server server(serv_sock); - server.run(); - } catch ( String e ) { - cout << "exception: " << e << endl; - return 1; - } - return 0; + uint32_t uid = 0; + int32_t ricci_port = RICCI_SERVER_PORT; + + int rv; + while ((rv = getopt(argc, argv, "cdfu:p:")) != EOF) { + switch (rv) { + case 'c': + advertise_cluster = true; + break; + + case 'd': + debug = true; + break; + + case 'f': + foreground = true; + break; + + case 'p': + if (optarg != NULL) { + uint32_t port; + char *e = NULL; + + port = strtoul(optarg, &e, 10); + if (*e != '\0' || !port || (port & 0xffff) != port) { + fprintf(stderr, "Invalid port: %s\n", optarg); + exit(1); + } + ricci_port = port; + } + break; + + case 'u': + if (optarg != NULL) { + char *e = NULL; + uid = strtoul(optarg, &e, 10); + if (*e != '\0') { + fprintf(stderr, "Invalid uid: %s\n", optarg); + exit(1); + } + } + break; + + default: + break; + } + } + + if (geteuid() != 0) { + fprintf(stderr, "You must be root to run this program.\n"); + exit(1); + } + + try { + ServerSocket serv_sock(RICCI_SERVER_PORT); + + if (!foreground) + daemon_init(argv[0]); + + if (uid != getuid()) { + // change user + if (setreuid(uid, uid)) { + fprintf(stderr, "Error changing uid to %u: %s\n", + uid, strerror(errno)); + exit(1); + } + } + + Server server(serv_sock); + server.run(); + } catch ( String e ) { + cerr << "exception: " << e << endl; + exit(1); + } catch ( ... ) { + cerr << "exception caught" << endl; + exit(1); + } + + exit(0); } --- conga/ricci/ricci/ricci_defines.h 2006/08/16 06:34:20 1.8 +++ conga/ricci/ricci/ricci_defines.h 2007/08/30 17:07:14 1.9 @@ -1,5 +1,5 @@ /* - Copyright Red Hat, Inc. 2005 + Copyright Red Hat, Inc. 2005-2007 This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the @@ -13,7 +13,7 @@ You should have received a copy of the GNU General Public License along with this program; see the file COPYING. If not, write to the - Free Software Foundation, Inc., 675 Mass Ave, Cambridge, + Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ /* @@ -25,19 +25,17 @@ #define ricci_defines_h +#define RICCI_SERVER_PORT 11111 -#define RICCI_SERVER_PORT 11111 +#define SERVER_CERT_PATH "/var/lib/ricci/certs/cacert.pem" +#define SERVER_KEY_PATH "/var/lib/ricci/certs/privkey.pem" +#define CLIENT_AUTH_CAs_PATH "/var/lib/ricci/certs/auth_CAs.pem" +#define CLIENT_CERTS_DIR_PATH "/var/lib/ricci/certs/clients/" -#define SERVER_CERT_PATH "/var/lib/ricci/certs/cacert.pem" -#define SERVER_KEY_PATH "/var/lib/ricci/certs/privkey.pem" -#define CLIENT_AUTH_CAs_PATH "/var/lib/ricci/certs/auth_CAs.pem" -#define CLIENT_CERTS_DIR_PATH "/var/lib/ricci/certs/clients/" +#define QUEUE_DIR_PATH "/var/lib/ricci/queue/" +#define QUEUE_LOCK_PATH "/var/lib/ricci/queue/lock" -#define QUEUE_DIR_PATH "/var/lib/ricci/queue/" -#define QUEUE_LOCK_PATH "/var/lib/ricci/queue/lock" +#define AUTH_HELPER_PATH "/usr/libexec/ricci/ricci-auth" +#define RICCI_WORKER_PATH "/usr/libexec/ricci/ricci-worker" -#define AUTH_HELPER_PATH "/usr/libexec/ricci/ricci-auth" -#define RICCI_WORKER_PATH "/usr/libexec/ricci/ricci-worker" - - -#endif // ricci_defines_h +#endif // ricci_defines_h