// -*- c-basic-offset: 4; tab-width: 8; indent-tabs-mode: t -*- // Copyright (c) 2001-2007 International Computer Science Institute // // Permission is hereby granted, free of charge, to any person obtaining a // copy of this software and associated documentation files (the "Software") // to deal in the Software without restriction, subject to the conditions // listed in the XORP LICENSE file. These conditions include: you must // preserve this copyright notice, and you cannot mention the copyright // holders in advertising related to the Software without their permission. // The Software is provided WITHOUT ANY WARRANTY, EXPRESS OR IMPLIED. This // notice is a summary of the XORP LICENSE file; the license in that file is // legally binding. #ident "$XORP: xorp/rtrmgr/xrl_rtrmgr_interface.cc,v 1.54 2007/02/16 22:47:28 pavlin Exp $" #include "rtrmgr_module.h" #include "libxorp/xorp.h" #include "libxorp/xlog.h" #include "libxorp/debug.h" #include "libxorp/status_codes.h" #ifdef HAVE_SYS_STAT_H #include #endif #include "main_rtrmgr.hh" #include "master_conf_tree.hh" #include "module_manager.hh" #include "randomness.hh" #include "userdb.hh" #include "xrl_rtrmgr_interface.hh" XrlRtrmgrInterface::XrlRtrmgrInterface(XrlRouter& r, UserDB& userdb, EventLoop& eventloop, RandomGen& randgen, Rtrmgr& rtrmgr) : XrlRtrmgrTargetBase(&r), _xrl_router(r), _client_interface(&r), _finder_notifier_interface(&r), _userdb(userdb), _master_config_tree(NULL), _eventloop(eventloop), _randgen(randgen), _rtrmgr(rtrmgr), _exclusive(false), _config_locked(false), _lock_holder_token(""), _verbose(rtrmgr.verbose()) { } XrlRtrmgrInterface::~XrlRtrmgrInterface() { multimap::iterator iter; for (iter = _users.begin(); iter != _users.end(); ++iter) { delete iter->second; } } XrlCmdError XrlRtrmgrInterface::common_0_1_get_target_name(// Output values, string& name) { name = XrlRtrmgrTargetBase::name(); return XrlCmdError::OKAY(); } XrlCmdError XrlRtrmgrInterface::common_0_1_get_version(// Output values, string& v) { v = string(version()); return XrlCmdError::OKAY(); } XrlCmdError XrlRtrmgrInterface::common_0_1_get_status(// Output values, uint32_t& status, string& reason) { // XXX placeholder only status = PROC_READY; reason = "Ready"; return XrlCmdError::OKAY(); } XrlCmdError XrlRtrmgrInterface::common_0_1_shutdown() { string error_msg; // The rtrmgr does not accept XRL requests to shutdown via this interface. error_msg = "Command not supported"; return XrlCmdError::COMMAND_FAILED(error_msg); } XrlCmdError XrlRtrmgrInterface::rtrmgr_0_1_get_pid(// Output values, uint32_t& pid) { pid = getpid(); return XrlCmdError::OKAY(); } XrlCmdError XrlRtrmgrInterface::rtrmgr_0_1_register_client( // Input values, const uint32_t& user_id, const string& clientname, // Output values, string& filename, uint32_t& pid, uint32_t& clientid) { #ifdef HOST_OS_WINDOWS pid = GetCurrentProcessId(); #else pid = getpid(); #endif const User* user; UserInstance* newuser; string error_msg; // // Prevent a clientname passing characters that might cause us to // overwrite files later. Prohibiting "/" makes allowing ".." safe. // if (strchr(clientname.c_str(), '/') != NULL) { error_msg = c_format("Illegal character in clientname: %s", clientname.c_str()); return XrlCmdError::COMMAND_FAILED(error_msg); } // // Note that clientname is user supplied data, so this would be // dangerous if the user could pass "..". // #ifdef HOST_OS_WINDOWS char tmppath[128]; GetTempPathA(sizeof(tmppath), tmppath); filename = tmppath + clientname; #else filename = "/tmp/rtrmgr-" + clientname; mode_t oldmode = umask(S_IRWXG|S_IRWXO); debug_msg("newmode: %o oldmode: %o\n", S_IRWXG|S_IRWXO, XORP_UINT_CAST(oldmode)); #endif FILE* file = fopen(filename.c_str(), "w+"); if (file == NULL) { error_msg = c_format("Failed to create temporary file: %s", filename.c_str()); return XrlCmdError::COMMAND_FAILED(error_msg); } #ifndef HOST_OS_WINDOWS umask(oldmode); #endif user = _userdb.find_user_by_user_id(user_id); if (user == NULL) { #ifdef HOST_OS_WINDOWS DeleteFileA(filename.c_str()); #else unlink(filename.c_str()); #endif error_msg = c_format("User ID %u not found", XORP_UINT_CAST(user_id)); return XrlCmdError::COMMAND_FAILED(error_msg); } newuser = new UserInstance(user->user_id(), user->username()); newuser->set_clientname(clientname); newuser->set_authtoken(generate_auth_token(user_id, clientname)); newuser->set_authenticated(false); clientid = allocate_clientid(); newuser->set_clientid(clientid); _users.insert(pair(user_id, newuser)); // // Be careful here - if for any reason we fail to create, write to, // or close the temporary auth file, that's a very different error // from if the xorpsh process can't read it correctly. // if (fprintf(file, "%s", newuser->authtoken().c_str()) < (int)(newuser->authtoken().size())) { #ifdef HOST_OS_WINDOWS DeleteFileA(filename.c_str()); #else unlink(filename.c_str()); #endif error_msg = c_format("Failed to write to temporary file: %s", filename.c_str()); return XrlCmdError::COMMAND_FAILED(error_msg); } #ifndef HOST_OS_WINDOWS if (fchown(fileno(file), user_id, (gid_t)-1) != 0) { unlink(filename.c_str()); error_msg = c_format("Failed to chown temporary file %s to user_id %u", filename.c_str(), XORP_UINT_CAST(user_id)); return XrlCmdError::COMMAND_FAILED(error_msg); } #endif if (fclose(file) != 0) { #ifdef HOST_OS_WINDOWS DeleteFileA(filename.c_str()); #else unlink(filename.c_str()); #endif error_msg = c_format("Failed to close temporary file: %s", filename.c_str()); return XrlCmdError::COMMAND_FAILED(error_msg); } #ifdef NO_XORPSH_AUTHENTICATION // // XXX: a hack to return back the key itself in case we run // xorpsh on a remote machine. // filename = newuser->authtoken(); #endif return XrlCmdError::OKAY(); } XrlCmdError XrlRtrmgrInterface::rtrmgr_0_1_unregister_client(const string& token) { string error_msg; if (!verify_token(token)) { error_msg = "AUTH_FAIL"; return XrlCmdError::COMMAND_FAILED(error_msg); } multimap::iterator iter; for (iter = _config_users.begin(); iter != _config_users.end(); ++iter) { if (iter->second->authtoken() == token) { _config_users.erase(iter); return XrlCmdError::OKAY(); } } for (iter = _users.begin(); iter != _users.end(); ++iter) { if (iter->second->authtoken() == token) { deallocate_clientid(iter->second->clientid()); delete iter->second; _users.erase(iter); return XrlCmdError::OKAY(); } } // This cannot happen, because the token wouldn't have verified XLOG_UNREACHABLE(); } XrlCmdError XrlRtrmgrInterface::rtrmgr_0_1_authenticate_client( // Input values, const uint32_t& user_id, const string& clientname, const string& token) { UserInstance *user; string error_msg; user = find_user_instance(user_id, clientname); if (user == NULL) { error_msg = "User instance not found (maybe login timed out)"; return XrlCmdError::COMMAND_FAILED(error_msg); } if (token == user->authtoken()) { user->set_authenticated(true); initialize_client_state(user_id, user); return XrlCmdError::OKAY(); } else { error_msg = "Bad authtoken"; return XrlCmdError::COMMAND_FAILED(error_msg); } } void XrlRtrmgrInterface::initialize_client_state(uid_t user_id, UserInstance *user) { // We need to register interest via the finder in the XRL target // associated with this user instance, so that when the user // instance goes away without deregistering, we can clean up the // state we associated with them. XrlFinderEventNotifierV0p1Client::RegisterInstanceEventInterestCB cb; cb = callback(this, &XrlRtrmgrInterface::finder_register_done, user->clientname()); _finder_notifier_interface. send_register_class_event_interest("finder", _xrl_router.instance_name(), user->clientname(), cb); XLOG_TRACE(_verbose, "registering interest in %s\n", user->clientname().c_str()); // // We need to send the running config and module state to the // client, but we first need to return from the current XRL, so we // schedule this on a zero-second timer. // XorpTimer t; uint32_t delay = 0; if (!_rtrmgr.ready()) { delay = 2000; } t = _eventloop.new_oneoff_after_ms(delay, callback(this, &XrlRtrmgrInterface::send_client_state, user_id, user->clientname())); _background_tasks.push_front(t); } void XrlRtrmgrInterface::finder_register_done(const XrlError& e, string clientname) { if (e != XrlError::OKAY()) { XLOG_ERROR("Failed to register with finder about XRL %s (err: %s)\n", clientname.c_str(), e.error_msg()); } } void XrlRtrmgrInterface::send_client_state(uid_t user_id, string client) { UserInstance *user = find_user_instance(user_id, client); if (user == NULL) return; debug_msg("send_client_state %s\n", client.c_str()); if (!_rtrmgr.ready()) { // // We're still in the process of reconfiguring, so delay this // until later. // initialize_client_state(user_id, user); return; } GENERIC_CALLBACK cb2; cb2 = callback(this, &XrlRtrmgrInterface::client_updated, user_id, user); // // Send the module status // debug_msg("Sending mod status changed to %s\n", client.c_str()); list module_names; ModuleManager &mmgr(_master_config_tree->module_manager()); module_names = mmgr.get_module_names(); list::iterator iter; for (iter = module_names.begin(); iter != module_names.end(); ++iter) { const string& module_name = *iter; debug_msg("module: %s\n", module_name.c_str()); Module::ModuleStatus status = mmgr.module_status(module_name); if (status != Module::NO_SUCH_MODULE) { debug_msg("status %d\n", status); _client_interface.send_module_status(client.c_str(), module_name, static_cast(status), cb2); } } // // Send the configuration // debug_msg("Sending config changed to %s\n", client.c_str()); string config = _master_config_tree->show_tree(/*numbered*/ true); _client_interface.send_config_changed(client.c_str(), 0, config, "", cb2); } XrlCmdError XrlRtrmgrInterface::rtrmgr_0_1_enter_config_mode( // Input values, const string& token, const bool& exclusive) { string error_msg; if (! verify_token(token)) { error_msg = "AUTH_FAIL"; return XrlCmdError::COMMAND_FAILED(error_msg); } uid_t user_id = get_user_id_from_token(token); if (_userdb.has_capability(user_id, "config") == false) { error_msg = "You do not have permission for this operation"; return XrlCmdError::COMMAND_FAILED(error_msg); } XLOG_TRACE(_verbose, "user %u entering config mode\n", XORP_UINT_CAST(user_id)); if (exclusive) XLOG_TRACE(_verbose, "user requested exclusive config\n"); else XLOG_TRACE(_verbose, "user requested non-exclusive config\n"); // // If he's asking for exclusive, and we've already got config users, // or there's already an exclusive user, deny the request. // multimap::iterator iter; if (exclusive && !_config_users.empty()) { string user_names; for (iter = _config_users.begin(); iter != _config_users.end(); ++iter) { UserInstance* user = iter->second; if (! user_names.empty()) user_names += ", "; user_names += user->username(); } error_msg = c_format("Exclusive config mode requested, but there are " "already other configuration mode users: %s", user_names.c_str()); return XrlCmdError::COMMAND_FAILED(error_msg); } if (_exclusive && !_config_users.empty()) { error_msg = c_format("User %s is in exclusive configuration mode", _exclusive_username.c_str()); return XrlCmdError::COMMAND_FAILED(error_msg); } for (iter = _users.begin(); iter != _users.end(); ++iter) { if (iter->second->authtoken() == token) { UserInstance* this_user = iter->second; _config_users.insert(make_pair(user_id, this_user)); if (exclusive) { _exclusive = true; _exclusive_username = this_user->username(); } else { _exclusive = false; _exclusive_username = ""; } return XrlCmdError::OKAY(); } } XLOG_UNREACHABLE(); } XrlCmdError XrlRtrmgrInterface::rtrmgr_0_1_leave_config_mode( // Input values, const string& token) { string error_msg; if (!verify_token(token)) { error_msg = "AUTH_FAIL"; return XrlCmdError::COMMAND_FAILED(error_msg); } XLOG_TRACE(_verbose, "user %u leaving config mode\n", XORP_UINT_CAST(get_user_id_from_token(token))); multimap::iterator iter; for (iter = _config_users.begin(); iter != _config_users.end(); ++iter) { if (iter->second->authtoken() == token) { _config_users.erase(iter); return XrlCmdError::OKAY(); } } error_msg = "User was not in configuration mode"; return XrlCmdError::COMMAND_FAILED(error_msg); } XrlCmdError XrlRtrmgrInterface::rtrmgr_0_1_get_config_users( // Input values, const string& token, // Output values, XrlAtomList& users) { string error_msg; if (!verify_token(token)) { error_msg = "AUTH_FAIL"; return XrlCmdError::COMMAND_FAILED(error_msg); } uid_t user_id = get_user_id_from_token(token); if (_userdb.has_capability(user_id, "config") == false) { error_msg = "You do not have permission to view the configuration " "mode users"; return XrlCmdError::COMMAND_FAILED(error_msg); } multimap::const_iterator iter; for (iter = _config_users.begin(); iter != _config_users.end(); ++iter) { UserInstance* user = iter->second; if (!user->is_a_zombie()) { users.append(XrlAtom(static_cast(user->user_id()))); } else { XLOG_WARNING("user %u is a zombie\n", XORP_UINT_CAST(user->user_id())); } } return XrlCmdError::OKAY(); } /** * This interface is deprecated as the main way for xorpsh to get the * running config from the router manager. It is retained for * debugging purposes. xorpsh now gets its config automatically * immediatedly after registering which removes a potential timing * hole where the client could be told about a change to the config * before it has asked what the current config is. */ XrlCmdError XrlRtrmgrInterface::rtrmgr_0_1_get_running_config( // Input values, const string& token, // Output values, bool& ready, string& config) { string error_msg; if (!verify_token(token)) { error_msg = "AUTH_FAIL"; return XrlCmdError::COMMAND_FAILED(error_msg); } if (_rtrmgr.ready()) { ready = true; config = _master_config_tree->show_tree(/*numbered*/ true); } else { ready = false; config = ""; } return XrlCmdError::OKAY(); } XrlCmdError XrlRtrmgrInterface::rtrmgr_0_1_apply_config_change( // Input values, const string& token, const string& target, const string& deltas, const string& deletions) { string error_msg; if (!verify_token(token)) { error_msg = "AUTH_FAIL"; return XrlCmdError::COMMAND_FAILED(error_msg); } if (_config_locked == false) { error_msg = "Cannot commit config changes without locking the config"; return XrlCmdError::COMMAND_FAILED(error_msg); } uid_t user_id = get_user_id_from_token(token); if (_userdb.has_capability(user_id, "config") == false) { error_msg = "You do not have permission for this operation"; return XrlCmdError::COMMAND_FAILED(error_msg); } // XXX: TBD XLOG_TRACE(_verbose, "\nXRL got config change: deltas: \n%s\nend deltas\ndeletions:\n%s\nend deletions\n", deltas.c_str(), deletions.c_str()); ConfigChangeCallBack cb; cb = callback(this, &XrlRtrmgrInterface::apply_config_change_done, user_id, string(target)); if (_master_config_tree->apply_config_change(user_id, error_msg, deltas, deletions, cb) != true) { return XrlCmdError::COMMAND_FAILED(error_msg); } return XrlCmdError::OKAY(); } void XrlRtrmgrInterface::apply_config_change_done(bool success, string error_msg, string deltas, string deletions, uid_t user_id, string target) { XLOG_TRACE(_verbose, "apply_config_change_done: status: %d response: %s target: %s", success, error_msg.c_str(), target.c_str()); if (success) { // Check everything really worked, and finalize the commit if (_master_config_tree->check_commit_status(error_msg) == false) { XLOG_TRACE(_verbose, "check commit status indicates failure: >%s<\n", error_msg.c_str()); success = false; } } else { XLOG_TRACE(_verbose, "request failed: >%s<\n", error_msg.c_str()); } GENERIC_CALLBACK cb1; cb1 = callback(this, &XrlRtrmgrInterface::apply_config_change_done_cb); if (success) { // Send the changes to all the clients, including the client // that originally sent them. multimap::iterator iter; for (iter = _users.begin(); iter != _users.end(); ++iter) { string client = iter->second->clientname(); GENERIC_CALLBACK cb2; cb2 = callback(this, &XrlRtrmgrInterface::client_updated, iter->first, iter->second); debug_msg("Sending config changed to %s\n", client.c_str()); _client_interface.send_config_changed(client.c_str(), user_id, deltas, deletions, cb2); } debug_msg("Sending config change done to %s\n", target.c_str()); _client_interface.send_config_change_done(target.c_str(), true, "", cb1); } else { // Something went wrong _master_config_tree->discard_changes(); debug_msg("Sending config change failed to %s\n", target.c_str()); _client_interface.send_config_change_done(target.c_str(), false, error_msg, cb1); } } void XrlRtrmgrInterface::config_saved_done_cb(const XrlError& e) { if (e != XrlError::OKAY()) { XLOG_ERROR("Failed to notify client that config change was saved: %s", e.error_msg()); } } void XrlRtrmgrInterface::apply_config_change_done_cb(const XrlError& e) { if (e != XrlError::OKAY()) { XLOG_ERROR("Failed to notify client that config change was done: %s", e.error_msg()); } } void XrlRtrmgrInterface::client_updated(const XrlError& e, uid_t user_id, UserInstance* user) { if (e != XrlError::OKAY()) { XLOG_ERROR("Failed to notify client that config changed: %s\n", e.error_msg()); if (e != XrlError::COMMAND_FAILED()) { // We failed to notify the user instance, so we note that // they are probably dead. We can't guarantee that the // "user" pointer is still valid, so check before using it. multimap::iterator iter; for (iter = _users.lower_bound(user_id); iter != _users.end(); iter++) { if (iter->second == user) { user->set_zombie(true); return; } } } } } void XrlRtrmgrInterface::module_status_changed(const string& modname, GenericModule::ModuleStatus status) { multimap::iterator iter; for (iter = _users.begin(); iter != _users.end(); ++iter) { string client = iter->second->clientname(); GENERIC_CALLBACK cb2; cb2 = callback(this, &XrlRtrmgrInterface::client_updated, iter->first, iter->second); debug_msg("Sending mod statis changed to %s\n", client.c_str()); _client_interface.send_module_status(client.c_str(), modname, (uint32_t)status, cb2); } } XrlCmdError XrlRtrmgrInterface::rtrmgr_0_1_lock_config( // Input values, const string& token, const uint32_t& timeout /* in milliseconds */, // Output values, bool& success, uint32_t& holder) { string error_msg; if (!verify_token(token)) { error_msg = "AUTH_FAIL"; return XrlCmdError::COMMAND_FAILED(error_msg); } uid_t user_id = get_user_id_from_token(token); if (_userdb.has_capability(user_id, "config") == false) { error_msg = "You do not have permission to lock the configuration"; return XrlCmdError::COMMAND_FAILED(error_msg); } if (_config_locked) { // Can't return COMMAND_FAILED and return the lock holder success = false; holder = get_user_id_from_token(_lock_holder_token); return XrlCmdError::OKAY(); } else { success = true; _config_locked = true; _lock_holder_token = token; _lock_timer = _eventloop.new_oneoff_after_ms( timeout, callback(this, &XrlRtrmgrInterface::lock_timeout)); return XrlCmdError::OKAY(); } } void XrlRtrmgrInterface::lock_timeout() { _config_locked = false; _lock_holder_token = ""; } XrlCmdError XrlRtrmgrInterface::rtrmgr_0_1_unlock_config( // Input values const string& token) { string error_msg; if (!verify_token(token)) { error_msg = "AUTH_FAIL"; return XrlCmdError::COMMAND_FAILED(error_msg); } if (_config_locked) { if (token != _lock_holder_token) { error_msg = c_format("Configuration is not held by process %s", token.c_str()); return XrlCmdError::COMMAND_FAILED(error_msg); } _config_locked = false; _lock_timer.unschedule(); _lock_holder_token = ""; return XrlCmdError::OKAY(); } else { error_msg = "Configuration is not locked"; return XrlCmdError::COMMAND_FAILED(error_msg); } } XrlCmdError XrlRtrmgrInterface::rtrmgr_0_1_lock_node( // Input values, const string& token, const string& node, const uint32_t& timeout, // Output values, bool& success, uint32_t& holder) { string error_msg; if (!verify_token(token)) { error_msg = "AUTH_FAIL"; return XrlCmdError::COMMAND_FAILED(error_msg); } uid_t user_id = get_user_id_from_token(token); if (_userdb.has_capability(user_id, "config") == false) { error_msg = "You do not have permission to lock the configuration"; return XrlCmdError::COMMAND_FAILED(error_msg); } if (user_id == (uid_t)-1) { // Shouldn't be possible as we already checked the token XLOG_UNREACHABLE(); } success = _master_config_tree->lock_node(node, user_id, timeout, holder); return XrlCmdError::OKAY(); } XrlCmdError XrlRtrmgrInterface::rtrmgr_0_1_unlock_node( // Input values, const string& token, const string& node) { string error_msg; if (!verify_token(token)) { error_msg = "AUTH_FAIL"; return XrlCmdError::COMMAND_FAILED(error_msg); } uid_t user_id = get_user_id_from_token(token); if (user_id == (uid_t)-1) { // Shouldn't be possible as we already checked the token XLOG_UNREACHABLE(); } bool success; success = _master_config_tree->unlock_node(node, user_id); if (success) { return XrlCmdError::OKAY(); } else { error_msg = "Unlocking the configuration failed"; return XrlCmdError::COMMAND_FAILED(error_msg); } } XrlCmdError XrlRtrmgrInterface::rtrmgr_0_1_save_config(// Input values: const string& token, const string& target, const string& filename) { string error_msg; if (!verify_token(token)) { error_msg = "AUTH_FAIL"; return XrlCmdError::COMMAND_FAILED(error_msg); } uid_t user_id = get_user_id_from_token(token); if (_userdb.has_capability(user_id, "config") == false) { error_msg = "You do not have permission to save the configuration"; return XrlCmdError::COMMAND_FAILED(error_msg); } if (_config_locked && (token != _lock_holder_token)) { uid_t uid = get_user_id_from_token(_lock_holder_token); string holder = _userdb.find_user_by_user_id(uid)->username(); error_msg = c_format("The configuration is currently locked by user %s", holder.c_str()); return XrlCmdError::COMMAND_FAILED(error_msg); } ConfigSaveCallBack cb; cb = callback(this, &XrlRtrmgrInterface::save_config_done, filename, user_id, target); if (_master_config_tree->save_config(filename, user_id, error_msg, cb) != true) { return XrlCmdError::COMMAND_FAILED(error_msg); } return XrlCmdError::OKAY(); } XrlCmdError XrlRtrmgrInterface::rtrmgr_0_1_load_config(// Input values: const string& token, const string& target, const string& filename) { string error_msg; if (!verify_token(token)) { error_msg = "AUTH_FAIL"; return XrlCmdError::COMMAND_FAILED(error_msg); } uid_t user_id = get_user_id_from_token(token); if (_userdb.has_capability(user_id, "config") == false) { error_msg = "You do not have permission to reload the configuration"; return XrlCmdError::COMMAND_FAILED(error_msg); } if (_config_locked && (token != _lock_holder_token)) { uid_t uid = get_user_id_from_token(_lock_holder_token); string holder = _userdb.find_user_by_user_id(uid)->username(); error_msg = c_format("The configuration is currently locked by user %s", holder.c_str()); return XrlCmdError::COMMAND_FAILED(error_msg); } ConfigLoadCallBack cb; cb = callback(this, &XrlRtrmgrInterface::load_config_done, filename, user_id, target); if (_master_config_tree->load_config(filename, user_id, error_msg, cb) != true) { return XrlCmdError::COMMAND_FAILED(error_msg); } return XrlCmdError::OKAY(); } void XrlRtrmgrInterface::save_config_done(bool success, string error_msg, string filename, uid_t user_id, string target) { GENERIC_CALLBACK cb1; cb1 = callback(this, &XrlRtrmgrInterface::config_saved_done_cb); _client_interface.send_config_saved_done(target.c_str(), success, error_msg, cb1); UNUSED(filename); UNUSED(user_id); } void XrlRtrmgrInterface::load_config_done(bool success, string error_msg, string deltas, string deletions, string filename, uid_t user_id, string target) { // Propagate the changes to all clients apply_config_change_done(success, error_msg, deltas, deletions, user_id, target); UNUSED(filename); } XrlCmdError XrlRtrmgrInterface::rtrmgr_0_1_set_config_directory( // Input values, const string& config_directory) { _master_config_tree->set_config_directory(config_directory); return XrlCmdError::OKAY(); } UserInstance * XrlRtrmgrInterface::find_user_instance(uid_t user_id, const string& clientname) { multimap::iterator iter; iter = _users.lower_bound(user_id); while (iter != _users.end() && iter->second->user_id() == user_id) { if (iter->second->clientname() == clientname) return iter->second; ++iter; } return NULL; } bool XrlRtrmgrInterface::verify_token(const string& token) const { uid_t user_id = get_user_id_from_token(token); if (user_id == (uid_t)-1) return false; multimap::const_iterator iter; iter = _users.lower_bound(user_id); while (iter != _users.end() && iter->second->user_id() == user_id) { if (iter->second->authtoken() == token) return true; ++iter; } return false; } uid_t XrlRtrmgrInterface::get_user_id_from_token(const string& token) const { uid_t user_id; unsigned int u; size_t tlen = token.size(); if (token.size() < 10) return (uid_t)-1; string uidstr = token.substr(0, 10); string authstr = token.substr(10, tlen - 10); sscanf(uidstr.c_str(), "%u", &u); user_id = u; return user_id; } string XrlRtrmgrInterface::generate_auth_token(uid_t user_id, const string& clientname) { string token; token = c_format("%10u", XORP_UINT_CAST(user_id)); string shortcname; size_t clen = clientname.size(); if (clen > CNAMELEN) { shortcname = clientname.substr(clen - CNAMELEN, CNAMELEN); } else { shortcname = clientname; for (size_t i = 0; i < (CNAMELEN - clen); i++) shortcname += '*'; } token += shortcname; string randomness; uint8_t buf[16]; _randgen.get_random_bytes(16, buf); for (size_t i = 0; i < 16; i++) randomness += c_format("%2x", buf[i]); token += randomness; return token; } XrlCmdError XrlRtrmgrInterface::finder_event_observer_0_1_xrl_target_birth( const string& target_class, const string& target_instance) { XLOG_TRACE(_verbose, "XRL Birth: class %s instance %s\n", target_class.c_str(), target_instance.c_str()); return XrlCmdError::OKAY(); } XrlCmdError XrlRtrmgrInterface::finder_event_observer_0_1_xrl_target_death( const string& target_class, const string& target_instance) { XLOG_TRACE(_verbose, "XRL Death: class %s instance %s\n", target_class.c_str(), target_instance.c_str()); multimap::iterator iter; for (iter = _config_users.begin(); iter != _config_users.end(); ++iter) { UserInstance* user = iter->second; if (user->clientname() == target_class) { debug_msg("removing user %s from list of config users\n", target_class.c_str()); _config_users.erase(iter); break; } } for (iter = _users.begin(); iter != _users.end(); ++iter) { UserInstance* user = iter->second; if (user->clientname() == target_class) { debug_msg("removing user %s from list of regular users\n", target_class.c_str()); _users.erase(iter); break; } } return XrlCmdError::OKAY(); } uint32_t XrlRtrmgrInterface::allocate_clientid() { /* find the first unused client ID number */ uint32_t expected = 1; set::iterator i; for (i = _clientids.begin();; i++) { if ((i == _clientids.end()) || (*i > expected)) { _clientids.insert(expected); return expected; } expected++; } XLOG_UNREACHABLE(); } void XrlRtrmgrInterface::deallocate_clientid(uint32_t clientid) { set::iterator i; i = _clientids.find(clientid); XLOG_ASSERT(i != _clientids.end()); _clientids.erase(i); }