2 * InspIRCd -- Internet Relay Chat Daemon
4 * Copyright (C) 2009 Robin Burchell <robin+git@viroteck.net>
5 * Copyright (C) 2008 Pippijn van Steenhoven <pip88nl@gmail.com>
6 * Copyright (C) 2008 Craig Edwards <craigedwards@brainbox.cc>
7 * Copyright (C) 2007 Carsten Valdemar Munk <carsten.munk+inspircd@gmail.com>
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.
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
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/>.
31 # pragma comment(lib, "ldap.lib")
32 # pragma comment(lib, "lber.lib")
35 /* $ModDesc: Adds the ability to authenticate opers via LDAP */
36 /* $LinkerFlags: -lldap */
42 RAIILDAPString(char *Str)
57 operator std::string()
63 class ModuleLDAPAuth : public Module
66 std::string ldapserver;
69 std::string attribute;
73 bool HandleOper(LocalUser* user, const std::string& opername, const std::string& inputpass)
75 OperIndex::iterator it = ServerInstance->Config->oper_blocks.find(opername);
76 if (it == ServerInstance->Config->oper_blocks.end())
79 ConfigTag* tag = it->second->oper_block;
83 std::string acceptedhosts = tag->getString("host");
84 std::string hostname = user->ident + "@" + user->host;
85 if (!InspIRCd::MatchMask(acceptedhosts, hostname, user->GetIPString()))
88 if (!LookupOper(opername, inputpass))
91 user->Oper(it->second);
101 void init() CXX11_OVERRIDE
103 Implementation eventlist[] = { I_OnRehash, I_OnPreCommand };
104 ServerInstance->Modules->Attach(eventlist, this, sizeof(eventlist)/sizeof(Implementation));
111 ldap_unbind_ext(conn, NULL, NULL);
114 void OnRehash(User* user) CXX11_OVERRIDE
116 ConfigTag* tag = ServerInstance->Config->ConfValue("ldapoper");
118 base = tag->getString("baserdn");
119 ldapserver = tag->getString("server");
120 std::string scope = tag->getString("searchscope");
121 username = tag->getString("binddn");
122 password = tag->getString("bindauth");
123 attribute = tag->getString("attribute");
126 searchscope = LDAP_SCOPE_BASE;
127 else if (scope == "onelevel")
128 searchscope = LDAP_SCOPE_ONELEVEL;
129 else searchscope = LDAP_SCOPE_SUBTREE;
137 ldap_unbind_ext(conn, NULL, NULL);
138 int res, v = LDAP_VERSION3;
139 res = ldap_initialize(&conn, ldapserver.c_str());
140 if (res != LDAP_SUCCESS)
146 res = ldap_set_option(conn, LDAP_OPT_PROTOCOL_VERSION, (void *)&v);
147 if (res != LDAP_SUCCESS)
149 ldap_unbind_ext(conn, NULL, NULL);
156 ModResult OnPreCommand(std::string& command, std::vector<std::string>& parameters, LocalUser* user, bool validated, const std::string& original_line) CXX11_OVERRIDE
158 if (validated && command == "OPER" && parameters.size() >= 2)
160 if (HandleOper(user, parameters[0], parameters[1]))
163 return MOD_RES_PASSTHRU;
166 bool LookupOper(const std::string& opername, const std::string& opassword)
173 char* authpass = strdup(password.c_str());
174 // bind anonymously if no bind DN and authentication are given in the config
176 cred.bv_val = authpass;
177 cred.bv_len = password.length();
179 if ((res = ldap_sasl_bind_s(conn, username.c_str(), LDAP_SASL_SIMPLE, &cred, NULL, NULL, NULL)) != LDAP_SUCCESS)
181 if (res == LDAP_SERVER_DOWN)
183 // Attempt to reconnect if the connection dropped
184 ServerInstance->SNO->WriteToSnoMask('a', "LDAP server has gone away - reconnecting...");
186 res = ldap_sasl_bind_s(conn, username.c_str(), LDAP_SASL_SIMPLE, &cred, NULL, NULL, NULL);
189 if (res != LDAP_SUCCESS)
192 ldap_unbind_ext(conn, NULL, NULL);
199 LDAPMessage *msg, *entry;
200 std::string what = attribute + "=" + opername;
201 if ((res = ldap_search_ext_s(conn, base.c_str(), searchscope, what.c_str(), NULL, 0, NULL, NULL, NULL, 0, &msg)) != LDAP_SUCCESS)
205 if (ldap_count_entries(conn, msg) > 1)
210 if ((entry = ldap_first_entry(conn, msg)) == NULL)
215 authpass = strdup(opassword.c_str());
216 cred.bv_val = authpass;
217 cred.bv_len = opassword.length();
218 RAIILDAPString DN(ldap_get_dn(conn, entry));
219 if ((res = ldap_sasl_bind_s(conn, DN, LDAP_SASL_SIMPLE, &cred, NULL, NULL, NULL)) == LDAP_SUCCESS)
233 Version GetVersion() CXX11_OVERRIDE
235 return Version("Adds the ability to authenticate opers via LDAP", VF_VENDOR);
240 MODULE_INIT(ModuleLDAPAuth)