aboutsummaryrefslogtreecommitdiffstats
path: root/modules/sethost.cpp
diff options
context:
space:
mode:
authorGravatar Sadie Powell2026-03-01 16:13:53 +0000
committerGravatar Sadie Powell2026-03-01 18:05:14 +0000
commitf311ac1ecee20e164666e3d63a349c54c780aabd (patch)
treec30c2a6c0351abef3b38c3c6b47a291a51081083 /modules/sethost.cpp
parentDebug log when an encapsulated command fails. (diff)
Merge the chg* and set* modules.
Diffstat (limited to 'modules/sethost.cpp')
-rw-r--r--modules/sethost.cpp71
1 files changed, 57 insertions, 14 deletions
diff --git a/modules/sethost.cpp b/modules/sethost.cpp
index e5804cad8..5a5c10db4 100644
--- a/modules/sethost.cpp
+++ b/modules/sethost.cpp
@@ -23,52 +23,96 @@
#include "inspircd.h"
+#include "modules/ircv3.h"
+#include "numerichelper.h"
-class CommandSethost final
+class CommandSetHost final
: public Command
{
public:
+ IRCv3::ReplyCapReference cap;
CharState hostmap;
- CommandSethost(Module* Creator)
- : Command(Creator, "SETHOST", 1)
+ CommandSetHost(Module* mod)
+ : Command(mod, "SETHOST", 1, 2)
+ , cap(mod)
{
access_needed = CmdAccess::OPERATOR;
- syntax = { "<host>" };
+ syntax = { "[<nick>] :<newhost>" };
}
CmdResult Handle(User* user, const Params& parameters) override
{
- if (parameters[0].length() > ServerInstance->Config->Limits.MaxHost)
+ auto* target = user;
+ if (parameters.size() > 1)
{
- user->WriteNotice("*** SETHOST: Host too long");
+ const auto& targetnick = parameters[0];
+ if (IS_LOCAL(user))
+ {
+ // For local users we need to check if they can use the command.
+ target = ServerInstance->Users.FindNick(targetnick, true);
+ if (user != target && !user->HasPrivPermission("users/sethost-others"))
+ {
+ user->WriteNumeric(Numerics::NoPrivileges("your server operator account does not have the users/sethost-others privilege"));
+ return CmdResult::FAILURE;
+ }
+ }
+ else
+ {
+ // For remote users their server will have checked privs.
+ target = ServerInstance->Users.Find(targetnick);
+ }
+
+ if (!target)
+ {
+ user->WriteNumeric(Numerics::NoSuchNick(targetnick));
+ return CmdResult::FAILURE;
+ }
+ }
+
+ if (!IS_LOCAL(target))
+ return CmdResult::SUCCESS; // Their server will handle this.
+
+ const auto& newhost = parameters.back();
+ if (newhost.size() > ServerInstance->Config->Limits.MaxHost)
+ {
+ IRCv3::WriteReply(Reply::Type::FAIL, user, cap, this, "INVALID_HOSTNAME", "Hostname is too long");
return CmdResult::FAILURE;
}
- for (const auto chr : parameters[0])
+ for (const auto chr : newhost)
{
if (!hostmap.test(static_cast<unsigned char>(chr)))
{
- user->WriteNotice("*** SETHOST: Invalid characters in hostname");
+ IRCv3::WriteReply(Reply::Type::FAIL, user, cap, this, "INVALID_HOSTNAME", "Invalid characters in hostname");
return CmdResult::FAILURE;
}
}
- user->ChangeDisplayedHost(parameters[0]);
- ServerInstance->SNO.WriteGlobalSno('a', user->nick+" used SETHOST to change their displayed host to "+user->GetDisplayedHost());
+ target->ChangeDisplayedHost(newhost);
+ if (!user->server->IsService())
+ {
+ ServerInstance->SNO.WriteGlobalSno('a', "{} ({}) used {} to change the hostname of {} to \"{}\x0F\"",
+ user->GetRealMask(), user->GetAddress(), this->name, target->nick, newhost);
+ }
return CmdResult::SUCCESS;
}
+
+ RouteDescriptor GetRouting(User* user, const Params& parameters) override
+ {
+ return parameters.size() > 1 ? ROUTE_OPT_UCAST(parameters[0]) : ROUTE_LOCALONLY;
+ }
};
class ModuleSetHost final
: public Module
{
private:
- CommandSethost cmd;
+ CommandSetHost cmd;
public:
ModuleSetHost()
- : Module(VF_VENDOR, "Adds the /SETHOST command which allows server operators to change their displayed hostname.")
+ : Module(VF_VENDOR | VF_OPTCOMMON, "Adds the /SETHOST command which allows server operators to change the hostname of users.")
, cmd(this)
{
}
@@ -76,10 +120,9 @@ public:
void ReadConfig(ConfigStatus& status) override
{
const auto& tag = ServerInstance->Config->ConfValue("hostname");
- const std::string hmap = tag->getString("charmap", "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz.-_/0123456789", 1);
CharState newhostmap;
- for (const auto chr : hmap)
+ for (const auto chr : tag->getString("charmap", "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz.-_/0123456789", 1))
{
// A hostname can not contain NUL, LF, CR, or SPACE.
if (chr == 0x00 || chr == 0x0A || chr == 0x0D || chr == 0x20)