00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024 #include "inspircd.h"
00025 #include "users.h"
00026 #include "channels.h"
00027 #include "modules.h"
00028
00029 #include <ldap.h>
00030
00031
00032
00033
00034 class ModuleLDAPAuth : public Module
00035 {
00036 std::string base;
00037 std::string attribute;
00038 std::string ldapserver;
00039 std::string allowpattern;
00040 std::string killreason;
00041 std::string username;
00042 std::string password;
00043 int searchscope;
00044 bool verbose;
00045 bool useusername;
00046 LDAP *conn;
00047
00048 public:
00049 ModuleLDAPAuth(InspIRCd* Me)
00050 : Module(Me)
00051 {
00052 conn = NULL;
00053 Implementation eventlist[] = { I_OnUserDisconnect, I_OnCheckReady, I_OnRehash, I_OnUserRegister };
00054 ServerInstance->Modules->Attach(eventlist, this, 4);
00055 OnRehash(NULL,"");
00056 }
00057
00058 virtual ~ModuleLDAPAuth()
00059 {
00060 if (conn)
00061 ldap_unbind_ext(conn, NULL, NULL);
00062 }
00063
00064 virtual void OnRehash(User* user, const std::string ¶meter)
00065 {
00066 ConfigReader Conf(ServerInstance);
00067
00068 base = Conf.ReadValue("ldapauth", "baserdn", 0);
00069 attribute = Conf.ReadValue("ldapauth", "attribute", 0);
00070 ldapserver = Conf.ReadValue("ldapauth", "server", 0);
00071 allowpattern = Conf.ReadValue("ldapauth", "allowpattern", 0);
00072 killreason = Conf.ReadValue("ldapauth", "killreason", 0);
00073 std::string scope = Conf.ReadValue("ldapauth", "searchscope", 0);
00074 username = Conf.ReadValue("ldapauth", "binddn", 0);
00075 password = Conf.ReadValue("ldapauth", "bindauth", 0);
00076 verbose = Conf.ReadFlag("ldapauth", "verbose", 0);
00077 useusername = Conf.ReadFlag("ldapauth", "userfield", 0);
00078
00079 if (scope == "base")
00080 searchscope = LDAP_SCOPE_BASE;
00081 else if (scope == "onelevel")
00082 searchscope = LDAP_SCOPE_ONELEVEL;
00083 else searchscope = LDAP_SCOPE_SUBTREE;
00084
00085 Connect();
00086 }
00087
00088 bool Connect()
00089 {
00090 if (conn != NULL)
00091 ldap_unbind_ext(conn, NULL, NULL);
00092 int res, v = LDAP_VERSION3;
00093 res = ldap_initialize(&conn, ldapserver.c_str());
00094 if (res != LDAP_SUCCESS)
00095 {
00096 if (verbose)
00097 ServerInstance->SNO->WriteToSnoMask('A', "LDAP connection failed: %s", ldap_err2string(res));
00098 conn = NULL;
00099 return false;
00100 }
00101
00102 res = ldap_set_option(conn, LDAP_OPT_PROTOCOL_VERSION, (void *)&v);
00103 if (res != LDAP_SUCCESS)
00104 {
00105 if (verbose)
00106 ServerInstance->SNO->WriteToSnoMask('A', "LDAP set protocol to v3 failed: %s", ldap_err2string(res));
00107 ldap_unbind_ext(conn, NULL, NULL);
00108 conn = NULL;
00109 return false;
00110 }
00111 return true;
00112 }
00113
00114 virtual int OnUserRegister(User* user)
00115 {
00116 if ((!allowpattern.empty()) && (InspIRCd::Match(user->nick,allowpattern)))
00117 {
00118 user->Extend("ldapauthed");
00119 return 0;
00120 }
00121
00122 if (!CheckCredentials(user))
00123 {
00124 ServerInstance->Users->QuitUser(user, killreason);
00125 return 1;
00126 }
00127 return 0;
00128 }
00129
00130 bool CheckCredentials(User* user)
00131 {
00132 if (conn == NULL)
00133 if (!Connect())
00134 return false;
00135
00136 int res;
00137 char* authpass = strdup(password.c_str());
00138
00139 struct berval cred;
00140 cred.bv_val = authpass;
00141 cred.bv_len = password.length();
00142
00143 if ((res = ldap_sasl_bind_s(conn, username.c_str(), LDAP_SASL_SIMPLE, &cred, NULL, NULL, NULL)) != LDAP_SUCCESS)
00144 {
00145 free(authpass);
00146 if (verbose)
00147 ServerInstance->SNO->WriteToSnoMask('A', "Forbidden connection from %s!%s@%s (LDAP bind failed: %s)", user->nick.c_str(), user->ident.c_str(), user->host.c_str(), ldap_err2string(res));
00148 ldap_unbind_ext(conn, NULL, NULL);
00149 conn = NULL;
00150 return false;
00151 }
00152 free(authpass);
00153
00154 LDAPMessage *msg, *entry;
00155 std::string what = (attribute + "=" + (useusername ? user->ident : user->nick));
00156 if ((res = ldap_search_ext_s(conn, base.c_str(), searchscope, what.c_str(), NULL, 0, NULL, NULL, NULL, 0, &msg)) != LDAP_SUCCESS)
00157 {
00158 if (verbose)
00159 ServerInstance->SNO->WriteToSnoMask('A', "Forbidden connection from %s!%s@%s (LDAP search failed: %s)", user->nick.c_str(), user->ident.c_str(), user->host.c_str(), ldap_err2string(res));
00160 return false;
00161 }
00162 if (ldap_count_entries(conn, msg) > 1)
00163 {
00164 if (verbose)
00165 ServerInstance->SNO->WriteToSnoMask('A', "Forbidden connection from %s!%s@%s (LDAP search returned more than one result: %s)", user->nick.c_str(), user->ident.c_str(), user->host.c_str(), ldap_err2string(res));
00166 ldap_msgfree(msg);
00167 return false;
00168 }
00169 if ((entry = ldap_first_entry(conn, msg)) == NULL)
00170 {
00171 if (verbose)
00172 ServerInstance->SNO->WriteToSnoMask('A', "Forbidden connection from %s!%s@%s (LDAP search returned no results: %s)", user->nick.c_str(), user->ident.c_str(), user->host.c_str(), ldap_err2string(res));
00173 ldap_msgfree(msg);
00174 return false;
00175 }
00176 if (user->password.empty())
00177 {
00178 if (verbose)
00179 ServerInstance->SNO->WriteToSnoMask('A', "Forbidden connection from %s!%s@%s (No password provided)", user->nick.c_str(), user->ident.c_str(), user->host.c_str());
00180 user->Extend("ldapauth_failed");
00181 return false;
00182 }
00183 cred.bv_val = (char*)user->password.data();
00184 cred.bv_len = user->password.length();
00185 if ((res = ldap_sasl_bind_s(conn, ldap_get_dn(conn, entry), LDAP_SASL_SIMPLE, &cred, NULL, NULL, NULL)) == LDAP_SUCCESS)
00186 {
00187 ldap_msgfree(msg);
00188 user->Extend("ldapauthed");
00189 return true;
00190 }
00191 else
00192 {
00193 if (verbose)
00194 ServerInstance->SNO->WriteToSnoMask('A', "Forbidden connection from %s!%s@%s (%s)", user->nick.c_str(), user->ident.c_str(), user->host.c_str(), ldap_err2string(res));
00195 ldap_msgfree(msg);
00196 user->Extend("ldapauth_failed");
00197 return false;
00198 }
00199 }
00200
00201
00202 virtual void OnUserDisconnect(User* user)
00203 {
00204 user->Shrink("ldapauthed");
00205 user->Shrink("ldapauth_failed");
00206 }
00207
00208 virtual bool OnCheckReady(User* user)
00209 {
00210 return user->GetExt("ldapauthed");
00211 }
00212
00213 virtual Version GetVersion()
00214 {
00215 return Version("$Id: m_ldapauth.cpp 10394 2008-09-05 11:22:50Z brain $", VF_VENDOR, API_VERSION);
00216 }
00217
00218 };
00219
00220 MODULE_INIT(ModuleLDAPAuth)