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