diff options
author | Sadie Powell <sadie@witchery.services> | 2025-04-24 12:46:58 +0100 |
---|---|---|
committer | Sadie Powell <sadie@witchery.services> | 2025-04-24 12:46:58 +0100 |
commit | fad0a4a0e888b8025b0ae4e456085e28415b0453 (patch) | |
tree | 98bf9f117eaed9c0cad6af2dd049cf55c2ef0dd7 | |
parent | 1630ccedb11842dbe56d8ce2b9e9f54a53b01b8c (diff) |
Add support for hashing operator passwords in the config.
Closes #327.
-rw-r--r-- | data/anope.example.conf | 10 | ||||
-rw-r--r-- | include/opertype.h | 1 | ||||
-rw-r--r-- | modules/operserv/os_login.cpp | 17 | ||||
-rw-r--r-- | src/config.cpp | 2 |
4 files changed, 29 insertions, 1 deletions
diff --git a/data/anope.example.conf b/data/anope.example.conf index 4e81cd3c3..e8e587b97 100644 --- a/data/anope.example.conf +++ b/data/anope.example.conf @@ -875,6 +875,16 @@ opertype /* An optional password. If defined, the user must login using "/OPERSERV LOGIN" first */ #password = "secret" + /* + * The algorithm which the above password is hashed with. If this is not set then services will + * assume the above password is not hashed. + * + * You will need to have the appropriate encryption module (e.g. enc_bcrypt) loaded in order + * for this to work. + * + */ + #password_hash = "bcrypt" + /* An optional SSL fingerprint. If defined, it's required to be able to use this opertype. */ #certfp = "ed3383b3f7d74e89433ddaa4a6e5b2d7" diff --git a/include/opertype.h b/include/opertype.h index 16b52a34a..4094866ea 100644 --- a/include/opertype.h +++ b/include/opertype.h @@ -23,6 +23,7 @@ struct CoreExport Oper /* Whether the user must be an IRC operator (umode +o) to be considered a services operator */ bool require_oper = true; Anope::string password; + Anope::string password_hash; std::vector<Anope::string> certfp; /* Hosts allowed to use this operator block */ std::vector<Anope::string> hosts; diff --git a/modules/operserv/os_login.cpp b/modules/operserv/os_login.cpp index f453bd8f0..21c5897f6 100644 --- a/modules/operserv/os_login.cpp +++ b/modules/operserv/os_login.cpp @@ -10,10 +10,25 @@ */ #include "module.h" +#include "modules/encryption.h" class CommandOSLogin final : public Command { +private: + bool ComparePassword(const Oper *o, const Anope::string &password) + { + if (o->password_hash.empty()) + return o->password.equals_cs(password); // Plaintext password. + + auto *service = Service::FindService("Encryption::Provider", o->password_hash); + if (!service) + return false; // Malformed hash. + + auto *hashprov = static_cast<Encryption::Provider *>(service); + return hashprov->Compare(o->password, password); + } + public: CommandOSLogin(Module *creator) : Command(creator, "operserv/login", 0, 1) { @@ -31,7 +46,7 @@ public: source.Reply(_("Your oper block doesn't require logging in.")); else if (u->HasExt("os_login")) source.Reply(_("You are already identified.")); - else if (params.empty() || o->password != params[0]) + else if (params.empty() || !ComparePassword(o, params[0])) { source.Reply(PASSWORD_INCORRECT); u->BadPassword(); diff --git a/src/config.cpp b/src/config.cpp index 1a1c91cc1..a356bcd80 100644 --- a/src/config.cpp +++ b/src/config.cpp @@ -300,6 +300,7 @@ Conf::Conf() : Block("") const Anope::string &nname = oper.Get<const Anope::string>("name"), &type = oper.Get<const Anope::string>("type"), &password = oper.Get<const Anope::string>("password"), + &password_hash = oper.Get<const Anope::string>("password_hash"), &certfp = oper.Get<const Anope::string>("certfp"), &host = oper.Get<const Anope::string>("host"), &vhost = oper.Get<const Anope::string>("vhost"); @@ -320,6 +321,7 @@ Conf::Conf() : Block("") auto *o = new Oper(nname, ot); o->require_oper = require_oper; o->password = password; + o->password_hash = password_hash; spacesepstream(certfp).GetTokens(o->certfp); spacesepstream(host).GetTokens(o->hosts); o->vhost = vhost; |