]> git.netwichtig.de Git - user/henk/code/inspircd.git/blob - src/modules/m_sqloper.cpp
Change SQLv3 to format queries during submission, not before
[user/henk/code/inspircd.git] / src / modules / m_sqloper.cpp
1 /*       +------------------------------------+
2  *       | Inspire Internet Relay Chat Daemon |
3  *       +------------------------------------+
4  *
5  *  InspIRCd: (C) 2002-2010 InspIRCd Development Team
6  * See: http://wiki.inspircd.org/Credits
7  *
8  * This program is free but copyrighted software; see
9  *          the file COPYING for details.
10  *
11  * ---------------------------------------------------
12  */
13
14 #include "inspircd.h"
15 #include "sql.h"
16 #include "hash.h"
17
18 /* $ModDesc: Allows storage of oper credentials in an SQL table */
19
20 static bool OneOfMatches(const char* host, const char* ip, const std::string& hostlist)
21 {
22         std::stringstream hl(hostlist);
23         std::string xhost;
24         while (hl >> xhost)
25         {
26                 if (InspIRCd::Match(host, xhost, ascii_case_insensitive_map) || InspIRCd::MatchCIDR(ip, xhost, ascii_case_insensitive_map))
27                 {
28                         return true;
29                 }
30         }
31         return false;
32 }
33
34 class OpMeQuery : public SQLQuery
35 {
36  public:
37         const std::string uid, username, password;
38         OpMeQuery(Module* me, const std::string& u, const std::string& un, const std::string& pw)
39                 : SQLQuery(me), uid(u), username(un), password(pw)
40         {
41         }
42
43         void OnResult(SQLResult& res)
44         {
45                 ServerInstance->Logs->Log("m_sqloper",DEBUG, "SQLOPER: result for %s", uid.c_str());
46                 User* user = ServerInstance->FindNick(uid);
47                 if (!user)
48                         return;
49
50                 // multiple rows may exist
51                 SQLEntries row;
52                 while (res.GetRow(row))
53                 {
54 #if 0
55                         parameterlist cols;
56                         res.GetCols(cols);
57
58                         std::vector<KeyVal>* items;
59                         reference<ConfigTag> tag = ConfigTag::create("oper", "<m_sqloper>", 0, items);
60                         for(unsigned int i=0; i < cols.size(); i++)
61                         {
62                                 if (!row[i].nul)
63                                         items->insert(std::make_pair(cols[i], row[i]));
64                         }
65 #else
66                         if (OperUser(user, row[0], row[1]))
67                                 return;
68 #endif
69                 }
70                 ServerInstance->Logs->Log("m_sqloper",DEBUG, "SQLOPER: no matches for %s (checked %d rows)", uid.c_str(), res.Rows());
71                 // nobody succeeded... fall back to OPER
72                 fallback();
73         }
74
75         void OnError(SQLerror& error)
76         {
77                 ServerInstance->Logs->Log("m_sqloper",DEFAULT, "SQLOPER: query failed (%s)", error.Str());
78                 fallback();
79         }
80
81         void fallback()
82         {
83                 User* user = ServerInstance->FindNick(uid);
84                 if (!user)
85                         return;
86
87                 Command* oper_command = ServerInstance->Parser->GetHandler("OPER");
88
89                 if (oper_command)
90                 {
91                         std::vector<std::string> params;
92                         params.push_back(username);
93                         params.push_back(password);
94                         oper_command->Handle(params, user);
95                 }
96                 else
97                 {
98                         ServerInstance->Logs->Log("m_sqloper",SPARSE, "BUG: WHAT?! Why do we have no OPER command?!");
99                 }
100         }
101
102         bool OperUser(User* user, const std::string &pattern, const std::string &type)
103         {
104                 OperIndex::iterator iter = ServerInstance->Config->oper_blocks.find(" " + type);
105                 if (iter == ServerInstance->Config->oper_blocks.end())
106                 {
107                         ServerInstance->Logs->Log("m_sqloper",DEFAULT, "SQLOPER: bad type '%s' in returned row for oper %s", type.c_str(), username.c_str());
108                         return false;
109                 }
110                 OperInfo* ifo = iter->second;
111
112                 std::string hostname(user->ident);
113
114                 hostname.append("@").append(user->host);
115
116                 if (OneOfMatches(hostname.c_str(), user->GetIPString(), pattern.c_str()))
117                 {
118                         /* Opertype and host match, looks like this is it. */
119
120                         user->Oper(ifo);
121                         return true;
122                 }
123
124                 return false;
125         }
126 };
127
128 class ModuleSQLOper : public Module
129 {
130         std::string query;
131         std::string hashtype;
132         dynamic_reference<SQLProvider> SQL;
133
134 public:
135         ModuleSQLOper() : SQL(this, "SQL") {}
136
137         void init()
138         {
139                 OnRehash(NULL);
140
141                 Implementation eventlist[] = { I_OnRehash, I_OnPreCommand };
142                 ServerInstance->Modules->Attach(eventlist, this, 2);
143         }
144
145         void OnRehash(User* user)
146         {
147                 ConfigTag* tag = ServerInstance->Config->ConfValue("sqloper");
148
149                 SQL.SetProvider("SQL/" + tag->getString("dbid"));
150                 SQL.lookup();
151                 hashtype = tag->getString("hash");
152                 query = tag->getString("query", "SELECT hostname as host, type FROM ircd_opers WHERE username='$username' AND password='$password'");
153         }
154
155         ModResult OnPreCommand(std::string &command, std::vector<std::string> &parameters, LocalUser *user, bool validated, const std::string &original_line)
156         {
157                 if (validated && command == "OPER" && parameters.size() == 2 && SQL)
158                 {
159                         LookupOper(user, parameters[0], parameters[1]);
160                         /* Query is in progress, it will re-invoke OPER if needed */
161                         return MOD_RES_DENY;
162                 }
163                 return MOD_RES_PASSTHRU;
164         }
165
166         void LookupOper(User* user, const std::string &username, const std::string &password)
167         {
168                 HashProvider* hash = ServerInstance->Modules->FindDataService<HashProvider>("hash/" + hashtype);
169
170                 ParamM userinfo;
171                 SQL->PopulateUserInfo(user, userinfo);
172                 userinfo["username"] = username;
173                 userinfo["password"] = hash ? hash->hexsum(password) : password;
174
175                 SQL->submit(new OpMeQuery(this, user->uuid, username, password), query, userinfo);
176         }
177
178         Version GetVersion()
179         {
180                 return Version("Allows storage of oper credentials in an SQL table", VF_VENDOR);
181         }
182
183 };
184
185 MODULE_INIT(ModuleSQLOper)