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