summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSadie Powell <sadie@witchery.services>2025-04-24 12:46:58 +0100
committerSadie Powell <sadie@witchery.services>2025-04-24 12:46:58 +0100
commitfad0a4a0e888b8025b0ae4e456085e28415b0453 (patch)
tree98bf9f117eaed9c0cad6af2dd049cf55c2ef0dd7
parent1630ccedb11842dbe56d8ce2b9e9f54a53b01b8c (diff)
Add support for hashing operator passwords in the config.
Closes #327.
-rw-r--r--data/anope.example.conf10
-rw-r--r--include/opertype.h1
-rw-r--r--modules/operserv/os_login.cpp17
-rw-r--r--src/config.cpp2
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;