00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014 #include "inspircd.h"
00015 #include "users.h"
00016 #include "channels.h"
00017 #include "modules.h"
00018 #include "configreader.h"
00019
00020 #include "m_sqlv2.h"
00021 #include "m_sqlutils.h"
00022 #include "m_hash.h"
00023 #include "commands/cmd_oper.h"
00024
00025
00026
00027
00028 typedef std::map<irc::string, Module*> hashymodules;
00029
00030 class ModuleSQLOper : public Module
00031 {
00032 Module* SQLutils;
00033 std::string databaseid;
00034 irc::string hashtype;
00035 hashymodules hashers;
00036 bool diduseiface;
00037 std::deque<std::string> names;
00038
00039 public:
00040 ModuleSQLOper(InspIRCd* Me)
00041 : Module(Me)
00042 {
00043 ServerInstance->Modules->UseInterface("SQLutils");
00044 ServerInstance->Modules->UseInterface("SQL");
00045 ServerInstance->Modules->UseInterface("HashRequest");
00046
00047 OnRehash(NULL, "");
00048
00049 diduseiface = false;
00050
00051
00052 modulelist* ml = ServerInstance->Modules->FindInterface("HashRequest");
00053
00054
00055 if (ml)
00056 {
00057
00058 for (modulelist::iterator m = ml->begin(); m != ml->end(); m++)
00059 {
00060
00061
00062
00063 std::string name = HashNameRequest(this, *m).Send();
00064
00065 hashers[name.c_str()] = *m;
00066 names.push_back(name);
00067 }
00068
00069 diduseiface = true;
00070 ServerInstance->Modules->UseInterface("HashRequest");
00071 }
00072
00073 SQLutils = ServerInstance->Modules->Find("m_sqlutils.so");
00074 if (!SQLutils)
00075 throw ModuleException("Can't find m_sqlutils.so. Please load m_sqlutils.so before m_sqloper.so.");
00076
00077 Implementation eventlist[] = { I_OnRequest, I_OnRehash, I_OnPreCommand, I_OnLoadModule };
00078 ServerInstance->Modules->Attach(eventlist, this, 3);
00079 }
00080
00081
00082 bool OneOfMatches(const char* host, const char* ip, const char* hostlist)
00083 {
00084 std::stringstream hl(hostlist);
00085 std::string xhost;
00086 while (hl >> xhost)
00087 {
00088 if (InspIRCd::Match(host, xhost, NULL) || InspIRCd::MatchCIDR(ip, xhost, NULL))
00089 {
00090 return true;
00091 }
00092 }
00093 return false;
00094 }
00095
00096 virtual void OnLoadModule(Module* mod, const std::string& name)
00097 {
00098 if (ServerInstance->Modules->ModuleHasInterface(mod, "HashRequest"))
00099 {
00100 ServerInstance->Logs->Log("m_sqloper",DEBUG, "Post-load registering hasher: %s", name.c_str());
00101 std::string sname = HashNameRequest(this, mod).Send();
00102 hashers[sname.c_str()] = mod;
00103 names.push_back(sname);
00104 if (!diduseiface)
00105 {
00106 ServerInstance->Modules->UseInterface("HashRequest");
00107 diduseiface = true;
00108 }
00109 }
00110 }
00111
00112 virtual ~ModuleSQLOper()
00113 {
00114 ServerInstance->Modules->DoneWithInterface("SQL");
00115 ServerInstance->Modules->DoneWithInterface("SQLutils");
00116 if (diduseiface)
00117 ServerInstance->Modules->DoneWithInterface("HashRequest");
00118 }
00119
00120
00121 virtual void OnRehash(User* user, const std::string ¶meter)
00122 {
00123 ConfigReader Conf(ServerInstance);
00124
00125 databaseid = Conf.ReadValue("sqloper", "dbid", 0);
00126 hashtype = assign(Conf.ReadValue("sqloper", "hash", 0));
00127 }
00128
00129 virtual int OnPreCommand(std::string &command, std::vector<std::string> ¶meters, User *user, bool validated, const std::string &original_line)
00130 {
00131 if ((validated) && (command == "OPER"))
00132 {
00133 if (LookupOper(user, parameters[0], parameters[1]))
00134 {
00135
00136
00137
00138
00139
00140 return 1;
00141 }
00142 }
00143 return 0;
00144 }
00145
00146 bool LookupOper(User* user, const std::string &username, const std::string &password)
00147 {
00148 Module* target;
00149
00150 target = ServerInstance->Modules->FindFeature("SQL");
00151
00152 if (target)
00153 {
00154 hashymodules::iterator x = hashers.find(hashtype);
00155 if (x == hashers.end())
00156 return false;
00157
00158
00159 HashResetRequest(this, x->second).Send();
00160
00161 std::string md5_pass_hash = HashSumRequest(this, x->second, password.c_str()).Send();
00162
00163
00164
00165
00166 SQLrequest req = SQLrequest(this, target, databaseid,
00167 SQLquery("SELECT username, password, hostname, type FROM ircd_opers WHERE username = '?' AND password='?'") % username % md5_pass_hash);
00168
00169 if (req.Send())
00170 {
00171
00172
00173
00174
00175
00176
00177
00178 AssociateUser(this, SQLutils, req.id, user).Send();
00179
00180 user->Extend("oper_user", strdup(username.c_str()));
00181 user->Extend("oper_pass", strdup(password.c_str()));
00182
00183 return true;
00184 }
00185 else
00186 {
00187 return false;
00188 }
00189 }
00190 else
00191 {
00192 ServerInstance->Logs->Log("m_sqloper",SPARSE, "WARNING: Couldn't find SQL provider module. NOBODY will be able to oper up unless their o:line is statically configured");
00193 return false;
00194 }
00195 }
00196
00197 virtual const char* OnRequest(Request* request)
00198 {
00199 if (strcmp(SQLRESID, request->GetId()) == 0)
00200 {
00201 SQLresult* res = static_cast<SQLresult*>(request);
00202
00203 User* user = GetAssocUser(this, SQLutils, res->id).S().user;
00204 UnAssociate(this, SQLutils, res->id).S();
00205
00206 char* tried_user = NULL;
00207 char* tried_pass = NULL;
00208
00209 user->GetExt("oper_user", tried_user);
00210 user->GetExt("oper_pass", tried_pass);
00211
00212 if (user)
00213 {
00214 if (res->error.Id() == SQL_NO_ERROR)
00215 {
00216 if (res->Rows())
00217 {
00218
00219
00220
00221
00222
00223
00224
00225
00226
00227
00228
00229
00230
00231 for (SQLfieldMap& row = res->GetRowMap(); row.size(); row = res->GetRowMap())
00232 {
00233 if (OperUser(user, row["hostname"].d, row["type"].d))
00234 {
00235
00236 return SQLSUCCESS;
00237 }
00238 if (tried_user && tried_pass)
00239 {
00240 LoginFail(user, tried_user, tried_pass);
00241 free(tried_user);
00242 free(tried_pass);
00243 user->Shrink("oper_user");
00244 user->Shrink("oper_pass");
00245 }
00246 }
00247 }
00248 else
00249 {
00250
00251
00252
00253
00254 if (tried_user && tried_pass)
00255 {
00256 LoginFail(user, tried_user, tried_pass);
00257 free(tried_user);
00258 free(tried_pass);
00259 user->Shrink("oper_user");
00260 user->Shrink("oper_pass");
00261 }
00262 }
00263 }
00264 else
00265 {
00266
00267
00268
00269
00270 if (tried_user && tried_pass)
00271 {
00272 LoginFail(user, tried_user, tried_pass);
00273 free(tried_user);
00274 free(tried_pass);
00275 user->Shrink("oper_user");
00276 user->Shrink("oper_pass");
00277 }
00278
00279 }
00280 }
00281
00282 return SQLSUCCESS;
00283 }
00284
00285 return NULL;
00286 }
00287
00288 void LoginFail(User* user, const std::string &username, const std::string &pass)
00289 {
00290 Command* oper_command = ServerInstance->Parser->GetHandler("OPER");
00291
00292 if (oper_command)
00293 {
00294 std::vector<std::string> params;
00295 params.push_back(username);
00296 params.push_back(pass);
00297 oper_command->Handle(params, user);
00298 }
00299 else
00300 {
00301 ServerInstance->Logs->Log("m_sqloper",DEBUG, "BUG: WHAT?! Why do we have no OPER command?!");
00302 }
00303 }
00304
00305 bool OperUser(User* user, const std::string &pattern, const std::string &type)
00306 {
00307 ConfigReader Conf(ServerInstance);
00308
00309 for (int j = 0; j < Conf.Enumerate("type"); j++)
00310 {
00311 std::string tname = Conf.ReadValue("type","name",j);
00312 std::string hostname(user->ident);
00313
00314 hostname.append("@").append(user->host);
00315
00316 if ((tname == type) && OneOfMatches(hostname.c_str(), user->GetIPString(), pattern.c_str()))
00317 {
00318
00319 std::string operhost = Conf.ReadValue("type", "host", j);
00320
00321 if (operhost.size())
00322 user->ChangeDisplayedHost(operhost.c_str());
00323
00324 user->Oper(type, tname);
00325 return true;
00326 }
00327 }
00328
00329 return false;
00330 }
00331
00332 virtual Version GetVersion()
00333 {
00334 return Version("$Id: m_sqloper.cpp 10424 2008-09-06 21:55:47Z brain $", VF_VENDOR, API_VERSION);
00335 }
00336
00337 };
00338
00339 MODULE_INIT(ModuleSQLOper)