]> git.netwichtig.de Git - user/henk/code/inspircd.git/blob - src/modules/m_sqlauth.cpp
Change SQLv3 to format queries during submission, not before
[user/henk/code/inspircd.git] / src / modules / m_sqlauth.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: Allow/Deny connections based upon an arbitary SQL table */
19
20 enum AuthState {
21         AUTH_STATE_NONE = 0,
22         AUTH_STATE_BUSY = 1,
23         AUTH_STATE_FAIL = 2
24 };
25
26 class AuthQuery : public SQLQuery
27 {
28  public:
29         const std::string uid;
30         LocalIntExt& pendingExt;
31         bool verbose;
32         AuthQuery(Module* me, const std::string& u, LocalIntExt& e, bool v)
33                 : SQLQuery(me), uid(u), pendingExt(e), verbose(v)
34         {
35         }
36         
37         void OnResult(SQLResult& res)
38         {
39                 User* user = ServerInstance->FindNick(uid);
40                 if (!user)
41                         return;
42                 if (res.Rows())
43                 {
44                         pendingExt.set(user, AUTH_STATE_NONE);
45                 }
46                 else
47                 {
48                         if (verbose)
49                                 ServerInstance->SNO->WriteGlobalSno('a', "Forbidden connection from %s!%s@%s (SQL query returned no matches)", user->nick.c_str(), user->ident.c_str(), user->host.c_str());
50                         pendingExt.set(user, AUTH_STATE_FAIL);
51                 }
52         }
53
54         void OnError(SQLerror& error)
55         {
56                 User* user = ServerInstance->FindNick(uid);
57                 if (!user)
58                         return;
59                 pendingExt.set(user, AUTH_STATE_FAIL);
60                 if (verbose)
61                         ServerInstance->SNO->WriteGlobalSno('a', "Forbidden connection from %s!%s@%s (SQL query failed: %s)", user->nick.c_str(), user->ident.c_str(), user->host.c_str(), error.Str());
62         }
63 };
64
65 class ModuleSQLAuth : public Module
66 {
67         LocalIntExt pendingExt;
68         dynamic_reference<SQLProvider> SQL;
69
70         std::string freeformquery;
71         std::string killreason;
72         std::string allowpattern;
73         bool verbose;
74
75  public:
76         ModuleSQLAuth() : pendingExt("sqlauth-wait", this), SQL(this, "SQL")
77         {
78         }
79
80         void init()
81         {
82                 ServerInstance->Modules->AddService(pendingExt);
83                 OnRehash(NULL);
84                 Implementation eventlist[] = { I_OnUserDisconnect, I_OnCheckReady, I_OnRehash, I_OnUserRegister };
85                 ServerInstance->Modules->Attach(eventlist, this, 4);
86         }
87
88         void OnRehash(User* user)
89         {
90                 ConfigReader Conf;
91
92                 SQL.SetProvider("SQL/" + Conf.ReadValue("sqlauth", "dbid", 0));         /* Database ID, given to the SQL service provider */
93                 freeformquery   = Conf.ReadValue("sqlauth", "query", 0);        /* Field name where username can be found */
94                 killreason      = Conf.ReadValue("sqlauth", "killreason", 0);   /* Reason to give when access is denied to a user (put your reg details here) */
95                 allowpattern    = Conf.ReadValue("sqlauth", "allowpattern",0 ); /* Allow nicks matching this pattern without requiring auth */
96                 verbose         = Conf.ReadFlag("sqlauth", "verbose", 0);               /* Set to true if failed connects should be reported to operators */
97                 SQL.lookup();
98         }
99
100         ModResult OnUserRegister(LocalUser* user)
101         {
102                 // Note this is their initial (unresolved) connect block
103                 ConfigTag* tag = user->MyClass->config;
104                 if (!tag->getBool("usesqlauth", true))
105                         return MOD_RES_PASSTHRU;
106
107                 if (!allowpattern.empty() && InspIRCd::Match(user->nick,allowpattern))
108                         return MOD_RES_PASSTHRU;
109
110                 if (pendingExt.get(user))
111                         return MOD_RES_PASSTHRU;
112
113                 pendingExt.set(user, AUTH_STATE_BUSY);
114
115                 ParamM userinfo;
116                 SQL->PopulateUserInfo(user, userinfo);
117                 userinfo["pass"] = user->password;
118
119                 HashProvider* md5 = ServerInstance->Modules->FindDataService<HashProvider>("hash/md5");
120                 if (md5)
121                         userinfo["md5pass"] = md5->hexsum(user->password);
122
123                 HashProvider* sha256 = ServerInstance->Modules->FindDataService<HashProvider>("hash/sha256");
124                 if (sha256)
125                         userinfo["sha256pass"] = sha256->hexsum(user->password);
126
127                 SQL->submit(new AuthQuery(this, user->uuid, pendingExt, verbose), freeformquery, userinfo);
128
129                 return MOD_RES_PASSTHRU;
130         }
131
132         ModResult OnCheckReady(LocalUser* user)
133         {
134                 switch (pendingExt.get(user))
135                 {
136                         case AUTH_STATE_NONE:
137                                 return MOD_RES_PASSTHRU;
138                         case AUTH_STATE_BUSY:
139                                 return MOD_RES_DENY;
140                         case AUTH_STATE_FAIL:
141                                 ServerInstance->Users->QuitUser(user, killreason);
142                                 return MOD_RES_DENY;
143                 }
144                 return MOD_RES_PASSTHRU;
145         }
146
147         Version GetVersion()
148         {
149                 return Version("Allow/Deny connections based upon an arbitary SQL table", VF_VENDOR);
150         }
151 };
152
153 MODULE_INIT(ModuleSQLAuth)