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 */
38 // Duplicated code, also found in cmd_oper and m_sqloper
39 static bool OneOfMatches(const char* host, const char* ip, const std::string& hostlist)
41 std::stringstream hl(hostlist);
45 if (InspIRCd::Match(host, xhost, ascii_case_insensitive_map) || InspIRCd::MatchCIDR(ip, xhost, ascii_case_insensitive_map))
57 RAIILDAPString(char *Str)
72 operator std::string()
78 class ModuleLDAPAuth : public Module
81 std::string ldapserver;
84 std::string attribute;
88 bool HandleOper(LocalUser* user, const std::string& opername, const std::string& inputpass)
90 OperIndex::iterator it = ServerInstance->Config->oper_blocks.find(opername);
91 if (it == ServerInstance->Config->oper_blocks.end())
94 ConfigTag* tag = it->second->oper_block;
98 std::string acceptedhosts = tag->getString("host");
99 std::string hostname = user->ident + "@" + user->host;
100 if (!OneOfMatches(hostname.c_str(), user->GetIPString(), acceptedhosts))
103 if (!LookupOper(opername, inputpass))
106 user->Oper(it->second);
118 Implementation eventlist[] = { I_OnRehash, I_OnPreCommand };
119 ServerInstance->Modules->Attach(eventlist, this, sizeof(eventlist)/sizeof(Implementation));
123 virtual ~ModuleLDAPAuth()
126 ldap_unbind_ext(conn, NULL, NULL);
129 virtual void OnRehash(User* user)
131 ConfigTag* tag = ServerInstance->Config->ConfValue("ldapoper");
133 base = tag->getString("baserdn");
134 ldapserver = tag->getString("server");
135 std::string scope = tag->getString("searchscope");
136 username = tag->getString("binddn");
137 password = tag->getString("bindauth");
138 attribute = tag->getString("attribute");
141 searchscope = LDAP_SCOPE_BASE;
142 else if (scope == "onelevel")
143 searchscope = LDAP_SCOPE_ONELEVEL;
144 else searchscope = LDAP_SCOPE_SUBTREE;
152 ldap_unbind_ext(conn, NULL, NULL);
153 int res, v = LDAP_VERSION3;
154 res = ldap_initialize(&conn, ldapserver.c_str());
155 if (res != LDAP_SUCCESS)
161 res = ldap_set_option(conn, LDAP_OPT_PROTOCOL_VERSION, (void *)&v);
162 if (res != LDAP_SUCCESS)
164 ldap_unbind_ext(conn, NULL, NULL);
171 ModResult OnPreCommand(std::string& command, std::vector<std::string>& parameters, LocalUser* user, bool validated, const std::string& original_line)
173 if (validated && command == "OPER" && parameters.size() >= 2)
175 if (HandleOper(user, parameters[0], parameters[1]))
178 return MOD_RES_PASSTHRU;
181 bool LookupOper(const std::string& opername, const std::string& opassword)
188 char* authpass = strdup(password.c_str());
189 // bind anonymously if no bind DN and authentication are given in the config
191 cred.bv_val = authpass;
192 cred.bv_len = password.length();
194 if ((res = ldap_sasl_bind_s(conn, username.c_str(), LDAP_SASL_SIMPLE, &cred, NULL, NULL, NULL)) != LDAP_SUCCESS)
196 if (res == LDAP_SERVER_DOWN)
198 // Attempt to reconnect if the connection dropped
199 ServerInstance->SNO->WriteToSnoMask('a', "LDAP server has gone away - reconnecting...");
201 res = ldap_sasl_bind_s(conn, username.c_str(), LDAP_SASL_SIMPLE, &cred, NULL, NULL, NULL);
204 if (res != LDAP_SUCCESS)
207 ldap_unbind_ext(conn, NULL, NULL);
214 LDAPMessage *msg, *entry;
215 std::string what = attribute + "=" + opername;
216 if ((res = ldap_search_ext_s(conn, base.c_str(), searchscope, what.c_str(), NULL, 0, NULL, NULL, NULL, 0, &msg)) != LDAP_SUCCESS)
220 if (ldap_count_entries(conn, msg) > 1)
225 if ((entry = ldap_first_entry(conn, msg)) == NULL)
230 authpass = strdup(opassword.c_str());
231 cred.bv_val = authpass;
232 cred.bv_len = opassword.length();
233 RAIILDAPString DN(ldap_get_dn(conn, entry));
234 if ((res = ldap_sasl_bind_s(conn, DN, LDAP_SASL_SIMPLE, &cred, NULL, NULL, NULL)) == LDAP_SUCCESS)
248 virtual Version GetVersion()
250 return Version("Adds the ability to authenticate opers via LDAP", VF_VENDOR);
255 MODULE_INIT(ModuleLDAPAuth)