diff --git a/include/maxscale/users.h b/include/maxscale/users.h index c7d20a403..787017569 100644 --- a/include/maxscale/users.h +++ b/include/maxscale/users.h @@ -13,8 +13,7 @@ */ /** - * @file users.h The functions to manipulate the table of users maintained - * for each service + * @file users.h The functions to manipulate a set of administrative users */ #include @@ -26,81 +25,68 @@ MXS_BEGIN_DECLS -#define USERS_HASHTABLE_DEFAULT_SIZE 52 - /** - * The users table statistics structure - */ -typedef struct -{ - int n_entries; /**< The number of entries */ - int n_adds; /**< The number of inserts */ - int n_deletes; /**< The number of deletes */ - int n_fetches; /**< The number of fetchs */ -} USERS_STATS; - -/** - * A generic user table containing the username and authentication data + * An opaque users object */ typedef struct users { - HASHTABLE *data; /**< The hashtable containing the actual data */ - USERS_STATS stats; /**< The statistics for the users table */ } USERS; - /** * Allocate a new users table * - * @return The users table + * @return The users table or NULL if memory allocation failed */ -USERS *users_alloc(); +USERS* users_alloc(); /** - * Remove the users table + * Free a users table * - * @param users The users table to remove + * @param users Users table to free */ -void users_free(USERS *); +void users_free(USERS* users); /** * Add a new user to the user table. The user name must be unique * - * @param users The users table - * @param user The user name - * @param auth The authentication data - * @return The number of users added to the table + * @param users The users table + * @param user The user name + * @param password The password for the user + * + * @return True if user was added */ -int users_add(USERS *, const char *, const char *); +bool users_add(USERS *users, const char *user, const char *password); /** * Delete a user from the user table. * * @param users The users table * @param user The user name - * @return The number of users deleted from the table + * + * @return True if user was deleted */ -int users_delete(USERS *, const char *); +bool users_delete(USERS *users, const char *user); /** - * Fetch the authentication data for a particular user from the users table + * Authenticate a user * - * @param users The users table - * @param user The user name - * @return The authentication data or NULL on error + * @param users The users table + * @param user The user name + * @param pw The password sent by the user + * + * @return True if authentication data matched the stored value */ -const char *users_fetch(USERS *, const char *); +bool users_auth(USERS* users, const char* user, const char* password); /** - * Change the password data associated with a user in the users - * table. + * Check if a user exists * - * @param users The users table - * @param user The user name - * @param auth The new authentication details - * @return Number of users updated + * @param users The users table + * @param user User to find + * + * @return True if user exists */ -int users_update(USERS *, const char *, const char *); +bool users_find(USERS* users, const char* user); /** * @brief Default user loading function @@ -128,10 +114,20 @@ void users_default_diagnostic(DCB *dcb, SERV_LISTENER *port); json_t* users_default_diagnostic_json(const SERV_LISTENER *port); /** - * Print details of the users storage mechanism + * Print users to a DCB * - * @param users The users table + * @param dcb DCB where users are printed + * @param users Users to print */ -void usersPrint(const USERS *); +void users_diagnostic(DCB* dcb, USERS* users); + +/** + * Convert users to JSON + * + * @param users Users to convert + * + * @return JSON version of users + */ +json_t* users_diagnostic_json(USERS* users); MXS_END_DECLS diff --git a/server/core/users.cc b/server/core/users.cc index 0c56da0eb..5231f80d1 100644 --- a/server/core/users.cc +++ b/server/core/users.cc @@ -10,155 +10,173 @@ * of this software will be governed by version 2 or later of the General * Public License. */ -#include -#include -#include -#include -#include -#include -#include -/** - * @file users.c User table maintenance routines - * - * @verbatim - * Revision History - * - * Date Who Description - * 23/06/2013 Mark Riddoch Initial implementation - * 08/01/2014 Massimiliano Pinto In user_alloc now we can pass function pointers for - * copying/freeing keys and values independently via - * hashtable_memory_fns() routine - * - * @endverbatim - */ +#include + +#include +#include +#include + +#include +#include + +class Users +{ + Users(const Users&); + Users& operator=(const Users&); + +public: + typedef std::tr1::unordered_map UserMap; + + Users() + { + } + + ~Users() + { + } + + bool add(std::string user, std::string password) + { + return m_data.insert(std::make_pair(user, password)).second; + } + + bool remove(std::string user) + { + bool rval = false; + + if (get(user)) + { + m_data.erase(user); + rval = true; + } + + return rval; + } + + bool get(std::string user, std::string* output = NULL) const + { + UserMap::const_iterator it = m_data.find(user); + bool rval = false; + + if (it != m_data.end()) + { + rval = true; + + if (output) + { + *output = it->second; + } + } + + return rval; + } + + json_t* diagnostic_json() const + { + json_t* rval = json_array(); + + for (UserMap::const_iterator it = m_data.begin(); it != m_data.end(); it++) + { + json_array_append_new(rval, json_string(it->first.c_str())); + } + + return rval; + } + + void diagnostic(DCB* dcb) const + { + if (m_data.size()) + { + + dcb_printf(dcb, "User names: "); + const char *sep = ""; + + for (UserMap::const_iterator it = m_data.begin(); it != m_data.end(); it++) + { + dcb_printf(dcb, "%s%s", sep, it->first.c_str()); + sep = ", "; + } + dcb_printf(dcb, "\n"); + } + else + { + dcb_printf(dcb, "Users table is empty\n"); + } + } + +private: + UserMap m_data; +}; USERS *users_alloc() { - USERS *rval; - - if ((rval = (USERS*)MXS_CALLOC(1, sizeof(USERS))) == NULL) - { - return NULL; - } - - if ((rval->data = hashtable_alloc(USERS_HASHTABLE_DEFAULT_SIZE, - hashtable_item_strhash, hashtable_item_strcmp)) == NULL) - { - MXS_ERROR("[%s:%d]: Memory allocation failed.", __FUNCTION__, __LINE__); - MXS_FREE(rval); - return NULL; - } - - hashtable_memory_fns(rval->data, - hashtable_item_strdup, hashtable_item_strdup, - hashtable_item_free, hashtable_item_free); - - return rval; + Users* rval = new (std::nothrow) Users(); + MXS_OOM_IFNULL(rval); + return reinterpret_cast(rval); } void users_free(USERS *users) { - if (users) + Users* u = reinterpret_cast(users); + delete u; +} + +bool users_add(USERS *users, const char *user, const char *password) +{ + Users* u = reinterpret_cast(users); + return u->add(user, password); +} + +bool users_delete(USERS *users, const char *user) +{ + Users* u = reinterpret_cast(users); + return u->remove(user); +} + +bool users_find(USERS* users, const char* user) +{ + Users* u = reinterpret_cast(users); + return u->get(user); +} + +bool users_auth(USERS* users, const char* user, const char* password) +{ + Users* u = reinterpret_cast(users); + bool rval = false; + std::string str; + + if (u->get(user, &str)) { - hashtable_free(users->data); - MXS_FREE(users); + rval = strcmp(password, str.c_str()) == 0; } + + return rval; } -int users_add(USERS *users, const char *user, const char *auth) +void users_diagnostic(DCB* dcb, USERS* users) { - int add; - - atomic_add(&users->stats.n_adds, 1); - add = hashtable_add(users->data, (char*)user, (char*)auth); - atomic_add(&users->stats.n_entries, add); - return add; + Users* u = reinterpret_cast(users); + u->diagnostic(dcb); } -int users_delete(USERS *users, const char *user) +json_t* users_diagnostic_json(USERS* users) { - int del; - - atomic_add(&users->stats.n_deletes, 1); - del = hashtable_delete(users->data, (char*)user); - atomic_add(&users->stats.n_entries, -del); - return del; + Users* u = reinterpret_cast(users); + return u->diagnostic_json(); } -const char *users_fetch(USERS *users, const char *user) +void users_default_diagnostic(DCB* dcb, SERV_LISTENER* port) { - atomic_add(&users->stats.n_fetches, 1); - // TODO: Returning data from the hashtable is not threadsafe. - return (const char*)hashtable_fetch(users->data, (char*)user); -} - -int users_update(USERS *users, const char *user, const char *auth) -{ - if (hashtable_delete(users->data, (char*)user) == 0) + if (port->users) { - return 0; - } - return hashtable_add(users->data, (char*)user, (char*)auth); -} - - -void usersPrint(const USERS *users) -{ - printf("Users table data\n"); - hashtable_stats(users->data); -} - -void users_default_diagnostic(DCB *dcb, SERV_LISTENER *port) -{ - if (port->users && port->users->data) - { - HASHITERATOR *iter = hashtable_iterator(port->users->data); - - if (iter) - { - dcb_printf(dcb, "User names: "); - const char *sep = ""; - void *user; - - while ((user = hashtable_next(iter)) != NULL) - { - dcb_printf(dcb, "%s%s", sep, (char *)user); - sep = ", "; - } - - dcb_printf(dcb, "\n"); - hashtable_iterator_free(iter); - } - } - else - { - dcb_printf(dcb, "Users table is empty\n"); + users_diagnostic(dcb, port->users); } } json_t* users_default_diagnostic_json(const SERV_LISTENER *port) { - json_t* rval = json_array(); - - if (port->users && port->users->data) - { - HASHITERATOR *iter = hashtable_iterator(port->users->data); - - if (iter) - { - char* user; - - while ((user = (char*)hashtable_next(iter))) - { - json_array_append_new(rval, json_string(user)); - } - - hashtable_iterator_free(iter); - } - } - - return rval; + return port->users ? users_diagnostic_json(port->users) : json_array(); } int users_default_loadusers(SERV_LISTENER *port)