diff options
Diffstat (limited to 'modules')
-rw-r--r-- | modules/commands/cs_ban.cpp | 24 | ||||
-rw-r--r-- | modules/commands/cs_clone.cpp | 182 | ||||
-rw-r--r-- | modules/commands/cs_kick.cpp | 15 | ||||
-rw-r--r-- | modules/commands/ns_register.cpp | 6 | ||||
-rw-r--r-- | modules/commands/ns_set.cpp | 17 | ||||
-rw-r--r-- | modules/commands/os_sxline.cpp | 4 | ||||
-rw-r--r-- | modules/extra/m_ldap.cpp | 621 | ||||
-rw-r--r-- | modules/extra/m_ldap_authentication.cpp | 136 | ||||
-rw-r--r-- | modules/fantasy.cpp | 24 | ||||
-rw-r--r-- | modules/m_xmlrpc.cpp | 4 | ||||
-rw-r--r-- | modules/protocol/hybrid.cpp | 21 | ||||
-rw-r--r-- | modules/protocol/inspircd20.cpp | 2 | ||||
-rw-r--r-- | modules/pseudoclients/operserv.cpp | 11 |
13 files changed, 570 insertions, 497 deletions
diff --git a/modules/commands/cs_ban.cpp b/modules/commands/cs_ban.cpp index 648e379e3..be15df66c 100644 --- a/modules/commands/cs_ban.cpp +++ b/modules/commands/cs_ban.cpp @@ -156,15 +156,18 @@ class CommandCSBan : public Command { bool founder = u_access.HasPriv("FOUNDER"); bool override = !founder && !u_access.HasPriv("BAN"); - Log(override ? LOG_OVERRIDE : LOG_COMMAND, source, this, ci) << "for " << target; - if (!c->HasMode(mode, target)) + Anope::string mask = IRCD->NormalizeMask(target); + + Log(override ? LOG_OVERRIDE : LOG_COMMAND, source, this, ci) << "for " << mask; + + if (!c->HasMode(mode, mask)) { - c->SetMode(NULL, mode, target); + c->SetMode(NULL, mode, mask); if (ban_time) { - new TempBan(ban_time, c, target, mode); - source.Reply(_("Ban on \002%s\002 expires in %s."), target.c_str(), Anope::Duration(ban_time, source.GetAccount()).c_str()); + new TempBan(ban_time, c, mask, mode); + source.Reply(_("Ban on \002%s\002 expires in %s."), mask.c_str(), Anope::Duration(ban_time, source.GetAccount()).c_str()); } } @@ -174,7 +177,8 @@ class CommandCSBan : public Command ChanUserContainer *uc = it->second; ++it; - if (Anope::Match(uc->user->nick, target) || Anope::Match(uc->user->GetDisplayedMask(), target)) + Entry e(mode, mask); + if (e.Matches(uc->user)) { ++matched; @@ -193,17 +197,17 @@ class CommandCSBan : public Command { ++kicked; if (ci->HasExt("SIGNKICK") || (ci->HasExt("SIGNKICK_LEVEL") && !u_access.HasPriv("SIGNKICK"))) - c->Kick(ci->WhoSends(), uc->user, "%s (Matches %s) (%s)", reason.c_str(), target.c_str(), source.GetNick().c_str()); + c->Kick(ci->WhoSends(), uc->user, "%s (Matches %s) (%s)", reason.c_str(), mask.c_str(), source.GetNick().c_str()); else - c->Kick(ci->WhoSends(), uc->user, "%s (Matches %s)", reason.c_str(), target.c_str()); + c->Kick(ci->WhoSends(), uc->user, "%s (Matches %s)", reason.c_str(), mask.c_str()); } } } if (matched) - source.Reply(_("Kicked %d/%d users matching %s from %s."), kicked, matched, target.c_str(), c->name.c_str()); + source.Reply(_("Kicked %d/%d users matching %s from %s."), kicked, matched, mask.c_str(), c->name.c_str()); else - source.Reply(_("No users on %s match %s."), c->name.c_str(), target.c_str()); + source.Reply(_("No users on %s match %s."), c->name.c_str(), mask.c_str()); } } diff --git a/modules/commands/cs_clone.cpp b/modules/commands/cs_clone.cpp index 8365091cf..cbf53e892 100644 --- a/modules/commands/cs_clone.cpp +++ b/modules/commands/cs_clone.cpp @@ -14,6 +14,100 @@ class CommandCSClone : public Command { + void CopySetting(ChannelInfo *ci, ChannelInfo *target_ci, const Anope::string &setting) + { + if (ci->HasExt(setting)) + target_ci->Extend<bool>(setting); + } + + void CopyAccess(CommandSource &source, ChannelInfo *ci, ChannelInfo *target_ci) + { + std::set<Anope::string> masks; + unsigned access_max = Config->GetModule("chanserv")->Get<unsigned>("accessmax", "1024"); + unsigned count = 0; + + for (unsigned i = 0; i < target_ci->GetAccessCount(); ++i) + masks.insert(target_ci->GetAccess(i)->Mask()); + + for (unsigned i = 0; i < ci->GetAccessCount(); ++i) + { + const ChanAccess *taccess = ci->GetAccess(i); + AccessProvider *provider = taccess->provider; + + if (access_max && target_ci->GetDeepAccessCount() >= access_max) + break; + + if (masks.count(taccess->Mask())) + continue; + masks.insert(taccess->Mask()); + + ChanAccess *newaccess = provider->Create(); + newaccess->SetMask(taccess->Mask(), target_ci); + newaccess->creator = taccess->creator; + newaccess->last_seen = taccess->last_seen; + newaccess->created = taccess->created; + newaccess->AccessUnserialize(taccess->AccessSerialize()); + + target_ci->AddAccess(newaccess); + + ++count; + } + + source.Reply(_("%d access entries from \002%s\002 have been cloned to \002%s\002."), count, ci->name.c_str(), target_ci->name.c_str()); + } + + void CopyAkick(CommandSource &source, ChannelInfo *ci, ChannelInfo *target_ci) + { + target_ci->ClearAkick(); + for (unsigned i = 0; i < ci->GetAkickCount(); ++i) + { + const AutoKick *akick = ci->GetAkick(i); + if (akick->nc) + target_ci->AddAkick(akick->creator, akick->nc, akick->reason, akick->addtime, akick->last_used); + else + target_ci->AddAkick(akick->creator, akick->mask, akick->reason, akick->addtime, akick->last_used); + } + + source.Reply(_("All akick entries from \002%s\002 have been cloned to \002%s\002."), ci->name.c_str(), target_ci->name.c_str()); + } + + void CopyBadwords(CommandSource &source, ChannelInfo *ci, ChannelInfo *target_ci) + { + BadWords *target_badwords = target_ci->Require<BadWords>("badwords"), + *badwords = ci->Require<BadWords>("badwords"); + + if (!target_badwords || !badwords) + { + source.Reply(ACCESS_DENIED); // BotServ doesn't exist/badwords isn't loaded + return; + } + + target_badwords->ClearBadWords(); + + for (unsigned i = 0; i < badwords->GetBadWordCount(); ++i) + { + const BadWord *bw = badwords->GetBadWord(i); + target_badwords->AddBadWord(bw->word, bw->type); + } + + badwords->Check(); + target_badwords->Check(); + + source.Reply(_("All badword entries from \002%s\002 have been cloned to \002%s\002."), ci->name.c_str(), target_ci->name.c_str()); + } + + void CopyLevels(CommandSource &source, ChannelInfo *ci, ChannelInfo *target_ci) + { + const Anope::map<int16_t> &cilevels = ci->GetLevelEntries(); + + for (Anope::map<int16_t>::const_iterator it = cilevels.begin(); it != cilevels.end(); ++it) + { + target_ci->SetLevel(it->first, it->second); + } + + source.Reply(_("All level entries from \002%s\002 have been cloned into \002%s\002."), ci->name.c_str(), target_ci->name.c_str()); + } + public: CommandCSClone(Module *creator) : Command(creator, "chanserv/clone", 2, 3) { @@ -100,82 +194,36 @@ public: else target_ci->last_topic_setter = source.service->nick; + const Anope::string settings[] = { "NOAUTOOP", "CS_KEEP_MODES", "PEACE", "PERSIST", "RESTRICTED", + "CS_SECURE", "SECUREFOUNDER", "SECUREOPS", "SIGNKICK", "SIGNKICK_LEVEL", "CS_NO_EXPIRE" }; + + for (unsigned int i = 0; i < sizeof(settings) / sizeof(Anope::string); ++i) + CopySetting(ci, target_ci, settings[i]); + + CopyAccess(source, ci, target_ci); + CopyAkick(source, ci, target_ci); + CopyBadwords(source, ci, target_ci); + CopyLevels(source, ci, target_ci); + FOREACH_MOD(OnChanRegistered, (target_ci)); - source.Reply(_("All settings from \002%s\002 have been cloned to \002%s\002."), channel.c_str(), target.c_str()); + source.Reply(_("All settings from \002%s\002 have been cloned to \002%s\002."), ci->name.c_str(), target_ci->name.c_str()); } else if (what.equals_ci("ACCESS")) { - std::set<Anope::string> masks; - unsigned access_max = Config->GetModule("chanserv")->Get<unsigned>("accessmax", "1024"); - unsigned count = 0; - - for (unsigned i = 0; i < target_ci->GetAccessCount(); ++i) - masks.insert(target_ci->GetAccess(i)->Mask()); - - for (unsigned i = 0; i < ci->GetAccessCount(); ++i) - { - const ChanAccess *taccess = ci->GetAccess(i); - AccessProvider *provider = taccess->provider; - - if (access_max && target_ci->GetDeepAccessCount() >= access_max) - break; - - if (masks.count(taccess->Mask())) - continue; - masks.insert(taccess->Mask()); - - ChanAccess *newaccess = provider->Create(); - newaccess->SetMask(taccess->Mask(), target_ci); - newaccess->creator = taccess->creator; - newaccess->last_seen = taccess->last_seen; - newaccess->created = taccess->created; - newaccess->AccessUnserialize(taccess->AccessSerialize()); - - target_ci->AddAccess(newaccess); - - ++count; - } - - source.Reply(_("%d access entries from \002%s\002 have been cloned to \002%s\002."), count, channel.c_str(), target.c_str()); + CopyAccess(source, ci, target_ci); } else if (what.equals_ci("AKICK")) { - target_ci->ClearAkick(); - for (unsigned i = 0; i < ci->GetAkickCount(); ++i) - { - const AutoKick *akick = ci->GetAkick(i); - if (akick->nc) - target_ci->AddAkick(akick->creator, akick->nc, akick->reason, akick->addtime, akick->last_used); - else - target_ci->AddAkick(akick->creator, akick->mask, akick->reason, akick->addtime, akick->last_used); - } - - source.Reply(_("All akick entries from \002%s\002 have been cloned to \002%s\002."), channel.c_str(), target.c_str()); + CopyAkick(source, ci, target_ci); } else if (what.equals_ci("BADWORDS")) { - BadWords *target_badwords = target_ci->Require<BadWords>("badwords"), - *badwords = ci->Require<BadWords>("badwords"); - - if (!target_badwords || !badwords) - { - source.Reply(ACCESS_DENIED); // BotServ doesn't exist/badwords isn't loaded - return; - } - - target_badwords->ClearBadWords(); - - for (unsigned i = 0; i < badwords->GetBadWordCount(); ++i) - { - const BadWord *bw = badwords->GetBadWord(i); - target_badwords->AddBadWord(bw->word, bw->type); - } - - badwords->Check(); - target_badwords->Check(); - - source.Reply(_("All badword entries from \002%s\002 have been cloned to \002%s\002."), channel.c_str(), target.c_str()); + CopyBadwords(source, ci, target_ci); + } + else if (what.equals_ci("LEVELS")) + { + CopyLevels(source, ci, target_ci); } else { @@ -191,8 +239,8 @@ public: this->SendSyntax(source); source.Reply(" "); source.Reply(_("Copies all settings, access, akicks, etc from \002channel\002 to the\n" - "\002target\002 channel. If \037what\037 is \002ACCESS\002, \002AKICK\002, or \002BADWORDS\002\n" - "then only the respective settings are cloned.\n" + "\002target\002 channel. If \037what\037 is \002ACCESS\002, \002AKICK\002, \002BADWORDS\002,\n" + "or \002LEVELS\002 then only the respective settings are cloned.\n" "You must be the founder of \037channel\037 and \037target\037.")); return true; } diff --git a/modules/commands/cs_kick.cpp b/modules/commands/cs_kick.cpp index c95445557..a3505d254 100644 --- a/modules/commands/cs_kick.cpp +++ b/modules/commands/cs_kick.cpp @@ -73,7 +73,9 @@ class CommandCSKick : public Command } else if (u_access.HasPriv("FOUNDER")) { - Log(LOG_COMMAND, source, this, ci) << "for " << target; + Anope::string mask = IRCD->NormalizeMask(target); + + Log(LOG_COMMAND, source, this, ci) << "for " << mask; int matched = 0, kicked = 0; for (Channel::ChanUserList::iterator it = c->users.begin(), it_end = c->users.end(); it != it_end;) @@ -81,7 +83,8 @@ class CommandCSKick : public Command ChanUserContainer *uc = it->second; ++it; - if (Anope::Match(uc->user->nick, target) || Anope::Match(uc->user->GetDisplayedMask(), target)) + Entry e("", mask); + if (e.Matches(uc->user)) { ++matched; @@ -93,16 +96,16 @@ class CommandCSKick : public Command ++kicked; if (ci->HasExt("SIGNKICK") || (ci->HasExt("SIGNKICK_LEVEL") && !u_access.HasPriv("SIGNKICK"))) - c->Kick(ci->WhoSends(), uc->user, "%s (Matches %s) (%s)", reason.c_str(), target.c_str(), source.GetNick().c_str()); + c->Kick(ci->WhoSends(), uc->user, "%s (Matches %s) (%s)", reason.c_str(), mask.c_str(), source.GetNick().c_str()); else - c->Kick(ci->WhoSends(), uc->user, "%s (Matches %s)", reason.c_str(), target.c_str()); + c->Kick(ci->WhoSends(), uc->user, "%s (Matches %s)", reason.c_str(), mask.c_str()); } } if (matched) - source.Reply(_("Kicked %d/%d users matching %s from %s."), kicked, matched, target.c_str(), c->name.c_str()); + source.Reply(_("Kicked %d/%d users matching %s from %s."), kicked, matched, mask.c_str(), c->name.c_str()); else - source.Reply(_("No users on %s match %s."), c->name.c_str(), target.c_str()); + source.Reply(_("No users on %s match %s."), c->name.c_str(), mask.c_str()); } else source.Reply(NICK_X_NOT_IN_USE, target.c_str()); diff --git a/modules/commands/ns_register.cpp b/modules/commands/ns_register.cpp index 4793b2269..75ef5a9fb 100644 --- a/modules/commands/ns_register.cpp +++ b/modules/commands/ns_register.cpp @@ -170,6 +170,8 @@ class CommandNSRegister : public Command } } + unsigned int passlen = Config->GetModule("nickserv")->Get<unsigned>("passlen", "32"); + if (Config->GetModule("nickserv")->Get<bool>("forceemail", "yes") && email.empty()) this->OnSyntaxError(source, ""); else if (u && Anope::CurTime < u->lastnickreg + reg_delay) @@ -178,8 +180,8 @@ class CommandNSRegister : public Command source.Reply(NICK_ALREADY_REGISTERED, u_nick.c_str()); else if (pass.equals_ci(u_nick) || (Config->GetBlock("options")->Get<bool>("strictpasswords") && pass.length() < 5)) source.Reply(MORE_OBSCURE_PASSWORD); - else if (pass.length() > Config->GetModule("nickserv")->Get<unsigned>("passlen", "32")) - source.Reply(PASSWORD_TOO_LONG); + else if (pass.length() > passlen) + source.Reply(PASSWORD_TOO_LONG, passlen); else if (!email.empty() && !Mail::Validate(email)) source.Reply(MAIL_X_INVALID, email.c_str()); else diff --git a/modules/commands/ns_set.cpp b/modules/commands/ns_set.cpp index 03ebae85c..e8e7c335c 100644 --- a/modules/commands/ns_set.cpp +++ b/modules/commands/ns_set.cpp @@ -133,9 +133,11 @@ class CommandNSSetPassword : public Command source.Reply(MORE_OBSCURE_PASSWORD); return; } - else if (len > Config->GetModule("nickserv")->Get<unsigned>("passlen", "32")) + + unsigned int passlen = Config->GetModule("nickserv")->Get<unsigned>("passlen", "32"); + if (len > passlen) { - source.Reply(PASSWORD_TOO_LONG); + source.Reply(PASSWORD_TOO_LONG, passlen); return; } @@ -191,14 +193,17 @@ class CommandNSSASetPassword : public Command source.Reply(_("You may not change the password of other Services Operators.")); return; } - else if (nc->display.equals_ci(params[1]) || (Config->GetBlock("options")->Get<bool>("strictpasswords") && len < 5)) + + if (nc->display.equals_ci(params[1]) || (Config->GetBlock("options")->Get<bool>("strictpasswords") && len < 5)) { source.Reply(MORE_OBSCURE_PASSWORD); return; } - else if (len > Config->GetModule("nickserv")->Get<unsigned>("passlen", "32")) + + unsigned int passlen = Config->GetModule("nickserv")->Get<unsigned>("passlen", "32"); + if (len > passlen) { - source.Reply(PASSWORD_TOO_LONG); + source.Reply(PASSWORD_TOO_LONG, passlen); return; } @@ -414,10 +419,12 @@ class CommandNSSetEmail : public Command message = Config->GetBlock("mail")->Get<const Anope::string>("emailchange_message"); subject = subject.replace_all_cs("%e", u->Account()->email); + subject = subject.replace_all_cs("%E", new_email); subject = subject.replace_all_cs("%N", Config->GetBlock("networkinfo")->Get<const Anope::string>("networkname")); subject = subject.replace_all_cs("%c", code); message = message.replace_all_cs("%e", u->Account()->email); + message = message.replace_all_cs("%E", new_email); message = message.replace_all_cs("%N", Config->GetBlock("networkinfo")->Get<const Anope::string>("networkname")); message = message.replace_all_cs("%c", code); diff --git a/modules/commands/os_sxline.cpp b/modules/commands/os_sxline.cpp index 80b7c5586..3fde89871 100644 --- a/modules/commands/os_sxline.cpp +++ b/modules/commands/os_sxline.cpp @@ -664,7 +664,9 @@ class CommandOSSQLine : public CommandOSSXLineBase "connect, Services will not allow it to pursue his IRC\n" "session.\n" "If the first character of the mask is #, services will\n" - "prevent the use of matching channels.")); + "prevent the use of matching channels. If the mask is a\n" + "regular expression, the expression will be matched against\n" + "channels too.")); source.Reply(_(" \n" "\002SQLINE ADD\002 adds the given (nick's) mask to the SQLINE\n" "list for the given reason (which \002must\002 be given).\n" diff --git a/modules/extra/m_ldap.cpp b/modules/extra/m_ldap.cpp index 05d54e896..ff63be5c6 100644 --- a/modules/extra/m_ldap.cpp +++ b/modules/extra/m_ldap.cpp @@ -1,3 +1,14 @@ +/* + * + * (C) 2011-2015 Anope Team + * Contact us at team@anope.org + * + * Please read COPYING and README for further details. + * + * Based on the original code of Epona by Lara. + * Based on the original code of Services by Andy Church. + */ + /* RequiredLibraries: ldap_r,lber */ /* RequiredWindowsLibraries: libldap_r,liblber */ @@ -5,8 +16,124 @@ #include "modules/ldap.h" #include <ldap.h> +class LDAPService; static Pipe *me; +class LDAPRequest +{ + public: + LDAPService *service; + LDAPInterface *inter; + LDAPMessage *message; /* message returned by ldap_ */ + LDAPResult *result; /* final result */ + struct timeval tv; + QueryType type; + + LDAPRequest(LDAPService *s, LDAPInterface *i) + : service(s) + , inter(i) + , message(NULL) + , result(NULL) + { + type = QUERY_UNKNOWN; + tv.tv_sec = 0; + tv.tv_usec = 100000; + } + + virtual ~LDAPRequest() + { + delete result; + if (inter != NULL) + inter->OnDelete(); + if (message != NULL) + ldap_msgfree(message); + } + + virtual int run() = 0; +}; + +class LDAPBind : public LDAPRequest +{ + Anope::string who, pass; + + public: + LDAPBind(LDAPService *s, LDAPInterface *i, const Anope::string &w, const Anope::string &p) + : LDAPRequest(s, i) + , who(w) + , pass(p) + { + type = QUERY_BIND; + } + + int run() anope_override; +}; + +class LDAPSearch : public LDAPRequest +{ + Anope::string base; + Anope::string filter; + + public: + LDAPSearch(LDAPService *s, LDAPInterface *i, const Anope::string &b, const Anope::string &f) + : LDAPRequest(s, i) + , base(b) + , filter(f) + { + type = QUERY_SEARCH; + } + + int run() anope_override; +}; + +class LDAPAdd : public LDAPRequest +{ + Anope::string dn; + LDAPMods attributes; + + public: + LDAPAdd(LDAPService *s, LDAPInterface *i, const Anope::string &d, const LDAPMods &attr) + : LDAPRequest(s, i) + , dn(d) + , attributes(attr) + { + type = QUERY_ADD; + } + + int run() anope_override; +}; + +class LDAPDel : public LDAPRequest +{ + Anope::string dn; + + public: + LDAPDel(LDAPService *s, LDAPInterface *i, const Anope::string &d) + : LDAPRequest(s, i) + , dn(d) + { + type = QUERY_DELETE; + } + + int run() anope_override; +}; + +class LDAPModify : public LDAPRequest +{ + Anope::string base; + LDAPMods attributes; + + public: + LDAPModify(LDAPService *s, LDAPInterface *i, const Anope::string &b, const LDAPMods &attr) + : LDAPRequest(s, i) + , base(b) + , attributes(attr) + { + type = QUERY_MODIFY; + } + + int run() anope_override; +}; + class LDAPService : public LDAPProvider, public Thread, public Condition { Anope::string server; @@ -19,7 +146,8 @@ class LDAPService : public LDAPProvider, public Thread, public Condition time_t last_connect; - LDAPMod **BuildMods(const LDAPMods &attributes) + public: + static LDAPMod **BuildMods(const LDAPMods &attributes) { LDAPMod **mods = new LDAPMod*[attributes.size() + 1]; memset(mods, 0, sizeof(LDAPMod*) * (attributes.size() + 1)); @@ -46,7 +174,7 @@ class LDAPService : public LDAPProvider, public Thread, public Condition return mods; } - void FreeMods(LDAPMod **mods) + static void FreeMods(LDAPMod **mods) { for (int i = 0; mods[i] != NULL; ++i) { @@ -58,6 +186,7 @@ class LDAPService : public LDAPProvider, public Thread, public Condition delete [] mods; } + private: void Reconnect() { /* Only try one connect a minute. It is an expensive blocking operation */ @@ -71,11 +200,18 @@ class LDAPService : public LDAPProvider, public Thread, public Condition throw LDAPException("Unable to connect to LDAP service " + this->name + ": " + ldap_err2string(i)); } + void QueueRequest(LDAPRequest *r) + { + this->Lock(); + this->queries.push_back(r); + this->Wakeup(); + this->Unlock(); + } + public: - typedef std::map<LDAPQuery, std::pair<time_t, LDAPInterface *> > query_queue; - typedef std::vector<std::pair<LDAPInterface *, LDAPResult *> > result_queue; - query_queue queries; - result_queue results; + typedef std::vector<LDAPRequest *> query_queue; + query_queue queries, results; + Mutex process_mutex; /* held when processing requests not in either queue */ LDAPService(Module *o, const Anope::string &n, const Anope::string &s, int po, const Anope::string &b, const Anope::string &p, time_t t) : LDAPProvider(o, n), server(s), port(po), admin_binddn(b), admin_pass(p), timeout(t), last_connect(0) { @@ -96,363 +232,210 @@ class LDAPService : public LDAPProvider, public Thread, public Condition ~LDAPService() { + /* At this point the thread has stopped so we don't need to hold process_mutex */ + this->Lock(); - for (query_queue::iterator it = this->queries.begin(), it_end = this->queries.end(); it != it_end; ++it) + for (unsigned int i = 0; i < this->queries.size(); ++i) { - LDAPQuery msgid = it->first; - LDAPInterface *i = it->second.second; + LDAPRequest *req = this->queries[i]; - ldap_abandon_ext(this->con, msgid, NULL, NULL); - if (i) - i->OnDelete(); + /* queries have no results yet */ + req->result = new LDAPResult(); + req->result->type = req->type; + req->result->error = "LDAP Interface is going away"; + if (req->inter) + req->inter->OnError(*req->result); + + delete req; } this->queries.clear(); - for (result_queue::iterator it = this->results.begin(), it_end = this->results.end(); it != it_end; ++it) + for (unsigned int i = 0; i < this->results.size(); ++i) { - LDAPInterface *i = it->first; - LDAPResult *r = it->second; + LDAPRequest *req = this->results[i]; - r->error = "LDAP Interface is going away"; - if (i) - i->OnError(*r); + /* even though this may have already finished successfully we return that it didn't */ + req->result->error = "LDAP Interface is going away"; + if (req->inter) + req->inter->OnError(*req->result); - delete r; + delete req; } - this->results.clear(); this->Unlock(); ldap_unbind_ext(this->con, NULL, NULL); } - LDAPQuery BindAsAdmin(LDAPInterface *i) + void BindAsAdmin(LDAPInterface *i) anope_override { - return this->Bind(i, this->admin_binddn, this->admin_pass); + this->Bind(i, this->admin_binddn, this->admin_pass); } - LDAPQuery Bind(LDAPInterface *i, const Anope::string &who, const Anope::string &pass) anope_override + void Bind(LDAPInterface *i, const Anope::string &who, const Anope::string &pass) anope_override { - berval cred; - cred.bv_val = strdup(pass.c_str()); - cred.bv_len = pass.length(); - - LDAPQuery msgid; - int ret = ldap_sasl_bind(con, who.c_str(), LDAP_SASL_SIMPLE, &cred, NULL, NULL, &msgid); - free(cred.bv_val); - if (ret != LDAP_SUCCESS) - { - if (ret == LDAP_SERVER_DOWN || ret == LDAP_TIMEOUT) - { - this->Reconnect(); - return this->Bind(i, who, pass); - } - else - throw LDAPException(ldap_err2string(ret)); - } - - if (i != NULL) - { - this->Lock(); - this->queries[msgid] = std::make_pair(Anope::CurTime, i); - this->Unlock(); - } - this->Wakeup(); - - return msgid; + LDAPBind *b = new LDAPBind(this, i, who, pass); + QueueRequest(b); } - LDAPQuery Search(LDAPInterface *i, const Anope::string &base, const Anope::string &filter) anope_override + void Search(LDAPInterface *i, const Anope::string &base, const Anope::string &filter) anope_override { if (i == NULL) throw LDAPException("No interface"); - LDAPQuery msgid; - int ret = ldap_search_ext(this->con, base.c_str(), LDAP_SCOPE_SUBTREE, filter.c_str(), NULL, 0, NULL, NULL, NULL, 0, &msgid); - if (ret != LDAP_SUCCESS) - { - if (ret == LDAP_SERVER_DOWN || ret == LDAP_TIMEOUT) - { - this->Reconnect(); - return this->Search(i, base, filter); - } - else - throw LDAPException(ldap_err2string(ret)); - } - - this->Lock(); - this->queries[msgid] = std::make_pair(Anope::CurTime, i); - this->Unlock(); - this->Wakeup(); - - return msgid; + LDAPSearch *s = new LDAPSearch(this, i, base, filter); + QueueRequest(s); } - LDAPQuery Add(LDAPInterface *i, const Anope::string &dn, LDAPMods &attributes) anope_override + void Add(LDAPInterface *i, const Anope::string &dn, LDAPMods &attributes) anope_override { - LDAPMod **mods = this->BuildMods(attributes); - LDAPQuery msgid; - int ret = ldap_add_ext(this->con, dn.c_str(), mods, NULL, NULL, &msgid); - this->FreeMods(mods); - - if (ret != LDAP_SUCCESS) - { - if (ret == LDAP_SERVER_DOWN || ret == LDAP_TIMEOUT) - { - this->Reconnect(); - return this->Add(i, dn, attributes); - } - else - throw LDAPException(ldap_err2string(ret)); - } + LDAPAdd *add = new LDAPAdd(this, i, dn, attributes); + QueueRequest(add); + } - if (i != NULL) - { - this->Lock(); - this->queries[msgid] = std::make_pair(Anope::CurTime, i); - this->Unlock(); - } - this->Wakeup(); + void Del(LDAPInterface *i, const Anope::string &dn) anope_override + { + LDAPDel *del = new LDAPDel(this, i, dn); + QueueRequest(del); + } - return msgid; + void Modify(LDAPInterface *i, const Anope::string &base, LDAPMods &attributes) anope_override + { + LDAPModify *mod = new LDAPModify(this, i, base, attributes); + QueueRequest(mod); } - LDAPQuery Del(LDAPInterface *i, const Anope::string &dn) anope_override + private: + void BuildReply(int res, LDAPRequest *req) { - LDAPQuery msgid; - int ret = ldap_delete_ext(this->con, dn.c_str(), NULL, NULL, &msgid); + LDAPResult *ldap_result = req->result = new LDAPResult(); + req->result->type = req->type; - if (ret != LDAP_SUCCESS) + if (res != LDAP_SUCCESS) { - if (ret == LDAP_SERVER_DOWN || ret == LDAP_TIMEOUT) - { - this->Reconnect(); - return this->Del(i, dn); - } - else - throw LDAPException(ldap_err2string(ret)); + ldap_result->error = ldap_err2string(res); + return; } - if (i != NULL) + if (req->message == NULL) { - this->Lock(); - this->queries[msgid] = std::make_pair(Anope::CurTime, i); - this->Unlock(); + return; } - this->Wakeup(); - return msgid; - } + /* a search result */ - LDAPQuery Modify(LDAPInterface *i, const Anope::string &base, LDAPMods &attributes) anope_override - { - LDAPMod **mods = this->BuildMods(attributes); - LDAPQuery msgid; - int ret = ldap_modify_ext(this->con, base.c_str(), mods, NULL, NULL, &msgid); - this->FreeMods(mods); - - if (ret != LDAP_SUCCESS) + for (LDAPMessage *cur = ldap_first_message(this->con, req->message); cur; cur = ldap_next_message(this->con, cur)) { - if (ret == LDAP_SERVER_DOWN || ret == LDAP_TIMEOUT) + LDAPAttributes attributes; + + char *dn = ldap_get_dn(this->con, cur); + if (dn != NULL) { - this->Reconnect(); - return this->Modify(i, base, attributes); + attributes["dn"].push_back(dn); + ldap_memfree(dn); + dn = NULL; } - else - throw LDAPException(ldap_err2string(ret)); - } - if (i != NULL) - { - this->Lock(); - this->queries[msgid] = std::make_pair(Anope::CurTime, i); - this->Unlock(); - } - this->Wakeup(); - - return msgid; - } - - private: - void Timeout() - { - this->Lock(); - for (query_queue::iterator it = this->queries.begin(), it_end = this->queries.end(); it != it_end;) - { - LDAPQuery msgid = it->first; - time_t created = it->second.first; - LDAPInterface *i = it->second.second; - ++it; + BerElement *ber = NULL; - if (Anope::CurTime > created + timeout) + for (char *attr = ldap_first_attribute(this->con, cur, &ber); attr; attr = ldap_next_attribute(this->con, cur, ber)) { - LDAPResult *ldap_result = new LDAPResult(); - ldap_result->id = msgid; - ldap_result->error = "Query timed out"; + berval **vals = ldap_get_values_len(this->con, cur, attr); + int count = ldap_count_values_len(vals); - this->queries.erase(msgid); - this->results.push_back(std::make_pair(i, ldap_result)); + std::vector<Anope::string> attrs; + for (int j = 0; j < count; ++j) + attrs.push_back(vals[j]->bv_val); + attributes[attr] = attrs; - me->Notify(); + ldap_value_free_len(vals); + ldap_memfree(attr); } + + if (ber != NULL) + ber_free(ber, 0); + + ldap_result->messages.push_back(attributes); } - this->Unlock(); } - public: - void Run() anope_override + void SendRequests() { - while (!this->GetExitState()) - { - if (this->queries.empty()) - { - this->Lock(); - this->Wait(); - this->Unlock(); - continue; - } - else - this->Timeout(); - - struct timeval tv = { 1, 0 }; - LDAPMessage *result; - int rtype = ldap_result(this->con, LDAP_RES_ANY, 1, &tv, &result); - if (rtype <= 0) - continue; - - int cur_id = ldap_msgid(result); + process_mutex.Lock(); - this->Lock(); - - query_queue::iterator it = this->queries.find(cur_id); - if (it == this->queries.end()) - { - this->Unlock(); - ldap_msgfree(result); - continue; - } - LDAPInterface *i = it->second.second; - this->queries.erase(it); + query_queue q; + this->Lock(); + queries.swap(q); + this->Unlock(); - this->Unlock(); + if (q.empty()) + { + process_mutex.Unlock(); + return; + } - LDAPResult *ldap_result = new LDAPResult(); - ldap_result->id = cur_id; + for (unsigned int i = 0; i < q.size(); ++i) + { + LDAPRequest *req = q[i]; + int ret = req->run(); - for (LDAPMessage *cur = ldap_first_message(this->con, result); cur; cur = ldap_next_message(this->con, cur)) + if (ret == LDAP_SERVER_DOWN || ret == LDAP_TIMEOUT) { - int cur_type = ldap_msgtype(cur); - - LDAPAttributes attributes; - - char *dn = ldap_get_dn(this->con, cur); - if (dn != NULL) + /* try again */ + try { - attributes["dn"].push_back(dn); - ldap_memfree(dn); - dn = NULL; + Reconnect(); } - - switch (cur_type) + catch (const LDAPException &) { - case LDAP_RES_BIND: - ldap_result->type = LDAPResult::QUERY_BIND; - break; - case LDAP_RES_SEARCH_ENTRY: - ldap_result->type = LDAPResult::QUERY_SEARCH; - break; - case LDAP_RES_ADD: - ldap_result->type = LDAPResult::QUERY_ADD; - break; - case LDAP_RES_DELETE: - ldap_result->type = LDAPResult::QUERY_DELETE; - break; - case LDAP_RES_MODIFY: - ldap_result->type = LDAPResult::QUERY_MODIFY; - break; - case LDAP_RES_SEARCH_RESULT: - // If we get here and ldap_result->type is LDAPResult::QUERY_UNKNOWN - // then the result set is empty - ldap_result->type = LDAPResult::QUERY_SEARCH; - break; - default: - Log(LOG_DEBUG) << "m_ldap: Unknown msg type " << cur_type; - continue; } - switch (cur_type) - { - case LDAP_RES_BIND: - { - int errcode = -1; - int parse_result = ldap_parse_result(this->con, cur, &errcode, NULL, NULL, NULL, NULL, 0); - if (parse_result != LDAP_SUCCESS) - ldap_result->error = ldap_err2string(parse_result); - else if (errcode != LDAP_SUCCESS) - ldap_result->error = ldap_err2string(errcode); - break; - } - case LDAP_RES_SEARCH_ENTRY: - { - BerElement *ber = NULL; - for (char *attr = ldap_first_attribute(this->con, cur, &ber); attr; attr = ldap_next_attribute(this->con, cur, ber)) - { - berval **vals = ldap_get_values_len(this->con, cur, attr); - int count = ldap_count_values_len(vals); - - std::vector<Anope::string> attrs; - for (int j = 0; j < count; ++j) - attrs.push_back(vals[j]->bv_val); - attributes[attr] = attrs; - - ldap_value_free_len(vals); - ldap_memfree(attr); - } - if (ber != NULL) - ber_free(ber, 0); - - break; - } - case LDAP_RES_ADD: - case LDAP_RES_DELETE: - case LDAP_RES_MODIFY: - { - int errcode = -1; - int parse_result = ldap_parse_result(this->con, cur, &errcode, NULL, NULL, NULL, NULL, 0); - if (parse_result != LDAP_SUCCESS) - ldap_result->error = ldap_err2string(parse_result); - else if (errcode != LDAP_SUCCESS) - ldap_result->error = ldap_err2string(errcode); - break; - } - default: - continue; - } - - ldap_result->messages.push_back(attributes); + ret = req->run(); } - ldap_msgfree(result); + BuildReply(ret, req); this->Lock(); - this->results.push_back(std::make_pair(i, ldap_result)); + results.push_back(req); + this->Unlock(); + } + + me->Notify(); + + process_mutex.Unlock(); + } + + public: + void Run() anope_override + { + while (!this->GetExitState()) + { + this->Lock(); + /* Queries can be non empty if one is pushed during SendRequests() */ + if (queries.empty()) + this->Wait(); this->Unlock(); - me->Notify(); + SendRequests(); } } + + LDAP* GetConnection() + { + return con; + } }; class ModuleLDAP : public Module, public Pipe { std::map<Anope::string, LDAPService *> LDAPServices; + public: ModuleLDAP(const Anope::string &modname, const Anope::string &creator) : Module(modname, creator, EXTRA | VENDOR) { me = this; - } ~ModuleLDAP() @@ -489,6 +472,8 @@ class ModuleLDAP : public Module, public Pipe s->SetExitState(); s->Wakeup(); + s->Join(); + delete s; this->LDAPServices.erase(cname); } } @@ -528,32 +513,36 @@ class ModuleLDAP : public Module, public Pipe for (std::map<Anope::string, LDAPService *>::iterator it = this->LDAPServices.begin(); it != this->LDAPServices.end(); ++it) { LDAPService *s = it->second; + + s->process_mutex.Lock(); s->Lock(); - for (LDAPService::query_queue::iterator it2 = s->queries.begin(); it2 != s->queries.end();) + + for (unsigned int i = s->queries.size(); i > 0; --i) { - LDAPQuery msgid = it2->first; - LDAPInterface *i = it2->second.second; - ++it2; + LDAPRequest *req = s->queries[i - 1]; + LDAPInterface *li = req->inter; - if (i && i->owner == m) + if (li && li->owner == m) { - i->OnDelete(); - s->queries.erase(msgid); + s->queries.erase(s->queries.begin() + i - 1); + delete req; } } - for (unsigned i = s->results.size(); i > 0; --i) + for (unsigned int i = s->results.size(); i > 0; --i) { - LDAPInterface *li = s->results[i - 1].first; - LDAPResult *r = s->results[i - 1].second; + LDAPRequest *req = s->results[i - 1]; + LDAPInterface *li = req->inter; if (li && li->owner == m) { s->results.erase(s->results.begin() + i - 1); - delete r; + delete req; } } + s->Unlock(); - } + s->process_mutex.Unlock(); + } } void OnNotify() anope_override @@ -562,15 +551,16 @@ class ModuleLDAP : public Module, public Pipe { LDAPService *s = it->second; - LDAPService::result_queue results; + LDAPService::query_queue results; s->Lock(); results.swap(s->results); s->Unlock(); - for (unsigned i = 0; i < results.size(); ++i) + for (unsigned int i = 0; i < results.size(); ++i) { - LDAPInterface *li = results[i].first; - LDAPResult *r = results[i].second; + LDAPRequest *req = results[i]; + LDAPInterface *li = req->inter; + LDAPResult *r = req->result; if (li != NULL) { @@ -583,11 +573,50 @@ class ModuleLDAP : public Module, public Pipe li->OnResult(*r); } - delete r; + delete req; } } } }; +int LDAPBind::run() +{ + berval cred; + cred.bv_val = strdup(pass.c_str()); + cred.bv_len = pass.length(); + + int i = ldap_sasl_bind_s(service->GetConnection(), who.c_str(), LDAP_SASL_SIMPLE, &cred, NULL, NULL, NULL); + + free(cred.bv_val); + + return i; +} + +int LDAPSearch::run() +{ + return ldap_search_ext_s(service->GetConnection(), base.c_str(), LDAP_SCOPE_SUBTREE, filter.c_str(), NULL, 0, NULL, NULL, &tv, 0, &message); +} + +int LDAPAdd::run() +{ + LDAPMod **mods = LDAPService::BuildMods(attributes); + int i = ldap_add_ext_s(service->GetConnection(), dn.c_str(), mods, NULL, NULL); + LDAPService::FreeMods(mods); + return i; +} + +int LDAPDel::run() +{ + return ldap_delete_ext_s(service->GetConnection(), dn.c_str(), NULL, NULL); +} + +int LDAPModify::run() +{ + LDAPMod **mods = LDAPService::BuildMods(attributes); + int i = ldap_modify_ext_s(service->GetConnection(), base.c_str(), mods, NULL, NULL); + LDAPService::FreeMods(mods); + return i; +} + MODULE_INIT(ModuleLDAP) diff --git a/modules/extra/m_ldap_authentication.cpp b/modules/extra/m_ldap_authentication.cpp index 01bafac45..23f47c5e6 100644 --- a/modules/extra/m_ldap_authentication.cpp +++ b/modules/extra/m_ldap_authentication.cpp @@ -30,36 +30,29 @@ struct IdentifyInfo class IdentifyInterface : public LDAPInterface { - std::map<LDAPQuery, IdentifyInfo *> requests; + IdentifyInfo *ii; public: - IdentifyInterface(Module *m) : LDAPInterface(m) { } + IdentifyInterface(Module *m, IdentifyInfo *i) : LDAPInterface(m), ii(i) { } - void Add(LDAPQuery id, IdentifyInfo *ii) + ~IdentifyInterface() { - std::map<LDAPQuery, IdentifyInfo *>::iterator it = this->requests.find(id); - if (it != this->requests.end()) - delete it->second; - this->requests[id] = ii; + delete ii; } - void OnResult(const LDAPResult &r) anope_override + void OnDelete() anope_override { - std::map<LDAPQuery, IdentifyInfo *>::iterator it = this->requests.find(r.id); - if (it == this->requests.end()) - return; - IdentifyInfo *ii = it->second; - this->requests.erase(it); + delete this; + } + void OnResult(const LDAPResult &r) anope_override + { if (!ii->lprov) - { - delete ii; return; - } switch (r.type) { - case LDAPResult::QUERY_SEARCH: + case QUERY_SEARCH: { if (!r.empty()) { @@ -68,9 +61,9 @@ class IdentifyInterface : public LDAPInterface const LDAPAttributes &attr = r.get(0); ii->dn = attr.get("dn"); Log(LOG_DEBUG) << "m_ldap_authenticationn: binding as " << ii->dn; - LDAPQuery id = ii->lprov->Bind(this, ii->dn, ii->req->GetPassword()); - this->Add(id, ii); - return; + + ii->lprov->Bind(new IdentifyInterface(this->owner, ii), ii->dn, ii->req->GetPassword()); + ii = NULL; } catch (const LDAPException &ex) { @@ -79,7 +72,7 @@ class IdentifyInterface : public LDAPInterface } break; } - case LDAPResult::QUERY_BIND: + case QUERY_BIND: { if (ii->admin_bind) { @@ -87,10 +80,9 @@ class IdentifyInterface : public LDAPInterface try { Log(LOG_DEBUG) << "m_ldap_authentication: searching for " << sf; - LDAPQuery id = ii->lprov->Search(this, basedn, sf); - this->Add(id, ii); + ii->lprov->Search(new IdentifyInterface(this->owner, ii), basedn, sf); ii->admin_bind = false; - return; + ii = NULL; } catch (const LDAPException &ex) { @@ -120,40 +112,28 @@ class IdentifyInterface : public LDAPInterface default: break; } - - delete ii; } void OnError(const LDAPResult &r) anope_override { - std::map<LDAPQuery, IdentifyInfo *>::iterator it = this->requests.find(r.id); - if (it == this->requests.end()) - return; - IdentifyInfo *ii = it->second; - this->requests.erase(it); - delete ii; } }; class OnIdentifyInterface : public LDAPInterface { - std::map<LDAPQuery, Anope::string> requests; + Anope::string uid; public: - OnIdentifyInterface(Module *m) : LDAPInterface(m) { } + OnIdentifyInterface(Module *m, const Anope::string &i) : LDAPInterface(m), uid(i) { } - void Add(LDAPQuery id, const Anope::string &nick) + void OnDelete() anope_override { - this->requests[id] = nick; + delete this; } void OnResult(const LDAPResult &r) anope_override { - std::map<LDAPQuery, Anope::string>::iterator it = this->requests.find(r.id); - if (it == this->requests.end()) - return; - User *u = User::Find(it->second); - this->requests.erase(it); + User *u = User::Find(uid); if (!u || !u->Account() || r.empty()) return; @@ -180,7 +160,6 @@ class OnIdentifyInterface : public LDAPInterface void OnError(const LDAPResult &r) anope_override { - this->requests.erase(r.id); Log(this->owner) << r.error; } }; @@ -201,11 +180,9 @@ class OnRegisterInterface : public LDAPInterface } }; -class NSIdentifyLDAP : public Module +class ModuleLDAPAuthentication : public Module { ServiceReference<LDAPProvider> ldap; - IdentifyInterface iinterface; - OnIdentifyInterface oninterface; OnRegisterInterface orinterface; PrimitiveExtensibleItem<Anope::string> dn; @@ -214,11 +191,10 @@ class NSIdentifyLDAP : public Module Anope::string disable_register_reason; Anope::string disable_email_reason; public: - NSIdentifyLDAP(const Anope::string &modname, const Anope::string &creator) : - Module(modname, creator, EXTRA | VENDOR), ldap("LDAPProvider", "ldap/main"), iinterface(this), oninterface(this), orinterface(this), + ModuleLDAPAuthentication(const Anope::string &modname, const Anope::string &creator) : + Module(modname, creator, EXTRA | VENDOR), ldap("LDAPProvider", "ldap/main"), orinterface(this), dn(this, "m_ldap_authentication_dn") { - me = this; } @@ -271,16 +247,7 @@ class NSIdentifyLDAP : public Module return; IdentifyInfo *ii = new IdentifyInfo(u, req, this->ldap); - try - { - LDAPQuery id = this->ldap->BindAsAdmin(&this->iinterface); - this->iinterface.Add(id, ii); - } - catch (const LDAPException &ex) - { - delete ii; - Log(this) << ex.GetReason(); - } + this->ldap->BindAsAdmin(new IdentifyInterface(this, ii)); } void OnNickIdentify(User *u) anope_override @@ -292,15 +259,7 @@ class NSIdentifyLDAP : public Module if (!d || d->empty()) return; - try - { - LDAPQuery id = this->ldap->Search(&this->oninterface, *d, "(" + email_attribute + "=*)"); - this->oninterface.Add(id, u->nick); - } - catch (const LDAPException &ex) - { - Log(this) << ex.GetReason(); - } + this->ldap->Search(new OnIdentifyInterface(this, u->GetUID()), *d, "(" + email_attribute + "=*)"); } void OnNickRegister(User *, NickAlias *na, const Anope::string &pass) anope_override @@ -308,37 +267,30 @@ class NSIdentifyLDAP : public Module if (!this->disable_register_reason.empty() || !this->ldap) return; - try - { - this->ldap->BindAsAdmin(NULL); - - LDAPMods attributes; - attributes.resize(4); - - attributes[0].name = "objectClass"; - attributes[0].values.push_back("top"); - attributes[0].values.push_back(object_class); + this->ldap->BindAsAdmin(NULL); - attributes[1].name = username_attribute; - attributes[1].values.push_back(na->nick); + LDAPMods attributes; + attributes.resize(4); - if (!na->nc->email.empty()) - { - attributes[2].name = email_attribute; - attributes[2].values.push_back(na->nc->email); - } + attributes[0].name = "objectClass"; + attributes[0].values.push_back("top"); + attributes[0].values.push_back(object_class); - attributes[3].name = this->password_attribute; - attributes[3].values.push_back(pass); + attributes[1].name = username_attribute; + attributes[1].values.push_back(na->nick); - Anope::string new_dn = username_attribute + "=" + na->nick + "," + basedn; - this->ldap->Add(&this->orinterface, new_dn, attributes); - } - catch (const LDAPException &ex) + if (!na->nc->email.empty()) { - Log(this) << ex.GetReason(); + attributes[2].name = email_attribute; + attributes[2].values.push_back(na->nc->email); } + + attributes[3].name = this->password_attribute; + attributes[3].values.push_back(pass); + + Anope::string new_dn = username_attribute + "=" + na->nick + "," + basedn; + this->ldap->Add(&this->orinterface, new_dn, attributes); } }; -MODULE_INIT(NSIdentifyLDAP) +MODULE_INIT(ModuleLDAPAuthentication) diff --git a/modules/fantasy.cpp b/modules/fantasy.cpp index 58226699c..1bda6c106 100644 --- a/modules/fantasy.cpp +++ b/modules/fantasy.cpp @@ -103,12 +103,28 @@ class Fantasy : public Module std::vector<Anope::string> params; spacesepstream(msg).GetTokens(params); - if (!msg.find(c->ci->bi->nick)) + if (params.empty()) + return; + + Anope::string normalized_param0 = Anope::NormalizeBuffer(params[0]); + Anope::string fantasy_chars = Config->GetModule(this)->Get<Anope::string>("fantasycharacter", "!"); + + if (!normalized_param0.find(c->ci->bi->nick)) + { params.erase(params.begin()); - else if (!msg.find_first_of(Config->GetModule(this)->Get<const Anope::string>("fantasycharacter", "!"))) - params[0].erase(params[0].begin()); + } + else if (!normalized_param0.find_first_of(fantasy_chars)) + { + size_t sz = params[0].find_first_of(fantasy_chars); + if (sz == Anope::string::npos) + return; /* normalized_param0 is a subset of params[0] so this can't happen */ + + params[0].erase(0, sz + 1); + } else + { return; + } if (params.empty()) return; @@ -123,7 +139,7 @@ class Fantasy : public Module full_command.erase(full_command.begin()); ++count; - it = Config->Fantasy.find(full_command); + it = Config->Fantasy.find(Anope::NormalizeBuffer(full_command)); } if (it == Config->Fantasy.end()) diff --git a/modules/m_xmlrpc.cpp b/modules/m_xmlrpc.cpp index 2fd900e61..01300fbbb 100644 --- a/modules/m_xmlrpc.cpp +++ b/modules/m_xmlrpc.cpp @@ -179,10 +179,10 @@ class MyXMLRPCServiceInterface : public XMLRPCServiceInterface, public HTTPPage if (!request.id.empty()) request.reply("id", request.id); - Anope::string r = "<?xml version=\"1.0\" encoding=\"iso-8859-1\"?>\n<methodCall>\n<methodName>" + request.name + "</methodName>\n<params>\n<param>\n<value>\n<struct>\n"; + Anope::string r = "<?xml version=\"1.0\" encoding=\"iso-8859-1\"?>\n<methodResponse>\n<methodName>" + request.name + "</methodName>\n<params>\n<param>\n<value>\n<struct>\n"; for (std::map<Anope::string, Anope::string>::const_iterator it = request.get_replies().begin(); it != request.get_replies().end(); ++it) r += "<member>\n<name>" + it->first + "</name>\n<value>\n<string>" + this->Sanitize(it->second) + "</string>\n</value>\n</member>\n"; - r += "</struct>\n</value>\n</param>\n</params>\n</methodCall>"; + r += "</struct>\n</value>\n</param>\n</params>\n</methodResponse>"; request.r.Write(r); } diff --git a/modules/protocol/hybrid.cpp b/modules/protocol/hybrid.cpp index 5e4ce490e..150886232 100644 --- a/modules/protocol/hybrid.cpp +++ b/modules/protocol/hybrid.cpp @@ -1,7 +1,7 @@ /* ircd-hybrid-8 protocol module * * (C) 2003-2014 Anope Team - * (C) 2012-2014 ircd-hybrid development team + * (C) 2012-2015 ircd-hybrid development team * * Please read COPYING and README for further details. * @@ -36,7 +36,7 @@ class HybridProto : public IRCDProto } public: - HybridProto(Module *creator) : IRCDProto(creator, "Hybrid 8.1.x") + HybridProto(Module *creator) : IRCDProto(creator, "Hybrid 8.2.x") { DefaultPseudoclientModes = "+oi"; CanSVSNick = true; @@ -48,7 +48,7 @@ class HybridProto : public IRCDProto CanCertFP = true; CanSetVHost = true; RequiresID = true; - MaxModes = 4; + MaxModes = 6; } void SendInvite(const MessageSource &source, const Channel *c, User *u) anope_override @@ -204,7 +204,7 @@ class HybridProto : public IRCDProto SendServer(Me); - UplinkSocket::Message() << "SVINFO 6 5 0 :" << Anope::CurTime; + UplinkSocket::Message() << "SVINFO 6 6 0 :" << Anope::CurTime; } void SendClientIntroduction(User *u) anope_override @@ -212,7 +212,7 @@ class HybridProto : public IRCDProto Anope::string modes = "+" + u->GetModes(); UplinkSocket::Message(Me) << "UID " << u->nick << " 1 " << u->timestamp << " " << modes << " " - << u->GetIdent() << " " << u->host << " 0 " << u->GetUID() << " 0 :" << u->realname; + << u->GetIdent() << " " << u->host << " 0 " << u->GetUID() << " * :" << u->realname; } void SendEOB() anope_override @@ -232,7 +232,7 @@ class HybridProto : public IRCDProto void SendLogout(User *u) anope_override { - IRCD->SendMode(Config->GetClient("NickServ"), u, "+d 0"); + IRCD->SendMode(Config->GetClient("NickServ"), u, "+d *"); } void SendChannel(Channel *c) anope_override @@ -541,7 +541,7 @@ struct IRCDMessageUID : IRCDMessage IRCDMessageUID(Module *creator) : IRCDMessage(creator, "UID", 10) { SetFlag(IRCDMESSAGE_REQUIRE_SERVER); } /* 0 1 2 3 4 5 6 7 8 9 */ - /* :0MC UID Steve 1 1350157102 +oi ~steve resolved.host 10.0.0.1 0MCAAAAAB 1350157108 :Mining all the time */ + /* :0MC UID Steve 1 1350157102 +oi ~steve resolved.host 10.0.0.1 0MCAAAAAB Steve :Mining all the time */ void Run(MessageSource &source, const std::vector<Anope::string> ¶ms) anope_override { Anope::string ip = params[6]; @@ -550,7 +550,7 @@ struct IRCDMessageUID : IRCDMessage ip.clear(); NickAlias *na = NULL; - if (params[8] != "0") + if (params[8] != "0" && params[8] != "*") na = NickAlias::Find(params[8]); /* Source is always the server */ @@ -621,18 +621,21 @@ class ProtoHybrid : public Module { /* Add user modes */ ModeManager::AddUserMode(new UserModeOperOnly("ADMIN", 'a')); + ModeManager::AddUserMode(new UserMode("SOFTCALLERID", 'G')); ModeManager::AddUserMode(new UserModeOperOnly("CALLERID", 'g')); ModeManager::AddUserMode(new UserMode("INVIS", 'i')); ModeManager::AddUserMode(new UserModeOperOnly("LOCOPS", 'l')); ModeManager::AddUserMode(new UserModeOperOnly("OPER", 'o')); + ModeManager::AddUserMode(new UserMode("HIDECHANS", 'p')); + ModeManager::AddUserMode(new UserMode("HIDEIDLE", 'q')); ModeManager::AddUserMode(new UserModeNoone("REGISTERED", 'r')); ModeManager::AddUserMode(new UserModeOperOnly("SNOMASK", 's')); ModeManager::AddUserMode(new UserMode("WALLOPS", 'w')); - ModeManager::AddUserMode(new UserModeOperOnly("OPERWALLS", 'z')); ModeManager::AddUserMode(new UserMode("DEAF", 'D')); ModeManager::AddUserMode(new UserModeOperOnly("HIDEOPER", 'H')); ModeManager::AddUserMode(new UserMode("REGPRIV", 'R')); ModeManager::AddUserMode(new UserModeNoone("SSL", 'S')); + ModeManager::AddUserMode(new UserModeNoone("WEBIRC", 'W')); ModeManager::AddUserMode(new UserMode("CLOAK", 'x')); /* b/e/I */ diff --git a/modules/protocol/inspircd20.cpp b/modules/protocol/inspircd20.cpp index eb711e099..3d5d2a25f 100644 --- a/modules/protocol/inspircd20.cpp +++ b/modules/protocol/inspircd20.cpp @@ -789,9 +789,9 @@ struct IRCDMessageFHost : IRCDMessage void Run(MessageSource &source, const std::vector<Anope::string> ¶ms) anope_override { User *u = source.GetUser(); - u->SetDisplayedHost(params[0]); if (u->HasMode("CLOAK")) u->RemoveModeInternal(source, ModeManager::FindUserModeByName("CLOAK")); + u->SetDisplayedHost(params[0]); } }; diff --git a/modules/pseudoclients/operserv.cpp b/modules/pseudoclients/operserv.cpp index 67eaecd45..439c33708 100644 --- a/modules/pseudoclients/operserv.cpp +++ b/modules/pseudoclients/operserv.cpp @@ -117,13 +117,20 @@ class SQLineManager : public XLineManager for (std::vector<XLine *>::const_iterator it = this->GetList().begin(), it_end = this->GetList().end(); it != it_end; ++it) { XLine *x = *it; + if (x->regex) { if (x->regex->Matches(c->name)) return x; } - else if (Anope::Match(c->name, x->mask, false, true)) - return x; + else + { + if (x->mask.empty() || x->mask[0] != '#') + continue; + + if (Anope::Match(c->name, x->mask, false, true)) + return x; + } } return NULL; } |