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