diff options
| author | 2010-09-26 10:49:26 -0400 | |
|---|---|---|
| committer | 2010-09-26 10:50:02 -0400 | |
| commit | 8359b31c1ef815343dc415b65efd73bb9b2f81cc (patch) | |
| tree | 71809337667b8869fb614aa30de8ea719a47e967 /src/modules/m_sql_auth.cpp | |
| parent | Make 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.cpp | 174 |
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) |
