aboutsummaryrefslogtreecommitdiff
path: root/src/modules/m_sql_auth.cpp
diff options
context:
space:
mode:
authorGravatar Daniel De Graaf2010-09-26 10:49:26 -0400
committerGravatar Daniel De Graaf2010-09-26 10:50:02 -0400
commit8359b31c1ef815343dc415b65efd73bb9b2f81cc (patch)
tree71809337667b8869fb614aa30de8ea719a47e967 /src/modules/m_sql_auth.cpp
parentMake sure account exists before trying to use it (diff)
Make m_sql_* module names consistent
Diffstat (limited to 'src/modules/m_sql_auth.cpp')
-rw-r--r--src/modules/m_sql_auth.cpp174
1 files changed, 174 insertions, 0 deletions
diff --git a/src/modules/m_sql_auth.cpp b/src/modules/m_sql_auth.cpp
new file mode 100644
index 000000000..ddd708197
--- /dev/null
+++ b/src/modules/m_sql_auth.cpp
@@ -0,0 +1,174 @@
+/* +------------------------------------+
+ * | Inspire Internet Relay Chat Daemon |
+ * +------------------------------------+
+ *
+ * InspIRCd: (C) 2002-2010 InspIRCd Development Team
+ * See: http://wiki.inspircd.org/Credits
+ *
+ * This program is free but copyrighted software; see
+ * the file COPYING for details.
+ *
+ * ---------------------------------------------------
+ */
+
+#include "inspircd.h"
+#include "account.h"
+#include "sql.h"
+#include "hash.h"
+
+/* $ModDesc: Allow/Deny connections based upon an arbitary SQL table */
+
+enum AuthState {
+ AUTH_STATE_NONE = 0,
+ AUTH_STATE_BUSY = 1,
+ AUTH_STATE_FAIL = 2,
+ AUTH_STATE_OK = 3
+};
+
+static dynamic_reference<AccountProvider> account("account");
+
+class AuthQuery : public SQLQuery
+{
+ public:
+ const std::string uid;
+ LocalIntExt& pendingExt;
+ bool verbose;
+ AuthQuery(Module* me, const std::string& u, LocalIntExt& e, bool v)
+ : SQLQuery(me), uid(u), pendingExt(e), verbose(v)
+ {
+ }
+
+ void OnResult(SQLResult& res)
+ {
+ User* user = ServerInstance->FindNick(uid);
+ if (!user)
+ return;
+ SQLEntries result;
+ if (res.GetRow(result))
+ {
+ std::vector<std::string> cols;
+ res.GetCols(cols);
+ std::string acct, tag;
+ for(unsigned int i=0; i < cols.size(); i++)
+ {
+ if (result[i].nul)
+ continue;
+ if (cols[i] == "account")
+ acct = result[i].value;
+ if (cols[i] == "tag")
+ tag = result[i].value;
+ if (cols[i] == "class")
+ ServerInstance->ForcedClass.set(user, result[i].value);
+ }
+ if (!acct.empty() && account)
+ {
+ account->DoLogin(user, acct, tag);
+ }
+ pendingExt.set(user, AUTH_STATE_OK);
+ }
+ else
+ {
+ if (verbose)
+ ServerInstance->SNO->WriteGlobalSno('a', "Forbidden connection from %s!%s@%s (SQL query returned no matches)", user->nick.c_str(), user->ident.c_str(), user->host.c_str());
+ pendingExt.set(user, AUTH_STATE_FAIL);
+ }
+ }
+
+ void OnError(SQLerror& error)
+ {
+ User* user = ServerInstance->FindNick(uid);
+ if (!user)
+ return;
+ pendingExt.set(user, AUTH_STATE_FAIL);
+ if (verbose)
+ ServerInstance->SNO->WriteGlobalSno('a', "Forbidden connection from %s!%s@%s (SQL query failed: %s)", user->nick.c_str(), user->ident.c_str(), user->host.c_str(), error.Str());
+ }
+};
+
+class ModuleSQLAuth : public Module
+{
+ LocalIntExt pendingExt;
+ dynamic_reference<SQLProvider> SQL;
+
+ std::string freeformquery;
+ bool verbose;
+
+ public:
+ ModuleSQLAuth() : pendingExt(EXTENSIBLE_USER, "sqlauth-wait", this), SQL("SQL")
+ {
+ }
+
+ void init()
+ {
+ ServerInstance->Modules->AddService(pendingExt);
+ Implementation eventlist[] = { I_OnCheckReady, I_OnUserRegister, I_OnSetConnectClass };
+ ServerInstance->Modules->Attach(eventlist, this, sizeof(eventlist)/sizeof(Implementation));
+ }
+
+ void ReadConfig(ConfigReadStatus&)
+ {
+ ConfigTag* conf = ServerInstance->Config->GetTag("sqlauth");
+ std::string dbid = conf->getString("dbid");
+ if (dbid.empty())
+ SQL.SetProvider("SQL");
+ else
+ SQL.SetProvider("SQL/" + dbid);
+ freeformquery = conf->getString("query");
+ verbose = conf->getBool("verbose");
+ }
+
+ void OnUserRegister(LocalUser* user)
+ {
+ // Note this is their initial (unresolved) connect block
+ ConfigTag* tag = user->MyClass->config;
+ if (!tag->getBool("usesqlauth", true))
+ return;
+
+ if (pendingExt.get(user))
+ return;
+
+ if (!SQL)
+ {
+ ServerInstance->SNO->WriteGlobalSno('a', "SQLAUTH: No database present, connection denied");
+ pendingExt.set(user, AUTH_STATE_FAIL);
+ return;
+ }
+
+ pendingExt.set(user, AUTH_STATE_BUSY);
+
+ ParamM userinfo;
+ user->PopulateInfoMap(userinfo);
+ userinfo["pass"] = user->password;
+
+ HashProvider* md5 = ServerInstance->Modules->FindDataService<HashProvider>("hash/md5");
+ if (md5)
+ userinfo["md5pass"] = md5->hexsum(user->password);
+
+ HashProvider* sha256 = ServerInstance->Modules->FindDataService<HashProvider>("hash/sha256");
+ if (sha256)
+ userinfo["sha256pass"] = sha256->hexsum(user->password);
+
+ SQL->submit(new AuthQuery(this, user->uuid, pendingExt, verbose), freeformquery, userinfo);
+ }
+
+ ModResult OnCheckReady(LocalUser* user)
+ {
+ if (pendingExt.get(user) == AUTH_STATE_BUSY)
+ return MOD_RES_DENY;
+ return MOD_RES_PASSTHRU;
+ }
+
+ ModResult OnSetConnectClass(LocalUser* user, ConnectClass* myclass)
+ {
+ if (myclass->config->getBool("requiresqlauth", false) && pendingExt.get(user) == AUTH_STATE_FAIL)
+ return MOD_RES_DENY;
+ return MOD_RES_PASSTHRU;
+ }
+
+ Version GetVersion()
+ {
+ return Version("Allow/Deny connections based upon an arbitary SQL table", VF_VENDOR);
+ }
+};
+
+MODULE_INIT(ModuleSQLAuth)