summaryrefslogtreecommitdiff
path: root/src/modules/m_sqlauth.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/modules/m_sqlauth.cpp')
-rw-r--r--src/modules/m_sqlauth.cpp189
1 files changed, 82 insertions, 107 deletions
diff --git a/src/modules/m_sqlauth.cpp b/src/modules/m_sqlauth.cpp
index be6e50e52..df2dd0190 100644
--- a/src/modules/m_sqlauth.cpp
+++ b/src/modules/m_sqlauth.cpp
@@ -12,50 +12,78 @@
*/
#include "inspircd.h"
-#include "m_sqlv2.h"
-#include "m_sqlutils.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
+};
+
+class AuthQuery : public SQLQuery
+{
+ public:
+ const std::string uid;
+ LocalIntExt& pendingExt;
+ bool verbose;
+ AuthQuery(Module* me, const std::string& db, const std::string& q, const std::string& u, LocalIntExt& e, bool v)
+ : SQLQuery(me, db, q), uid(u), pendingExt(e), verbose(v) {}
+
+ void OnResult(SQLResult& res)
+ {
+ User* user = ServerInstance->FindNick(uid);
+ if (!user)
+ return;
+ if (res.Rows())
+ {
+ pendingExt.set(user, AUTH_STATE_NONE);
+ }
+ 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 sqlAuthed;
- Module* SQLutils;
- Module* SQLprovider;
+ LocalIntExt pendingExt;
+ dynamic_reference<SQLProvider> SQL;
std::string freeformquery;
std::string killreason;
std::string allowpattern;
std::string databaseid;
-
bool verbose;
-public:
- ModuleSQLAuth() : sqlAuthed("sqlauth", this)
+ public:
+ ModuleSQLAuth() : pendingExt("sqlauth-wait", this), SQL(this, "SQL")
{
}
void init()
{
- SQLutils = ServerInstance->Modules->Find("m_sqlutils.so");
- if (!SQLutils)
- throw ModuleException("Can't find m_sqlutils.so. Please load m_sqlutils.so before m_sqlauth.so.");
-
- ServiceProvider* prov = ServerInstance->Modules->FindService(SERVICE_DATA, "SQL");
- if (!prov)
- throw ModuleException("Can't find an SQL provider module. Please load one before attempting to load m_sqlauth.");
- SQLprovider = prov->creator;
-
+ ServerInstance->Modules->AddService(pendingExt);
OnRehash(NULL);
Implementation eventlist[] = { I_OnUserDisconnect, I_OnCheckReady, I_OnRehash, I_OnUserRegister };
ServerInstance->Modules->Attach(eventlist, this, 4);
}
- virtual ~ModuleSQLAuth()
- {
- }
-
void OnRehash(User* user)
{
ConfigReader Conf;
@@ -69,115 +97,62 @@ public:
ModResult OnUserRegister(LocalUser* user)
{
- if ((!allowpattern.empty()) && (InspIRCd::Match(user->nick,allowpattern)))
- {
- sqlAuthed.set(user, 1);
+ // Note this is their initial (unresolved) connect block
+ ConfigTag* tag = user->MyClass->config;
+ if (!tag->getBool("usesqlauth", true))
return MOD_RES_PASSTHRU;
- }
-
- if (!CheckCredentials(user))
- {
- ServerInstance->Users->QuitUser(user, killreason);
- return MOD_RES_DENY;
- }
- return MOD_RES_PASSTHRU;
- }
- bool CheckCredentials(LocalUser* user)
- {
- std::string thisquery = freeformquery;
- std::string safepass = user->password;
- std::string safegecos = user->fullname;
+ if (!allowpattern.empty() && InspIRCd::Match(user->nick,allowpattern))
+ return MOD_RES_PASSTHRU;
- /* Search and replace the escaped nick and escaped pass into the query */
+ if (pendingExt.get(user))
+ return MOD_RES_PASSTHRU;
- SearchAndReplace(safepass, std::string("\""), std::string("\\\""));
- SearchAndReplace(safegecos, std::string("\""), std::string("\\\""));
+ pendingExt.set(user, AUTH_STATE_BUSY);
- SearchAndReplace(thisquery, std::string("$nick"), user->nick);
- SearchAndReplace(thisquery, std::string("$pass"), safepass);
- SearchAndReplace(thisquery, std::string("$host"), user->host);
- SearchAndReplace(thisquery, std::string("$ip"), std::string(user->GetIPString()));
- SearchAndReplace(thisquery, std::string("$gecos"), safegecos);
- SearchAndReplace(thisquery, std::string("$ident"), user->ident);
- SearchAndReplace(thisquery, std::string("$server"), std::string(user->server));
- SearchAndReplace(thisquery, std::string("$uuid"), user->uuid);
+ std::string thisquery = freeformquery;
+ ParamM userinfo;
+ userinfo["nick"] = user->nick;
+ userinfo["pass"] = user->password;
+ userinfo["host"] = user->host;
+ userinfo["ip"] = user->GetIPString();
+ userinfo["gecos"] = user->fullname;
+ userinfo["ident"] = user->ident;
+ userinfo["server"] = user->server;
+ userinfo["uuid"] = user->uuid;
HashProvider* md5 = ServerInstance->Modules->FindDataService<HashProvider>("hash/md5");
if (md5)
- SearchAndReplace(thisquery, std::string("$md5pass"), md5->hexsum(user->password));
+ userinfo["md5pass"] = md5->hexsum(user->password);
HashProvider* sha256 = ServerInstance->Modules->FindDataService<HashProvider>("hash/sha256");
if (sha256)
- SearchAndReplace(thisquery, std::string("$sha256pass"), sha256->hexsum(user->password));
-
- /* Build the query */
- SQLrequest req = SQLrequest(this, SQLprovider, databaseid, SQLquery(thisquery));
-
- req.Send();
- /* When we get the query response from the service provider we will be given an ID to play with,
- * just an ID number which is unique to this query. We need a way of associating that ID with a User
- * so we insert it into a map mapping the IDs to users.
- * Thankfully m_sqlutils provides this, it will associate a ID with a user or channel, and if the user quits it removes the
- * association. This means that if the user quits during a query we will just get a failed lookup from m_sqlutils - telling
- * us to discard the query.
- */
- AssociateUser(this, SQLutils, req.id, user).Send();
-
- return true;
+ userinfo["$sha256pass"] = sha256->hexsum(user->password);
+
+ SQL->submit(new AuthQuery(this, databaseid, SQL->FormatQuery(freeformquery, userinfo), user->uuid, pendingExt, verbose));
+
+ return MOD_RES_PASSTHRU;
}
- void OnRequest(Request& request)
+ ModResult OnCheckReady(LocalUser* user)
{
- if(strcmp(SQLRESID, request.id) == 0)
+ switch (pendingExt.get(user))
{
- SQLresult* res = static_cast<SQLresult*>(&request);
-
- User* user = GetAssocUser(this, SQLutils, res->id).S().user;
- UnAssociate(this, SQLutils, res->id).S();
-
- if(user)
- {
- if(res->error.Id() == SQL_NO_ERROR)
- {
- if(res->Rows())
- {
- /* We got a row in the result, this is enough really */
- sqlAuthed.set(user, 1);
- }
- else if (verbose)
- {
- /* No rows in result, this means there was no record matching the user */
- 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());
- }
- }
- else 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(), res->error.Str());
- }
- }
- else
- {
- return;
- }
-
- if (!sqlAuthed.get(user))
- {
+ case AUTH_STATE_NONE:
+ return MOD_RES_PASSTHRU;
+ case AUTH_STATE_BUSY:
+ return MOD_RES_DENY;
+ case AUTH_STATE_FAIL:
ServerInstance->Users->QuitUser(user, killreason);
- }
+ return MOD_RES_DENY;
}
- }
-
- ModResult OnCheckReady(LocalUser* user)
- {
- return sqlAuthed.get(user) ? MOD_RES_PASSTHRU : 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)