]> git.netwichtig.de Git - user/henk/code/inspircd.git/blob - src/modules/m_ldapoper.cpp
9bfa3971f225225ecdf1e73048cb11fcd3b8a585
[user/henk/code/inspircd.git] / src / modules / m_ldapoper.cpp
1 /*
2  * InspIRCd -- Internet Relay Chat Daemon
3  *
4  *   Copyright (C) 2013 Adam <Adam@anope.org>
5  *   Copyright (C) 2009 Robin Burchell <robin+git@viroteck.net>
6  *   Copyright (C) 2008 Pippijn van Steenhoven <pip88nl@gmail.com>
7  *   Copyright (C) 2008 Craig Edwards <craigedwards@brainbox.cc>
8  *   Copyright (C) 2007 Carsten Valdemar Munk <carsten.munk+inspircd@gmail.com>
9  *
10  * This file is part of InspIRCd.  InspIRCd is free software: you can
11  * redistribute it and/or modify it under the terms of the GNU General Public
12  * License as published by the Free Software Foundation, version 2.
13  *
14  * This program is distributed in the hope that it will be useful, but WITHOUT
15  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
16  * FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
17  * details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
21  */
22
23
24 #include "inspircd.h"
25 #include "modules/ldap.h"
26
27 namespace
28 {
29         Module* me;
30 }
31
32 class LDAPOperBase : public LDAPInterface
33 {
34  protected:
35         const std::string uid;
36         const std::string opername;
37         const std::string password;
38
39         void Fallback(User* user)
40         {
41                 if (!user)
42                         return;
43
44                 Command* oper_command = ServerInstance->Parser->GetHandler("OPER");
45                 if (!oper_command)
46                         return;
47
48                 std::vector<std::string> params;
49                 params.push_back(opername);
50                 params.push_back(password);
51                 oper_command->Handle(params, user);
52         }
53
54         void Fallback()
55         {
56                 User* user = ServerInstance->FindUUID(uid);
57                 Fallback(user);
58         }
59
60  public:
61         LDAPOperBase(Module* mod, const std::string& uuid, const std::string& oper, const std::string& pass)
62                 : LDAPInterface(mod)
63                 , uid(uuid), opername(oper), password(pass)
64         {
65         }
66
67         void OnError(const LDAPResult& err) CXX11_OVERRIDE
68         {
69                 ServerInstance->SNO->WriteToSnoMask('a', "Error searching LDAP server: %s", err.getError().c_str());
70                 Fallback();
71                 delete this;
72         }
73 };
74
75 class BindInterface : public LDAPOperBase
76 {
77  public:
78         BindInterface(Module* mod, const std::string& uuid, const std::string& oper, const std::string& pass)
79                 : LDAPOperBase(mod, uuid, oper, pass)
80         {
81         }
82
83         void OnResult(const LDAPResult& r) CXX11_OVERRIDE
84         {
85                 User* user = ServerInstance->FindUUID(uid);
86                 OperIndex::iterator iter = ServerInstance->Config->oper_blocks.find(opername);
87
88                 if (!user || iter == ServerInstance->Config->oper_blocks.end())
89                 {
90                         Fallback();
91                         delete this;
92                         return;
93                 }
94
95                 OperInfo* ifo = iter->second;
96                 user->Oper(ifo);
97                 delete this;
98         }
99 };
100
101 class SearchInterface : public LDAPOperBase
102 {
103         const std::string provider;
104
105         bool HandleResult(const LDAPResult& result)
106         {
107                 dynamic_reference<LDAPProvider> LDAP(me, provider);
108                 if (!LDAP || result.empty())
109                         return false;
110
111                 try
112                 {
113                         const LDAPAttributes& attr = result.get(0);
114                         std::string bindDn = attr.get("dn");
115                         if (bindDn.empty())
116                                 return false;
117
118                         LDAP->Bind(new BindInterface(this->creator, uid, opername, password), bindDn, password);
119                 }
120                 catch (LDAPException& ex)
121                 {
122                         ServerInstance->SNO->WriteToSnoMask('a', "Error searching LDAP server: " + ex.GetReason());
123                 }
124
125                 return true;
126         }
127
128  public:
129         SearchInterface(Module* mod, const std::string& prov, const std::string &uuid, const std::string& oper, const std::string& pass)
130                 : LDAPOperBase(mod, uuid, oper, pass)
131                 , provider(prov)
132         {
133         }
134
135         void OnResult(const LDAPResult& result) CXX11_OVERRIDE
136         {
137                 if (!HandleResult(result))
138                         Fallback();
139                 delete this;
140         }
141 };
142
143 class AdminBindInterface : public LDAPInterface
144 {
145         const std::string provider;
146         const std::string user;
147         const std::string opername;
148         const std::string password;
149         const std::string base;
150         const std::string what;
151
152  public:
153         AdminBindInterface(Module* c, const std::string& p, const std::string& u, const std::string& o, const std::string& pa, const std::string& b, const std::string& w)
154                 : LDAPInterface(c), provider(p), user(u), opername(p), password(pa), base(b), what(w)
155         {
156         }
157
158         void OnResult(const LDAPResult& r) CXX11_OVERRIDE
159         {
160                 dynamic_reference<LDAPProvider> LDAP(me, provider);
161                 if (LDAP)
162                 {
163                         try
164                         {
165                                 LDAP->Search(new SearchInterface(this->creator, provider, user, opername, password), base, what);
166                         }
167                         catch (LDAPException& ex)
168                         {
169                                 ServerInstance->SNO->WriteToSnoMask('a', "Error searching LDAP server: " + ex.GetReason());
170                         }
171                 }
172                 delete this;
173         }
174
175         void OnError(const LDAPResult& err) CXX11_OVERRIDE
176         {
177                 ServerInstance->SNO->WriteToSnoMask('a', "Error binding as manager to LDAP server: " + err.getError());
178                 delete this;
179         }
180 };
181
182 class ModuleLDAPAuth : public Module
183 {
184         dynamic_reference<LDAPProvider> LDAP;
185         std::string base;
186         std::string attribute;
187
188  public:
189         ModuleLDAPAuth()
190                 : LDAP(this, "LDAP")
191         {
192                 me = this;
193         }
194
195         void ReadConfig(ConfigStatus& status) CXX11_OVERRIDE
196         {
197                 ConfigTag* tag = ServerInstance->Config->ConfValue("ldapoper");
198
199                 LDAP.SetProvider("LDAP/" + tag->getString("dbid"));
200                 base = tag->getString("baserdn");
201                 attribute = tag->getString("attribute");
202         }
203
204         ModResult OnPreCommand(std::string& command, std::vector<std::string>& parameters, LocalUser* user, bool validated, const std::string& original_line) CXX11_OVERRIDE
205         {
206                 if (validated && command == "OPER" && parameters.size() >= 2)
207                 {
208                         const std::string& opername = parameters[0];
209                         const std::string& password = parameters[1];
210
211                         OperIndex::iterator it = ServerInstance->Config->oper_blocks.find(opername);
212                         if (it == ServerInstance->Config->oper_blocks.end())
213                                 return MOD_RES_PASSTHRU;
214
215                         ConfigTag* tag = it->second->oper_block;
216                         if (!tag)
217                                 return MOD_RES_PASSTHRU;
218
219                         std::string acceptedhosts = tag->getString("host");
220                         std::string hostname = user->ident + "@" + user->host;
221                         if (!InspIRCd::MatchMask(acceptedhosts, hostname, user->GetIPString()))
222                                 return MOD_RES_PASSTHRU;
223
224                         if (!LDAP)
225                                 return MOD_RES_PASSTHRU;
226
227                         try
228                         {
229                                 std::string what = attribute + "=" + opername;
230                                 LDAP->BindAsManager(new AdminBindInterface(this, LDAP.GetProvider(), user->uuid, opername, password, base, what));
231                                 return MOD_RES_DENY;
232                         }
233                         catch (LDAPException& ex)
234                         {
235                                 ServerInstance->SNO->WriteToSnoMask('a', "LDAP exception: " + ex.GetReason());
236                         }
237                 }
238
239                 return MOD_RES_PASSTHRU;
240         }
241
242         Version GetVersion() CXX11_OVERRIDE
243         {
244                 return Version("Adds the ability to authenticate opers via LDAP", VF_VENDOR);
245         }
246 };
247
248 MODULE_INIT(ModuleLDAPAuth)