]> git.netwichtig.de Git - user/henk/code/inspircd.git/blob - src/modules/extra/m_sqlauth.cpp
More const ref fixes
[user/henk/code/inspircd.git] / src / modules / extra / m_sqlauth.cpp
1 /*       +------------------------------------+
2  *       | Inspire Internet Relay Chat Daemon |
3  *       +------------------------------------+
4  *
5  *  InspIRCd is copyright (C) 2002-2004 ChatSpike-Dev.
6  *                       E-mail:
7  *                <brain@chatspike.net>
8  *                <Craig@chatspike.net>
9  *     
10  * Written by Craig Edwards, Craig McLure, and others.
11  * This program is free but copyrighted software; see
12  *            the file COPYING for details.
13  *
14  * ---------------------------------------------------
15  */
16
17 using namespace std;
18
19 #include <stdio.h>
20 #include <string>
21 #include <stdlib.h>
22 #include <time.h>
23 #include <sys/types.h>
24 #include <sys/socket.h>
25 #include <sys/time.h>
26 #include <string.h>
27 #include <unistd.h>
28 #include <errno.h>
29 #include <fcntl.h>
30 #include <poll.h>
31 #include "users.h"
32 #include "channels.h"
33 #include "modules.h"
34 #include "inspircd.h"
35 #include "helperfuncs.h"
36 #include "m_sql.h"
37
38 /* $ModDesc: Allow/Deny connections based upon an arbitary SQL table */
39
40 class ModuleSQLAuth : public Module
41 {
42         Server* Srv;
43         ConfigReader* Conf;
44         std::string usertable;
45         std::string userfield;
46         std::string passfield;
47         std::string encryption;
48         std::string killreason;
49         std::string allowpattern;
50         bool WallOperFail;
51         unsigned long dbid;
52         Module* SQLModule;
53
54  public:
55         bool ReadConfig()
56         {
57                 Conf = new ConfigReader();
58                 usertable = Conf->ReadValue("sqlauth","usertable",0);   // user table name
59                 dbid = Conf->ReadInteger("sqlauth","dbid",0,true);      // database id of a database configured in m_sql (see m_sql config)
60                 userfield = Conf->ReadValue("sqlauth","userfield",0);   // field name where username can be found
61                 passfield = Conf->ReadValue("sqlauth","passfield",0);   // field name where password can be found
62                 killreason = Conf->ReadValue("sqlauth","killreason",0); // reason to give when access is denied to a user (put your reg details here)
63                 encryption = Conf->ReadValue("sqlauth","encryption",0); // name of sql function used to encrypt password, e.g. "md5" or "passwd".
64                                                                         // define, but leave blank if no encryption is to be used.
65                 WallOperFail = Conf->ReadFlag("sqlauth","verbose",0);   // set to 1 if failed connects should be reported to operators
66                 allowpattern = Conf->ReadValue("sqlauth","allowpattern",0);     // allow nicks matching the pattern without requiring auth
67                 if (encryption.find("(") == std::string::npos)
68                 {
69                         encryption.append("(");
70                 }
71                 delete Conf;
72                 SQLModule = Srv->FindModule("m_sql.so");
73                 if (!SQLModule)
74                         Srv->Log(DEFAULT,"WARNING: m_sqlauth.so could not initialize because m_sql.so is not loaded. Load the module and rehash your server.");
75                 return (SQLModule);
76         }
77
78         ModuleSQLAuth(Server* Me)
79                 : Module::Module(Me)
80         {
81                 Srv = Me;
82                 ReadConfig();
83         }
84
85         void Implements(char* List)
86         {
87                 List[I_OnRehash] = List[I_OnUserRegister] = 1;
88         }
89
90         virtual void OnRehash(const std::string &parameter)
91         {
92                 ReadConfig();
93         }
94
95         virtual void OnUserRegister(userrec* user)
96         {
97                 if ((allowpattern != "") && (Srv->MatchText(user->nick,allowpattern)))
98                         return;
99                 
100                 if (!CheckCredentials(user->nick,user->password))
101                 {
102                         if (WallOperFail)
103                                 WriteOpers("Forbidden connection from %s!%s@%s (invalid login/password)",user->nick,user->ident,user->host);
104                         Srv->QuitUser(user,killreason);
105                 }
106         }
107
108         bool CheckCredentials(const std::string &username, const std::string &password)
109         {
110                 bool found = false;
111
112                 // is the sql module loaded? If not, we don't attempt to do anything.
113                 if (!SQLModule)
114                         return false;
115
116                 // sanitize the password (we dont want any mysql insertion exploits!)
117                 std::string temp = "";
118                 for (unsigned int q = 0; q < password.length(); q++)
119                 {
120                         if (password[q] == '\'')
121                         {
122                                 temp = temp + "\'";
123                         }
124                         else if (password[q] == '"')
125                         {
126                                 temp = temp + "\\\"";
127                         }
128                         else temp = temp + password[q];
129                 }
130                 password = temp;
131
132                 // Create a request containing the SQL query and send it to m_sql.so
133                 std::string querystr("SELECT * FROM "+usertable+" WHERE "+userfield+"='"+username+"' AND "+passfield+"="+encryption+"'"+password+"')");
134                 
135                 Srv->Log(DEBUG, "m_sqlauth.so: Query: " + querystr);
136                 
137                 SQLRequest* query = new SQLRequest(SQL_RESULT,dbid,querystr);
138                 Request queryrequest((char*)query, this, SQLModule);
139                 SQLResult* result = (SQLResult*)queryrequest.Send();
140
141                 // Did we get "OK" as a result?
142                 if (result->GetType() == SQL_OK)
143                 {
144                         log(DEBUG, "m_sqlauth.so: Query OK");
145                         
146                         // if we did, this means we may now request a row... there should be only one row for each user, so,
147                         // we don't need to loop to fetch multiple rows.
148                         SQLRequest* rowrequest = new SQLRequest(SQL_ROW,dbid,"");
149                         Request rowquery((char*)rowrequest, this, SQLModule);
150                         SQLResult* rowresult = (SQLResult*)rowquery.Send();
151
152                         // did we get a row? If we did, we can now do something with the fields
153                         if (rowresult->GetType() == SQL_ROW)
154                         {
155                                 log(DEBUG, "m_sqlauth.so: Got row...user '%s'", rowresult->GetField(userfield).c_str());
156                                 
157                                 if (rowresult->GetField(userfield) == username)
158                                 {
159                                         log(DEBUG, "m_sqlauth.so: Got correct user...");
160                                         // because the query directly asked for the password hash, we do not need to check it -
161                                         // if it didnt match it wont be returned in the first place from the SELECT.
162                                         // This just checks we didnt get an empty row by accident.
163                                         found = true;
164                                 }
165                         }
166                         else
167                         {
168                                 log(DEBUG, "m_sqlauth.so: Couldn't find row");
169                                 // we didn't have a row.
170                                 found = false;
171                         }
172                         
173                         delete rowrequest;
174                         delete rowresult;
175                 }
176                 else
177                 {
178                         log(DEBUG, "m_sqlauth.so: Query failed");
179                         // the query was bad
180                         found = false;
181                 }
182                 
183                 query->SetQueryType(SQL_DONE);
184                 query->SetConnID(dbid);
185                 Request donerequest((char*)query, this, SQLModule);
186                 donerequest.Send();
187                 
188                 delete query;
189                 delete result;
190                 
191                 return found;
192         }
193
194         virtual ~ModuleSQLAuth()
195         {
196         }
197         
198         virtual Version GetVersion()
199         {
200                 return Version(1,0,0,2,VF_VENDOR);
201         }
202         
203 };
204
205 class ModuleSQLAuthFactory : public ModuleFactory
206 {
207  public:
208         ModuleSQLAuthFactory()
209         {
210         }
211         
212         ~ModuleSQLAuthFactory()
213         {
214         }
215         
216         virtual Module * CreateModule(Server* Me)
217         {
218                 return new ModuleSQLAuth(Me);
219         }
220         
221 };
222
223
224 extern "C" void * init_module( void )
225 {
226         return new ModuleSQLAuthFactory;
227 }
228