diff options
Diffstat (limited to 'include/modules')
-rw-r--r-- | include/modules/account.h | 48 | ||||
-rw-r--r-- | include/modules/away.h | 83 | ||||
-rw-r--r-- | include/modules/cap.h | 335 | ||||
-rw-r--r-- | include/modules/dns.h | 204 | ||||
-rw-r--r-- | include/modules/exemption.h | 75 | ||||
-rw-r--r-- | include/modules/hash.h | 72 | ||||
-rw-r--r-- | include/modules/httpd.h | 262 | ||||
-rw-r--r-- | include/modules/invite.h | 128 | ||||
-rw-r--r-- | include/modules/ircv3.h | 101 | ||||
-rw-r--r-- | include/modules/ircv3_batch.h | 185 | ||||
-rw-r--r-- | include/modules/ircv3_servertime.h | 88 | ||||
-rw-r--r-- | include/modules/ldap.h | 192 | ||||
-rw-r--r-- | include/modules/regex.h | 62 | ||||
-rw-r--r-- | include/modules/reload.h | 80 | ||||
-rw-r--r-- | include/modules/sasl.h | 33 | ||||
-rw-r--r-- | include/modules/server.h | 61 | ||||
-rw-r--r-- | include/modules/shun.h | 70 | ||||
-rw-r--r-- | include/modules/sql.h | 267 | ||||
-rw-r--r-- | include/modules/ssl.h | 305 | ||||
-rw-r--r-- | include/modules/stats.h | 191 | ||||
-rw-r--r-- | include/modules/whois.h | 146 |
21 files changed, 2988 insertions, 0 deletions
diff --git a/include/modules/account.h b/include/modules/account.h new file mode 100644 index 000000000..0368127a6 --- /dev/null +++ b/include/modules/account.h @@ -0,0 +1,48 @@ +/* + * InspIRCd -- Internet Relay Chat Daemon + * + * Copyright (C) 2008 Craig Edwards <craigedwards@brainbox.cc> + * + * This file is part of InspIRCd. InspIRCd is free software: you can + * redistribute it and/or modify it under the terms of the GNU General Public + * License as published by the Free Software Foundation, version 2. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + + +#pragma once + +#include <map> +#include <string> + +#include "event.h" + +typedef StringExtItem AccountExtItem; + +inline AccountExtItem* GetAccountExtItem() +{ + return static_cast<AccountExtItem*>(ServerInstance->Extensions.GetItem("accountname")); +} + +class AccountEventListener : public Events::ModuleEventListener +{ + public: + AccountEventListener(Module* mod) + : ModuleEventListener(mod, "event/account") + { + } + + /** Called when a user logs in or logs out + * @param user User logging in or out + * @param newaccount New account name of the user or empty string if the user + * logged out + */ + virtual void OnAccountChange(User* user, const std::string& newaccount) = 0; +}; diff --git a/include/modules/away.h b/include/modules/away.h new file mode 100644 index 000000000..f231f0a06 --- /dev/null +++ b/include/modules/away.h @@ -0,0 +1,83 @@ +/* + * InspIRCd -- Internet Relay Chat Daemon + * + * Copyright (C) 2016-2017 Peter Powell <petpow@saberuk.com> + * + * This file is part of InspIRCd. InspIRCd is free software: you can + * redistribute it and/or modify it under the terms of the GNU General Public + * License as published by the Free Software Foundation, version 2. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + + +#pragma once + +#include "event.h" + +namespace Away +{ + class EventListener; + class EventProvider; +} + +class Away::EventListener + : public Events::ModuleEventListener +{ + protected: + EventListener(Module* mod) + : ModuleEventListener(mod, "event/away") + { + } + + public: + /** Called when a user wishes to mark themselves as away. + * @param user The user who is going away. + * @param message The away message that the user set. + * @return Either MOD_RES_ALLOW to allow the user to mark themself as away, MOD_RES_DENY to + * disallow the user to mark themself as away, or MOD_RES_PASSTHRU to let another module + * handle the event. + */ + virtual ModResult OnUserPreAway(LocalUser* user, std::string& message) + { + return MOD_RES_PASSTHRU; + } + + /** Called when a user wishes to mark themselves as back. + * @param user The user who is going away. + * @param message The away message that the user set. + * @return Either MOD_RES_ALLOW to allow the user to mark themself as back, MOD_RES_DENY to + * disallow the user to mark themself as back, or MOD_RES_PASSTHRU to let another module + * handle the event. + */ + virtual ModResult OnUserPreBack(LocalUser* user) + { + return MOD_RES_PASSTHRU; + } + + /** Called when a user has marked themself as away. + * @param user The user who has gone away. + */ + virtual void OnUserAway(User* user) = 0; + + /** Called when a user has returned from being away. + * @param user The user who has returned from being away. + */ + virtual void OnUserBack(User* user) = 0; +}; + +class Away::EventProvider + : public Events::ModuleEventProvider +{ + public: + EventProvider(Module* mod) + : ModuleEventProvider(mod, "event/away") + { + } +}; diff --git a/include/modules/cap.h b/include/modules/cap.h new file mode 100644 index 000000000..6dcb9f3bc --- /dev/null +++ b/include/modules/cap.h @@ -0,0 +1,335 @@ +/* + * InspIRCd -- Internet Relay Chat Daemon + * + * Copyright (C) 2015 Attila Molnar <attilamolnar@hush.com> + * + * This file is part of InspIRCd. InspIRCd is free software: you can + * redistribute it and/or modify it under the terms of the GNU General Public + * License as published by the Free Software Foundation, version 2. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + + +#pragma once + +#include "event.h" + +namespace Cap +{ + static const unsigned int MAX_CAPS = (sizeof(intptr_t) * 8) - 1; + static const intptr_t CAP_302_BIT = (intptr_t)1 << MAX_CAPS; + static const unsigned int MAX_VALUE_LENGTH = 100; + + typedef intptr_t Ext; + class ExtItem : public LocalIntExt + { + public: + ExtItem(Module* mod); + std::string serialize(SerializeFormat format, const Extensible* container, void* item) const CXX11_OVERRIDE; + void unserialize(SerializeFormat format, Extensible* container, const std::string& value) CXX11_OVERRIDE; + }; + + class Capability; + + enum Protocol + { + /** Supports capability negotiation protocol v3.1, or none + */ + CAP_LEGACY, + + /** Supports capability negotiation v3.2 + */ + CAP_302 + }; + + class EventListener : public Events::ModuleEventListener + { + public: + EventListener(Module* mod) + : ModuleEventListener(mod, "event/cap") + { + } + + /** Called whenever a new client capability becomes available or unavailable + * @param cap Capability being added or removed + * @param add If true, the capability is being added, otherwise its being removed + */ + virtual void OnCapAddDel(Capability* cap, bool add) = 0; + + /** Called whenever the value of a cap changes. + * @param cap Capability whose value changed + */ + virtual void OnCapValueChange(Capability* cap) { } + }; + + class Manager : public DataProvider + { + public: + Manager(Module* mod) + : DataProvider(mod, "capmanager") + { + } + + /** Register a client capability. + * Modules should call Capability::SetActive(true) instead of this method. + * @param cap Capability to register + */ + virtual void AddCap(Capability* cap) = 0; + + /** Unregister a client capability. + * Modules should call Capability::SetActive(false) instead of this method. + * @param cap Capability to unregister + */ + virtual void DelCap(Capability* cap) = 0; + + /** Find a capability by name + * @param name Capability to find + * @return Capability object pointer if found, NULL otherwise + */ + virtual Capability* Find(const std::string& name) const = 0; + + /** Notify manager when a value of a cap changed + * @param cap Cap whose value changed + */ + virtual void NotifyValueChange(Capability* cap) = 0; + }; + + /** Represents a client capability. + * + * Capabilities offer extensions to the client to server protocol. They must be negotiated with clients before they have any effect on the protocol. + * Each cap must have a unique name that is used during capability negotiation. + * + * After construction the cap is ready to be used by clients without any further setup, like other InspIRCd services. + * The get() method accepts a user as parameter and can be used to check whether that user has negotiated usage of the cap. This is only known for local users. + * + * The cap module must be loaded for the capability to work. The IsRegistered() method can be used to query whether the cap is actually online or not. + * The capability can be deactivated and reactivated with the SetActive() method. Deactivated caps behave as if they don't exist. + * + * It is possible to implement special behavior by inheriting from this class and overriding some of its methods. + */ + class Capability : public ServiceProvider, private dynamic_reference_base::CaptureHook + { + typedef size_t Bit; + + /** Bit allocated to this cap, undefined if the cap is unregistered + */ + Bit bit; + + /** Extension containing all caps set by a user. NULL if the cap is unregistered. + */ + ExtItem* extitem; + + /** True if the cap is active. Only active caps are registered in the manager. + */ + bool active; + + /** Reference to the cap manager object + */ + dynamic_reference<Manager> manager; + + void OnCapture() CXX11_OVERRIDE + { + if (active) + SetActive(true); + } + + void Unregister() + { + bit = 0; + extitem = NULL; + } + + Ext AddToMask(Ext mask) const { return (mask | GetMask()); } + Ext DelFromMask(Ext mask) const { return (mask & (~GetMask())); } + Bit GetMask() const { return bit; } + + friend class ManagerImpl; + + protected: + /** Notify the manager that the value of the capability changed. + * Must be called if the value of the cap changes for any reason. + */ + void NotifyValueChange() + { + if (IsRegistered()) + manager->NotifyValueChange(this); + } + + public: + /** Constructor, initializes the capability. + * Caps are active by default. + * @param mod Module providing the cap + * @param Name Raw name of the cap as used in the protocol (CAP LS, etc.) + */ + Capability(Module* mod, const std::string& Name) + : ServiceProvider(mod, Name, SERVICE_CUSTOM) + , active(true) + , manager(mod, "capmanager") + { + Unregister(); + } + + ~Capability() + { + SetActive(false); + } + + void RegisterService() CXX11_OVERRIDE + { + manager.SetCaptureHook(this); + SetActive(true); + } + + /** Check whether a user has the capability turned on. + * This method is safe to call if the cap is unregistered and will return false. + * @param user User to check + * @return True if the user is using this capability, false otherwise + */ + bool get(User* user) const + { + if (!IsRegistered()) + return false; + Ext caps = extitem->get(user); + return ((caps & GetMask()) != 0); + } + + /** Turn the capability on/off for a user. If the cap is not registered this method has no effect. + * @param user User to turn the cap on/off for + * @param val True to turn the cap on, false to turn it off + */ + void set(User* user, bool val) + { + if (!IsRegistered()) + return; + Ext curr = extitem->get(user); + extitem->set(user, (val ? AddToMask(curr) : DelFromMask(curr))); + } + + /** Activate or deactivate the capability. + * If activating, the cap is marked as active and if the manager is available the cap is registered in the manager. + * If deactivating, the cap is marked as inactive and if it is registered, it will be unregistered. + * Users who had the cap turned on will have it turned off automatically. + * @param activate True to activate the cap, false to deactivate it + */ + void SetActive(bool activate) + { + active = activate; + if (manager) + { + if (activate) + manager->AddCap(this); + else + manager->DelCap(this); + } + } + + /** Get the name of the capability that's used in the protocol + * @return Name of the capability as used in the protocol + */ + const std::string& GetName() const { return name; } + + /** Check whether the capability is active. The cap must be active and registered to be used by users. + * @return True if the cap is active, false if it has been deactivated + */ + bool IsActive() const { return active; } + + /** Check whether the capability is registered + * The cap must be active and the manager must be available for a cap to be registered. + * @return True if the cap is registered in the manager, false otherwise + */ + bool IsRegistered() const { return (extitem != NULL); } + + /** Get the CAP negotiation protocol version of a user. + * The cap must be registered for this to return anything other than CAP_LEGACY. + * @param user User whose negotiation protocol version to query + * @return One of the Capability::Protocol enum indicating the highest supported capability negotiation protocol version + */ + Protocol GetProtocol(LocalUser* user) const + { + return ((IsRegistered() && (extitem->get(user) & CAP_302_BIT)) ? CAP_302 : CAP_LEGACY); + } + + /** Called when a user requests to turn this capability on or off. + * @param user User requesting to change the state of the cap + * @param add True if requesting to turn the cap on, false if requesting to turn it off + * @return True to allow the request, false to reject it + */ + virtual bool OnRequest(LocalUser* user, bool add) + { + return true; + } + + /** Called when a user requests a list of all capabilities and this capability is about to be included in the list. + * The default behavior always includes the cap in the list. + * @param user User querying a list capabilities + * @return True to add this cap to the list sent to the user, false to not list it + */ + virtual bool OnList(LocalUser* user) + { + return true; + } + + /** Query the value of this capability for a user + * @param user User who will get the value of the capability + * @return Value to show to the user. If NULL, the capability has no value (default). + */ + virtual const std::string* GetValue(LocalUser* user) const + { + return NULL; + } + }; + + /** Reference to a cap. The cap may be provided by another module. + */ + class Reference + { + dynamic_reference_nocheck<Capability> ref; + + public: + /** Constructor, initializes the capability reference + * @param mod Module creating this object + * @param Name Raw name of the cap as used in the protocol (CAP LS, etc.) + */ + Reference(Module* mod, const std::string& Name) + : ref(mod, "cap/" + Name) + { + } + + /** Check whether a user has the referenced capability turned on. + * @param user User to check + * @return True if the user is using the referenced capability, false otherwise + */ + bool get(LocalUser* user) + { + if (ref) + return ref->get(user); + return false; + } + }; + + class MessageBase : public ClientProtocol::Message + { + public: + MessageBase(const std::string& subcmd) + : ClientProtocol::Message("CAP", ServerInstance->Config->ServerName) + { + PushParamPlaceholder(); + PushParam(subcmd); + } + + void SetUser(LocalUser* user) + { + if (user->registered & REG_NICK) + ReplaceParamRef(0, user->nick); + else + ReplaceParam(0, "*"); + } + }; +} diff --git a/include/modules/dns.h b/include/modules/dns.h new file mode 100644 index 000000000..3db651798 --- /dev/null +++ b/include/modules/dns.h @@ -0,0 +1,204 @@ +/* + * InspIRCd -- Internet Relay Chat Daemon + * + * Copyright (C) 2013 Adam <Adam@anope.org> + * Copyright (C) 2003-2013 Anope Team <team@anope.org> + * + * This file is part of InspIRCd. InspIRCd is free software: you can + * redistribute it and/or modify it under the terms of the GNU General Public + * License as published by the Free Software Foundation, version 2. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#pragma once + +namespace DNS +{ + /** Valid query types + */ + enum QueryType + { + /* Nothing */ + QUERY_NONE, + /* A simple A lookup */ + QUERY_A = 1, + /* A CNAME lookup */ + QUERY_CNAME = 5, + /* Reverse DNS lookup */ + QUERY_PTR = 12, + /* TXT */ + QUERY_TXT = 16, + /* IPv6 AAAA lookup */ + QUERY_AAAA = 28 + }; + + /** Flags that can be AND'd into DNSPacket::flags to receive certain values + */ + enum + { + QUERYFLAGS_QR = 0x8000, + QUERYFLAGS_OPCODE = 0x7800, + QUERYFLAGS_AA = 0x400, + QUERYFLAGS_TC = 0x200, + QUERYFLAGS_RD = 0x100, + QUERYFLAGS_RA = 0x80, + QUERYFLAGS_Z = 0x70, + QUERYFLAGS_RCODE = 0xF + }; + + enum Error + { + ERROR_NONE, + ERROR_UNKNOWN, + ERROR_UNLOADED, + ERROR_TIMEDOUT, + ERROR_MALFORMED, + ERROR_NOT_AN_ANSWER, + ERROR_NONSTANDARD_QUERY, + ERROR_FORMAT_ERROR, + ERROR_SERVER_FAILURE, + ERROR_DOMAIN_NOT_FOUND, + ERROR_NOT_IMPLEMENTED, + ERROR_REFUSED, + ERROR_NO_RECORDS, + ERROR_INVALIDTYPE + }; + + typedef uint16_t RequestId; + + const int PORT = 53; + + class Exception : public ModuleException + { + public: + Exception(const std::string& message) : ModuleException(message) { } + }; + + struct Question + { + std::string name; + QueryType type; + + Question() : type(QUERY_NONE) { } + Question(const std::string& n, QueryType t) : name(n), type(t) { } + bool operator==(const Question& other) const { return ((name == other.name) && (type == other.type)); } + bool operator!=(const Question& other) const { return (!(*this == other)); } + + struct hash + { + size_t operator()(const Question& question) const + { + return irc::insensitive()(question.name); + } + }; + }; + + struct ResourceRecord : Question + { + unsigned int ttl; + std::string rdata; + time_t created; + + ResourceRecord(const std::string& n, QueryType t) : Question(n, t), ttl(0), created(ServerInstance->Time()) { } + ResourceRecord(const Question& question) : Question(question), ttl(0), created(ServerInstance->Time()) { } + }; + + struct Query + { + Question question; + std::vector<ResourceRecord> answers; + Error error; + bool cached; + + Query() : error(ERROR_NONE), cached(false) { } + Query(const Question& q) : question(q), error(ERROR_NONE), cached(false) { } + + const ResourceRecord* FindAnswerOfType(QueryType qtype) const + { + for (std::vector<DNS::ResourceRecord>::const_iterator i = answers.begin(); i != answers.end(); ++i) + { + const DNS::ResourceRecord& rr = *i; + if (rr.type == qtype) + return &rr; + } + + return NULL; + } + }; + + class ReplySocket; + class Request; + + /** DNS manager + */ + class Manager : public DataProvider + { + public: + Manager(Module* mod) : DataProvider(mod, "DNS") { } + + virtual void Process(Request* req) = 0; + virtual void RemoveRequest(Request* req) = 0; + virtual std::string GetErrorStr(Error) = 0; + }; + + /** A DNS query. + */ + class Request : public Timer + { + protected: + Manager* const manager; + public: + Question question; + /* Use result cache if available */ + bool use_cache; + /* Request id */ + RequestId id; + /* Creator of this request */ + Module* const creator; + + Request(Manager* mgr, Module* mod, const std::string& addr, QueryType qt, bool usecache = true) + : Timer(ServerInstance->Config->ConfValue("dns")->getDuration("timeout", 5, 1)) + , manager(mgr) + , question(addr, qt) + , use_cache(usecache) + , id(0) + , creator(mod) + { + } + + virtual ~Request() + { + manager->RemoveRequest(this); + } + + /** Called when this request succeeds + * @param r The query sent back from the nameserver + */ + virtual void OnLookupComplete(const Query* req) = 0; + + /** Called when this request fails or times out. + * @param r The query sent back from the nameserver, check the error code. + */ + virtual void OnError(const Query* req) { } + + /** Used to time out the query, calls OnError and asks the TimerManager + * to delete this request + */ + bool Tick(time_t now) CXX11_OVERRIDE + { + Query rr(this->question); + rr.error = ERROR_TIMEDOUT; + this->OnError(&rr); + delete this; + return false; + } + }; + +} // namespace DNS diff --git a/include/modules/exemption.h b/include/modules/exemption.h new file mode 100644 index 000000000..b590a5797 --- /dev/null +++ b/include/modules/exemption.h @@ -0,0 +1,75 @@ +/* + * InspIRCd -- Internet Relay Chat Daemon + * + * Copyright (C) 2016-2017 Peter Powell <petpow@saberuk.com> + * + * This file is part of InspIRCd. InspIRCd is free software: you can + * redistribute it and/or modify it under the terms of the GNU General Public + * License as published by the Free Software Foundation, version 2. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + + +#pragma once + +#include "event.h" + +namespace CheckExemption +{ + class EventListener; + class EventProvider; + + /** Helper function for calling the CheckExemption::EventListener::OnCheckExemption event. + * @param prov The CheckExemption::EventProvider which is calling the event. + * @param user The user to check exemption for. + * @param chan The channel to check exemption on. + * @param restriction The restriction to check for. + * @return Either MOD_RES_ALLOW if the exemption was confirmed, MOD_RES_DENY if the exemption was + * denied or MOD_RES_PASSTHRU if no module handled the event. + */ + inline ModResult Call(const CheckExemption::EventProvider& prov, User* user, Channel* chan, const std::string& restriction); +} + +class CheckExemption::EventListener + : public Events::ModuleEventListener +{ + protected: + EventListener(Module* mod) + : ModuleEventListener(mod, "event/exemption") + { + } + + public: + /** Called when checking if a user is exempt from something. + * @param user The user to check exemption for. + * @param chan The channel to check exemption on. + * @param restriction The restriction to check for. + * @return Either MOD_RES_ALLOW to confirm an exemption, MOD_RES_DENY to deny an exemption, + * or MOD_RES_PASSTHRU to let another module handle the event. + */ + virtual ModResult OnCheckExemption(User* user, Channel* chan, const std::string& restriction) = 0; +}; + +class CheckExemption::EventProvider + : public Events::ModuleEventProvider +{ + public: + EventProvider(Module* mod) + : ModuleEventProvider(mod, "event/exemption") + { + } +}; + +inline ModResult CheckExemption::Call(const CheckExemption::EventProvider& prov, User* user, Channel* chan, const std::string& restriction) +{ + ModResult result; + FIRST_MOD_RESULT_CUSTOM(prov, CheckExemption::EventListener, OnCheckExemption, result, (user, chan, restriction)); + return result; +} diff --git a/include/modules/hash.h b/include/modules/hash.h new file mode 100644 index 000000000..7d46ee74a --- /dev/null +++ b/include/modules/hash.h @@ -0,0 +1,72 @@ +/* + * InspIRCd -- Internet Relay Chat Daemon + * + * Copyright (C) 2010 Daniel De Graaf <danieldg@inspircd.org> + * + * This file is part of InspIRCd. InspIRCd is free software: you can + * redistribute it and/or modify it under the terms of the GNU General Public + * License as published by the Free Software Foundation, version 2. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + + +#pragma once + +#include "modules.h" + +class HashProvider : public DataProvider +{ + public: + const unsigned int out_size; + const unsigned int block_size; + HashProvider(Module* mod, const std::string& Name, unsigned int osiz = 0, unsigned int bsiz = 0) + : DataProvider(mod, "hash/" + Name), out_size(osiz), block_size(bsiz) + { + } + + virtual std::string GenerateRaw(const std::string& data) = 0; + + virtual std::string ToPrintable(const std::string& raw) + { + return BinToHex(raw); + } + + virtual bool Compare(const std::string& input, const std::string& hash) + { + return InspIRCd::TimingSafeCompare(Generate(input), hash); + } + + std::string Generate(const std::string& data) + { + return ToPrintable(GenerateRaw(data)); + } + + /** HMAC algorithm, RFC 2104 */ + std::string hmac(const std::string& key, const std::string& msg) + { + std::string hmac1, hmac2; + std::string kbuf = key.length() > block_size ? GenerateRaw(key) : key; + kbuf.resize(block_size); + + for (size_t n = 0; n < block_size; n++) + { + hmac1.push_back(static_cast<char>(kbuf[n] ^ 0x5C)); + hmac2.push_back(static_cast<char>(kbuf[n] ^ 0x36)); + } + hmac2.append(msg); + hmac1.append(GenerateRaw(hmac2)); + return GenerateRaw(hmac1); + } + + bool IsKDF() const + { + return (!block_size); + } +}; diff --git a/include/modules/httpd.h b/include/modules/httpd.h new file mode 100644 index 000000000..b4b88bed5 --- /dev/null +++ b/include/modules/httpd.h @@ -0,0 +1,262 @@ +/* + * InspIRCd -- Internet Relay Chat Daemon + * + * Copyright (C) 2009 Daniel De Graaf <danieldg@inspircd.org> + * Copyright (C) 2008 Pippijn van Steenhoven <pip88nl@gmail.com> + * Copyright (C) 2007 John Brooks <john.brooks@dereferenced.net> + * Copyright (C) 2007 Dennis Friis <peavey@inspircd.org> + * Copyright (C) 2006 Craig Edwards <craigedwards@brainbox.cc> + * + * This file is part of InspIRCd. InspIRCd is free software: you can + * redistribute it and/or modify it under the terms of the GNU General Public + * License as published by the Free Software Foundation, version 2. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + + +#pragma once + +#include "base.h" +#include "event.h" + +#include <string> +#include <sstream> +#include <map> + +/** A modifyable list of HTTP header fields + */ +class HTTPHeaders +{ + protected: + std::map<std::string,std::string> headers; + public: + + /** Set the value of a header + * Sets the value of the named header. If the header is already present, it will be replaced + */ + void SetHeader(const std::string &name, const std::string &data) + { + headers[name] = data; + } + + /** Set the value of a header, only if it doesn't exist already + * Sets the value of the named header. If the header is already present, it will NOT be updated + */ + void CreateHeader(const std::string &name, const std::string &data) + { + if (!IsSet(name)) + SetHeader(name, data); + } + + /** Remove the named header + */ + void RemoveHeader(const std::string &name) + { + headers.erase(name); + } + + /** Remove all headers + */ + void Clear() + { + headers.clear(); + } + + /** Get the value of a header + * @return The value of the header, or an empty string + */ + std::string GetHeader(const std::string &name) + { + std::map<std::string,std::string>::iterator it = headers.find(name); + if (it == headers.end()) + return std::string(); + + return it->second; + } + + /** Check if the given header is specified + * @return true if the header is specified + */ + bool IsSet(const std::string &name) + { + std::map<std::string,std::string>::iterator it = headers.find(name); + return (it != headers.end()); + } + + /** Get all headers, formatted by the HTTP protocol + * @return Returns all headers, formatted according to the HTTP protocol. There is no request terminator at the end + */ + std::string GetFormattedHeaders() + { + std::string re; + + for (std::map<std::string,std::string>::iterator i = headers.begin(); i != headers.end(); i++) + re += i->first + ": " + i->second + "\r\n"; + + return re; + } +}; + +class HttpServerSocket; + +/** This class represents a HTTP request. + */ +class HTTPRequest +{ + protected: + std::string type; + std::string document; + std::string ipaddr; + std::string postdata; + + public: + + HTTPHeaders *headers; + int errorcode; + + /** A socket pointer, which you must return in your HTTPDocument class + * if you reply to this request. + */ + HttpServerSocket* sock; + + /** Initialize HTTPRequest. + * This constructor is called by m_httpd.so to initialize the class. + * @param request_type The request type, e.g. GET, POST, HEAD + * @param uri The URI, e.g. /page + * @param hdr The headers sent with the request + * @param opaque An opaque pointer used internally by m_httpd, which you must pass back to the module in your reply. + * @param ip The IP address making the web request. + * @param pdata The post data (content after headers) received with the request, up to Content-Length in size + */ + HTTPRequest(const std::string& request_type, const std::string& uri, + HTTPHeaders* hdr, HttpServerSocket* socket, const std::string &ip, const std::string &pdata) + : type(request_type), document(uri), ipaddr(ip), postdata(pdata), headers(hdr), sock(socket) + { + } + + /** Get the post data (request content). + * All post data will be returned, including carriage returns and linefeeds. + * @return The postdata + */ + std::string& GetPostData() + { + return postdata; + } + + /** Get the request type. + * Any request type can be intercepted, even ones which are invalid in the HTTP/1.1 spec. + * @return The request type, e.g. GET, POST, HEAD + */ + std::string& GetType() + { + return type; + } + + /** Get URI. + * The URI string (URL minus hostname and scheme) will be provided by this function. + * @return The URI being requested + */ + std::string& GetURI() + { + return document; + } + + /** Get IP address of requester. + * The requesting system's ip address will be returned. + * @return The IP address as a string + */ + std::string& GetIP() + { + return ipaddr; + } +}; + +/** If you want to reply to HTTP requests, you must return a HTTPDocumentResponse to + * the httpd module via the HTTPdAPI. + * When you initialize this class you initialize it with all components required to + * form a valid HTTP response: the document data and a response code. + * You can add additional HTTP headers, if you want. + */ +class HTTPDocumentResponse +{ + public: + /** Module that generated this reply + */ + Module* const module; + + std::stringstream* document; + unsigned int responsecode; + + /** Any extra headers to include with the defaults + */ + HTTPHeaders headers; + + HTTPRequest& src; + + /** Initialize a HTTPDocumentResponse ready for sending to the httpd module. + * @param mod A pointer to the module who responded to the request + * @param req The request you obtained from the HTTPRequest at an earlier time + * @param doc A stringstream containing the document body + * @param response A valid HTTP/1.0 or HTTP/1.1 response code. The response text will be determined for you + * based upon the response code. + */ + HTTPDocumentResponse(Module* mod, HTTPRequest& req, std::stringstream* doc, unsigned int response) + : module(mod), document(doc), responsecode(response), src(req) + { + } +}; + +class HTTPdAPIBase : public DataProvider +{ + public: + HTTPdAPIBase(Module* parent) + : DataProvider(parent, "m_httpd_api") + { + } + + /** Answer an incoming HTTP request with the provided document + * @param response The response created by your module that will be sent to the client + */ + virtual void SendResponse(HTTPDocumentResponse& response) = 0; +}; + +/** The API provided by the httpd module that allows other modules to respond to incoming + * HTTP requests + */ +class HTTPdAPI : public dynamic_reference<HTTPdAPIBase> +{ + public: + HTTPdAPI(Module* parent) + : dynamic_reference<HTTPdAPIBase>(parent, "m_httpd_api") + { + } +}; + +class HTTPACLEventListener : public Events::ModuleEventListener +{ + public: + HTTPACLEventListener(Module* mod) + : ModuleEventListener(mod, "event/http-acl") + { + } + + virtual ModResult OnHTTPACLCheck(HTTPRequest& req) = 0; +}; + +class HTTPRequestEventListener : public Events::ModuleEventListener +{ + public: + HTTPRequestEventListener(Module* mod) + : ModuleEventListener(mod, "event/http-request") + { + } + + virtual ModResult OnHTTPRequest(HTTPRequest& req) = 0; +}; diff --git a/include/modules/invite.h b/include/modules/invite.h new file mode 100644 index 000000000..e53d5202f --- /dev/null +++ b/include/modules/invite.h @@ -0,0 +1,128 @@ +/* + * InspIRCd -- Internet Relay Chat Daemon + * + * Copyright (C) 2012, 2015 Attila Molnar <attilamolnar@hush.com> + * + * This file is part of InspIRCd. InspIRCd is free software: you can + * redistribute it and/or modify it under the terms of the GNU General Public + * License as published by the Free Software Foundation, version 2. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + + +#pragma once + +namespace Invite +{ + class APIBase; + class API; + class Invite; + + typedef insp::intrusive_list<Invite, LocalUser> List; +} + +class Invite::APIBase : public DataProvider +{ + public: + APIBase(Module* parent); + + /** Create or extend an Invite. + * When a user is invited to join a channel either a new Invite object is created or + * or the expiration timestamp is updated if there is already a pending Invite for + * the given (user, channel) pair and the new expiration time is further than the current. + * @param user Target user + * @param chan Target channel + * @param timeout Timestamp when the invite should expire, 0 for no expiration + */ + virtual void Create(LocalUser* user, Channel* chan, time_t timeout) = 0; + + /** Retrieves the Invite object for the given (user, channel) pair + * @param user Target user + * @param chan Target channel + * @return Invite object for the given (channel, user) pair if it exists, NULL otherwise + */ + virtual Invite* Find(LocalUser* user, Channel* chan) = 0; + + /** Returns the list of channels a user has been invited to but has not yet joined. + * @param user User whose invite list to retrieve + * @return List of channels the user is invited to or NULL if the list is empty + */ + virtual const List* GetList(LocalUser* user) = 0; + + /** Check if a user is invited to a channel + * @param user User to check + * @param chan Channel to check + * @return True if the user is invited to the channel, false otherwise + */ + bool IsInvited(LocalUser* user, Channel* chan) { return (Find(user, chan) != NULL); } + + /** Removes an Invite if it exists + * @param user User whose invite to remove + * @param chan Channel to remove the invite to + * @return True if the user was invited to the channel and the invite was removed, false if the user wasn't invited + */ + virtual bool Remove(LocalUser* user, Channel* chan) = 0; +}; + +class Invite::API : public dynamic_reference<APIBase> +{ + public: + API(Module* parent) + : dynamic_reference<APIBase>(parent, "core_channel_invite") + { + } +}; + +/** + * The Invite class contains all data about a pending invite. + * Invite objects are referenced from the user and the channel they belong to. + */ +class Invite::Invite : public insp::intrusive_list_node<Invite, LocalUser>, public insp::intrusive_list_node<Invite, Channel> +{ + public: + /** User the invite is for + */ + LocalUser* const user; + + /** Channel where the user is invited to + */ + Channel* const chan; + + /** Check whether the invite will expire or not + * @return True if the invite is timed, false if it doesn't expire + */ + bool IsTimed() const { return (expiretimer != NULL); } + + /** Serialize this object + * @param format Serialization format + * @param show_chans True to include channel in the output, false to include the nick/uuid + * @param out Output will be appended to this string + */ + void Serialize(SerializeFormat format, bool show_chans, std::string& out); + + friend class APIImpl; + + private: + /** Timer handling expiration. If NULL this invite doesn't expire. + */ + Timer* expiretimer; + + /** Constructor, only available to the module providing the invite API (core_channel). + * To create Invites use InviteAPI::Create(). + * @param user User being invited + * @param chan Channel the user is invited to + */ + Invite(LocalUser* user, Channel* chan); + + /** Destructor, only available to the module providing the invite API (core_channel). + * To remove Invites use InviteAPI::Remove(). + */ + ~Invite(); +}; diff --git a/include/modules/ircv3.h b/include/modules/ircv3.h new file mode 100644 index 000000000..338abdeba --- /dev/null +++ b/include/modules/ircv3.h @@ -0,0 +1,101 @@ +/* + * InspIRCd -- Internet Relay Chat Daemon + * + * Copyright (C) 2015 Attila Molnar <attilamolnar@hush.com> + * + * This file is part of InspIRCd. InspIRCd is free software: you can + * redistribute it and/or modify it under the terms of the GNU General Public + * License as published by the Free Software Foundation, version 2. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + + +#pragma once + +#include "modules/cap.h" + +namespace IRCv3 +{ + class WriteNeighborsWithCap; + template <typename T> + class CapTag; +} + +class IRCv3::WriteNeighborsWithCap : public User::ForEachNeighborHandler +{ + const Cap::Capability& cap; + ClientProtocol::Event& protoev; + + void Execute(LocalUser* user) CXX11_OVERRIDE + { + if (cap.get(user)) + user->Send(protoev); + } + + public: + WriteNeighborsWithCap(User* user, ClientProtocol::Event& ev, const Cap::Capability& capability) + : cap(capability) + , protoev(ev) + { + user->ForEachNeighbor(*this, false); + } +}; + +/** Base class for simple message tags. + * Message tags provided by classes derived from this class will be sent to clients that have negotiated + * a client capability, also managed by this class. + * + * Derived classes specify the name of the capability and the message tag and provide a public GetValue() + * method with the following signature: const std::string* GetValue(ClientProtocol::Message& msg). + * The returned value determines whether to attach the tag to the message. If it is NULL, the tag won't + * be attached. If it is non-NULL the tag will be attached with the value in the string. If the string is + * empty the tag is attached without a value. + * + * Providers inheriting from this class don't accept incoming tags by default. + * + * For more control, inherit from ClientProtocol::MessageTagProvider directly. + * + * Template parameter T is the derived class. + */ +template <typename T> +class IRCv3::CapTag : public ClientProtocol::MessageTagProvider +{ + Cap::Capability cap; + const std::string tagname; + + bool ShouldSendTag(LocalUser* user, const ClientProtocol::MessageTagData& tagdata) CXX11_OVERRIDE + { + return cap.get(user); + } + + void OnClientProtocolPopulateTags(ClientProtocol::Message& msg) CXX11_OVERRIDE + { + T& tag = static_cast<T&>(*this); + const std::string* const val = tag.GetValue(msg); + if (val) + msg.AddTag(tagname, this, *val); + } + + public: + /** Constructor. + * @param mod Module that owns the tag. + * @param capname Name of the client capability. + * A client capability with this name will be created. It will be available to all clients and it won't + * have a value. + * See Cap::Capability for more info on client capabilities. + * @param Tagname Name of the message tag, to use in the protocol. + */ + CapTag(Module* mod, const std::string& capname, const std::string& Tagname) + : ClientProtocol::MessageTagProvider(mod) + , cap(mod, capname) + , tagname(Tagname) + { + } +}; diff --git a/include/modules/ircv3_batch.h b/include/modules/ircv3_batch.h new file mode 100644 index 000000000..841554bdb --- /dev/null +++ b/include/modules/ircv3_batch.h @@ -0,0 +1,185 @@ +/* + * InspIRCd -- Internet Relay Chat Daemon + * + * Copyright (C) 2016 Attila Molnar <attilamolnar@hush.com> + * + * This file is part of InspIRCd. InspIRCd is free software: you can + * redistribute it and/or modify it under the terms of the GNU General Public + * License as published by the Free Software Foundation, version 2. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + + +#pragma once + +// For CapReference +#include "modules/cap.h" + +namespace IRCv3 +{ + namespace Batch + { + typedef uint64_t RefTag; + class Manager; + class ManagerImpl; + class Batch; + struct BatchInfo; + class API; + class CapReference; + + static const unsigned int MAX_BATCHES = (sizeof(intptr_t) * 8) - 1; + } +} + +/** Batch Manager. + * Implements batch starting and stopping. When it becomes unavailable (due to e.g. module unload) + * all running batches are stopped. + */ +class IRCv3::Batch::Manager : public DataProvider, public ClientProtocol::MessageTagProvider +{ + public: + /** Constructor. + * @param mod Module that owns the Manager. + */ + Manager(Module* mod) + : DataProvider(mod, "batchapi") + , ClientProtocol::MessageTagProvider(mod) + { + } + + /** Start a batch. + * Check Batch::IsRunning() to learn if the batch has been started. + * @param batch Batch to start. + */ + virtual void Start(Batch& batch) = 0; + + /** End a batch. + * @param batch Batch to end. + */ + virtual void End(Batch& batch) = 0; +}; + +/** Represents a batch. + * Batches are used to group together physically separate client protocol messages that logically belong + * together for one reason or another. The type of a batch, if provided, indicates what kind of grouping + * it does. + * + * Batch objects have two states: running and stopped. If a batch is running, messages can be added to it. + * If a message has been added to a batch and that message is sent to a client that negotiated the batch + * capability then the client will receive a message tag attached to the message indicating the batch that + * the message is a part of. If a message M is part of a batch B and M is sent to a client that hasn't yet + * received any message from batch B it will get a batch start message for B before M. When a batch B is + * stopped, every client that received at least one message which was in batch B will receive an end of + * batch message for B. + * A message may only be part of a single batch at any given time. + */ +class IRCv3::Batch::Batch +{ + Manager* manager; + const std::string type; + RefTag reftag; + std::string reftagstr; + unsigned int bit; + BatchInfo* batchinfo; + ClientProtocol::Message* batchstartmsg; + + void Setup(unsigned int b) + { + bit = b; + reftag = (1 << bit); + reftagstr = ConvToStr(reftag); + } + + unsigned int GetId() const { return bit; } + intptr_t GetBit() const { return reftag; } + + public: + /** Constructor. + * The batch is initially stopped. To start it, pass it to Manager::Start(). + * @param Type Batch type string, used to indicate what kind of grouping the batch does. May be empty. + */ + Batch(const std::string& Type) + : manager(NULL) + , type(Type) + , batchinfo(NULL) + , batchstartmsg(NULL) + { + } + + /** Destructor. + * If the batch is running, it is ended. + */ + ~Batch() + { + if (manager) + manager->End(*this); + } + + /** Add a message to the batch. + * If the batch isn't running then this method does nothing. + * @param msg Message to add to the batch. If it is already part of any batch, this method is a no-op. + */ + void AddToBatch(ClientProtocol::Message& msg) + { + if (manager) + msg.AddTag("batch", manager, reftagstr, this); + } + + /** Get batch reference tag which is an opaque id for the batch and is used in the client protocol. + * Only running batches have a reference tag assigned. + * @return Reference tag as a string, only valid if the batch is running. + */ + const std::string& GetRefTagStr() const { return reftagstr; } + + /** Get batch type. + * @return Batch type string. + */ + const std::string& GetType() const { return type; } + + /** Check whether the batch is running. + * Batches can be started with Manager::Start() and stopped with Manager::End(). + * @return True if the batch is running, false otherwise. + */ + bool IsRunning() const { return (manager != NULL); } + + /** Get the batch start client protocol message. + * The returned message object can be manipulated to add extra parameters or labels to the message. The first + * parameter of the message is the batch reference tag generated by the module providing batch support. + * If the batch type string was specified, it will be the second parameter of the message. + * May only be called if IsRunning() == true. + * @return Mutable batch start client protocol message. + */ + ClientProtocol::Message& GetBatchStartMessage() { return *batchstartmsg; } + + friend class ManagerImpl; +}; + +/** Batch API. Use this to access the Manager. + */ +class IRCv3::Batch::API : public dynamic_reference_nocheck<Manager> +{ + public: + API(Module* mod) + : dynamic_reference_nocheck<Manager>(mod, "batchapi") + { + } +}; + +/** Reference to the batch cap. + * Can be used to check whether a user has the batch client cap enabled. + */ +class IRCv3::Batch::CapReference : public Cap::Reference +{ + public: + CapReference(Module* mod) + : Cap::Reference(mod, "batch") + { + } +}; diff --git a/include/modules/ircv3_servertime.h b/include/modules/ircv3_servertime.h new file mode 100644 index 000000000..b917531a0 --- /dev/null +++ b/include/modules/ircv3_servertime.h @@ -0,0 +1,88 @@ +/* + * InspIRCd -- Internet Relay Chat Daemon + * + * Copyright (C) 2016 Attila Molnar <attilamolnar@hush.com> + * + * This file is part of InspIRCd. InspIRCd is free software: you can + * redistribute it and/or modify it under the terms of the GNU General Public + * License as published by the Free Software Foundation, version 2. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + + +#pragma once + +namespace IRCv3 +{ + namespace ServerTime + { + class Manager; + class API; + + /** Format a unix timestamp into the format used by server-time. + * @param t Time to format. + * @return Time in server-time format, as a string. + */ + inline std::string FormatTime(time_t t) + { + return InspIRCd::TimeString(t, "%Y-%m-%dT%H:%M:%S.000Z", true); + } + } +} + +/** Implements manipulating the server time on messages. + * A timestamp can be attached to outgoing client protocol messages to indicate the time when the message + * was generated by us. If a message has server time attached then recipient clients who have negotiated + * the appropriate protocol extension will receive it. + */ +class IRCv3::ServerTime::Manager : public DataProvider +{ + protected: + ClientProtocol::MessageTagProvider* tagprov; + + public: + /** Constructor. + * @param mod Module that owns the Manager. + */ + Manager(Module* mod) + : DataProvider(mod, "servertimeapi") + { + } + + /** Set the server time on a message. + * @param msg Message to set the time on. No-op if the message already has server time set. + * @param t Unix timestamp to set. + */ + void Set(ClientProtocol::Message& msg, time_t t) + { + Set(msg, FormatTime(t)); + } + + /** Set the server time on a message. + * @param msg Message to set the time on. No-op if the message already has server time set. + * @param timestr Timestamp to set. Must be in server time format. + * The FormatTime() function can be used to convert unix timestamps into the required format. + */ + void Set(ClientProtocol::Message& msg, const std::string& timestr) + { + msg.AddTag("time", tagprov, timestr); + } +}; + +/** Server time API. Use this to access the Manager. + */ +class IRCv3::ServerTime::API : public dynamic_reference_nocheck<Manager> +{ + public: + API(Module* mod) + : dynamic_reference_nocheck<Manager>(mod, "servertimeapi") + { + } +}; diff --git a/include/modules/ldap.h b/include/modules/ldap.h new file mode 100644 index 000000000..aeb3aa335 --- /dev/null +++ b/include/modules/ldap.h @@ -0,0 +1,192 @@ +/* + * InspIRCd -- Internet Relay Chat Daemon + * + * Copyright (C) 2015 Adam <Adam@anope.org> + * Copyright (C) 2003-2015 Anope Team <team@anope.org> + * + * This file is part of InspIRCd. InspIRCd is free software: you can + * redistribute it and/or modify it under the terms of the GNU General Public + * License as published by the Free Software Foundation, version 2. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#pragma once + +typedef int LDAPQuery; + +class LDAPException : public ModuleException +{ + public: + LDAPException(const std::string& reason) : ModuleException(reason) { } + + virtual ~LDAPException() throw() { } +}; + +struct LDAPModification +{ + enum LDAPOperation + { + LDAP_ADD, + LDAP_DEL, + LDAP_REPLACE + }; + + LDAPOperation op; + std::string name; + std::vector<std::string> values; +}; + +typedef std::vector<LDAPModification> LDAPMods; + +struct LDAPAttributes : public std::map<std::string, std::vector<std::string> > +{ + size_t size(const std::string& attr) const + { + const std::vector<std::string>& array = this->getArray(attr); + return array.size(); + } + + const std::vector<std::string> keys() const + { + std::vector<std::string> k; + for (const_iterator it = this->begin(), it_end = this->end(); it != it_end; ++it) + k.push_back(it->first); + return k; + } + + const std::string& get(const std::string& attr) const + { + const std::vector<std::string>& array = this->getArray(attr); + if (array.empty()) + throw LDAPException("Empty attribute " + attr + " in LDAPResult::get"); + return array[0]; + } + + const std::vector<std::string>& getArray(const std::string& attr) const + { + const_iterator it = this->find(attr); + if (it == this->end()) + throw LDAPException("Unknown attribute " + attr + " in LDAPResult::getArray"); + return it->second; + } +}; + +enum QueryType +{ + QUERY_UNKNOWN, + QUERY_BIND, + QUERY_SEARCH, + QUERY_ADD, + QUERY_DELETE, + QUERY_MODIFY, + QUERY_COMPARE +}; + +struct LDAPResult +{ + std::vector<LDAPAttributes> messages; + std::string error; + + QueryType type; + LDAPQuery id; + + LDAPResult() + : type(QUERY_UNKNOWN), id(-1) + { + } + + size_t size() const + { + return this->messages.size(); + } + + bool empty() const + { + return this->messages.empty(); + } + + const LDAPAttributes& get(size_t sz) const + { + if (sz >= this->messages.size()) + throw LDAPException("Index out of range"); + return this->messages[sz]; + } + + const std::string& getError() const + { + return this->error; + } +}; + +class LDAPInterface +{ + public: + ModuleRef creator; + + LDAPInterface(Module* m) : creator(m) { } + virtual ~LDAPInterface() { } + + virtual void OnResult(const LDAPResult& r) = 0; + virtual void OnError(const LDAPResult& err) = 0; +}; + +class LDAPProvider : public DataProvider +{ + public: + LDAPProvider(Module* Creator, const std::string& Name) + : DataProvider(Creator, Name) { } + + /** Attempt to bind to the LDAP server as a manager + * @param i The LDAPInterface the result is sent to + */ + virtual void BindAsManager(LDAPInterface* i) = 0; + + /** Bind to LDAP + * @param i The LDAPInterface the result is sent to + * @param who The binddn + * @param pass The password + */ + virtual void Bind(LDAPInterface* i, const std::string& who, const std::string& pass) = 0; + + /** Search ldap for the specified filter + * @param i The LDAPInterface the result is sent to + * @param base The base DN to search + * @param filter The filter to apply + */ + virtual void Search(LDAPInterface* i, const std::string& base, const std::string& filter) = 0; + + /** Add an entry to LDAP + * @param i The LDAPInterface the result is sent to + * @param dn The dn of the entry to add + * @param attributes The attributes + */ + virtual void Add(LDAPInterface* i, const std::string& dn, LDAPMods& attributes) = 0; + + /** Delete an entry from LDAP + * @param i The LDAPInterface the result is sent to + * @param dn The dn of the entry to delete + */ + virtual void Del(LDAPInterface* i, const std::string& dn) = 0; + + /** Modify an existing entry in LDAP + * @param i The LDAPInterface the result is sent to + * @param base The base DN to modify + * @param attributes The attributes to modify + */ + virtual void Modify(LDAPInterface* i, const std::string& base, LDAPMods& attributes) = 0; + + /** Compare an attribute in LDAP with our value + * @param i The LDAPInterface the result is sent to + * @param dn DN to use for comparing + * @param attr Attr of DN to compare with + * @param val value to compare attr of dn + */ + virtual void Compare(LDAPInterface* i, const std::string& dn, const std::string& attr, const std::string& val) = 0; +}; diff --git a/include/modules/regex.h b/include/modules/regex.h new file mode 100644 index 000000000..5ef00cdd0 --- /dev/null +++ b/include/modules/regex.h @@ -0,0 +1,62 @@ +/* + * InspIRCd -- Internet Relay Chat Daemon + * + * Copyright (C) 2009 Daniel De Graaf <danieldg@inspircd.org> + * Copyright (C) 2008 Thomas Stagner <aquanight@inspircd.org> + * + * This file is part of InspIRCd. InspIRCd is free software: you can + * redistribute it and/or modify it under the terms of the GNU General Public + * License as published by the Free Software Foundation, version 2. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + + +#pragma once + +#include "inspircd.h" + +class Regex : public classbase +{ +protected: + /** The uncompiled regex string. */ + std::string regex_string; + + // Constructor may as well be protected, as this class is abstract. + Regex(const std::string& rx) : regex_string(rx) { } + +public: + + virtual ~Regex() { } + + virtual bool Matches(const std::string& text) = 0; + + const std::string& GetRegexString() const + { + return regex_string; + } +}; + +class RegexFactory : public DataProvider +{ + public: + RegexFactory(Module* Creator, const std::string& Name) : DataProvider(Creator, Name) { } + + virtual Regex* Create(const std::string& expr) = 0; +}; + +class RegexException : public ModuleException +{ + public: + RegexException(const std::string& regex, const std::string& error) + : ModuleException("Error in regex '" + regex + "': " + error) { } + + RegexException(const std::string& regex, const std::string& error, int offset) + : ModuleException("Error in regex '" + regex + "' at offset " + ConvToStr(offset) + ": " + error) { } +}; diff --git a/include/modules/reload.h b/include/modules/reload.h new file mode 100644 index 000000000..dcdbc95e9 --- /dev/null +++ b/include/modules/reload.h @@ -0,0 +1,80 @@ +/* + * InspIRCd -- Internet Relay Chat Daemon + * + * Copyright (C) 2015 Attila Molnar <attilamolnar@hush.com> + * + * This file is part of InspIRCd. InspIRCd is free software: you can + * redistribute it and/or modify it under the terms of the GNU General Public + * License as published by the Free Software Foundation, version 2. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + + +#pragma once + +#include "event.h" + +namespace ReloadModule +{ + class EventListener; + class DataKeeper; + + /** Container for data saved by modules before another module is reloaded. + */ + class CustomData + { + struct Data + { + EventListener* handler; + void* data; + Data(EventListener* Handler, void* moddata) : handler(Handler), data(moddata) { } + }; + typedef std::vector<Data> List; + List list; + + public: + /** Add data to the saved state of a module. + * The provided handler's OnReloadModuleRestore() method will be called when the reload is done with the pointer + * provided. + * @param handler Handler for restoring the data + * @param data Pointer to the data, will be passed back to the provided handler's OnReloadModuleRestore() after the + * reload finishes + */ + void add(EventListener* handler, void* data) + { + list.push_back(Data(handler, data)); + } + + friend class DataKeeper; + }; + + class EventListener : public Events::ModuleEventListener + { + public: + EventListener(Module* mod) + : ModuleEventListener(mod, "event/reloadmodule") + { + } + + /** Called whenever a module is about to be reloaded. Use this event to save data related to the module that you want + * to be restored after the reload. + * @param mod Module to be reloaded + * @param cd CustomData instance that can store your data once. + */ + virtual void OnReloadModuleSave(Module* mod, CustomData& cd) = 0; + + /** Restore data after a reload. Only called if data was added in OnReloadModuleSave(). + * @param mod Reloaded module, if NULL the reload failed and the module no longer exists + * @param data Pointer that was passed to CustomData::add() in OnReloadModuleSave() at the time when the module's state + * was saved + */ + virtual void OnReloadModuleRestore(Module* mod, void* data) = 0; + }; +} diff --git a/include/modules/sasl.h b/include/modules/sasl.h new file mode 100644 index 000000000..8a54cfdb3 --- /dev/null +++ b/include/modules/sasl.h @@ -0,0 +1,33 @@ +/* + * InspIRCd -- Internet Relay Chat Daemon + * + * Copyright (C) 2010 Daniel De Graaf <danieldg@inspircd.org> + * + * This file is part of InspIRCd. InspIRCd is free software: you can + * redistribute it and/or modify it under the terms of the GNU General Public + * License as published by the Free Software Foundation, version 2. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + + +#pragma once + +#include "event.h" + +class SASLEventListener : public Events::ModuleEventListener +{ + public: + SASLEventListener(Module* mod) + : ModuleEventListener(mod, "event/sasl") + { + } + + virtual void OnSASLAuth(const CommandBase::Params& params) = 0; +}; diff --git a/include/modules/server.h b/include/modules/server.h new file mode 100644 index 000000000..99bd2ee1d --- /dev/null +++ b/include/modules/server.h @@ -0,0 +1,61 @@ +/* + * InspIRCd -- Internet Relay Chat Daemon + * + * Copyright (C) 2009 Daniel De Graaf <danieldg@inspircd.org> + * + * This file is part of InspIRCd. InspIRCd is free software: you can + * redistribute it and/or modify it under the terms of the GNU General Public + * License as published by the Free Software Foundation, version 2. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + + +#pragma once + +#include "event.h" + +class ServerEventListener : public Events::ModuleEventListener +{ + public: + ServerEventListener(Module* mod) + : ModuleEventListener(mod, "event/server") + { + } + + /** Fired when a server finishes burst + * @param server Server that recently linked and finished burst + */ + virtual void OnServerLink(const Server* server) { } + + /** Fired when a server splits + * @param server Server that split + */ + virtual void OnServerSplit(const Server* server) { } + + /** Allows modules to synchronize user metadata during a netburst. This will + * be called for every user visible on your side of the burst. + * @param user The user being synchronized. + * @param server The target of the burst. + */ + virtual void OnSyncUser(User* user, ProtocolServer& server) { } + + /** Allows modules to synchronize channel metadata during a netburst. This will + * be called for every channel visible on your side of the burst. + * @param chan The channel being synchronized. + * @param server The target of the burst. + */ + virtual void OnSyncChannel(Channel* chan, ProtocolServer& server) { } + + /** Allows modules to synchronize network metadata during a netburst. + * @param server The target of the burst. + */ + virtual void OnSyncNetwork(ProtocolServer& server) { } + +}; diff --git a/include/modules/shun.h b/include/modules/shun.h new file mode 100644 index 000000000..9ce547e2d --- /dev/null +++ b/include/modules/shun.h @@ -0,0 +1,70 @@ +/* + * InspIRCd -- Internet Relay Chat Daemon + * + * Copyright (C) 2017 Dylan Frank <b00mx0r@aureus.pw> + * + * This file is part of InspIRCd. InspIRCd is free software: you can + * redistribute it and/or modify it under the terms of the GNU General Public + * License as published by the Free Software Foundation, version 2. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + + +#pragma once + +#include "xline.h" + +/** Shun class + */ +class Shun : public XLine +{ + public: + /** Create a Shun. + * @param s_time The set time + * @param d The duration of the xline + * @param src The sender of the xline + * @param re The reason of the xline + * @param shunmask Mask to match + */ + Shun(time_t s_time, long d, const std::string& src, const std::string& re, const std::string& shunmask) + : XLine(s_time, d, src, re, "SHUN") + , matchtext(shunmask) + { + } + + bool Matches(User* u) CXX11_OVERRIDE + { + LocalUser* lu = IS_LOCAL(u); + if (lu && lu->exempt) + return false; + + if (InspIRCd::Match(u->GetFullHost(), matchtext) || InspIRCd::Match(u->GetFullRealHost(), matchtext) || InspIRCd::Match(u->nick+"!"+u->ident+"@"+u->GetIPString(), matchtext)) + return true; + + if (InspIRCd::MatchCIDR(u->GetIPString(), matchtext, ascii_case_insensitive_map)) + return true; + + return false; + } + + bool Matches(const std::string& str) CXX11_OVERRIDE + { + return (matchtext == str); + } + + const std::string& Displayable() CXX11_OVERRIDE + { + return matchtext; + } + + private: + /** Matching mask **/ + std::string matchtext; +}; diff --git a/include/modules/sql.h b/include/modules/sql.h new file mode 100644 index 000000000..15e8260b6 --- /dev/null +++ b/include/modules/sql.h @@ -0,0 +1,267 @@ +/* + * InspIRCd -- Internet Relay Chat Daemon + * + * Copyright (C) 2017 Peter Powell <petpow@saberuk.com> + * Copyright (C) 2010 Daniel De Graaf <danieldg@inspircd.org> + * + * This file is part of InspIRCd. InspIRCd is free software: you can + * redistribute it and/or modify it under the terms of the GNU General Public + * License as published by the Free Software Foundation, version 2. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + + +#pragma once + + +namespace SQL +{ + class Error; + class Field; + class Provider; + class Query; + class Result; + + /** A list of parameter replacement values. */ + typedef std::vector<std::string> ParamList; + + /** A map of parameter replacement values. */ + typedef std::map<std::string, std::string> ParamMap; + + /** A list of SQL fields from a specific row. */ + typedef std::vector<Field> Row; + + /** An enumeration of possible error codes. */ + enum ErrorCode + { + /** No error has occurred. */ + SUCCESS, + + /** The database identifier is invalid. */ + BAD_DBID, + + /** The database connection has failed. */ + BAD_CONN, + + /** Executing the query failed. */ + QSEND_FAIL, + + /** Reading the response failed. */ + QREPLY_FAIL + }; + + /** Populates a parameter map with information about a user. + * @param user The user to collect information from. + * @param userinfo The map to populate. + */ + void PopulateUserInfo(User* user, ParamMap& userinfo); +} + +/** Represents a single SQL field. */ +class SQL::Field +{ + private: + /** Whether this SQL field is NULL. */ + bool null; + + /** The underlying SQL value. */ + std::string value; + + public: + /** Creates a new NULL SQL field. */ + Field() + : null(true) + { + } + + /** Creates a new non-NULL SQL field. + * @param v The value of the field. + */ + Field(const std::string& v) + : null(false) + , value(v) + { + } + + /** Determines whether this SQL entry is NULL. */ + inline bool IsNull() const { return null; } + + /** Retrieves the underlying value. */ + inline operator const std::string&() const { return value; } +}; + +/** Represents the result of an SQL query. */ +class SQL::Result : public classbase +{ + public: + /** + * Return the number of rows in the result. + * + * Note that if you have perfomed an INSERT or UPDATE query or other + * query which will not return rows, this will return the number of + * affected rows. In this case you SHOULD NEVER access any of the result + * set rows, as there aren't any! + * @returns Number of rows in the result set. + */ + virtual int Rows() = 0; + + /** Retrieves the next available row from the database. + * @param result A list to store the fields from this row in. + * @return True if a row could be retrieved; otherwise, false. + */ + virtual bool GetRow(Row& result) = 0; + + /** Retrieves a list of SQL columns in the result. + * @param result A reference to the vector to store column names in. + */ + virtual void GetCols(std::vector<std::string>& result) = 0; + + /** + * Check if there's a column with the specified name in the result + * + * @param the column name + * @param on success, this is the column index + * @returns true, or false if the column is not found + */ + virtual bool HasColumn(const std::string& column, size_t& index) = 0; +}; + +/** SQL::Error holds the error state of a request. + * The error string varies from database software to database software + * and should be used to display informational error messages to users. + */ +class SQL::Error +{ + private: + /** The custom error message if one has been specified. */ + const std::string message; + + public: + /** The code which represents this error. */ + const ErrorCode code; + + /** Initialize an SQL::Error from an error code. + * @param c A code which represents this error. + */ + Error(ErrorCode c) + : code(c) + { + } + + /** Initialize an SQL::Error from an error code and a custom error message. + * @param c A code which represents this error. + * @param m A custom error message. + */ + Error(ErrorCode c, const std::string m) + : message(m) + , code(c) + { + } + + /** Retrieves the error message. */ + const char* ToString() const + { + if (!message.empty()) + return message.c_str(); + + switch (code) + { + case BAD_DBID: + return "Invalid database identifier"; + case BAD_CONN: + return "Invalid connection"; + case QSEND_FAIL: + return "Sending query failed"; + case QREPLY_FAIL: + return "Getting query result failed"; + default: + return "Unknown error"; + } + } +}; + +/** + * Object representing an SQL query. This should be allocated on the heap and + * passed to an SQL::Provider, which will free it when the query is complete or + * when the querying module is unloaded. + * + * You should store whatever information is needed to have the callbacks work in + * this object (UID of user, channel name, etc). + */ +class SQL::Query : public classbase +{ + protected: + /** Creates a new SQL query. */ + Query(Module* Creator) + : creator(Creator) + { + } + + public: + const ModuleRef creator; + + /* Destroys this Query instance. */ + virtual ~Query() + { + } + + /** Called when an SQL error happens. + * @param error The error that occurred. + */ + virtual void OnError(Error& error) = 0; + + /** Called when a SQL result is received. + * @param result The result of the SQL query. + */ + virtual void OnResult(Result& result) = 0; +}; + +/** + * Provider object for SQL servers + */ +class SQL::Provider : public DataProvider +{ + public: + Provider(Module* Creator, const std::string& Name) + : DataProvider(Creator, Name) + { + } + + /** Submit an asynchronous SQL query. + * @param callback The result reporting point + * @param query The hardcoded query string. If you have parameters to substitute, see below. + */ + virtual void Submit(Query* callback, const std::string& query) = 0; + + /** Submit an asynchronous SQL query. + * @param callback The result reporting point + * @param format The simple parameterized query string ('?' parameters) + * @param p Parameters to fill in for the '?' entries + */ + virtual void Submit(Query* callback, const std::string& format, const SQL::ParamList& p) = 0; + + /** Submit an asynchronous SQL query. + * @param callback The result reporting point + * @param format The parameterized query string ('$name' parameters) + * @param p Parameters to fill in for the '$name' entries + */ + virtual void Submit(Query* callback, const std::string& format, const ParamMap& p) = 0; +}; + +inline void SQL::PopulateUserInfo(User* user, ParamMap& userinfo) +{ + userinfo["nick"] = user->nick; + userinfo["host"] = user->GetRealHost(); + userinfo["ip"] = user->GetIPString(); + userinfo["real"] = user->GetRealName(); + userinfo["ident"] = user->ident; + userinfo["server"] = user->server->GetName(); + userinfo["uuid"] = user->uuid; +} diff --git a/include/modules/ssl.h b/include/modules/ssl.h new file mode 100644 index 000000000..930cb6dc6 --- /dev/null +++ b/include/modules/ssl.h @@ -0,0 +1,305 @@ +/* + * InspIRCd -- Internet Relay Chat Daemon + * + * Copyright (C) 2009 Daniel De Graaf <danieldg@inspircd.org> + * Copyright (C) 2006 Craig Edwards <craigedwards@brainbox.cc> + * + * This file is part of InspIRCd. InspIRCd is free software: you can + * redistribute it and/or modify it under the terms of the GNU General Public + * License as published by the Free Software Foundation, version 2. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + + +#pragma once + +#include <string> +#include "iohook.h" + +/** ssl_cert is a class which abstracts SSL certificate + * and key information. + * + * Because gnutls and openssl represent key information in + * wildly different ways, this class allows it to be accessed + * in a unified manner. These classes are attached to ssl- + * connected local users using SSLCertExt + */ +class ssl_cert : public refcountbase +{ + public: + std::string dn; + std::string issuer; + std::string error; + std::string fingerprint; + bool trusted, invalid, unknownsigner, revoked; + + ssl_cert() : trusted(false), invalid(true), unknownsigner(true), revoked(false) {} + + /** Get certificate distinguished name + * @return Certificate DN + */ + const std::string& GetDN() + { + return dn; + } + + /** Get Certificate issuer + * @return Certificate issuer + */ + const std::string& GetIssuer() + { + return issuer; + } + + /** Get error string if an error has occured + * @return The error associated with this users certificate, + * or an empty string if there is no error. + */ + const std::string& GetError() + { + return error; + } + + /** Get key fingerprint. + * @return The key fingerprint as a hex string. + */ + const std::string& GetFingerprint() + { + return fingerprint; + } + + /** Get trust status + * @return True if this is a trusted certificate + * (the certificate chain validates) + */ + bool IsTrusted() + { + return trusted; + } + + /** Get validity status + * @return True if the certificate itself is + * correctly formed. + */ + bool IsInvalid() + { + return invalid; + } + + /** Get signer status + * @return True if the certificate appears to be + * self-signed. + */ + bool IsUnknownSigner() + { + return unknownsigner; + } + + /** Get revokation status. + * @return True if the certificate is revoked. + * Note that this only works properly for GnuTLS + * right now. + */ + bool IsRevoked() + { + return revoked; + } + + /** Get certificate usability + * @return True if the certificate is not expired nor revoked + */ + bool IsUsable() + { + return !invalid && !revoked && error.empty(); + } + + /** Get CA trust status + * @return True if the certificate is issued by a CA + * and valid. + */ + bool IsCAVerified() + { + return IsUsable() && trusted && !unknownsigner; + } + + std::string GetMetaLine() + { + std::stringstream value; + bool hasError = !error.empty(); + value << (IsInvalid() ? "v" : "V") << (IsTrusted() ? "T" : "t") << (IsRevoked() ? "R" : "r") + << (IsUnknownSigner() ? "s" : "S") << (hasError ? "E" : "e") << " "; + if (hasError) + value << GetError(); + else + value << GetFingerprint() << " " << GetDN() << " " << GetIssuer(); + return value.str(); + } +}; + +class SSLIOHook : public IOHook +{ + protected: + /** Peer SSL certificate, set by the SSL module + */ + reference<ssl_cert> certificate; + + /** Reduce elements in a send queue by appending later elements to the first element until there are no more + * elements to append or a desired length is reached + * @param sendq SendQ to work on + * @param targetsize Target size of the front element + */ + static void FlattenSendQueue(StreamSocket::SendQueue& sendq, size_t targetsize) + { + if ((sendq.size() <= 1) || (sendq.front().length() >= targetsize)) + return; + + // Avoid multiple repeated SSL encryption invocations + // This adds a single copy of the queue, but avoids + // much more overhead in terms of system calls invoked + // by an IOHook. + std::string tmp; + tmp.reserve(std::min(targetsize, sendq.bytes())+1); + do + { + tmp.append(sendq.front()); + sendq.pop_front(); + } + while (!sendq.empty() && tmp.length() < targetsize); + sendq.push_front(tmp); + } + + public: + static SSLIOHook* IsSSL(StreamSocket* sock) + { + IOHook* const iohook = sock->GetIOHook(); + if ((iohook) && ((iohook->prov->type == IOHookProvider::IOH_SSL))) + return static_cast<SSLIOHook*>(iohook); + return NULL; + } + + SSLIOHook(IOHookProvider* hookprov) + : IOHook(hookprov) + { + } + + /** + * Get the certificate sent by this peer + * @return The SSL certificate sent by the peer, NULL if no cert was sent + */ + ssl_cert* GetCertificate() const + { + if (certificate && certificate->IsUsable()) + return certificate; + return NULL; + } + + /** + * Get the fingerprint of the peer's certificate + * @return The fingerprint of the SSL client certificate sent by the peer, + * empty if no cert was sent + */ + std::string GetFingerprint() const + { + ssl_cert* cert = GetCertificate(); + if (cert) + return cert->GetFingerprint(); + return ""; + } + + /** + * Get the ciphersuite negotiated with the peer + * @param out String where the ciphersuite string will be appended to + */ + virtual void GetCiphersuite(std::string& out) const = 0; + + + /** Retrieves the name of the SSL connection which is sent via SNI. + * @param out String that the server name will be appended to. + * returns True if the server name was retrieved; otherwise, false. + */ + virtual bool GetServerName(std::string& out) const = 0; +}; + +/** Helper functions for obtaining SSL client certificates and key fingerprints + * from StreamSockets + */ +class SSLClientCert +{ + public: + /** + * Get the client certificate from a socket + * @param sock The socket to get the certificate from, the socket does not have to use SSL + * @return The SSL client certificate information, NULL if the peer is not using SSL + */ + static ssl_cert* GetCertificate(StreamSocket* sock) + { + SSLIOHook* ssliohook = SSLIOHook::IsSSL(sock); + if (!ssliohook) + return NULL; + + return ssliohook->GetCertificate(); + } + + /** + * Get the fingerprint of a client certificate from a socket + * @param sock The socket to get the certificate fingerprint from, the + * socket does not have to use SSL + * @return The key fingerprint from the SSL certificate sent by the peer, + * empty if no cert was sent or the peer is not using SSL + */ + static std::string GetFingerprint(StreamSocket* sock) + { + ssl_cert* cert = SSLClientCert::GetCertificate(sock); + if (cert) + return cert->GetFingerprint(); + return ""; + } +}; + +class UserCertificateAPIBase : public DataProvider +{ + public: + UserCertificateAPIBase(Module* parent) + : DataProvider(parent, "m_sslinfo_api") + { + } + + /** Get the SSL certificate of a user + * @param user The user whose certificate to get, user may be remote + * @return The SSL certificate of the user or NULL if the user is not using SSL + */ + virtual ssl_cert* GetCertificate(User* user) = 0; + + /** Get the key fingerprint from a user's certificate + * @param user The user whose key fingerprint to get, user may be remote + * @return The key fingerprint from the user's SSL certificate or an empty string + * if the user is not using SSL or did not provide a client certificate + */ + std::string GetFingerprint(User* user) + { + ssl_cert* cert = GetCertificate(user); + if (cert) + return cert->GetFingerprint(); + return ""; + } +}; + +/** API implemented by m_sslinfo that allows modules to retrive the SSL certificate + * information of local and remote users. It can also be used to find out whether a + * user is using SSL or not. + */ +class UserCertificateAPI : public dynamic_reference<UserCertificateAPIBase> +{ + public: + UserCertificateAPI(Module* parent) + : dynamic_reference<UserCertificateAPIBase>(parent, "m_sslinfo_api") + { + } +}; diff --git a/include/modules/stats.h b/include/modules/stats.h new file mode 100644 index 000000000..e69070c9f --- /dev/null +++ b/include/modules/stats.h @@ -0,0 +1,191 @@ +/* + * InspIRCd -- Internet Relay Chat Daemon + * + * Copyright (C) 2016 Attila Molnar <attilamolnar@hush.com> + * + * This file is part of InspIRCd. InspIRCd is free software: you can + * redistribute it and/or modify it under the terms of the GNU General Public + * License as published by the Free Software Foundation, version 2. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + + +#pragma once + +#include "event.h" + +namespace Stats +{ + class Context; + class EventListener; + class Row; +} + +class Stats::EventListener : public Events::ModuleEventListener +{ + public: + EventListener(Module* mod) + : ModuleEventListener(mod, "event/stats") + { + } + + /** Called when the STATS command is executed. + * @param stats Context of the /STATS request, contains requesting user, list of answer rows etc. + * @return MOD_RES_DENY if the stats request has been fulfilled. Otherwise, MOD_RES_PASSTHRU. + */ + virtual ModResult OnStats(Stats::Context& stats) = 0; +}; + +class Stats::Row : public Numeric::Numeric +{ + public: + Row(unsigned int num) + : Numeric(num) + { + } +}; + +class Stats::Context +{ + /** Source user of the STATS request + */ + User* const source; + + /** List of reply rows + */ + std::vector<Row> rows; + + /** Symbol indicating the type of this STATS request (usually a letter) + */ + const char symbol; + + public: + /** Constructor + * @param src Source user of the STATS request, can be a local or remote user + * @param sym Symbol (letter) indicating the type of the request + */ + Context(User* src, char sym) + : source(src) + , symbol(sym) + { + } + + /** Get the source user of the STATS request + * @return Source user of the STATS request + */ + User* GetSource() const { return source; } + + /** Get the list of reply rows + * @return List of rows generated as reply for the request + */ + const std::vector<Row>& GetRows() const { return rows; } + + /** Get the symbol (letter) indicating what type of STATS was requested + * @return Symbol specified by the requesting user + */ + char GetSymbol() const { return symbol; } + + /** Add a row to the reply list + * @param row Reply to add + */ + void AddRow(const Row& row) { rows.push_back(row); } + + template <typename T1> + void AddRow(unsigned int numeric, T1 p1) + { + Row n(numeric); + n.push(p1); + AddRow(n); + } + + template <typename T1, typename T2> + void AddRow(unsigned int numeric, T1 p1, T2 p2) + { + Row n(numeric); + n.push(p1); + n.push(p2); + AddRow(n); + } + + template <typename T1, typename T2, typename T3> + void AddRow(unsigned int numeric, T1 p1, T2 p2, T3 p3) + { + Row n(numeric); + n.push(p1); + n.push(p2); + n.push(p3); + AddRow(n); + } + + template <typename T1, typename T2, typename T3, typename T4> + void AddRow(unsigned int numeric, T1 p1, T2 p2, T3 p3, T4 p4) + { + Row n(numeric); + n.push(p1); + n.push(p2); + n.push(p3); + n.push(p4); + AddRow(n); + } + + template <typename T1, typename T2, typename T3, typename T4, typename T5> + void AddRow(unsigned int numeric, T1 p1, T2 p2, T3 p3, T4 p4, T5 p5) + { + Row n(numeric); + n.push(p1); + n.push(p2); + n.push(p3); + n.push(p4); + n.push(p5); + AddRow(n); + } + + template <typename T1, typename T2, typename T3, typename T4, typename T5, typename T6> + void AddRow(unsigned int numeric, T1 p1, T2 p2, T3 p3, T4 p4, T5 p5, T6 p6) + { + Row n(numeric); + n.push(p1); + n.push(p2); + n.push(p3); + n.push(p4); + n.push(p5); + n.push(p6); + AddRow(n); + } + + template <typename T1, typename T2, typename T3, typename T4, typename T5, typename T6, typename T7> + void AddRow(unsigned int numeric, T1 p1, T2 p2, T3 p3, T4 p4, T5 p5, T6 p6, T7 p7) + { + Row n(numeric); + n.push(p1); + n.push(p2); + n.push(p3); + n.push(p4); + n.push(p5); + n.push(p6); + n.push(p7); + AddRow(n); + } + + template <typename T1, typename T2, typename T3, typename T4, typename T5, typename T6, typename T7, typename T8> + void AddRow(unsigned int numeric, T1 p1, T2 p2, T3 p3, T4 p4, T5 p5, T6 p6, T7 p7, T8 p8) + { + Row n(numeric); + n.push(p1); + n.push(p2); + n.push(p3); + n.push(p4); + n.push(p5); + n.push(p6); + n.push(p7); + n.push(p8); + AddRow(n); + } +}; diff --git a/include/modules/whois.h b/include/modules/whois.h new file mode 100644 index 000000000..4f09d268b --- /dev/null +++ b/include/modules/whois.h @@ -0,0 +1,146 @@ +/* + * InspIRCd -- Internet Relay Chat Daemon + * + * Copyright (C) 2015 Attila Molnar <attilamolnar@hush.com> + * + * This file is part of InspIRCd. InspIRCd is free software: you can + * redistribute it and/or modify it under the terms of the GNU General Public + * License as published by the Free Software Foundation, version 2. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + + +#pragma once + +#include "event.h" + +namespace Whois +{ + class EventListener; + class LineEventListener; + class Context; +} + +class Whois::EventListener : public Events::ModuleEventListener +{ + public: + EventListener(Module* mod) + : ModuleEventListener(mod, "event/whois") + { + } + + /** Called whenever a /WHOIS is performed by a local user. + * @param whois Whois context, can be used to send numerics + */ + virtual void OnWhois(Context& whois) = 0; +}; + +class Whois::LineEventListener : public Events::ModuleEventListener +{ + public: + LineEventListener(Module* mod) + : ModuleEventListener(mod, "event/whoisline") + { + } + + /** Called whenever a line of WHOIS output is sent to a user. + * You may change the numeric and the text of the output by changing + * the values numeric and text, but you cannot change the user the + * numeric is sent to. + * @param whois Whois context, can be used to send numerics + * @param numeric Numeric being sent + * @return MOD_RES_DENY to drop the line completely so that the user does not + * receive it, or MOD_RES_PASSTHRU to allow the line to be sent. + */ + virtual ModResult OnWhoisLine(Context& whois, Numeric::Numeric& numeric) = 0; +}; + +class Whois::Context +{ + protected: + /** User doing the WHOIS + */ + LocalUser* const source; + + /** User being WHOISed + */ + User* const target; + + public: + Context(LocalUser* src, User* targ) + : source(src) + , target(targ) + { + } + + /** Returns true if the user is /WHOISing himself + * @return True if whois source is the same user as the whois target, false if they are different users + */ + bool IsSelfWhois() const { return (source == target); } + + /** Returns the LocalUser who has done the /WHOIS + * @return LocalUser doing the /WHOIS + */ + LocalUser* GetSource() const { return source; } + + /** Returns the target of the /WHOIS + * @return User who was /WHOIS'd + */ + User* GetTarget() const { return target; } + + /** Send a line of WHOIS data to the source of the WHOIS + */ + template <typename T1> + void SendLine(unsigned int numeric, T1 p1) + { + Numeric::Numeric n(numeric); + n.push(target->nick); + n.push(p1); + SendLine(n); + } + + template <typename T1, typename T2> + void SendLine(unsigned int numeric, T1 p1, T2 p2) + { + Numeric::Numeric n(numeric); + n.push(target->nick); + n.push(p1); + n.push(p2); + SendLine(n); + } + + template <typename T1, typename T2, typename T3> + void SendLine(unsigned int numeric, T1 p1, T2 p2, T3 p3) + { + Numeric::Numeric n(numeric); + n.push(target->nick); + n.push(p1); + n.push(p2); + n.push(p3); + SendLine(n); + } + + template <typename T1, typename T2, typename T3, typename T4> + void SendLine(unsigned int numeric, T1 p1, T2 p2, T3 p3, T4 p4) + { + Numeric::Numeric n(numeric); + n.push(target->nick); + n.push(p1); + n.push(p2); + n.push(p3); + n.push(p4); + SendLine(n); + } + + /** Send a line of WHOIS data to the source of the WHOIS + * @param numeric Numeric to send + */ + virtual void SendLine(Numeric::Numeric& numeric) = 0; +}; |