]> git.netwichtig.de Git - user/henk/code/inspircd.git/blob - src/modules/m_ldapoper.cpp
Sync helpop chmodes s and p with docs
[user/henk/code/inspircd.git] / src / modules / m_ldapoper.cpp
1 /*
2  * InspIRCd -- Internet Relay Chat Daemon
3  *
4  *   Copyright (C) 2020 Christos Triantafyllidis <ctria@users.noreply.github.com>
5  *   Copyright (C) 2018-2020 Sadie Powell <sadie@witchery.services>
6  *   Copyright (C) 2014, 2018 Attila Molnar <attilamolnar@hush.com>
7  *   Copyright (C) 2013-2014 Adam <Adam@anope.org>
8  *
9  * This file is part of InspIRCd.  InspIRCd is free software: you can
10  * redistribute it and/or modify it under the terms of the GNU General Public
11  * License as published by the Free Software Foundation, version 2.
12  *
13  * This program is distributed in the hope that it will be useful, but WITHOUT
14  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
15  * FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
16  * details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
20  */
21
22
23 #include "inspircd.h"
24 #include "modules/ldap.h"
25
26 namespace
27 {
28         Module* me;
29 }
30
31 class LDAPOperBase : public LDAPInterface
32 {
33  protected:
34         const std::string uid;
35         const std::string opername;
36         const std::string password;
37
38         void Fallback(User* user)
39         {
40                 if (!user)
41                         return;
42
43                 Command* oper_command = ServerInstance->Parser.GetHandler("OPER");
44                 if (!oper_command)
45                         return;
46
47                 CommandBase::Params params;
48                 params.push_back(opername);
49                 params.push_back(password);
50                 ClientProtocol::TagMap tags;
51                 oper_command->Handle(user, CommandBase::Params(params, tags));
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                 ServerConfig::OperIndex::const_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)
155                 , provider(p)
156                 , user(u)
157                 , opername(o)
158                 , password(pa)
159                 , base(b)
160                 , what(w)
161         {
162         }
163
164         void OnResult(const LDAPResult& r) CXX11_OVERRIDE
165         {
166                 dynamic_reference<LDAPProvider> LDAP(me, provider);
167                 if (LDAP)
168                 {
169                         try
170                         {
171                                 LDAP->Search(new SearchInterface(this->creator, provider, user, opername, password), base, what);
172                         }
173                         catch (LDAPException& ex)
174                         {
175                                 ServerInstance->SNO->WriteToSnoMask('a', "Error searching LDAP server: " + ex.GetReason());
176                         }
177                 }
178                 delete this;
179         }
180
181         void OnError(const LDAPResult& err) CXX11_OVERRIDE
182         {
183                 ServerInstance->SNO->WriteToSnoMask('a', "Error binding as manager to LDAP server: " + err.getError());
184                 delete this;
185         }
186 };
187
188 class ModuleLDAPOper : public Module
189 {
190         dynamic_reference<LDAPProvider> LDAP;
191         std::string base;
192         std::string attribute;
193
194  public:
195         ModuleLDAPOper()
196                 : LDAP(this, "LDAP")
197         {
198                 me = this;
199         }
200
201         void ReadConfig(ConfigStatus& status) CXX11_OVERRIDE
202         {
203                 ConfigTag* tag = ServerInstance->Config->ConfValue("ldapoper");
204
205                 LDAP.SetProvider("LDAP/" + tag->getString("dbid"));
206                 base = tag->getString("baserdn");
207                 attribute = tag->getString("attribute");
208         }
209
210         ModResult OnPreCommand(std::string& command, CommandBase::Params& parameters, LocalUser* user, bool validated) CXX11_OVERRIDE
211         {
212                 if (validated && command == "OPER" && parameters.size() >= 2)
213                 {
214                         const std::string& opername = parameters[0];
215                         const std::string& password = parameters[1];
216
217                         ServerConfig::OperIndex::const_iterator it = ServerInstance->Config->oper_blocks.find(opername);
218                         if (it == ServerInstance->Config->oper_blocks.end())
219                                 return MOD_RES_PASSTHRU;
220
221                         ConfigTag* tag = it->second->oper_block;
222                         if (!tag)
223                                 return MOD_RES_PASSTHRU;
224
225                         std::string acceptedhosts = tag->getString("host");
226                         if (!InspIRCd::MatchMask(acceptedhosts, user->MakeHost(), user->MakeHostIP()))
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)