anope- supernets anope source code & configuration |
git clone git://git.acid.vegas/anope.git |
Log | Files | Refs | Archive | README |
m_ldap_authentication.cpp (7889B)
1 /* 2 * 3 * (C) 2011-2022 Anope Team 4 * Contact us at team@anope.org 5 * 6 * Please read COPYING and README for further details. 7 */ 8 9 #include "module.h" 10 #include "modules/ldap.h" 11 12 static Module *me; 13 14 static Anope::string basedn; 15 static Anope::string search_filter; 16 static Anope::string object_class; 17 static Anope::string email_attribute; 18 static Anope::string username_attribute; 19 20 struct IdentifyInfo 21 { 22 Reference<User> user; 23 IdentifyRequest *req; 24 ServiceReference<LDAPProvider> lprov; 25 bool admin_bind; 26 Anope::string dn; 27 28 IdentifyInfo(User *u, IdentifyRequest *r, ServiceReference<LDAPProvider> &lp) : user(u), req(r), lprov(lp), admin_bind(true) 29 { 30 req->Hold(me); 31 } 32 33 ~IdentifyInfo() 34 { 35 req->Release(me); 36 } 37 }; 38 39 class IdentifyInterface : public LDAPInterface 40 { 41 IdentifyInfo *ii; 42 43 public: 44 IdentifyInterface(Module *m, IdentifyInfo *i) : LDAPInterface(m), ii(i) { } 45 46 ~IdentifyInterface() 47 { 48 delete ii; 49 } 50 51 void OnDelete() anope_override 52 { 53 delete this; 54 } 55 56 void OnResult(const LDAPResult &r) anope_override 57 { 58 if (!ii->lprov) 59 return; 60 61 switch (r.type) 62 { 63 case QUERY_SEARCH: 64 { 65 if (!r.empty()) 66 { 67 try 68 { 69 const LDAPAttributes &attr = r.get(0); 70 ii->dn = attr.get("dn"); 71 Log(LOG_DEBUG) << "m_ldap_authenticationn: binding as " << ii->dn; 72 73 ii->lprov->Bind(new IdentifyInterface(this->owner, ii), ii->dn, ii->req->GetPassword()); 74 ii = NULL; 75 } 76 catch (const LDAPException &ex) 77 { 78 Log(this->owner) << "Error binding after search: " << ex.GetReason(); 79 } 80 } 81 break; 82 } 83 case QUERY_BIND: 84 { 85 if (ii->admin_bind) 86 { 87 Anope::string sf = search_filter.replace_all_cs("%account", ii->req->GetAccount()).replace_all_cs("%object_class", object_class); 88 try 89 { 90 Log(LOG_DEBUG) << "m_ldap_authentication: searching for " << sf; 91 ii->lprov->Search(new IdentifyInterface(this->owner, ii), basedn, sf); 92 ii->admin_bind = false; 93 ii = NULL; 94 } 95 catch (const LDAPException &ex) 96 { 97 Log(this->owner) << "Unable to search for " << sf << ": " << ex.GetReason(); 98 } 99 } 100 else 101 { 102 NickAlias *na = NickAlias::Find(ii->req->GetAccount()); 103 if (na == NULL) 104 { 105 na = new NickAlias(ii->req->GetAccount(), new NickCore(ii->req->GetAccount())); 106 na->last_realname = ii->user ? ii->user->realname : ii->req->GetAccount(); 107 FOREACH_MOD(OnNickRegister, (ii->user, na, ii->req->GetPassword())); 108 BotInfo *NickServ = Config->GetClient("NickServ"); 109 if (ii->user && NickServ) 110 ii->user->SendMessage(NickServ, _("Your account \002%s\002 has been successfully created."), na->nick.c_str()); 111 } 112 // encrypt and store the password in the nickcore 113 Anope::Encrypt(ii->req->GetPassword(), na->nc->pass); 114 115 na->nc->Extend<Anope::string>("m_ldap_authentication_dn", ii->dn); 116 ii->req->Success(me); 117 } 118 break; 119 } 120 default: 121 break; 122 } 123 } 124 125 void OnError(const LDAPResult &r) anope_override 126 { 127 } 128 }; 129 130 class OnIdentifyInterface : public LDAPInterface 131 { 132 Anope::string uid; 133 134 public: 135 OnIdentifyInterface(Module *m, const Anope::string &i) : LDAPInterface(m), uid(i) { } 136 137 void OnDelete() anope_override 138 { 139 delete this; 140 } 141 142 void OnResult(const LDAPResult &r) anope_override 143 { 144 User *u = User::Find(uid); 145 146 if (!u || !u->Account() || r.empty()) 147 return; 148 149 try 150 { 151 const LDAPAttributes &attr = r.get(0); 152 Anope::string email = attr.get(email_attribute); 153 154 if (!email.equals_ci(u->Account()->email)) 155 { 156 u->Account()->email = email; 157 BotInfo *NickServ = Config->GetClient("NickServ"); 158 if (NickServ) 159 u->SendMessage(NickServ, _("Your email has been updated to \002%s\002"), email.c_str()); 160 Log(this->owner) << "Updated email address for " << u->nick << " (" << u->Account()->display << ") to " << email; 161 } 162 } 163 catch (const LDAPException &ex) 164 { 165 Log(this->owner) << ex.GetReason(); 166 } 167 } 168 169 void OnError(const LDAPResult &r) anope_override 170 { 171 Log(this->owner) << r.error; 172 } 173 }; 174 175 class OnRegisterInterface : public LDAPInterface 176 { 177 public: 178 OnRegisterInterface(Module *m) : LDAPInterface(m) { } 179 180 void OnResult(const LDAPResult &r) anope_override 181 { 182 Log(this->owner) << "Successfully added newly created account to LDAP"; 183 } 184 185 void OnError(const LDAPResult &r) anope_override 186 { 187 Log(this->owner) << "Error adding newly created account to LDAP: " << r.getError(); 188 } 189 }; 190 191 class ModuleLDAPAuthentication : public Module 192 { 193 ServiceReference<LDAPProvider> ldap; 194 OnRegisterInterface orinterface; 195 196 PrimitiveExtensibleItem<Anope::string> dn; 197 198 Anope::string password_attribute; 199 Anope::string disable_register_reason; 200 Anope::string disable_email_reason; 201 public: 202 ModuleLDAPAuthentication(const Anope::string &modname, const Anope::string &creator) : 203 Module(modname, creator, EXTRA | VENDOR), ldap("LDAPProvider", "ldap/main"), orinterface(this), 204 dn(this, "m_ldap_authentication_dn") 205 { 206 me = this; 207 } 208 209 void Prioritize() anope_override 210 { 211 ModuleManager::SetPriority(this, PRIORITY_FIRST); 212 } 213 214 void OnReload(Configuration::Conf *config) anope_override 215 { 216 Configuration::Block *conf = Config->GetModule(this); 217 218 basedn = conf->Get<const Anope::string>("basedn"); 219 search_filter = conf->Get<const Anope::string>("search_filter"); 220 object_class = conf->Get<const Anope::string>("object_class"); 221 username_attribute = conf->Get<const Anope::string>("username_attribute"); 222 this->password_attribute = conf->Get<const Anope::string>("password_attribute"); 223 email_attribute = conf->Get<const Anope::string>("email_attribute"); 224 this->disable_register_reason = conf->Get<const Anope::string>("disable_register_reason"); 225 this->disable_email_reason = conf->Get<const Anope::string>("disable_email_reason"); 226 227 if (!email_attribute.empty()) 228 /* Don't complain to users about how they need to update their email, we will do it for them */ 229 config->GetModule("nickserv")->Set("forceemail", "false"); 230 } 231 232 EventReturn OnPreCommand(CommandSource &source, Command *command, std::vector<Anope::string> ¶ms) anope_override 233 { 234 if (!this->disable_register_reason.empty()) 235 { 236 if (command->name == "nickserv/register" || command->name == "nickserv/group") 237 { 238 source.Reply(this->disable_register_reason); 239 return EVENT_STOP; 240 } 241 } 242 243 if (!email_attribute.empty() && !this->disable_email_reason.empty() && command->name == "nickserv/set/email") 244 { 245 source.Reply(this->disable_email_reason); 246 return EVENT_STOP; 247 } 248 249 return EVENT_CONTINUE; 250 } 251 252 void OnCheckAuthentication(User *u, IdentifyRequest *req) anope_override 253 { 254 if (!this->ldap) 255 return; 256 257 IdentifyInfo *ii = new IdentifyInfo(u, req, this->ldap); 258 this->ldap->BindAsAdmin(new IdentifyInterface(this, ii)); 259 } 260 261 void OnNickIdentify(User *u) anope_override 262 { 263 if (email_attribute.empty() || !this->ldap) 264 return; 265 266 Anope::string *d = dn.Get(u->Account()); 267 if (!d || d->empty()) 268 return; 269 270 this->ldap->Search(new OnIdentifyInterface(this, u->GetUID()), *d, "(" + email_attribute + "=*)"); 271 } 272 273 void OnNickRegister(User *, NickAlias *na, const Anope::string &pass) anope_override 274 { 275 if (!this->disable_register_reason.empty() || !this->ldap) 276 return; 277 278 this->ldap->BindAsAdmin(NULL); 279 280 LDAPMods attributes; 281 attributes.resize(4); 282 283 attributes[0].name = "objectClass"; 284 attributes[0].values.push_back("top"); 285 attributes[0].values.push_back(object_class); 286 287 attributes[1].name = username_attribute; 288 attributes[1].values.push_back(na->nick); 289 290 if (!na->nc->email.empty()) 291 { 292 attributes[2].name = email_attribute; 293 attributes[2].values.push_back(na->nc->email); 294 } 295 296 attributes[3].name = this->password_attribute; 297 attributes[3].values.push_back(pass); 298 299 Anope::string new_dn = username_attribute + "=" + na->nick + "," + basedn; 300 this->ldap->Add(&this->orinterface, new_dn, attributes); 301 } 302 }; 303 304 MODULE_INIT(ModuleLDAPAuthentication)