//------------------------------------------------------------------------------ // @file: AccessCmd.cc // @author: Fabio Luchetti - CERN //------------------------------------------------------------------------------ /************************************************************************ * EOS - the CERN Disk Storage System * * Copyright (C) 2018 CERN/Switzerland * * * * 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 Free Software Foundation, either version 3 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program. If not, see .* ************************************************************************/ #include #include "AccessCmd.hh" #include "mgm/proc/ProcInterface.hh" #include "XrdOuc/XrdOucEnv.hh" #include "mgm/XrdMgmOfs.hh" #include "mgm/Access.hh" #include "mgm/Stat.hh" EOSMGMNAMESPACE_BEGIN //------------------------------------------------------------------------------ // Process a rule key by converting the given username to a uid if necessary //------------------------------------------------------------------------------ std::string ProcessRuleKey(const std::string& key) { std::string new_key = key; if (new_key.find("threads:") == 0) { size_t pos = new_key.find(":"); if (pos + 1 == new_key.length()) { return std::string(); } std::string target = new_key.substr(pos + 1); if ((target != "max") && (target != "*")) { // Check if target is a username and then try to convert it if (std::find_if(begin(target), end(target), [](unsigned char c) { return std::isalpha(c); }) != target.end()) { int errc = 0; uid_t uid_target = eos::common::Mapping::UserNameToUid(target, errc); if (errc) { return std::string(); } new_key = "threads:" + std::to_string(uid_target); } } } return new_key; } //------------------------------------------------------------------------------ // Method implementing the specific behavior of the command executed by the // asynchronous thread //------------------------------------------------------------------------------ eos::console::ReplyProto AccessCmd::ProcessRequest() noexcept { eos::console::ReplyProto reply; eos::console::AccessProto access = mReqProto.access(); if ((mVid.uid != 0) && (!mVid.hasUid(3)) && (!mVid.hasGid(4)) && (!mVid.sudoer)) { // root and admins only reply.set_std_out(""); reply.set_std_err("error: you are not an access administrator!\""); reply.set_retc(EPERM); return reply; } switch (access.subcmd_case()) { case eos::console::AccessProto::kLs : LsSubcmd(access.ls(), reply); break; case eos::console::AccessProto::kRm : RmSubcmd(access.rm(), reply); break; case eos::console::AccessProto::kSet : SetSubcmd(access.set(), reply); break; case eos::console::AccessProto::kBan : BanSubcmd(access.ban(), reply); break; case eos::console::AccessProto::kUnban : UnbanSubcmd(access.unban(), reply); break; case eos::console::AccessProto::kAllow : AllowSubcmd(access.allow(), reply); break; case eos::console::AccessProto::kUnallow : UnallowSubcmd(access.unallow(), reply); break; case eos::console::AccessProto::kStallhosts : StallhostsSubcmd(access.stallhosts(), reply); break; default : reply.set_retc(EINVAL); reply.set_std_err("error: not supported"); } return reply; } //------------------------------------------------------------------------------ // Execute ls subcommand //------------------------------------------------------------------------------ void AccessCmd::LsSubcmd(const eos::console::AccessProto_LsProto& ls, eos::console::ReplyProto& reply) { std::ostringstream std_out {""}; std::ostringstream std_err {""}; int ret_c {0}; gOFS->MgmStats.Add("AccessControl", mVid.uid, mVid.gid, 1); eos::common::RWMutexReadLock lock(Access::gAccessMutex); int cnt {0}; if (!Access::gBannedUsers.empty()) { if (!ls.monitoring()) { std_out << "# ....................................................................................\n"; std_out << "# Banned Users ...\n"; std_out << "# ....................................................................................\n"; } cnt = 0; for (auto ituid = Access::gBannedUsers.begin(); ituid != Access::gBannedUsers.end(); ituid++) { cnt++; if (!ls.monitoring()) { char counter[16]; snprintf(counter, sizeof(counter) - 1, "%02d", cnt); std_out << "[ " << counter << " ] "; } else { std_out << "user.banned="; } if (ls.id2name()) { std_out << eos::common::Mapping::UidAsString(*ituid).c_str(); } else { int terrc = 0; std_out << eos::common::Mapping::UidToUserName(*ituid, terrc).c_str(); } std_out << '\n'; } } if (!Access::gBannedGroups.empty()) { if (!ls.monitoring()) { std_out << "# ....................................................................................\n"; std_out << "# Banned Groups...\n"; std_out << "# ....................................................................................\n"; } cnt = 0; for (auto itgid = Access::gBannedGroups.begin(); itgid != Access::gBannedGroups.end(); itgid++) { ++cnt; if (!ls.monitoring()) { char counter[16]; snprintf(counter, sizeof(counter) - 1, "%02d", cnt); std_out << "[ " << counter << " ] "; } else { std_out << "group.banned="; } if (ls.id2name()) { std_out << eos::common::Mapping::GidAsString(*itgid).c_str(); } else { int terrc = 0; std_out << eos::common::Mapping::GidToGroupName(*itgid, terrc).c_str(); } std_out << '\n'; } } if (!Access::gBannedHosts.empty()) { if (!ls.monitoring()) { std_out << "# ....................................................................................\n"; std_out << "# Banned Hosts ...\n"; std_out << "# ....................................................................................\n"; } cnt = 0; for (auto ithost = Access::gBannedHosts.begin(); ithost != Access::gBannedHosts.end(); ithost++) { cnt++; if (!ls.monitoring()) { char counter[16]; snprintf(counter, sizeof(counter) - 1, "%02d", cnt); std_out << "[ " << counter << " ] "; } else { std_out << "host.banned="; } std_out << ithost->c_str() << '\n'; } } if (!Access::gBannedDomains.empty()) { if (!ls.monitoring()) { std_out << "# ....................................................................................\n"; std_out << "# Banned Domains ...\n"; std_out << "# ....................................................................................\n"; } cnt = 0; for (auto itdomain = Access::gBannedDomains.begin(); itdomain != Access::gBannedDomains.end(); ++itdomain) { ++cnt; if (!ls.monitoring()) { char counter[16]; snprintf(counter, sizeof(counter) - 1, "%02d", cnt); std_out << "[ " << counter << " ] "; } else { std_out << "domain.banned="; } std_out << itdomain->c_str() << '\n'; } } if (!Access::gBannedTokens.empty()) { if (!ls.monitoring()) { std_out << "# ....................................................................................\n"; std_out << "# Banned Tokens ...\n"; std_out << "# ....................................................................................\n"; } cnt = 0; for (auto ittoken = Access::gBannedTokens.begin(); ittoken != Access::gBannedTokens.end(); ++ittoken) { ++cnt; if (!ls.monitoring()) { char counter[16]; snprintf(counter, sizeof(counter) - 1, "%02d", cnt); std_out << "[ " << counter << " ] "; } else { std_out << "tokens.banned="; } std_out << ittoken->c_str() << '\n'; } } if (!Access::gAllowedUsers.empty()) { if (!ls.monitoring()) { std_out << "# ....................................................................................\n"; std_out << "# Allowd Users ...\n"; std_out << "# ....................................................................................\n"; } cnt = 0; for (auto ituid = Access::gAllowedUsers.begin(); ituid != Access::gAllowedUsers.end(); ++ituid) { ++cnt; if (!ls.monitoring()) { char counter[16]; snprintf(counter, sizeof(counter) - 1, "%02d", cnt); std_out << "[ " << counter << " ] "; } else { std_out << "user.allowed="; } if (ls.id2name()) { std_out << eos::common::Mapping::UidAsString(*ituid).c_str(); } else { int terrc = 0; std_out << eos::common::Mapping::UidToUserName(*ituid, terrc).c_str(); } std_out << '\n'; } } if (!Access::gAllowedGroups.empty()) { if (!ls.monitoring()) { std_out << "# ....................................................................................\n"; std_out << "# Allowed Groups...\n"; std_out << "# ....................................................................................\n"; } cnt = 0; for (auto itgid = Access::gAllowedGroups.begin(); itgid != Access::gAllowedGroups.end(); itgid++) { ++cnt; if (!ls.monitoring()) { char counter[16]; snprintf(counter, sizeof(counter) - 1, "%02d", cnt); std_out << "[ " << counter << " ] "; } else { std_out << "group.allowed="; } if (ls.id2name()) { std_out << eos::common::Mapping::GidAsString(*itgid).c_str(); } else { int terrc = 0; std_out << eos::common::Mapping::GidToGroupName(*itgid, terrc).c_str(); } std_out << '\n'; } } if (!Access::gAllowedHosts.empty()) { if (!ls.monitoring()) { std_out << "# ....................................................................................\n"; std_out << "# Allowed Hosts ...\n"; std_out << "# ....................................................................................\n"; } cnt = 0; for (auto ithost = Access::gAllowedHosts.begin(); ithost != Access::gAllowedHosts.end(); ithost++) { cnt++; if (!ls.monitoring()) { char counter[16]; snprintf(counter, sizeof(counter) - 1, "%02d", cnt); std_out << "[ " << counter << " ] "; } else { std_out << "host.allowed="; } std_out << ithost->c_str() << '\n'; } } if (!Access::gAllowedDomains.empty()) { if (!ls.monitoring()) { std_out << "# ....................................................................................\n"; std_out << "# Allowed Domains ...\n"; std_out << "# ....................................................................................\n"; } cnt = 0; for (auto itdomain = Access::gAllowedDomains.begin(); itdomain != Access::gAllowedDomains.end(); ++itdomain) { ++cnt; if (!ls.monitoring()) { char counter[16]; snprintf(counter, sizeof(counter) - 1, "%02d", cnt); std_out << "[ " << counter << " ] "; } else { std_out << "domain.allowed="; } std_out << itdomain->c_str() << '\n'; } } if (!Access::gAllowedTokens.empty()) { if (!ls.monitoring()) { std_out << "# ....................................................................................\n"; std_out << "# Allowed Tokens ...\n"; std_out << "# ....................................................................................\n"; } cnt = 0; for (auto ittoken = Access::gAllowedTokens.begin(); ittoken != Access::gAllowedTokens.end(); ++ittoken) { ++cnt; if (!ls.monitoring()) { char counter[16]; snprintf(counter, sizeof(counter) - 1, "%02d", cnt); std_out << "[ " << counter << " ] "; } else { std_out << "tokens.allowed="; } std_out << ittoken->c_str() << '\n'; } } if (!Access::gRedirectionRules.empty()) { if (!ls.monitoring()) { std_out << "# ....................................................................................\n"; std_out << "# Redirection Rules ...\n"; std_out << "# ....................................................................................\n"; } cnt = 0; for (auto itred = Access::gRedirectionRules.begin(); itred != Access::gRedirectionRules.end(); ++itred) { ++cnt; if (!ls.monitoring()) { char counter[1024]; snprintf(counter, sizeof(counter) - 1, "[ %02d ] %32s => ", cnt, itred->first.c_str()); std_out << counter; } else { std_out << "redirect." << itred->first.c_str() << "="; } std_out << itred->second.c_str() << '\n'; } } if (!Access::gStallRules.empty()) { if (!ls.monitoring()) { std_out << "# ....................................................................................\n"; std_out << "# Stall Rules ...\n"; std_out << "# ....................................................................................\n"; } cnt = 0; for (auto itred = Access::gStallRules.begin(); itred != Access::gStallRules.end(); ++itred) { ++cnt; if (!ls.monitoring()) { char counter[1024]; snprintf(counter, sizeof(counter) - 1, "[ %02d ] %32s => ", cnt, itred->first.c_str()); std_out << counter; } else { std_out << "stall." << itred->first.c_str() << "="; } std_out << itred->second.c_str(); if (!ls.monitoring()) { std_out << "\t" << Access::gStallComment[itred->first].c_str(); } else { std_out << " mComment=\"" << Access::gStallComment[itred->first].c_str() << "\""; } std_out << '\n'; } } if (!Access::gStallHosts.empty()) { if (!ls.monitoring()) { std_out << "# ....................................................................................\n"; std_out << "# Hosts in the stall white list ...\n"; std_out << "# ....................................................................................\n"; } cnt = 0; for (auto ithost = Access::gStallHosts.begin(); ithost != Access::gStallHosts.end(); ithost++) { cnt++; if (!ls.monitoring()) { char counter[16]; snprintf(counter, sizeof(counter) - 1, "%02d", cnt); std_out << "[ " << counter << " ] "; } else { std_out << "host.stallhosts="; } std_out << ithost->c_str() << '\n'; } } if (!Access::gNoStallHosts.empty()) { if (!ls.monitoring()) { std_out << "# ....................................................................................\n"; std_out << "# Hosts in the no-stall black list ...\n"; std_out << "# ....................................................................................\n"; } cnt = 0; for (auto ithost = Access::gNoStallHosts.begin(); ithost != Access::gNoStallHosts.end(); ithost++) { cnt++; if (!ls.monitoring()) { char counter[16]; snprintf(counter, sizeof(counter) - 1, "%02d", cnt); std_out << "[ " << counter << " ] "; } else { std_out << "host.nostallhosts="; } std_out << ithost->c_str() << '\n'; } } reply.set_std_out(std_out.str()); reply.set_std_err(std_err.str()); reply.set_retc(ret_c); } //------------------------------------------------------------------------------ // Execute rm subcommand //------------------------------------------------------------------------------ void AccessCmd::RmSubcmd(const eos::console::AccessProto_RmProto& rm, eos::console::ReplyProto& reply) { std::ostringstream std_out {""}; std::ostringstream std_err {""}; int ret_c = 0; gOFS->MgmStats.Add("AccessControl", mVid.uid, mVid.gid, 1); eos::common::RWMutexWriteLock lock(Access::gAccessMutex); switch (rm.rule()) { case eos::console::AccessProto_RmProto::REDIRECT : { if (!((Access::gRedirectionRules.count("*") && rm.key().empty()) || (Access::gRedirectionRules.count("r:*") && rm.key() == "r") || (Access::gRedirectionRules.count("w:*") && rm.key() == "w") || (Access::gRedirectionRules.count("ENONET:*") && rm.key() == "ENONET") || (Access::gRedirectionRules.count("ENOENT:*") && rm.key() == "ENOENT") || (Access::gRedirectionRules.count("ENETUNREACH:*") && rm.key() == "ENETUNREACH"))) { reply.set_std_err("error: there is no global redirection defined with " "such key: '" + rm.key() + '\''); reply.set_retc(EINVAL); return; } else { std_out << "success: removing global redirection"; if (!rm.key().empty()) { std_out << " for <" << rm.key() << ">"; } if (rm.key().empty()) { Access::gRedirectionRules.erase("*"); } else { Access::gRedirectionRules.erase(rm.key() + ":*"); } lock.Release(); eos::common::RWMutexReadLock lock(Access::gAccessMutex); if (!Access::StoreAccessConfig()) { reply.set_std_err("error: unable to store access configuration"); reply.set_retc(EIO); return; } } } break; case eos::console::AccessProto_RmProto::STALL : case eos::console::AccessProto_RmProto::LIMIT : { if (!((Access::gStallRules.count("*") && rm.key().empty()) || (Access::gStallRules.count("r:*") && (rm.key() == "r")) || (Access::gStallRules.count("w:*") && (rm.key() == "w")) || (Access::gStallRules.count("ENONET:*") && (rm.key() == "ENONET")) || (Access::gStallRules.count("ENOENT:*") && (rm.key() == "ENOENT")) || (Access::gStallRules.count("ENETUNREACH:*") && (rm.key() == "ENETUNREACH")) || !rm.key().empty())) { reply.set_std_err("error: there is no global redirection defined with " "such key: '" + rm.key() + '\''); reply.set_retc(EINVAL); return; } else { std_out << "success: removing global "; if (!rm.key().empty()) { if ((rm.key().find("rate:user:") == 0) || (rm.key().find("rate:group:") == 0) || (rm.key().find("threads:") == 0)) { std_out << "limit"; } else { std_out << "stall"; } std_out << " for <" << rm.key() << ">"; } if ((rm.key().find("rate:user:") == 0) || (rm.key().find("rate:group:") == 0) || (rm.key().find("threads:") == 0)) { const std::string rule_key = ProcessRuleKey(rm.key()); if (rule_key.empty()) { reply.set_std_err("error: malformed access rule"); reply.set_retc(EINVAL); return; } // Remove by uid Access::gStallRules.erase(rule_key); Access::gStallComment.erase(rule_key); // Also remove by username to cover old bug Access::gStallRules.erase(rm.key()); Access::gStallComment.erase(rm.key()); } else if (rm.key().empty()) { Access::gStallRules.erase("*"); Access::gStallComment.erase("*"); } else { Access::gStallRules.erase(rm.key() + ":*"); Access::gStallComment.erase(rm.key() + ":*"); } lock.Release(); eos::common::RWMutexReadLock rlock(Access::gAccessMutex); if (!Access::StoreAccessConfig()) { reply.set_std_err("error: unable to store access configuration"); reply.set_retc(EIO); return; } } } break; default : // should never happen reply.set_std_err("error: rule not found, it should be one of redirect|stall|limit"); reply.set_retc(EINVAL); return; } reply.set_std_out(std_out.str()); reply.set_std_err(std_err.str()); reply.set_retc(ret_c); } //------------------------------------------------------------------------------ // Execute set subcommand //------------------------------------------------------------------------------ void AccessCmd::SetSubcmd(const eos::console::AccessProto_SetProto& set, eos::console::ReplyProto& reply) { std::ostringstream std_out {""}; std::ostringstream std_err {""}; int ret_c = 0; gOFS->MgmStats.Add("AccessControl", mVid.uid, mVid.gid, 1); eos::common::RWMutexWriteLock lock(Access::gAccessMutex); switch (set.rule()) { case eos::console::AccessProto_SetProto::REDIRECT : { if (!(set.key().empty() || (set.key() == "r") || (set.key() == "w") || (set.key() == "ENONET") || (set.key() == "ENOENT") || (set.key() == "ENETUNREACH"))) { reply.set_std_err("error: there is no redirection to set with such " "key: '" + set.key() + '\''); reply.set_retc(EINVAL); return; } else { std_out << "success: setting global redirection to '" << set.target() << '\''; if (!set.key().empty()) { std_out << " for <" << set.key() << ">"; } if (set.key().empty()) { Access::gRedirectionRules["*"] = set.target(); } else { Access::gRedirectionRules[set.key() + ":*"] = set.target(); } lock.Release(); eos::common::RWMutexReadLock rlock(Access::gAccessMutex); if (!Access::StoreAccessConfig()) { reply.set_std_err("error: unable to store access configuration"); reply.set_retc(EIO); return; } } } break; case eos::console::AccessProto_SetProto::STALL : case eos::console::AccessProto_SetProto::LIMIT : { int target; try { target = (std::stoi(set.target())); } catch (const std::exception& e) { reply.set_std_err("error: target must be an integer equal or greater than 0 (value zero allowed just for 'rate:' limit)"); reply.set_retc(EINVAL); return; } if (!((set.key().find("rate:") == 0 && target >= 0) || (target > 0))) { reply.set_std_err("error: target must be an integer equal or greater than 0 (value zero allowed just for 'rate:' limit)"); reply.set_retc(EINVAL); return; } if (set.key().find("rate:") == 0) { std_out << "success: setting rate cutoff at " << set.target() << " Hz for rate::=" << set.key(); } else if (set.key().find("threads:") == 0) { std_out << "success: setting thread limit at " << set.target() << " for " << set.key(); } else { if (!(set.key().empty() || (set.key() == "r") || (set.key() == "w") || (set.key() == "ENONET") || (set.key() == "ENOENT") || (set.key() == "ENETUNREACH"))) { reply.set_std_err("error: there is no stall to set with such " "key: '" + set.key() + '\''); reply.set_retc(EINVAL); return; } std_out << "success: setting global stall to " << set.target() << " seconds"; if (!set.key().empty()) { std_out << " for <" << set.key() << ">"; } } if ((set.key().find("rate:user:") == 0) || (set.key().find("rate:group:") == 0) || (set.key().find("threads:") == 0)) { const std::string rule_key = ProcessRuleKey(set.key()); if (rule_key.empty()) { reply.set_std_err("error: malformed access rule"); reply.set_retc(EINVAL); return; } Access::gStallRules[rule_key] = set.target(); Access::gStallComment[rule_key] = mReqProto.comment(); } else if (set.key().empty()) { Access::gStallRules["*"] = set.target(); Access::gStallComment["*"] = mReqProto.comment(); } else { Access::gStallRules[set.key() + ":*"] = set.target(); Access::gStallComment[set.key() + ":*"] = mReqProto.comment(); } lock.Release(); eos::common::RWMutexReadLock rlock(Access::gAccessMutex); if (!Access::StoreAccessConfig()) { reply.set_std_err("error: unable to store access configuration"); reply.set_retc(EIO); return; } } break; default : // should never happen reply.set_std_err("error: rule not found, it should be one of redirect|stall|limit"); reply.set_retc(EINVAL); return; } reply.set_std_out(std_out.str()); reply.set_std_err(std_err.str()); reply.set_retc(ret_c); } // @note (faluchet) all this machinery (and more) should be done with templates and funct programming... Later void AccessCmd::aux(const string& sid, std::ostringstream& std_out, std::ostringstream& std_err, int& ret_c) { std::string saction; switch (mReqProto.access().subcmd_case()) { case eos::console::AccessProto::kBan: saction = "ban"; break; case eos::console::AccessProto::kUnban: saction = "unban"; break; case eos::console::AccessProto::kAllow: saction = "allow"; break; case eos::console::AccessProto::kUnallow: saction = "unallow"; break; case eos::console::AccessProto::kStallhosts: saction = "(un-)stallhosts"; break; default : ; } eos::common::RWMutexReadLock rlock(Access::gAccessMutex); if (Access::StoreAccessConfig()) { std_out << "success: " << saction << " '" << sid << '\''; ret_c = 0; } else { std_err << "error: unable to store access configuration"; ret_c = EIO; } } //---------------------------------------------------------------------------- // Execute ban subcommand //---------------------------------------------------------------------------- void AccessCmd::BanSubcmd(const eos::console::AccessProto_BanProto& ban, eos::console::ReplyProto& reply) { std::ostringstream std_out{""}; std::ostringstream std_err{""}; int ret_c = 0; int errc = 0; gOFS->MgmStats.Add("AccessControl", mVid.uid, mVid.gid, 1); eos::common::RWMutexWriteLock lock(Access::gAccessMutex); switch (ban.idtype()) { case eos::console::AccessProto_BanProto::USER : { uid_t uid = eos::common::Mapping::UserNameToUid(ban.id(), errc); if (!errc) { Access::gBannedUsers.insert(uid); lock.Release(); aux(ban.id(), std_out, std_err, ret_c); } else { std_err << "error: no such user - cannot ban '" << ban.id() << '\''; ret_c = EINVAL; } } break; case eos::console::AccessProto_BanProto::GROUP : { gid_t gid = eos::common::Mapping::GroupNameToGid(ban.id(), errc); if (!errc) { Access::gBannedGroups.insert(gid); lock.Release(); aux(ban.id(), std_out, std_err, ret_c); } else { std_err << "error: no such group - cannot ban '" << ban.id() << '\''; ret_c = EINVAL; } } break; case eos::console::AccessProto_BanProto::HOST : { Access::gBannedHosts.insert(ban.id()); lock.Release(); aux(ban.id(), std_out, std_err, ret_c); } break; case eos::console::AccessProto_BanProto::DOMAINNAME : { Access::gBannedDomains.insert(ban.id()); lock.Release(); aux(ban.id(), std_out, std_err, ret_c); } break; case eos::console::AccessProto_BanProto::TOKEN : { Access::gBannedTokens.insert(ban.id()); lock.Release(); aux(ban.id(), std_out, std_err, ret_c); } break; default: ; } reply.set_std_out(std_out.str()); reply.set_std_err(std_err.str()); reply.set_retc(ret_c); } //------------------------------------------------------------------------------ // Execute unban subcommand //------------------------------------------------------------------------------ void AccessCmd::UnbanSubcmd(const eos::console::AccessProto_UnbanProto& unban, eos::console::ReplyProto& reply) { std::ostringstream std_out{""}; std::ostringstream std_err{""}; int ret_c = 0; int errc = 0; gOFS->MgmStats.Add("AccessControl", mVid.uid, mVid.gid, 1); eos::common::RWMutexWriteLock lock(Access::gAccessMutex); switch (unban.idtype()) { case eos::console::AccessProto_UnbanProto::USER : { uid_t uid = eos::common::Mapping::UserNameToUid(unban.id(), errc); if (!errc) { if (Access::gBannedUsers.count(uid)) { Access::gBannedUsers.erase(uid); lock.Release(); aux(unban.id(), std_out, std_err, ret_c); } else { std_err << "error: user '" << unban.id() << "' is not banned anyway"; ret_c = ENOENT; } } else { std_err << "error: no such user - cannot unban '" << unban.id() << '\''; ret_c = EINVAL; } } break; case eos::console::AccessProto_UnbanProto::GROUP : { gid_t gid = eos::common::Mapping::GroupNameToGid(unban.id(), errc); if (!errc) { if (Access::gBannedGroups.count(gid)) { Access::gBannedGroups.erase(gid); lock.Release(); aux(unban.id(), std_out, std_err, ret_c); } else { std_err << "error: group '" << unban.id() << "' is not banned anyway"; ret_c = ENOENT; } } else { std_err << "error: no such group - cannot unban '" << unban.id() << '\''; ret_c = EINVAL; } } break; case eos::console::AccessProto_UnbanProto::HOST : { if (Access::gBannedHosts.count(unban.id())) { Access::gBannedHosts.erase(unban.id()); lock.Release(); aux(unban.id(), std_out, std_err, ret_c); lock.Grab(Access::gAccessMutex); } else { std_err << "error: host '" << unban.id() << "' is not banned anyway"; ret_c = ENOENT; } } break; case eos::console::AccessProto_UnbanProto::DOMAINNAME : { if (Access::gBannedDomains.count(unban.id())) { Access::gBannedDomains.erase(unban.id()); lock.Release(); aux(unban.id(), std_out, std_err, ret_c); lock.Grab(Access::gAccessMutex); } else { std_err << "error: domain '" << unban.id() << "' is not banned anyway"; ret_c = ENOENT; } } break; case eos::console::AccessProto_UnbanProto::TOKEN : { if (Access::gBannedTokens.count(unban.id())) { Access::gBannedTokens.erase(unban.id()); lock.Release(); aux(unban.id(), std_out, std_err, ret_c); lock.Grab(Access::gAccessMutex); } else { std_err << "error: token '" << unban.id() << "' is not banned anyway"; ret_c = ENOENT; } } break; default: ; } reply.set_std_out(std_out.str()); reply.set_std_err(std_err.str()); reply.set_retc(ret_c); } //------------------------------------------------------------------------------ // Execute allow subcommand //------------------------------------------------------------------------------ void AccessCmd::AllowSubcmd(const eos::console::AccessProto_AllowProto& allow, eos::console::ReplyProto& reply) { std::ostringstream std_out{""}; std::ostringstream std_err{""}; int ret_c = 0; int errc = 0; gOFS->MgmStats.Add("AccessControl", mVid.uid, mVid.gid, 1); eos::common::RWMutexWriteLock lock(Access::gAccessMutex); switch (allow.idtype()) { case eos::console::AccessProto_AllowProto::USER : { uid_t uid = eos::common::Mapping::UserNameToUid(allow.id(), errc); if (!errc) { Access::gAllowedUsers.insert(uid); lock.Release(); aux(allow.id(), std_out, std_err, ret_c); } else { std_err << "error: no such user - cannot allow '" << allow.id() << '\''; ret_c = EINVAL; } } break; case eos::console::AccessProto_AllowProto::GROUP : { gid_t gid = eos::common::Mapping::GroupNameToGid(allow.id(), errc); if (!errc) { Access::gAllowedGroups.insert(gid); lock.Release(); aux(allow.id(), std_out, std_err, ret_c); } else { std_err << "error: no such group - cannot allow '" << allow.id() << '\''; ret_c = EINVAL; } } break; case eos::console::AccessProto_AllowProto::HOST : { Access::gAllowedHosts.insert(allow.id()); lock.Release(); aux(allow.id(), std_out, std_err, ret_c); } break; case eos::console::AccessProto_AllowProto::DOMAINNAME : { Access::gAllowedDomains.insert(allow.id()); lock.Release(); aux(allow.id(), std_out, std_err, ret_c); } break; case eos::console::AccessProto_AllowProto::TOKEN : { Access::gAllowedTokens.insert(allow.id()); lock.Release(); aux(allow.id(), std_out, std_err, ret_c); } break; default: ; } reply.set_std_out(std_out.str()); reply.set_std_err(std_err.str()); reply.set_retc(ret_c); } //------------------------------------------------------------------------------ // Execute unallow subcommand //------------------------------------------------------------------------------ void AccessCmd::UnallowSubcmd(const eos::console::AccessProto_UnallowProto& unallow, eos::console::ReplyProto& reply) { std::ostringstream std_out{""}; std::ostringstream std_err{""}; int ret_c = 0; int errc = 0; gOFS->MgmStats.Add("AccessControl", mVid.uid, mVid.gid, 1); eos::common::RWMutexWriteLock lock(Access::gAccessMutex); switch (unallow.idtype()) { case eos::console::AccessProto_UnallowProto::USER : { uid_t uid = eos::common::Mapping::UserNameToUid(unallow.id(), errc); if (!errc) { if (Access::gAllowedUsers.count(uid)) { Access::gAllowedUsers.erase(uid); lock.Release(); aux(unallow.id(), std_out, std_err, ret_c); } else { std_err << "error: user '" << unallow.id() << "' is not allowed anyway"; ret_c = ENOENT; } } else { std_err << "error: no such user - cannot unallow '" << unallow.id() << '\''; ret_c = EINVAL; } } break; case eos::console::AccessProto_UnallowProto::GROUP : { gid_t gid = eos::common::Mapping::GroupNameToGid(unallow.id(), errc); if (!errc) { if (Access::gAllowedGroups.count(gid)) { Access::gAllowedGroups.erase(gid); lock.Release(); aux(unallow.id(), std_out, std_err, ret_c); } else { std_err << "error: group '" << unallow.id() << "' is not allowed anyway"; ret_c = ENOENT; } } else { std_err << "error: no such group - cannot unallow '" << unallow.id() << '\''; ret_c = EINVAL; } } break; case eos::console::AccessProto_UnallowProto::HOST : { if (Access::gAllowedHosts.count(unallow.id())) { Access::gAllowedHosts.erase(unallow.id()); lock.Release(); aux(unallow.id(), std_out, std_err, ret_c); } else { std_err << "error: host '" << unallow.id() << "' is not allowed anyway"; ret_c = ENOENT; } } break; case eos::console::AccessProto_UnallowProto::DOMAINNAME : { if (Access::gAllowedDomains.count(unallow.id())) { Access::gAllowedDomains.erase(unallow.id()); lock.Release(); aux(unallow.id(), std_out, std_err, ret_c); } else { std_err << "error: domain '" << unallow.id() << "' is not allowed anyway"; ret_c = ENOENT; } } break; case eos::console::AccessProto_UnallowProto::TOKEN : { if (Access::gAllowedTokens.count(unallow.id())) { Access::gAllowedTokens.erase(unallow.id()); lock.Release(); aux(unallow.id(), std_out, std_err, ret_c); } else { std_err << "error: domain '" << unallow.id() << "' is not allowed anyway"; ret_c = ENOENT; } } break; default: ; } reply.set_std_out(std_out.str()); reply.set_std_err(std_err.str()); reply.set_retc(ret_c); } //---------------------------------------------------------------------------- // Execute stallhostssubcommand //---------------------------------------------------------------------------- void AccessCmd::StallhostsSubcmd(const eos::console::AccessProto_StallHostsProto& stall, eos::console::ReplyProto& reply) { std::ostringstream std_out{""}; std::ostringstream std_err{""}; int ret_c = 0; gOFS->MgmStats.Add("AccessControl", mVid.uid, mVid.gid, 1); eos::common::RWMutexWriteLock lock(Access::gAccessMutex); switch (stall.type()) { case eos::console::AccessProto_StallHostsProto::STALL : switch (stall.op()) { case eos::console::AccessProto_StallHostsProto::ADD: { if (Access::gStallHosts.count(stall.hostpattern())) { ret_c = EEXIST; std_err << "error: entry exists already in the stall list\n"; } else { if (Access::gNoStallHosts.count(stall.hostpattern())) { ret_c = EEXIST; std_err << "error: this pattern is in the no-stall list!\n"; } else { Access::gStallHosts.insert(stall.hostpattern()); } } lock.Release(); if (!ret_c) { aux(stall.hostpattern(), std_out, std_err, ret_c); } break; } case eos::console::AccessProto_StallHostsProto::REMOVE: { if (!Access::gStallHosts.count(stall.hostpattern())) { ret_c = ENOENT; std_err << "error: this pattern is not in the stall list\n"; } else { Access::gStallHosts.erase(stall.hostpattern()); } lock.Release(); if (!ret_c) { aux(stall.hostpattern(), std_out, std_err, ret_c); } break; } default: lock.Release(); ret_c = EINVAL; } break; case eos::console::AccessProto_StallHostsProto::NOSTALL : switch (stall.op()) { case eos::console::AccessProto_StallHostsProto::ADD: { if (Access::gNoStallHosts.count(stall.hostpattern())) { ret_c = EEXIST; std_err << "error: entry exists already in the no-stall list\n"; } else { if (Access::gStallHosts.count(stall.hostpattern())) { ret_c = EEXIST; std_err << "error: this pattern is in the stall list!\n"; } else { Access::gNoStallHosts.insert(stall.hostpattern()); } } lock.Release(); aux(stall.hostpattern(), std_out, std_err, ret_c); break; } case eos::console::AccessProto_StallHostsProto::REMOVE: { if (!Access::gNoStallHosts.count(stall.hostpattern())) { ret_c = ENOENT; std_err << "error: this pattern is not in the nostall list\n"; } else { Access::gNoStallHosts.erase(stall.hostpattern()); } lock.Release(); aux(stall.hostpattern(), std_out, std_err, ret_c); break; } default: lock.Release(); ret_c = EINVAL; aux(stall.hostpattern(), std_out, std_err, ret_c); } default: break; } reply.set_std_out(std_out.str()); reply.set_std_err(std_err.str()); reply.set_retc(ret_c); } EOSMGMNAMESPACE_END