00001 #include "module.h"
00002 #include "nickserv.h"
00003 #include "ldap.h"
00004
00005 static Module *me;
00006
00007 static Anope::string basedn;
00008 static Anope::string search_filter;
00009 static Anope::string object_class;
00010 static Anope::string email_attribute;
00011 static Anope::string username_attribute;
00012
00013 struct IdentifyInfo
00014 {
00015 Reference<User> user;
00016 IdentifyRequest *req;
00017 ServiceReference<LDAPProvider> lprov;
00018 bool admin_bind;
00019 Anope::string dn;
00020
00021 IdentifyInfo(User *u, IdentifyRequest *r, ServiceReference<LDAPProvider> &lp) : user(u), req(r), lprov(lp), admin_bind(true)
00022 {
00023 req->Hold(me);
00024 }
00025
00026 ~IdentifyInfo()
00027 {
00028 req->Release(me);
00029 }
00030 };
00031
00032 class IdentifyInterface : public LDAPInterface
00033 {
00034 std::map<LDAPQuery, IdentifyInfo *> requests;
00035
00036 public:
00037 IdentifyInterface(Module *m) : LDAPInterface(m) { }
00038
00039 void Add(LDAPQuery id, IdentifyInfo *ii)
00040 {
00041 std::map<LDAPQuery, IdentifyInfo *>::iterator it = this->requests.find(id);
00042 if (it != this->requests.end())
00043 delete it->second;
00044 this->requests[id] = ii;
00045 }
00046
00047 void OnResult(const LDAPResult &r) anope_override
00048 {
00049 std::map<LDAPQuery, IdentifyInfo *>::iterator it = this->requests.find(r.id);
00050 if (it == this->requests.end())
00051 return;
00052 IdentifyInfo *ii = it->second;
00053 this->requests.erase(it);
00054
00055 if (!ii->lprov)
00056 {
00057 delete ii;
00058 return;
00059 }
00060
00061 switch (r.type)
00062 {
00063 case LDAPResult::QUERY_SEARCH:
00064 {
00065 if (!r.empty())
00066 {
00067 try
00068 {
00069 const LDAPAttributes &attr = r.get(0);
00070 ii->dn = attr.get("dn");
00071 Log(LOG_DEBUG) << "m_ldap_authenticationn: binding as " << ii->dn;
00072 LDAPQuery id = ii->lprov->Bind(this, ii->dn, ii->req->GetPassword());
00073 this->Add(id, ii);
00074 return;
00075 }
00076 catch (const LDAPException &ex)
00077 {
00078 Log(this->owner) << "m_ldap_authentication: Error binding after search: " << ex.GetReason();
00079 }
00080 }
00081 break;
00082 }
00083 case LDAPResult::QUERY_BIND:
00084 {
00085 if (ii->admin_bind)
00086 {
00087 Anope::string sf = search_filter.replace_all_cs("%account", ii->req->GetAccount()).replace_all_cs("%object_class", object_class);
00088 try
00089 {
00090 Log(LOG_DEBUG) << "m_ldap_authentication: searching for " << sf;
00091 LDAPQuery id = ii->lprov->Search(this, basedn, sf);
00092 this->Add(id, ii);
00093 ii->admin_bind = false;
00094 return;
00095 }
00096 catch (const LDAPException &ex)
00097 {
00098 Log(this->owner) << "m_ldap_authentication: Unable to search for " << sf << ": " << ex.GetReason();
00099 }
00100 }
00101 else
00102 {
00103 NickAlias *na = NickAlias::Find(ii->req->GetAccount());
00104 if (na == NULL)
00105 {
00106 na = new NickAlias(ii->req->GetAccount(), new NickCore(ii->req->GetAccount()));
00107 if (ii->user)
00108 {
00109 if (Config->NSAddAccessOnReg)
00110 na->nc->AddAccess(ii->user->Mask());
00111
00112 if (NickServ)
00113 ii->user->SendMessage(NickServ, _("Your account \002%s\002 has been successfully created."), na->nick.c_str());
00114 }
00115 }
00116
00117 Anope::Encrypt(ii->req->GetPassword(), na->nc->pass);
00118
00119 na->nc->Extend("m_ldap_authentication_dn", new ExtensibleItemClass<Anope::string>(ii->dn));
00120 ii->req->Success(me);
00121 }
00122 break;
00123 }
00124 default:
00125 break;
00126 }
00127
00128 delete ii;
00129 }
00130
00131 void OnError(const LDAPResult &r) anope_override
00132 {
00133 std::map<LDAPQuery, IdentifyInfo *>::iterator it = this->requests.find(r.id);
00134 if (it == this->requests.end())
00135 return;
00136 IdentifyInfo *ii = it->second;
00137 this->requests.erase(it);
00138 delete ii;
00139 }
00140 };
00141
00142 class OnIdentifyInterface : public LDAPInterface
00143 {
00144 std::map<LDAPQuery, Anope::string> requests;
00145
00146 public:
00147 OnIdentifyInterface(Module *m) : LDAPInterface(m) { }
00148
00149 void Add(LDAPQuery id, const Anope::string &nick)
00150 {
00151 this->requests[id] = nick;
00152 }
00153
00154 void OnResult(const LDAPResult &r) anope_override
00155 {
00156 std::map<LDAPQuery, Anope::string>::iterator it = this->requests.find(r.id);
00157 if (it == this->requests.end())
00158 return;
00159 User *u = User::Find(it->second);
00160 this->requests.erase(it);
00161
00162 if (!u || !u->Account() || r.empty())
00163 return;
00164
00165 try
00166 {
00167 const LDAPAttributes &attr = r.get(0);
00168 Anope::string email = attr.get(email_attribute);
00169
00170 if (!email.equals_ci(u->Account()->email))
00171 {
00172 u->Account()->email = email;
00173 if (NickServ)
00174 u->SendMessage(NickServ, _("Your email has been updated to \002%s\002"), email.c_str());
00175 Log(this->owner) << "m_ldap_authentication: Updated email address for " << u->nick << " (" << u->Account()->display << ") to " << email;
00176 }
00177 }
00178 catch (const LDAPException &ex)
00179 {
00180 Log(this->owner) << "m_ldap_authentication: " << ex.GetReason();
00181 }
00182 }
00183
00184 void OnError(const LDAPResult &r) anope_override
00185 {
00186 this->requests.erase(r.id);
00187 Log(this->owner) << "m_ldap_authentication: " << r.error;
00188 }
00189 };
00190
00191 class OnRegisterInterface : public LDAPInterface
00192 {
00193 public:
00194 OnRegisterInterface(Module *m) : LDAPInterface(m) { }
00195
00196 void OnResult(const LDAPResult &r) anope_override
00197 {
00198 Log(this->owner) << "m_ldap_authentication: Successfully added newly created account to LDAP";
00199 }
00200
00201 void OnError(const LDAPResult &r) anope_override
00202 {
00203 Log(this->owner) << "m_ldap_authentication: Error adding newly created account to LDAP: " << r.getError();
00204 }
00205 };
00206
00207 class NSIdentifyLDAP : public Module
00208 {
00209 ServiceReference<LDAPProvider> ldap;
00210 IdentifyInterface iinterface;
00211 OnIdentifyInterface oninterface;
00212 OnRegisterInterface orinterface;
00213
00214 Anope::string password_attribute;
00215 Anope::string disable_register_reason;
00216 Anope::string disable_email_reason;
00217 public:
00218 NSIdentifyLDAP(const Anope::string &modname, const Anope::string &creator) :
00219 Module(modname, creator, SUPPORTED), ldap("LDAPProvider", "ldap/main"), iinterface(this), oninterface(this), orinterface(this)
00220 {
00221 this->SetAuthor("Anope");
00222
00223 me = this;
00224
00225 Implementation i[] = { I_OnReload, I_OnPreCommand, I_OnCheckAuthentication, I_OnNickIdentify, I_OnNickRegister };
00226 ModuleManager::Attach(i, this, sizeof(i) / sizeof(Implementation));
00227 ModuleManager::SetPriority(this, PRIORITY_FIRST);
00228
00229 OnReload();
00230 }
00231
00232 void OnReload() anope_override
00233 {
00234 ConfigReader config;
00235
00236 basedn = config.ReadValue("m_ldap_authentication", "basedn", "", 0);
00237 search_filter = config.ReadValue("m_ldap_authentication", "search_filter", "", 0);
00238 object_class = config.ReadValue("m_ldap_authentication", "object_class", "", 0);
00239 username_attribute = config.ReadValue("m_ldap_authentication", "username_attribute", "", 0);
00240 this->password_attribute = config.ReadValue("m_ldap_authentication", "password_attribute", "", 0);
00241 email_attribute = config.ReadValue("m_ldap_authentication", "email_attribute", "", 0);
00242 this->disable_register_reason = config.ReadValue("m_ldap_authentication", "disable_register_reason", "", 0);
00243 this->disable_email_reason = config.ReadValue("m_ldap_authentication", "disable_email_reason", "", 0);
00244
00245 if (!email_attribute.empty())
00246
00247 Config->NSForceEmail = false;
00248 }
00249
00250 EventReturn OnPreCommand(CommandSource &source, Command *command, std::vector<Anope::string> ¶ms) anope_override
00251 {
00252 if (!this->disable_register_reason.empty() && command->name == "nickserv/register")
00253 {
00254 source.Reply(this->disable_register_reason);
00255 return EVENT_STOP;
00256 }
00257 else if (!email_attribute.empty() && !this->disable_email_reason.empty() && command->name == "nickserv/set/email")
00258 {
00259 source.Reply(this->disable_email_reason);
00260 return EVENT_STOP;
00261 }
00262
00263 return EVENT_CONTINUE;
00264 }
00265
00266 void OnCheckAuthentication(User *u, IdentifyRequest *req) anope_override
00267 {
00268 if (!this->ldap)
00269 return;
00270
00271 IdentifyInfo *ii = new IdentifyInfo(u, req, this->ldap);
00272 try
00273 {
00274 LDAPQuery id = this->ldap->BindAsAdmin(&this->iinterface);
00275 this->iinterface.Add(id, ii);
00276 }
00277 catch (const LDAPException &ex)
00278 {
00279 delete ii;
00280 Log(this) << ex.GetReason();
00281 }
00282 }
00283
00284 void OnNickIdentify(User *u) anope_override
00285 {
00286 if (email_attribute.empty() || !this->ldap || !u->Account()->HasExt("m_ldap_authentication_dn"))
00287 return;
00288
00289 Anope::string *dn = u->Account()->GetExt<ExtensibleItemClass<Anope::string> *>("m_ldap_authentication_dn");
00290 if (!dn || dn->empty())
00291 return;
00292
00293 try
00294 {
00295 LDAPQuery id = this->ldap->Search(&this->oninterface, *dn, "(" + email_attribute + "=*)");
00296 this->oninterface.Add(id, u->nick);
00297 }
00298 catch (const LDAPException &ex)
00299 {
00300 Log(this) << ex.GetReason();
00301 }
00302 }
00303
00304 void OnNickRegister(NickAlias *na) anope_override
00305 {
00306 if (!this->disable_register_reason.empty() || !this->ldap)
00307 return;
00308
00309 try
00310 {
00311 this->ldap->BindAsAdmin(NULL);
00312
00313 LDAPMods attributes;
00314 attributes.resize(4);
00315
00316 attributes[0].name = "objectClass";
00317 attributes[0].values.push_back("top");
00318 attributes[0].values.push_back(object_class);
00319
00320 attributes[1].name = username_attribute;
00321 attributes[1].values.push_back(na->nick);
00322
00323 if (!na->nc->email.empty())
00324 {
00325 attributes[2].name = email_attribute;
00326 attributes[2].values.push_back(na->nc->email);
00327 }
00328
00329 attributes[3].name = this->password_attribute;
00330 attributes[3].values.push_back(na->nc->pass);
00331
00332 Anope::string new_dn = username_attribute + "=" + na->nick + "," + basedn;
00333 this->ldap->Add(&this->orinterface, new_dn, attributes);
00334 }
00335 catch (const LDAPException &ex)
00336 {
00337 Log(this) << ex.GetReason();
00338 }
00339 }
00340 };
00341
00342 MODULE_INIT(NSIdentifyLDAP)