1
0
mirror of https://github.com/anope/anope.git synced 2026-07-06 05:13:13 +02:00

Compare commits

...

67 Commits

Author SHA1 Message Date
Adam c2e09fdaea Anope 2.0.4 Release 2016-07-23 16:26:14 -04:00
Adam 01768bc73e Update Changes.conf 2016-07-23 16:25:37 -04:00
Adam c18eedec18 ns_set: clear last modes before unserializing them 2016-07-23 16:20:54 -04:00
Adam 0e0615c6fe Note Windows installer fixes in changelog 2016-07-23 16:17:33 -04:00
Adam 5bd3fde79b cs_set: clear last modes before unserializing them 2016-07-23 16:17:21 -04:00
Adam 647f8cd4e6 Add/fix various checks on source user existing in the protocol modules 2016-07-23 15:47:33 -04:00
Adam b2e25db159 Merge pull request #171 from Techman-/2.0+charybdis-resv-fixes
charybdis.cpp: Properly support RESVs
2016-07-23 15:38:26 -04:00
Adam 9f9371531d Fix making directories from the Windows installer 2016-07-23 15:22:54 -04:00
Michael Hazell b578ed2544 charybdis.cpp: Properly support RESVs
Properly support RESV and UNRESV in Charybdis, and improve RESV setting for pseudoclients when bursting.
2016-07-21 23:27:20 -04:00
Adam 0a7f167060 m_dns: accept unpacking the root domain, and don't consider exceptions from nameserver/additional record unpacking as fatal to query parsing 2016-07-19 21:17:58 -04:00
Adam d427772bd3 os_defcon: find module by name, it might not be loaded yet 2016-07-10 20:51:03 -04:00
Robby b2d670298b Update the dutch language file. 2016-07-07 16:07:24 +02:00
Adam 6b646fa1f8 Update Changes 2016-07-03 13:57:11 -04:00
Adam 72269c44e5 Merge pull request #170 from Zoddo/charybdis/join0
Thanks
2016-07-03 13:47:49 -04:00
Adam 3b2366e4ba Merge pull request #169 from SaberUK/2.0+which
Use "cmake --version" instead of "which cmake" to detect CMake.
2016-07-03 13:46:41 -04:00
Adam 257a8a9a24 ns_maxemail: optionally remove gmail aliases 2016-07-03 13:42:18 -04:00
Adam 7a1d2e11dd chankill: don't add duplicate akills 2016-07-03 13:31:12 -04:00
Adam 8dc687b657 #1682: store aftype with masks and include cidrs in GetNUHMask 2016-07-03 13:29:27 -04:00
Adam 18fc113984 #1681 update last realname always on signon 2016-07-03 13:06:06 -04:00
Adam 20c1a5d638 #1680: fix Anope::Duration with one year durations 2016-07-03 12:42:16 -04:00
Adam 8000ae0c0f #1677 apply sqlines even if the ircd doesn't on non opers 2016-07-03 12:36:34 -04:00
Adam 284d95bfe2 #1675: fix saset display to update the account name on the correct clients 2016-07-03 12:27:01 -04:00
Adam c7d5ee4bec Fix /ns confirm to set +r/accounts when appropriate 2016-07-03 12:17:44 -04:00
Adam 4c4cc0ded7 Fix xmlrpc notice call to return something to prevent m_xmlrpc from thinking it is a http 404 2016-07-03 12:08:21 -04:00
Adam 83f89bfece Clarify botserv repeat kicker message and allow setting repeat times to 1 2016-06-25 13:04:32 -04:00
Adam 7cf4245359 Enable -fno-delete-null-pointer-checks on GCC 6 2016-06-22 20:20:28 -04:00
Zoddo 9284441491 Handle /join 0 for ratbox & charybdis 2016-06-02 12:23:26 +02:00
Peter Powell 7592a6981b Use "cmake --version" instead of "which cmake" to detect CMake. 2016-05-21 17:54:33 +01:00
Adam 56b158ea43 Fix handling nick introduction collisions on unreal4 2016-05-20 21:18:34 -04:00
Adam 0143dafe51 Merge pull request #165 from sketchni/patch-1
Add the notice method to XMLRPC.
2016-04-22 10:17:41 -05:00
Adam a2dbcc620e Merge pull request #166 from jmdh/2.0-reproducible
Optionally strip variable build date from compiled program
2016-04-22 10:17:11 -05:00
Adam 9b5fdea8f2 Fix randomnews to work when there are more than newscount random news 2016-04-22 11:15:42 -04:00
Dominic Hargreaves fab07d6b75 Optionally strip variable build date from compiled program
To aid build reproducibility, don't include the build date/time if
-DREPRODUCIBLE_BUILD is defined.

Based on the patch provided by Alexis BienvenĂĽe in the Debian report.

Bug-Debian: https://bugs.debian.org/820152
Patch-Name: reproducible_datetime.diff
2016-04-21 23:08:12 +01:00
Sketch 1d198da436 Add the notice method to XMLRPC. 2016-04-20 15:41:23 +01:00
Adam 8b6e17fe7e Change access check in cs_updown to not allow actions on users with equal access 2016-04-16 18:14:23 -04:00
Adam 86484b6c2b Merge pull request #164 from SaberUK/2.0+extras
Remove references to cmake-bin which was removed ages ago.
2016-04-16 16:59:21 -05:00
Adam c14ae99d32 Merge pull request #163 from Zoddo/fix_sasl_reauth
Send new account name to the IRCd on SASL reauth
2016-04-16 16:59:00 -05:00
Adam cb0cda2f8d Missed channel deletion in ~ChannelInfo 2016-04-16 18:00:47 -04:00
Peter Powell 2af363755a Remove references to cmake-bin which was removed ages ago. 2016-04-16 13:05:44 +01:00
Zoddo 753b8dc989 Send new account name to the IRCd on SASL reauth 2016-04-15 10:49:30 +02:00
Adam d2ea1e7917 Merge pull request #160 from Zoddo/charybdis/fix_euid
Fix host on charybdis if there is no vhost
2016-04-14 19:18:14 -05:00
Adam a8f66578b1 Merge pull request #161 from Zoddo/charybdis/vhost_svslogin
Send vident/vhost in SVSLOGIN with SASL
2016-04-14 19:17:39 -05:00
Adam ca39aeb554 Merge pull request #162 from SaberUK/2.0+sasl
Remove support for DH-AES and DH-BLOWFISH.
2016-04-14 19:16:56 -05:00
Adam a941f9bde0 Remove memos from memoinfo more reliably 2016-04-14 20:15:53 -04:00
Peter Powell f4f6787c9c Remove support for DH-AES and DH-BLOWFISH.
These SASL mechanisms are considered insecure and should not be
used anymore.
2016-04-13 20:26:50 +01:00
Zoddo 82816cb206 Send vident/vhost in SVSLOGIN with SASL
Only charybdis seems to support that for the moment.
2016-04-10 18:24:25 +02:00
Zoddo 58f0c8c612 Fix host on charybdis if there is no vhost 2016-04-10 17:53:53 +02:00
Adam 21e1913c0f Fix subtle typo in command initializer list 2016-04-05 16:01:16 -04:00
Adam 79e7c3f98a Also defer channel deletion when processing sjoins 2016-03-19 16:21:40 -04:00
Adam 72127e1b00 Merge pull request #159 from Diftraku/2.0
proto/charybdis: Add support for MECHLIST
2016-03-17 17:15:56 -05:00
Toni Kaija ed47588087 proto/charybdis: Add support for MECHLIST 2016-03-17 15:13:11 +02:00
Adam 448967cefc Merge pull request #156 from SaberUK/2.0+sasl-mechlist
Implement support for SASL 3.2 mechanism lists.
2016-03-15 17:41:48 -05:00
Adam 979027138b Merge pull request #155 from SaberUK/2.0+sasl-reauth
Fix logging into accounts with SASL on servers that support reauth.
2016-03-15 17:40:26 -05:00
Robby 176e0e4f37 Update the dutch language file. 2016-03-09 22:42:45 +01:00
Adam b431d4dccf cs_clone: don't clone registered time 2016-03-08 19:49:30 -05:00
Adam 1b12b80b48 language: incrementing _nl_msg_cat_cntr is still required on some systems apparently (freebsd 10?). I don't know why. 2016-03-08 19:47:06 -05:00
Peter Powell 52fdc45597 Implement support for SASL 3.2 mechanism lists. 2016-02-28 16:36:43 +00:00
Peter Powell 91762524e2 Fix logging into accounts with SASL on servers that support reauth. 2016-02-28 13:22:19 +00:00
Adam 413b38b1c1 Fail sasl external auth immediately if cert is empty 2016-02-13 18:25:04 -05:00
Adam ecdccd6ad6 And use account here, user might be null 2016-02-13 18:19:47 -05:00
Adam e0fd118b3e Fix access path changes in ns_alist from earlier 2016-02-13 18:11:03 -05:00
Adam c10d7bdada Update chanserv secure help to reflect more accurately what it does 2016-02-13 14:41:23 -05:00
Adam 4e2ca31cf5 Rewrite access path system to be simplier and use recursion
Show where access is "from" in chanserv/status
2016-02-13 14:16:29 -05:00
Adam addd2a1987 Correct umode +I change in Changelog, is for unreal 2016-02-11 08:36:12 -05:00
Adam 4071487f80 Merge pull request #154 from SaberUK/2.0+inspfix
Fix a low risk privilege escalation exploit on InspIRCd with m_autoop.
2016-02-11 07:03:55 -06:00
Peter Powell 9c17c2d818 Fix a privilege escalation exploit on InspIRCd with m_autoop. 2016-02-10 08:56:23 +00:00
Adam dd9fcca45d Anope 2.0.4-git 2016-01-30 18:50:28 -05:00
60 changed files with 851 additions and 860 deletions
+14 -6
View File
@@ -87,6 +87,9 @@ if(CMAKE_COMPILER_IS_GNUCXX)
if(GCC_VERSION LESS 4.2) if(GCC_VERSION LESS 4.2)
message(FATAL_ERROR "Your compiler is too old to build Anope. Upgrade to GCC 4.2 or newer!") message(FATAL_ERROR "Your compiler is too old to build Anope. Upgrade to GCC 4.2 or newer!")
endif(GCC_VERSION LESS 4.2) endif(GCC_VERSION LESS 4.2)
if(GCC_VERSION GREATER 6.0 OR GCC_VERSION EQUAL 6.0)
set(CXXFLAGS "${CXXFLAGS} -fno-delete-null-pointer-checks")
endif(GCC_VERSION GREATER 6.0 OR GCC_VERSION EQUAL 6.0)
endif(CMAKE_COMPILER_IS_GNUCXX) endif(CMAKE_COMPILER_IS_GNUCXX)
# If we are using a GNU compiler (have to use CXX because it seems to fail on C), we will be able to determine it's default paths for libraries and includes # If we are using a GNU compiler (have to use CXX because it seems to fail on C), we will be able to determine it's default paths for libraries and includes
@@ -239,6 +242,11 @@ option(USE_PCH "Use precompiled headers" OFF)
# source include directory so the precompiled headers work correctly. # source include directory so the precompiled headers work correctly.
include_directories(${Anope_BINARY_DIR}/include ${Anope_SOURCE_DIR}/include ${Anope_BINARY_DIR}/language ${Anope_SOURCE_DIR}/modules/pseudoclients) include_directories(${Anope_BINARY_DIR}/include ${Anope_SOURCE_DIR}/include ${Anope_BINARY_DIR}/language ${Anope_SOURCE_DIR}/modules/pseudoclients)
# Pass on REPRODUCIBLE_BUILD
if(REPRODUCIBLE_BUILD)
add_definitions(-DREPRODUCIBLE_BUILD)
endif(REPRODUCIBLE_BUILD)
# If using Windows, always add the _WIN32 define # If using Windows, always add the _WIN32 define
if(WIN32) if(WIN32)
add_definitions(-D_WIN32) add_definitions(-D_WIN32)
@@ -481,16 +489,16 @@ get_target_property(SERVICES_BINARY ${PROGRAM_NAME} LOCATION)
get_filename_component(SERVICES_BINARY ${SERVICES_BINARY} NAME) get_filename_component(SERVICES_BINARY ${SERVICES_BINARY} NAME)
# At install time, create the following additional directories # At install time, create the following additional directories
install(CODE "file(MAKE_DIRECTORY \"\$ENV{DESTDIR}${CMAKE_INSTALL_PREFIX}/${DB_DIR}/backups\")") install(CODE "file(MAKE_DIRECTORY \"\$ENV{DESTDIR}\${CMAKE_INSTALL_PREFIX}/${DB_DIR}/backups\")")
install(CODE "file(MAKE_DIRECTORY \"\$ENV{DESTDIR}${CMAKE_INSTALL_PREFIX}/${LOGS_DIR}\")") install(CODE "file(MAKE_DIRECTORY \"\$ENV{DESTDIR}\${CMAKE_INSTALL_PREFIX}/${LOGS_DIR}\")")
if(WIN32) if(WIN32)
install(CODE "file(MAKE_DIRECTORY \"\${CMAKE_INSTALL_PREFIX}/${DB_DIR}/runtime\")") install(CODE "file(MAKE_DIRECTORY \"\$ENV{DESTDIR}\${CMAKE_INSTALL_PREFIX}/${DB_DIR}/runtime\")")
endif(WIN32) endif(WIN32)
# On non-Windows platforms, if RUNGROUP is set, change the permissions of the below directories, as well as the group of the data directory # On non-Windows platforms, if RUNGROUP is set, change the permissions of the below directories, as well as the group of the data directory
if(NOT WIN32 AND RUNGROUP) if(NOT WIN32 AND RUNGROUP)
install(CODE "execute_process(COMMAND ${CHMOD} 2775 \"\$ENV{DESTDIR}${CMAKE_INSTALL_PREFIX}/\${DB_DIR}/backups\")") install(CODE "execute_process(COMMAND ${CHMOD} 2775 \"\$ENV{DESTDIR}\${CMAKE_INSTALL_PREFIX}/\${DB_DIR}/backups\")")
install(CODE "execute_process(COMMAND ${CHMOD} 2775 \"\$ENV{DESTDIR}${CMAKE_INSTALL_PREFIX}/\${LOGS_DIR}\")") install(CODE "execute_process(COMMAND ${CHMOD} 2775 \"\$ENV{DESTDIR}\${CMAKE_INSTALL_PREFIX}/\${LOGS_DIR}\")")
install(CODE "execute_process(COMMAND ${CHGRP} -R ${RUNGROUP} \"\$ENV{DESTDIR}${CMAKE_INSTALL_PREFIX}\")") install(CODE "execute_process(COMMAND ${CHGRP} -R ${RUNGROUP} \"\$ENV{DESTDIR}\${CMAKE_INSTALL_PREFIX}\")")
endif(NOT WIN32 AND RUNGROUP) endif(NOT WIN32 AND RUNGROUP)
# On Windows platforms, install extra files # On Windows platforms, install extra files
if(WIN32) if(WIN32)
+1 -1
View File
@@ -166,7 +166,7 @@ done
# Check for CMake and (optionally) install it # Check for CMake and (optionally) install it
########################################################################### ###########################################################################
which cmake > /dev/null cmake --version 2>&1 > /dev/null
if [ $? -ne 0 ] ; then if [ $? -ne 0 ] ; then
clear clear
echo "Anope requires CMake 2.4 or newer, which can be downloaded at http://cmake.org or through your system's package manager." echo "Anope requires CMake 2.4 or newer, which can be downloaded at http://cmake.org or through your system's package manager."
-18
View File
@@ -542,24 +542,6 @@ module { name = "help" }
*/ */
#module { name = "m_sasl" } #module { name = "m_sasl" }
/*
* m_sasl_dh-aes [EXTRA]
*
* Add the DH-AES mechanism to SASL.
* Requires m_sasl to be loaded.
* Requires openssl.
*/
#module { name = "m_sasl_dh-aes" }
/*
* m_sasl_dh-blowfish [EXTRA]
*
* Add the DH-BLOWFISH mechanism to SASL.
* Requires m_sasl to be loaded.
* Requires openssl.
*/
#module { name = "m_sasl_dh-blowfish" }
/* /*
* m_ssl_gnutls [EXTRA] * m_ssl_gnutls [EXTRA]
* *
+21 -2
View File
@@ -1,4 +1,23 @@
Anope Version 2.0.3-git Anope Version 2.0.4
-------------------
Add notice rpc method to XMLRPC
Fix access check in cs_updown to not allow actions on users with equal access
Fix randomnews to work when there are more than 'newscount' random news
Fix crash from handling nick introduction collisions on unreal4
Add support for GCC6
Fix handling /join 0 on ratbox
Fix saset display to update the account of the proper user
Fix nickserv/confirm to send account and +r when appropriate
Fix chankill to not add duplicate akills
Allow nickserv/maxemail to disregard gmail style aliases when comparing emails
Fix chanserv/mode when setting listmodes with CIDR ranges
Fix reported expiry time when the time is divisible by 1 year
Clearify botserv repeat kicker help and allow setting repeat times to 1
Send vident/vhost with SASL login
Add support for SASL reauth
Fix log and database backup directories to be properly created by the installer
Anope Version 2.0.3
------------------- -------------------
Add support for UnrealIRCd 4 Add support for UnrealIRCd 4
Fix cs_access to respect chanserv/access/list privilege Fix cs_access to respect chanserv/access/list privilege
@@ -16,7 +35,7 @@ Fix crash from unloading regex modules when regex xlines exist
Fix irc2sql to store away messages Fix irc2sql to store away messages
Add notice method to m_xmlrpc_main Add notice method to m_xmlrpc_main
Fix numerics on InspIRCd from being sent to user UID Fix numerics on InspIRCd from being sent to user UID
Fix +I on InspIRCd to be considered oper only Fix usermode +I on UnrealIRCd to be considered oper only
Fix crash in webcpanel when deleting your own access on a channel Fix crash in webcpanel when deleting your own access on a channel
Fix webcpanel allowing suspended users to login Fix webcpanel allowing suspended users to login
Fix hs_off on InspIRCd to not desync active user host Fix hs_off on InspIRCd to not desync active user host
+5 -1
View File
@@ -1,4 +1,8 @@
Anope Version 2.0.3-git Anope Version 2.0.4
-------------------
Removed m_sasl_dh-aes and m_sasl_dh-blowfish
Anope Version 2.0.3
------------------- -------------------
Add operserv/chankill to default globops log Add operserv/chankill to default globops log
Add ns_identify:maxlogins to limit the max number of concurrent logins per account Add ns_identify:maxlogins to limit the max number of concurrent logins per account
+15
View File
@@ -114,6 +114,21 @@ class AnopeXMLRPC
return $this->run("channel", [$channel]); return $this->run("channel", [$channel]);
} }
/**
* Sent a notice to a user.
* Returns an array containing channel information, or an array of size one
* (just containing the name) if the channel does not exist
*
* @param $source
* @param $target
* @param $message
* @return array|null
*/
public function notice($source, $target, $message)
{
return $this->run("notice", [$source, $target, $message]);
}
/** /**
* Like channel(), but different. * Like channel(), but different.
* *
+1 -6
View File
@@ -148,12 +148,7 @@ while (1)
if ($input eq "q") { if ($input eq "q") {
if (-e "build/CMakeFiles") { if (-e "build/CMakeFiles") {
if (-e "cmake-bin") { system("cmake", "build/.");
my $cmake_path = `find cmake-bin -name cmake -print0`;
system($cmake_path, "build/.");
} else {
system("cmake", "build/.");
}
print "\nNow cd build, then run make to build Anope.\n\n"; print "\nNow cd build, then run make to build Anope.\n\n";
} else { } else {
print "\nBuild directory not found. You should run ./Config now.\n\n" print "\nBuild directory not found. You should run ./Config now.\n\n"
+10 -11
View File
@@ -78,12 +78,7 @@ class CoreExport ChanAccess : public Serializable
Serialize::Reference<NickCore> nc; Serialize::Reference<NickCore> nc;
public: public:
typedef std::multimap<const ChanAccess *, const ChanAccess *> Set; typedef std::vector<ChanAccess *> Path;
/* shows the 'path' taken to determine if an access entry matches a user
* .first are access entries checked
* .second are access entries which match
*/
typedef std::pair<Set, Set> Path;
/* The provider that created this access entry */ /* The provider that created this access entry */
AccessProvider *provider; AccessProvider *provider;
@@ -103,12 +98,14 @@ class CoreExport ChanAccess : public Serializable
void Serialize(Serialize::Data &data) const anope_override; void Serialize(Serialize::Data &data) const anope_override;
static Serializable* Unserialize(Serializable *obj, Serialize::Data &); static Serializable* Unserialize(Serializable *obj, Serialize::Data &);
static const unsigned int MAX_DEPTH = 4;
/** Check if this access entry matches the given user or account /** Check if this access entry matches the given user or account
* @param u The user * @param u The user
* @param nc The account * @param nc The account
* @param p The path to the access object which matches will be put here * @param next Next channel to check if any
*/ */
virtual bool Matches(const User *u, const NickCore *nc, Path &p) const; virtual bool Matches(const User *u, const NickCore *nc, ChannelInfo* &next) const;
/** Check if this access entry has the given privilege. /** Check if this access entry has the given privilege.
* @param name The privilege name * @param name The privilege name
@@ -136,13 +133,13 @@ class CoreExport ChanAccess : public Serializable
/* A group of access entries. This is used commonly, for example with ChannelInfo::AccessFor, /* A group of access entries. This is used commonly, for example with ChannelInfo::AccessFor,
* to show what access a user has on a channel because users can match multiple access entries. * to show what access a user has on a channel because users can match multiple access entries.
*/ */
class CoreExport AccessGroup : public std::vector<ChanAccess *> class CoreExport AccessGroup
{ {
public: public:
/* access entries + paths */
std::vector<ChanAccess::Path> paths;
/* Channel these access entries are on */ /* Channel these access entries are on */
const ChannelInfo *ci; const ChannelInfo *ci;
/* Path from these entries to other entries that they depend on */
ChanAccess::Path path;
/* Account these entries affect, if any */ /* Account these entries affect, if any */
const NickCore *nc; const NickCore *nc;
/* super_admin always gets all privs. founder is a special case where ci->founder == nc */ /* super_admin always gets all privs. founder is a special case where ci->founder == nc */
@@ -170,6 +167,8 @@ class CoreExport AccessGroup : public std::vector<ChanAccess *>
bool operator<(const AccessGroup &other) const; bool operator<(const AccessGroup &other) const;
bool operator>=(const AccessGroup &other) const; bool operator>=(const AccessGroup &other) const;
bool operator<=(const AccessGroup &other) const; bool operator<=(const AccessGroup &other) const;
inline bool empty() const { return paths.empty(); }
}; };
#endif #endif
+2
View File
@@ -336,7 +336,9 @@ namespace Anope
template<typename T> class multimap : public std::multimap<string, T, ci::less> { }; template<typename T> class multimap : public std::multimap<string, T, ci::less> { };
template<typename T> class hash_map : public TR1NS::unordered_map<string, T, hash_ci, compare> { }; template<typename T> class hash_map : public TR1NS::unordered_map<string, T, hash_ci, compare> { };
#ifndef REPRODUCIBLE_BUILD
static const char *const compiled = __TIME__ " " __DATE__; static const char *const compiled = __TIME__ " " __DATE__;
#endif
/** The time Anope started. /** The time Anope started.
*/ */
+2
View File
@@ -302,6 +302,8 @@ class CoreExport Channel : public Base, public Extensible
*/ */
static Channel *FindOrCreate(const Anope::string &name, bool &created, time_t ts = Anope::CurTime); static Channel *FindOrCreate(const Anope::string &name, bool &created, time_t ts = Anope::CurTime);
void QueueForDeletion();
static void DeleteChannels(); static void DeleteChannels();
}; };
+1
View File
@@ -18,6 +18,7 @@
class CoreExport Memo : public Serializable class CoreExport Memo : public Serializable
{ {
public: public:
MemoInfo *mi;
bool unread; bool unread;
bool receipt; bool receipt;
Memo(); Memo();
+1
View File
@@ -395,6 +395,7 @@ class CoreExport Entry
Anope::string mask; Anope::string mask;
public: public:
unsigned short cidr_len; unsigned short cidr_len;
int family;
Anope::string nick, user, host, real; Anope::string nick, user, host, real;
/** Constructor /** Constructor
+2 -1
View File
@@ -227,8 +227,9 @@ class CoreExport IRCDProto : public Service
*/ */
virtual void SendOper(User *u); virtual void SendOper(User *u);
virtual void SendSASLMechanisms(std::vector<Anope::string> &) { }
virtual void SendSASLMessage(const SASL::Message &) { } virtual void SendSASLMessage(const SASL::Message &) { }
virtual void SendSVSLogin(const Anope::string &uid, const Anope::string &acc) { } virtual void SendSVSLogin(const Anope::string &uid, const Anope::string &acc, const Anope::string &vident, const Anope::string &vhost) { }
virtual bool IsNickValid(const Anope::string &); virtual bool IsNickValid(const Anope::string &);
virtual bool IsChannelValid(const Anope::string &); virtual bool IsChannelValid(const Anope::string &);
+4
View File
@@ -38,6 +38,10 @@ union CoreExport sockaddrs
*/ */
void clear(); void clear();
/** Get address family.
*/
int family() const;
/** Get the size of the sockaddr we represent /** Get the size of the sockaddr we represent
* @return The size * @return The size
*/ */
+273 -248
View File
File diff suppressed because it is too large Load Diff
+19 -6
View File
@@ -663,17 +663,30 @@ class CommandBSKickRepeat : public CommandBSKickBase
kd->repeattimes = convertTo<int16_t>(times); kd->repeattimes = convertTo<int16_t>(times);
} }
catch (const ConvertException &) { } catch (const ConvertException &) { }
if (kd->repeattimes < 2) if (kd->repeattimes < 1)
kd->repeattimes = 3; kd->repeattimes = 3;
kd->repeat = true; kd->repeat = true;
if (kd->ttb[TTB_REPEAT]) if (kd->ttb[TTB_REPEAT])
source.Reply(_("Bot will now kick for \002repeats\002 (users that say the\n" {
"same thing %d times), and will place a ban after %d\n" if (kd->repeattimes != 1)
"kicks for the same user."), kd->repeattimes + 1, kd->ttb[TTB_REPEAT]); source.Reply(_("Bot will now kick for \002repeats\002 (users that repeat the\n"
"same message %d times), and will place a ban after %d\n"
"kicks for the same user."), kd->repeattimes, kd->ttb[TTB_REPEAT]);
else
source.Reply(_("Bot will now kick for \002repeats\002 (users that repeat the\n"
"same message %d time), and will place a ban after %d\n"
"kicks for the same user."), kd->repeattimes, kd->ttb[TTB_REPEAT]);
}
else else
source.Reply(_("Bot will now kick for \002repeats\002 (users that say the\n" {
"same thing %d times)."), kd->repeattimes + 1); if (kd->repeattimes != 1)
source.Reply(_("Bot will now kick for \002repeats\002 (users that repeat the\n"
"same message %d times)."), kd->repeattimes);
else
source.Reply(_("Bot will now kick for \002repeats\002 (users that repeat the\n"
"same message %d time)."), kd->repeattimes);
}
} }
else if (params[1].equals_ci("OFF")) else if (params[1].equals_ci("OFF"))
{ {
+2 -2
View File
@@ -370,7 +370,7 @@ class CommandCSAccess : public Command
if (ci->c) if (ci->c)
for (Channel::ChanUserList::const_iterator cit = ci->c->users.begin(), cit_end = ci->c->users.end(); cit != cit_end; ++cit) for (Channel::ChanUserList::const_iterator cit = ci->c->users.begin(), cit_end = ci->c->users.end(); cit != cit_end; ++cit)
{ {
ChanAccess::Path p; ChannelInfo *p;
if (access->Matches(cit->second->user, cit->second->user->Account(), p)) if (access->Matches(cit->second->user, cit->second->user->Account(), p))
timebuf = "Now"; timebuf = "Now";
} }
@@ -407,7 +407,7 @@ class CommandCSAccess : public Command
if (ci->c) if (ci->c)
for (Channel::ChanUserList::const_iterator cit = ci->c->users.begin(), cit_end = ci->c->users.end(); cit != cit_end; ++cit) for (Channel::ChanUserList::const_iterator cit = ci->c->users.begin(), cit_end = ci->c->users.end(); cit != cit_end; ++cit)
{ {
ChanAccess::Path p; ChannelInfo *p;
if (access->Matches(cit->second->user, cit->second->user->Account(), p)) if (access->Matches(cit->second->user, cit->second->user->Account(), p))
timebuf = "Now"; timebuf = "Now";
} }
+1
View File
@@ -169,6 +169,7 @@ public:
delete target_ci; delete target_ci;
target_ci = new ChannelInfo(*ci); target_ci = new ChannelInfo(*ci);
target_ci->name = target; target_ci->name = target;
target_ci->time_registered = Anope::CurTime;
(*RegisteredChannelList)[target_ci->name] = target_ci; (*RegisteredChannelList)[target_ci->name] = target_ci;
target_ci->c = Channel::Find(target_ci->name); target_ci->c = Channel::Find(target_ci->name);
+7 -2
View File
@@ -236,9 +236,14 @@ class CommandSeen : public Command
AccessGroup ag = source.c->ci->AccessFor(na->nc); AccessGroup ag = source.c->ci->AccessFor(na->nc);
time_t last = 0; time_t last = 0;
for (unsigned i = 0; i < ag.size(); ++i) for (unsigned int i = 0; i < ag.paths.size(); ++i)
{ {
ChanAccess *a = ag[i]; ChanAccess::Path &p = ag.paths[i];
if (p.empty())
continue;
ChanAccess *a = p[p.size() - 1];
if (a->GetAccount() == na->nc && a->last_seen > last) if (a->GetAccount() == na->nc && a->last_seen > last)
last = a->last_seen; last = a->last_seen;
+4 -4
View File
@@ -742,10 +742,9 @@ class CommandCSSetSecure : public Command
this->SendSyntax(source); this->SendSyntax(source);
source.Reply(" "); source.Reply(" ");
source.Reply(_("Enables or disables security features for a\n" source.Reply(_("Enables or disables security features for a\n"
"channel. When \002%s\002 is set, only users who have\n" "channel. When \002SECURE\002 is set, only users who have\n"
"registered their nicknames and IDENTIFY'd\n" "identified to services, and are not only recognized, will be\n"
"with their password will be given access to the channel\n" "given access to channels from account-based access entries."));
"as controlled by the access list."), this->name.c_str());
return true; return true;
} }
}; };
@@ -1136,6 +1135,7 @@ class CSSet : public Module
ChannelInfo *ci = anope_dynamic_static_cast<ChannelInfo *>(s); ChannelInfo *ci = anope_dynamic_static_cast<ChannelInfo *>(s);
Anope::string modes; Anope::string modes;
data["last_modes"] >> modes; data["last_modes"] >> modes;
ci->last_modes.clear();
for (spacesepstream sep(modes); sep.GetToken(modes);) for (spacesepstream sep(modes); sep.GetToken(modes);)
{ {
size_t c = modes.find(','); size_t c = modes.find(',');
+18 -3
View File
@@ -57,11 +57,26 @@ public:
{ {
source.Reply(_("Access for \002%s\002 on \002%s\002:"), nick.c_str(), ci->name.c_str()); source.Reply(_("Access for \002%s\002 on \002%s\002:"), nick.c_str(), ci->name.c_str());
for (unsigned i = 0; i < ag.size(); ++i) for (unsigned i = 0; i < ag.paths.size(); ++i)
{ {
ChanAccess *acc = ag[i]; ChanAccess::Path &p = ag.paths[i];
source.Reply(_("\002%s\002 matches access entry %s, which has privilege %s."), nick.c_str(), acc->Mask().c_str(), acc->AccessSerialize().c_str()); if (p.empty())
continue;
if (p.size() == 1)
{
ChanAccess *acc = p[0];
source.Reply(_("\002%s\002 matches access entry %s, which has privilege %s."), nick.c_str(), acc->Mask().c_str(), acc->AccessSerialize().c_str());
}
else
{
ChanAccess *first = p[0];
ChanAccess *acc = p[p.size() - 1];
source.Reply(_("\002%s\002 matches access entry %s (from entry %s), which has privilege %s."), nick.c_str(), acc->Mask().c_str(), first->Mask().c_str(), acc->AccessSerialize().c_str());
}
} }
} }
+2 -2
View File
@@ -101,7 +101,7 @@ class CommandCSUp : public Command
} }
else if (source.GetUser() && u != source.GetUser() && c->ci->HasExt("PEACE")) else if (source.GetUser() && u != source.GetUser() && c->ci->HasExt("PEACE"))
{ {
if (c->ci->AccessFor(u) > c->ci->AccessFor(source.GetUser())) if (c->ci->AccessFor(u) >= c->ci->AccessFor(source.GetUser()))
{ {
if (source.HasPriv("chanserv/administration")) if (source.HasPriv("chanserv/administration"))
override = true; override = true;
@@ -199,7 +199,7 @@ class CommandCSDown : public Command
} }
else if (source.GetUser() && u != source.GetUser() && c->ci->HasExt("PEACE")) else if (source.GetUser() && u != source.GetUser() && c->ci->HasExt("PEACE"))
{ {
if (c->ci->AccessFor(u) > c->ci->AccessFor(source.GetUser())) if (c->ci->AccessFor(u) >= c->ci->AccessFor(source.GetUser()))
{ {
if (source.HasPriv("chanserv/administration")) if (source.HasPriv("chanserv/administration"))
override = true; override = true;
+11 -2
View File
@@ -86,8 +86,17 @@ class CommandNSAList : public Command
entry["Number"] = stringify(chan_count); entry["Number"] = stringify(chan_count);
entry["Channel"] = (ci->HasExt("CS_NO_EXPIRE") ? "!" : "") + ci->name; entry["Channel"] = (ci->HasExt("CS_NO_EXPIRE") ? "!" : "") + ci->name;
for (unsigned j = 0; j < access.size(); ++j) for (unsigned j = 0; j < access.paths.size(); ++j)
entry["Access"] = entry["Access"] + ", " + access[j]->AccessSerialize(); {
ChanAccess::Path &p = access.paths[j];
// not interested in indirect access
if (p.size() != 1)
continue;
ChanAccess *a = p[0];
entry["Access"] = entry["Access"] + ", " + a->AccessSerialize();
}
entry["Access"] = entry["Access"].substr(2); entry["Access"] = entry["Access"].substr(2);
entry["Description"] = ci->desc; entry["Description"] = ci->desc;
list.AddEntry(entry); list.AddEntry(entry);
+14
View File
@@ -40,6 +40,20 @@ class CommandNSConfirm : public Command
FOREACH_MOD(OnNickConfirm, (source.GetUser(), na->nc)); FOREACH_MOD(OnNickConfirm, (source.GetUser(), na->nc));
Log(LOG_ADMIN, source, this) << "to confirm nick " << na->nick << " (" << na->nc->display << ")"; Log(LOG_ADMIN, source, this) << "to confirm nick " << na->nick << " (" << na->nc->display << ")";
source.Reply(_("Nick \002%s\002 has been confirmed."), na->nick.c_str()); source.Reply(_("Nick \002%s\002 has been confirmed."), na->nick.c_str());
/* Login the users online already */
for (std::list<User *>::iterator it = na->nc->users.begin(); it != na->nc->users.end(); ++it)
{
User *u = *it;
IRCD->SendLogin(u, na);
NickAlias *u_na = NickAlias::Find(u->nick);
/* Set +r if they're on a nick in the group */
if (!Config->GetModule("nickserv")->Get<bool>("nonicknameownership") && u_na && *u_na->nc == *na->nc)
u->SetMode(source.service, "REGISTERED");
}
} }
} }
else if (source.nc) else if (source.nc)
+9 -2
View File
@@ -361,8 +361,14 @@ class CommandNSSetDisplay : public Command
Log(user_na->nc == source.GetAccount() ? LOG_COMMAND : LOG_ADMIN, source, this) << "to change the display of " << user_na->nc->display << " to " << na->nick; Log(user_na->nc == source.GetAccount() ? LOG_COMMAND : LOG_ADMIN, source, this) << "to change the display of " << user_na->nc->display << " to " << na->nick;
user_na->nc->SetDisplay(na); user_na->nc->SetDisplay(na);
if (source.GetUser())
IRCD->SendLogin(source.GetUser(), na); /* Send updated account name */
for (std::list<User *>::iterator it = user_na->nc->users.begin(); it != user_na->nc->users.end(); ++it)
{
User *u = *it;
IRCD->SendLogin(u, user_na);
}
source.Reply(NICK_SET_DISPLAY_CHANGED, user_na->nc->display.c_str()); source.Reply(NICK_SET_DISPLAY_CHANGED, user_na->nc->display.c_str());
} }
@@ -1205,6 +1211,7 @@ class NSSet : public Module
NickCore *nc = anope_dynamic_static_cast<NickCore *>(s); NickCore *nc = anope_dynamic_static_cast<NickCore *>(s);
Anope::string modes; Anope::string modes;
data["last_modes"] >> modes; data["last_modes"] >> modes;
nc->last_modes.clear();
for (spacesepstream sep(modes); sep.GetToken(modes);) for (spacesepstream sep(modes); sep.GetToken(modes);)
{ {
size_t c = modes.find(','); size_t c = modes.find(',');
+5 -1
View File
@@ -76,7 +76,11 @@ class CommandOSChanKill : public Command
if (uc->user->server == Me || uc->user->HasMode("OPER")) if (uc->user->server == Me || uc->user->HasMode("OPER"))
continue; continue;
XLine *x = new XLine("*@" + uc->user->host, source.GetNick(), expires, realreason, XLineManager::GenerateUID()); Anope::string akillmask = "*@" + uc->user->host;
if (akills->HasEntry(akillmask))
continue;
XLine *x = new XLine(akillmask, source.GetNick(), expires, realreason, XLineManager::GenerateUID());
akills->AddXLine(x); akills->AddXLine(x);
akills->OnMatch(uc->user, x); akills->OnMatch(uc->user, x);
} }
+1 -2
View File
@@ -354,8 +354,7 @@ class OSDefcon : public Module
dconfig.message = block->Get<const Anope::string>("message"); dconfig.message = block->Get<const Anope::string>("message");
dconfig.offmessage = block->Get<const Anope::string>("offmessage"); dconfig.offmessage = block->Get<const Anope::string>("offmessage");
Module *session = ModuleManager::FindModule("os_session"); block = conf->GetModule("os_session");
block = conf->GetModule(session);
dconfig.max_session_kill = block->Get<int>("maxsessionkill"); dconfig.max_session_kill = block->Get<int>("maxsessionkill");
dconfig.session_autokill_expiry = block->Get<time_t>("sessionautokillexpiry"); dconfig.session_autokill_expiry = block->Get<time_t>("sessionautokillexpiry");
+1 -1
View File
@@ -405,7 +405,7 @@ class OSNews : public Module
int start = 0; int start = 0;
if (type != NEWS_RANDOM) if (Type != NEWS_RANDOM)
{ {
start = newsList.size() - news_count; start = newsList.size() - news_count;
if (start < 0) if (start < 0)
+4 -4
View File
@@ -23,8 +23,8 @@ class StatusUpdate : public Module
{ {
User *user = it->second->user; User *user = it->second->user;
ChanAccess::Path p; ChannelInfo *next;
if (user->server != Me && access->Matches(user, user->Account(), p)) if (user->server != Me && access->Matches(user, user->Account(), next))
{ {
AccessGroup ag = ci->AccessFor(user); AccessGroup ag = ci->AccessFor(user);
@@ -46,8 +46,8 @@ class StatusUpdate : public Module
{ {
User *user = it->second->user; User *user = it->second->user;
ChanAccess::Path p; ChannelInfo *next;
if (user->server != Me && access->Matches(user, user->Account(), p)) if (user->server != Me && access->Matches(user, user->Account(), next))
{ {
AccessGroup ag = ci->AccessFor(user); AccessGroup ag = ci->AccessFor(user);
+2
View File
@@ -590,6 +590,7 @@ static void LoadNicks()
READ(read_string(m->text, f)); READ(read_string(m->text, f));
m->owner = nc->display; m->owner = nc->display;
nc->memos.memos->push_back(m); nc->memos.memos->push_back(m);
m->mi = &nc->memos;
} }
READ(read_uint16(&u16, f)); READ(read_uint16(&u16, f));
READ(read_int16(&i16, f)); READ(read_int16(&i16, f));
@@ -956,6 +957,7 @@ static void LoadChannels()
READ(read_string(m->text, f)); READ(read_string(m->text, f));
m->owner = ci->name; m->owner = ci->name;
ci->memos.memos->push_back(m); ci->memos.memos->push_back(m);
m->mi = &ci->memos;
} }
READ(read_string(buffer, f)); READ(read_string(buffer, f));
-193
View File
@@ -1,193 +0,0 @@
/*
*
* (C) 2014 Daniel Vassdal <shutter@canternet.org>
* (C) 2014-2016 Anope Team
* Contact us at team@anope.org
*
* Please read COPYING and README for further details.
*/
/* RequiredLibraries: ssl,crypto */
/* RequiredWindowsLibraries: ssleay32,libeay32 */
#include "module.h"
#include "modules/sasl.h"
#include <openssl/bn.h>
#include <openssl/dh.h>
#include <openssl/aes.h>
using namespace SASL;
class DHAES : public Mechanism
{
void Err(Session* sess, BIGNUM* key = NULL)
{
if (key)
BN_free(key);
sasl->Fail(sess);
delete sess;
}
public:
struct DHAESSession : SASL::Session
{
DH* dh;
DHAESSession(Mechanism *m, const Anope::string &u, DH* dh_params) : SASL::Session(m, u)
{
if (!(dh = DH_new()))
return;
dh->g = BN_dup(dh_params->g);
dh->p = BN_dup(dh_params->p);
if (!DH_generate_key(dh))
{
DH_free(dh);
dh = NULL;
}
}
~DHAESSession()
{
if (dh)
DH_free(dh);
}
};
DH* dh_params;
const size_t keysize;
SASL::Session* CreateSession(const Anope::string &uid) anope_override
{
return new DHAESSession(this, uid, dh_params);
}
DHAES(Module *o) : Mechanism(o, "DH-AES"), keysize(256 / 8)
{
if (!(dh_params = DH_new()))
throw ModuleException("DH_new() failed!");
if (!DH_generate_parameters_ex(dh_params, keysize * 8, 5, NULL))
{
DH_free(dh_params);
throw ModuleException("Could not generate DH-params");
}
}
~DHAES()
{
DH_free(dh_params);
}
void ProcessMessage(SASL::Session *session, const SASL::Message &m) anope_override
{
DHAESSession *sess = anope_dynamic_static_cast<DHAESSession *>(session);
if (!sess->dh)
{
sasl->SendMessage(sess, "D", "A");
delete sess;
return;
}
if (m.type == "S")
{
// Format: [ss]<p>[ss]<g>[ss]<pub_key>
// Where ss is a unsigned short with the size of the key
const BIGNUM* dhval[] = { sess->dh->p, sess->dh->g, sess->dh->pub_key };
// Find the size of our buffer - initialized at 6 because of string size data
size_t size = 6;
for (size_t i = 0; i < 3; i++)
size += BN_num_bytes(dhval[i]);
// Fill in the DH data
std::vector<unsigned char> buffer(size);
for (size_t i = 0, pos = 0; i < 3; i++)
{
*reinterpret_cast<uint16_t*>(&buffer[pos]) = htons(BN_num_bytes(dhval[i]));
pos += 2;
BN_bn2bin(dhval[i], &buffer[pos]);
pos += BN_num_bytes(dhval[i]);
}
Anope::string encoded;
Anope::B64Encode(Anope::string(buffer.begin(), buffer.end()), encoded);
sasl->SendMessage(sess, "C", encoded);
}
else if (m.type == "C")
{
// Make sure we have some data - actual size check is done later
if (m.data.length() < 10)
return Err(sess);
// Format: [ss]<key>[ss]<iv>[ss]<encrypted>
// <encrypted> = <username>\0<password>\0
Anope::string decoded;
Anope::B64Decode(m.data, decoded);
// Make sure we have an IV and at least one encrypted block
if ((decoded.length() < keysize + 2 + (AES_BLOCK_SIZE * 2)) || ((decoded.length() - keysize - 2) % AES_BLOCK_SIZE))
return Err(sess);
const unsigned char* data = reinterpret_cast<const unsigned char*>(decoded.data());
// Control the size of the key
if (ntohs(*reinterpret_cast<const uint16_t*>(&data[0])) != keysize)
return Err(sess);
// Convert pubkey from binary
size_t pos = 2;
BIGNUM* pubkey = BN_bin2bn(&data[pos], keysize, NULL);
if (!pubkey)
return Err(sess);
// Find shared key
std::vector<unsigned char> secretkey(keysize);
if (DH_compute_key(&secretkey[0], pubkey, sess->dh) != static_cast<int>(keysize))
return Err(sess, pubkey);
// Set decryption key
AES_KEY AESKey;
AES_set_decrypt_key(&secretkey[0], keysize * 8, &AESKey);
// Fetch IV
pos += keysize;
std::vector<unsigned char> IV(data + pos, data + pos + AES_BLOCK_SIZE);
// Find encrypted blocks, and decrypt
pos += AES_BLOCK_SIZE;
size_t size = decoded.length() - pos;
std::vector<char> decrypted(size + 2, 0);
AES_cbc_encrypt(&data[pos], reinterpret_cast<unsigned char*>(&decrypted[0]), size, &AESKey, &IV[0], AES_DECRYPT);
std::string username = &decrypted[0];
std::string password = &decrypted[username.length() + 1];
if (username.empty() || password.empty() || !IRCD->IsNickValid(username) || password.find_first_of("\r\n") != Anope::string::npos)
return Err(sess, pubkey);
SASL::IdentifyRequest* req = new SASL::IdentifyRequest(this->owner, m.source, username, password);
FOREACH_MOD(OnCheckAuthentication, (NULL, req));
req->Dispatch();
BN_free(pubkey);
}
}
};
class ModuleSASLDHAES : public Module
{
DHAES dhaes;
public:
ModuleSASLDHAES(const Anope::string &modname, const Anope::string &creator) : Module(modname, creator, VENDOR | EXTRA),
dhaes(this)
{
}
};
MODULE_INIT(ModuleSASLDHAES)
-203
View File
@@ -1,203 +0,0 @@
/*
*
* (C) 2014 Daniel Vassdal <shutter@canternet.org>
* (C) 2011-2016 Anope Team
* Contact us at team@anope.org
*
* Please read COPYING and README for further details.
*/
/* RequiredLibraries: ssl,crypto */
/* RequiredWindowsLibraries: ssleay32,libeay32 */
#include "module.h"
#include "modules/sasl.h"
#include <openssl/bn.h>
#include <openssl/dh.h>
#include <openssl/blowfish.h>
using namespace SASL;
class DHBS : public Mechanism
{
void Err(Session* sess, BIGNUM* key = NULL)
{
if (key)
BN_free(key);
sasl->Fail(sess);
delete sess;
}
public:
struct DHBSSession : SASL::Session
{
DH* dh;
DHBSSession(Mechanism *m, const Anope::string &u, DH* dh_params) : SASL::Session(m, u)
{
if (!(dh = DH_new()))
return;
dh->g = BN_dup(dh_params->g);
dh->p = BN_dup(dh_params->p);
if (!DH_generate_key(dh))
{
DH_free(dh);
dh = NULL;
}
}
~DHBSSession()
{
if (dh)
DH_free(dh);
}
};
DH* dh_params;
const size_t keysize;
SASL::Session* CreateSession(const Anope::string &uid) anope_override
{
return new DHBSSession(this, uid, dh_params);
}
DHBS(Module *o) : Mechanism(o, "DH-BLOWFISH"), keysize(256 / 8)
{
if (!(dh_params = DH_new()))
throw ModuleException("DH_new() failed!");
if (!DH_generate_parameters_ex(dh_params, keysize * 8, 5, NULL))
{
DH_free(dh_params);
throw ModuleException("Could not generate DH-params");
}
}
~DHBS()
{
DH_free(dh_params);
}
void ProcessMessage(SASL::Session *session, const SASL::Message &m) anope_override
{
DHBSSession *sess = anope_dynamic_static_cast<DHBSSession *>(session);
if (!sess->dh)
{
sasl->SendMessage(sess, "D", "A");
delete sess;
return;
}
if (m.type == "S")
{
// Format: [ss]<p>[ss]<g>[ss]<pub_key>
// Where ss is a unsigned short with the size of the key
const BIGNUM* dhval[] = { sess->dh->p, sess->dh->g, sess->dh->pub_key };
// Find the size of our buffer - initialized at 6 because of string size data
size_t size = 6;
for (size_t i = 0; i < 3; i++)
size += BN_num_bytes(dhval[i]);
// Fill in the DH data
std::vector<unsigned char> buffer(size);
for (size_t i = 0, pos = 0; i < 3; i++)
{
*reinterpret_cast<uint16_t*>(&buffer[pos]) = htons(BN_num_bytes(dhval[i]));
pos += 2;
BN_bn2bin(dhval[i], &buffer[pos]);
pos += BN_num_bytes(dhval[i]);
}
Anope::string encoded;
Anope::B64Encode(Anope::string(buffer.begin(), buffer.end()), encoded);
sasl->SendMessage(sess, "C", encoded);
}
else if (m.type == "C")
{
// Make sure we have some data - actual size check is done later
if (m.data.length() < 10)
return Err(sess);
// Format: [ss]<key><username><\0><encrypted>
Anope::string decoded;
Anope::B64Decode(m.data, decoded);
// As we rely on the client giving us a null terminator at the right place,
// let's add one extra in case the client tries to crash us
const size_t decodedlen = decoded.length();
decoded.push_back('\0');
// Make sure we have enough data for at least the key, a one letter username, and a block of data
if (decodedlen < keysize + 2 + 2 + 8)
return Err(sess);
const unsigned char* data = reinterpret_cast<const unsigned char*>(decoded.data());
// Control the size of the key
if (ntohs(*reinterpret_cast<const uint16_t*>(&data[0])) != keysize)
return Err(sess);
// Convert pubkey from binary
size_t pos = 2;
BIGNUM* pubkey = BN_bin2bn(&data[pos], keysize, NULL);
if (!pubkey)
return Err(sess);
// Find shared key
std::vector<unsigned char> secretkey(DH_size(sess->dh) + 1, 0);
if (DH_compute_key(&secretkey[0], pubkey, sess->dh) != static_cast<int>(keysize))
return Err(sess, pubkey);
// Set decryption key
BF_KEY BFKey;
BF_set_key(&BFKey, keysize, &secretkey[0]);
pos += keysize;
const Anope::string username = reinterpret_cast<const char*>(&data[pos]);
// Check that the username is valid, and that we have at least one block of data
// 2 + 1 + 8 = uint16_t size for keylen, \0 for username, 8 for one block of data
if (username.empty() || username.length() + keysize + 2 + 1 + 8 > decodedlen || !IRCD->IsNickValid(username))
return Err(sess, pubkey);
pos += username.length() + 1;
size_t size = decodedlen - pos;
// Blowfish data blocks are 64 bits wide - valid format?
if (size % 8)
return Err(sess, pubkey);
std::vector<char> decrypted(size + 1, 0);
for (size_t i = 0; i < size; i += 8)
BF_ecb_encrypt(&data[pos + i], reinterpret_cast<unsigned char*>(&decrypted[i]), &BFKey, BF_DECRYPT);
std::string password = &decrypted[0];
if (password.empty() || password.find_first_of("\r\n") != Anope::string::npos)
return Err(sess, pubkey);
SASL::IdentifyRequest* req = new SASL::IdentifyRequest(this->owner, m.source, username, password);
FOREACH_MOD(OnCheckAuthentication, (NULL, req));
req->Dispatch();
BN_free(pubkey);
}
}
};
class ModuleSASLDHBS : public Module
{
DHBS dhbs;
public:
ModuleSASLDHBS(const Anope::string &modname, const Anope::string &creator) : Module(modname, creator, VENDOR | EXTRA),
dhbs(this)
{
}
};
MODULE_INIT(ModuleSASLDHBS)
+12 -6
View File
@@ -103,8 +103,7 @@ class Packet : public Query
/* +1 pos either to one byte after the compression pointer or one byte after the ending \0 */ /* +1 pos either to one byte after the compression pointer or one byte after the ending \0 */
++pos; ++pos;
if (name.empty()) /* Empty names are valid (root domain) */
throw SocketException("Unable to unpack name - no name");
Log(LOG_DEBUG_2) << "Resolver: UnpackName successfully unpacked " << name; Log(LOG_DEBUG_2) << "Resolver: UnpackName successfully unpacked " << name;
@@ -253,11 +252,18 @@ class Packet : public Query
for (unsigned i = 0; i < ancount; ++i) for (unsigned i = 0; i < ancount; ++i)
this->answers.push_back(this->UnpackResourceRecord(input, len, packet_pos)); this->answers.push_back(this->UnpackResourceRecord(input, len, packet_pos));
for (unsigned i = 0; i < nscount; ++i) try
this->authorities.push_back(this->UnpackResourceRecord(input, len, packet_pos)); {
for (unsigned i = 0; i < nscount; ++i)
this->authorities.push_back(this->UnpackResourceRecord(input, len, packet_pos));
for (unsigned i = 0; i < arcount; ++i) for (unsigned i = 0; i < arcount; ++i)
this->additional.push_back(this->UnpackResourceRecord(input, len, packet_pos)); this->additional.push_back(this->UnpackResourceRecord(input, len, packet_pos));
}
catch (const SocketException &ex)
{
Log(LOG_DEBUG_2) << "Unable to parse ns/ar records: " << ex.GetReason();
}
} }
unsigned short Pack(unsigned char *output, unsigned short output_size) unsigned short Pack(unsigned char *output, unsigned short output_size)
+45 -2
View File
@@ -97,7 +97,7 @@ class External : public Mechanism
} }
else if (m.type == "C") else if (m.type == "C")
{ {
if (!certs) if (!certs || mysess->cert.empty())
{ {
sasl->Fail(sess); sasl->Fail(sess);
delete sess; delete sess;
@@ -223,7 +223,18 @@ class SASLService : public SASL::Service, public Timer
void Succeed(Session *session, NickCore *nc) anope_override void Succeed(Session *session, NickCore *nc) anope_override
{ {
IRCD->SendSVSLogin(session->uid, nc->display); // If the user is already introduced then we log them in now.
// Otherwise, we send an SVSLOGIN to log them in later.
User *user = User::Find(session->uid);
NickAlias *na = NickAlias::Find(nc->display);
if (user)
{
user->Identify(na);
}
else
{
IRCD->SendSVSLogin(session->uid, nc->display, na->GetVhostIdent(), na->GetVhostHost());
}
this->SendMessage(session, "D", "S"); this->SendMessage(session, "D", "S");
} }
@@ -266,6 +277,21 @@ class ModuleSASL : public Module
Plain plain; Plain plain;
External *external; External *external;
std::vector<Anope::string> mechs;
void CheckMechs()
{
std::vector<Anope::string> newmechs = ::Service::GetServiceKeys("SASL::Mechanism");
if (newmechs == mechs)
return;
mechs = newmechs;
// If we are connected to the network then broadcast the mechlist.
if (Me && Me->IsSynced())
IRCD->SendSASLMechanisms(mechs);
}
public: public:
ModuleSASL(const Anope::string &modname, const Anope::string &creator) : Module(modname, creator, VENDOR), ModuleSASL(const Anope::string &modname, const Anope::string &creator) : Module(modname, creator, VENDOR),
sasl(this), plain(this), external(NULL) sasl(this), plain(this), external(NULL)
@@ -273,6 +299,7 @@ class ModuleSASL : public Module
try try
{ {
external = new External(this); external = new External(this);
CheckMechs();
} }
catch (ModuleException &) { } catch (ModuleException &) { }
} }
@@ -281,6 +308,22 @@ class ModuleSASL : public Module
{ {
delete external; delete external;
} }
void OnModuleLoad(User *, Module *) anope_override
{
CheckMechs();
}
void OnModuleUnload(User *, Module *) anope_override
{
CheckMechs();
}
void OnPreUplinkSync(Server *) anope_override
{
// We have not yet sent a mechanism list so always do it here.
IRCD->SendSASLMechanisms(mechs);
}
}; };
MODULE_INIT(ModuleSASL) MODULE_INIT(ModuleSASL)
+2
View File
@@ -273,6 +273,8 @@ class MyXMLRPCEvent : public XMLRPCEvent
return; return;
u->SendMessage(bi, message); u->SendMessage(bi, message);
request.reply("result", "Success");
} }
}; };
+32 -1
View File
@@ -14,6 +14,27 @@
class NSMaxEmail : public Module class NSMaxEmail : public Module
{ {
bool clean;
/* strip dots from username, and remove anything after the first + */
Anope::string CleanMail(const Anope::string &email)
{
size_t host = email.find('@');
if (host == Anope::string::npos)
return email;
Anope::string username = email.substr(0, host);
username = username.replace_all_cs(".", "");
size_t sz = username.find('+');
if (sz != Anope::string::npos)
username = username.substr(0, sz);
Anope::string cleaned = username + email.substr(host);
Log(LOG_DEBUG) << "cleaned " << email << " to " << cleaned;
return cleaned;
}
bool CheckLimitReached(CommandSource &source, const Anope::string &email) bool CheckLimitReached(CommandSource &source, const Anope::string &email)
{ {
int NSEmailMax = Config->GetModule(this)->Get<int>("maxemails"); int NSEmailMax = Config->GetModule(this)->Get<int>("maxemails");
@@ -39,11 +60,15 @@ class NSMaxEmail : public Module
if (email.empty()) if (email.empty())
return 0; return 0;
Anope::string cleanemail = clean ? CleanMail(email) : email;
for (nickcore_map::const_iterator it = NickCoreList->begin(), it_end = NickCoreList->end(); it != it_end; ++it) for (nickcore_map::const_iterator it = NickCoreList->begin(), it_end = NickCoreList->end(); it != it_end; ++it)
{ {
const NickCore *nc = it->second; const NickCore *nc = it->second;
if (unc != nc && !nc->email.empty() && nc->email.equals_ci(email)) Anope::string cleannc = clean ? CleanMail(nc->email) : nc->email;
if (unc != nc && cleanemail == cleannc)
++count; ++count;
} }
@@ -52,9 +77,15 @@ class NSMaxEmail : public Module
public: public:
NSMaxEmail(const Anope::string &modname, const Anope::string &creator) : Module(modname, creator, VENDOR) NSMaxEmail(const Anope::string &modname, const Anope::string &creator) : Module(modname, creator, VENDOR)
, clean(false)
{ {
} }
void OnReload(Configuration::Conf *conf) anope_override
{
clean = conf->GetModule(this)->Get<bool>("remove_aliases", "true");
}
EventReturn OnPreCommand(CommandSource &source, Command *command, std::vector<Anope::string> &params) anope_override EventReturn OnPreCommand(CommandSource &source, Command *command, std::vector<Anope::string> &params) anope_override
{ {
if (source.IsOper()) if (source.IsOper())
+6 -1
View File
@@ -386,7 +386,12 @@ struct IRCDMessageNick : IRCDMessage
User::OnIntroduce(params[0], params[4], params[5], "", params[8], s, params[9], signon, params[3], "", na ? *na->nc : NULL); User::OnIntroduce(params[0], params[4], params[5], "", params[8], s, params[9], signon, params[3], "", na ? *na->nc : NULL);
} }
else else
source.GetUser()->ChangeNick(params[0]); {
User *u = source.GetUser();
if (u)
u->ChangeNick(params[0]);
}
} }
}; };
+48 -6
View File
@@ -31,13 +31,29 @@ class ChannelModeLargeBan : public ChannelMode
class CharybdisProto : public IRCDProto class CharybdisProto : public IRCDProto
{ {
BotInfo *FindIntroduced()
{
BotInfo *bi = Config->GetClient("OperServ");
if (bi && bi->introduced)
return bi;
for (botinfo_map::iterator it = BotListByNick->begin(), it_end = BotListByNick->end(); it != it_end; ++it)
if (it->second->introduced)
return it->second;
return NULL;
}
public: public:
CharybdisProto(Module *creator) : IRCDProto(creator, "Charybdis 3.4+") CharybdisProto(Module *creator) : IRCDProto(creator, "Charybdis 3.4+")
{ {
DefaultPseudoclientModes = "+oiS"; DefaultPseudoclientModes = "+oiS";
CanCertFP = true; CanCertFP = true;
CanSNLine = true; CanSNLine = true;
CanSQLine = true; CanSQLine = true;
CanSQLineChannel = true;
CanSZLine = true; CanSZLine = true;
CanSVSNick = true; CanSVSNick = true;
CanSVSHold = true; CanSVSHold = true;
@@ -54,7 +70,6 @@ class CharybdisProto : public IRCDProto
void SendSGLineDel(const XLine *x) anope_override { ratbox->SendSGLineDel(x); } void SendSGLineDel(const XLine *x) anope_override { ratbox->SendSGLineDel(x); }
void SendAkill(User *u, XLine *x) anope_override { ratbox->SendAkill(u, x); } void SendAkill(User *u, XLine *x) anope_override { ratbox->SendAkill(u, x); }
void SendAkillDel(const XLine *x) anope_override { ratbox->SendAkillDel(x); } void SendAkillDel(const XLine *x) anope_override { ratbox->SendAkillDel(x); }
void SendSQLineDel(const XLine *x) anope_override { ratbox->SendSQLineDel(x); }
void SendJoin(User *user, Channel *c, const ChannelStatus *status) anope_override { ratbox->SendJoin(user, c, status); } void SendJoin(User *user, Channel *c, const ChannelStatus *status) anope_override { ratbox->SendJoin(user, c, status); }
void SendServer(const Server *server) anope_override { ratbox->SendServer(server); } void SendServer(const Server *server) anope_override { ratbox->SendServer(server); }
void SendChannel(Channel *c) anope_override { ratbox->SendChannel(c); } void SendChannel(Channel *c) anope_override { ratbox->SendChannel(c); }
@@ -63,9 +78,32 @@ class CharybdisProto : public IRCDProto
void SendLogin(User *u, NickAlias *na) anope_override { ratbox->SendLogin(u, na); } void SendLogin(User *u, NickAlias *na) anope_override { ratbox->SendLogin(u, na); }
void SendLogout(User *u) anope_override { ratbox->SendLogout(u); } void SendLogout(User *u) anope_override { ratbox->SendLogout(u); }
void SendSASLMechanisms(std::vector<Anope::string> &mechanisms) anope_override
{
Anope::string mechlist;
for (unsigned i = 0; i < mechanisms.size(); ++i)
{
mechlist += "," + mechanisms[i];
}
UplinkSocket::Message(Me) << "ENCAP * MECHLIST :" << (mechanisms.empty() ? "" : mechlist.substr(1));
}
void SendSQLine(User *, const XLine *x) anope_override void SendSQLine(User *, const XLine *x) anope_override
{ {
UplinkSocket::Message(Me) << "RESV * " << x->mask << " :" << x->GetReason(); /* Calculate the time left before this would expire, capping it at 2 days */
time_t timeleft = x->expires - Anope::CurTime;
if (timeleft > 172800 || !x->expires)
timeleft = 172800;
UplinkSocket::Message(FindIntroduced()) << "ENCAP * RESV " << timeleft << " " << x->mask << " 0 :" << x->GetReason();
}
void SendSQLineDel(const XLine *x) anope_override
{
UplinkSocket::Message(Config->GetClient("OperServ")) << "ENCAP * UNRESV " << x->mask;
} }
void SendConnect() anope_override void SendConnect() anope_override
@@ -147,17 +185,21 @@ class CharybdisProto : public IRCDProto
UplinkSocket::Message(Me) << "ENCAP " << (s ? s->GetName() : message.target.substr(0, 3)) << " SASL " << message.source << " " << message.target << " " << message.type << " " << message.data << (message.ext.empty() ? "" : (" " + message.ext)); UplinkSocket::Message(Me) << "ENCAP " << (s ? s->GetName() : message.target.substr(0, 3)) << " SASL " << message.source << " " << message.target << " " << message.type << " " << message.data << (message.ext.empty() ? "" : (" " + message.ext));
} }
void SendSVSLogin(const Anope::string &uid, const Anope::string &acc) anope_override void SendSVSLogin(const Anope::string &uid, const Anope::string &acc, const Anope::string &vident, const Anope::string &vhost) anope_override
{ {
Server *s = Server::Find(uid.substr(0, 3)); Server *s = Server::Find(uid.substr(0, 3));
UplinkSocket::Message(Me) << "ENCAP " << (s ? s->GetName() : uid.substr(0, 3)) << " SVSLOGIN " << uid << " * * * " << acc; UplinkSocket::Message(Me) << "ENCAP " << (s ? s->GetName() : uid.substr(0, 3)) << " SVSLOGIN " << uid << " * " << (!vident.empty() ? vident : '*') << " " << (!vhost.empty() ? vhost : '*') << " " << acc;
} }
}; };
struct IRCDMessageEncap : IRCDMessage struct IRCDMessageEncap : IRCDMessage
{ {
IRCDMessageEncap(Module *creator) : IRCDMessage(creator, "ENCAP", 3) { SetFlag(IRCDMESSAGE_SOFT_LIMIT);} IRCDMessageEncap(Module *creator) : IRCDMessage(creator, "ENCAP", 3)
{
SetFlag(IRCDMESSAGE_SOFT_LIMIT);
SetFlag(IRCDMESSAGE_REQUIRE_USER);
}
void Run(MessageSource &source, const std::vector<Anope::string> &params) anope_override void Run(MessageSource &source, const std::vector<Anope::string> &params) anope_override
{ {
@@ -225,7 +267,7 @@ struct IRCDMessageEUID : IRCDMessage
if (params[9] != "*") if (params[9] != "*")
na = NickAlias::Find(params[9]); na = NickAlias::Find(params[9]);
User::OnIntroduce(params[0], params[4], params[8], params[5], params[6], source.GetServer(), params[10], params[2].is_pos_number_only() ? convertTo<time_t>(params[2]) : Anope::CurTime, params[3], params[7], na ? *na->nc : NULL); User::OnIntroduce(params[0], params[4], (params[8] != "*" ? params[8] : params[5]), params[5], params[6], source.GetServer(), params[10], params[2].is_pos_number_only() ? convertTo<time_t>(params[2]) : Anope::CurTime, params[3], params[7], na ? *na->nc : NULL);
} }
}; };
+1 -1
View File
@@ -406,7 +406,7 @@ class InspIRCd12Proto : public IRCDProto
UplinkSocket::Message(Me) << "ENCAP " << message.target.substr(0, 3) << " SASL " << message.source << " " << message.target << " " << message.type << " " << message.data << (message.ext.empty() ? "" : (" " + message.ext)); UplinkSocket::Message(Me) << "ENCAP " << message.target.substr(0, 3) << " SASL " << message.source << " " << message.target << " " << message.type << " " << message.data << (message.ext.empty() ? "" : (" " + message.ext));
} }
void SendSVSLogin(const Anope::string &uid, const Anope::string &acc) anope_override void SendSVSLogin(const Anope::string &uid, const Anope::string &acc, const Anope::string &vident, const Anope::string &vhost) anope_override
{ {
UplinkSocket::Message(Me) << "METADATA " << uid << " accountname :" << acc; UplinkSocket::Message(Me) << "METADATA " << uid << " accountname :" << acc;
+27 -1
View File
@@ -42,6 +42,15 @@ class InspIRCd20Proto : public IRCDProto
insp12->SendConnect(); insp12->SendConnect();
} }
void SendSASLMechanisms(std::vector<Anope::string> &mechanisms) anope_override
{
Anope::string mechlist;
for (unsigned i = 0; i < mechanisms.size(); ++i)
mechlist += "," + mechanisms[i];
UplinkSocket::Message(Me) << "METADATA * saslmechlist :" << (mechanisms.empty() ? "" : mechlist.substr(1));
}
void SendSVSKillInternal(const MessageSource &source, User *user, const Anope::string &buf) anope_override { insp12->SendSVSKillInternal(source, user, buf); } void SendSVSKillInternal(const MessageSource &source, User *user, const Anope::string &buf) anope_override { insp12->SendSVSKillInternal(source, user, buf); }
void SendGlobalNotice(BotInfo *bi, const Server *dest, const Anope::string &msg) anope_override { insp12->SendGlobalNotice(bi, dest, msg); } void SendGlobalNotice(BotInfo *bi, const Server *dest, const Anope::string &msg) anope_override { insp12->SendGlobalNotice(bi, dest, msg); }
void SendGlobalPrivmsg(BotInfo *bi, const Server *dest, const Anope::string &msg) anope_override { insp12->SendGlobalPrivmsg(bi, dest, msg); } void SendGlobalPrivmsg(BotInfo *bi, const Server *dest, const Anope::string &msg) anope_override { insp12->SendGlobalPrivmsg(bi, dest, msg); }
@@ -72,11 +81,26 @@ class InspIRCd20Proto : public IRCDProto
void SendLogout(User *u) anope_override { insp12->SendLogout(u); } void SendLogout(User *u) anope_override { insp12->SendLogout(u); }
void SendChannel(Channel *c) anope_override { insp12->SendChannel(c); } void SendChannel(Channel *c) anope_override { insp12->SendChannel(c); }
void SendSASLMessage(const SASL::Message &message) anope_override { insp12->SendSASLMessage(message); } void SendSASLMessage(const SASL::Message &message) anope_override { insp12->SendSASLMessage(message); }
void SendSVSLogin(const Anope::string &uid, const Anope::string &acc) anope_override { insp12->SendSVSLogin(uid, acc); } void SendSVSLogin(const Anope::string &uid, const Anope::string &acc, const Anope::string &vident, const Anope::string &vhost) anope_override { insp12->SendSVSLogin(uid, acc, vident, vhost); }
bool IsExtbanValid(const Anope::string &mask) anope_override { return insp12->IsExtbanValid(mask); } bool IsExtbanValid(const Anope::string &mask) anope_override { return insp12->IsExtbanValid(mask); }
bool IsIdentValid(const Anope::string &ident) anope_override { return insp12->IsIdentValid(ident); } bool IsIdentValid(const Anope::string &ident) anope_override { return insp12->IsIdentValid(ident); }
}; };
class InspIRCdAutoOpMode : public ChannelModeList
{
public:
InspIRCdAutoOpMode(char mode) : ChannelModeList("AUTOOP", mode)
{
}
bool IsValid(Anope::string &mask) const anope_override
{
// We can not validate this because we don't know about the
// privileges of the setter so just reject attempts to set it.
return false;
}
};
class InspIRCdExtBan : public ChannelModeVirtual<ChannelModeList> class InspIRCdExtBan : public ChannelModeVirtual<ChannelModeList>
{ {
char ext; char ext;
@@ -395,6 +419,8 @@ struct IRCDMessageCapab : Message::Capab
} }
else if (modename.equals_cs("auditorium")) else if (modename.equals_cs("auditorium"))
cm = new ChannelMode("AUDITORIUM", modechar[0]); cm = new ChannelMode("AUDITORIUM", modechar[0]);
else if (modename.equals_cs("autoop"))
cm = new InspIRCdAutoOpMode(modechar[0]);
else if (modename.equals_cs("ban")) else if (modename.equals_cs("ban"))
cm = new ChannelModeList("BAN", modechar[0]); cm = new ChannelModeList("BAN", modechar[0]);
else if (modename.equals_cs("banexception")) else if (modename.equals_cs("banexception"))
+5 -2
View File
@@ -280,7 +280,7 @@ struct IRCDMessageChaninfo : IRCDMessage
struct IRCDMessageJoin : Message::Join struct IRCDMessageJoin : Message::Join
{ {
IRCDMessageJoin(Module *creator) : Message::Join(creator, "JOIN") { } IRCDMessageJoin(Module *creator) : Message::Join(creator, "JOIN") { SetFlag(IRCDMESSAGE_REQUIRE_USER); }
/* /*
* <@po||ux> DukeP: RFC 2813, 4.2.1: the JOIN command on server-server links * <@po||ux> DukeP: RFC 2813, 4.2.1: the JOIN command on server-server links
@@ -440,8 +440,11 @@ struct IRCDMessageNick : IRCDMessage
{ {
if (params.size() == 1) if (params.size() == 1)
{ {
User *u = source.GetUser();
// we have a nickchange // we have a nickchange
source.GetUser()->ChangeNick(params[0]); if (u)
u->ChangeNick(params[0]);
} }
else if (params.size() == 7) else if (params.size() == 7)
{ {
+25 -6
View File
@@ -139,6 +139,25 @@ struct IRCDMessageEncap : IRCDMessage
} }
}; };
struct IRCDMessageJoin : Message::Join
{
IRCDMessageJoin(Module *creator) : Message::Join(creator, "JOIN") { }
void Run(MessageSource &source, const std::vector<Anope::string> &params) anope_override
{
if (params.size() == 1 && params[0] == "0")
return Message::Join::Run(source, params);
if (params.size() < 2)
return;
std::vector<Anope::string> p = params;
p.erase(p.begin());
return Message::Join::Run(source, p);
}
};
struct IRCDMessagePass : IRCDMessage struct IRCDMessagePass : IRCDMessage
{ {
IRCDMessagePass(Module *creator) : IRCDMessage(creator, "PASS", 4) { SetFlag(IRCDMESSAGE_REQUIRE_SERVER); } IRCDMessagePass(Module *creator) : IRCDMessage(creator, "PASS", 4) { SetFlag(IRCDMESSAGE_REQUIRE_SERVER); }
@@ -229,11 +248,12 @@ class ProtoRatbox : public Module
Message::Whois message_whois; Message::Whois message_whois;
/* Hybrid message handlers */ /* Hybrid message handlers */
ServiceAlias message_bmask, message_join, message_nick, message_pong, message_sid, ServiceAlias message_bmask, message_nick, message_pong, message_sid,
message_sjoin, message_tmode; message_sjoin, message_tmode;
/* Our message handlers */ /* Our message handlers */
IRCDMessageEncap message_encap; IRCDMessageEncap message_encap;
IRCDMessageJoin message_join;
IRCDMessagePass message_pass; IRCDMessagePass message_pass;
IRCDMessageServer message_server; IRCDMessageServer message_server;
IRCDMessageTBurst message_tburst; IRCDMessageTBurst message_tburst;
@@ -296,12 +316,11 @@ class ProtoRatbox : public Module
message_ping(this), message_privmsg(this), message_quit(this), message_squit(this), message_stats(this), message_ping(this), message_privmsg(this), message_quit(this), message_squit(this), message_stats(this),
message_time(this), message_topic(this), message_version(this), message_whois(this), message_time(this), message_topic(this), message_version(this), message_whois(this),
message_bmask("IRCDMessage", "ratbox/bmask", "hybrid/bmask"), message_join("IRCDMessage", "ratbox/join", "hybrid/join"), message_bmask("IRCDMessage", "ratbox/bmask", "hybrid/bmask"), message_nick("IRCDMessage", "ratbox/nick", "hybrid/nick"),
message_nick("IRCDMessage", "ratbox/nick", "hybrid/nick"), message_pong("IRCDMessage", "ratbox/pong", "hybrid/pong"), message_pong("IRCDMessage", "ratbox/pong", "hybrid/pong"), message_sid("IRCDMessage", "ratbox/sid", "hybrid/sid"),
message_sid("IRCDMessage", "ratbox/sid", "hybrid/sid"), message_sjoin("IRCDMessage", "ratbox/sjoin", "hybrid/sjoin"), message_sjoin("IRCDMessage", "ratbox/sjoin", "hybrid/sjoin"), message_tmode("IRCDMessage", "ratbox/tmode", "hybrid/tmode"),
message_tmode("IRCDMessage", "ratbox/tmode", "hybrid/tmode"),
message_encap(this), message_pass(this), message_server(this), message_tburst(this), message_uid(this) message_encap(this), message_join(this), message_pass(this), message_server(this), message_tburst(this), message_uid(this)
{ {
if (ModuleManager::LoadModule("hybrid", User::Find(creator)) != MOD_ERR_OK) if (ModuleManager::LoadModule("hybrid", User::Find(creator)) != MOD_ERR_OK)
+6 -2
View File
@@ -386,7 +386,7 @@ class UnrealIRCdProto : public IRCDProto
UplinkSocket::Message(BotInfo::Find(message.source)) << "SASL " << message.target.substr(0, p) << " " << message.target << " " << message.type << " " << message.data << (message.ext.empty() ? "" : " " + message.ext); UplinkSocket::Message(BotInfo::Find(message.source)) << "SASL " << message.target.substr(0, p) << " " << message.target << " " << message.type << " " << message.data << (message.ext.empty() ? "" : " " + message.ext);
} }
void SendSVSLogin(const Anope::string &uid, const Anope::string &acc) anope_override void SendSVSLogin(const Anope::string &uid, const Anope::string &acc, const Anope::string &vident, const Anope::string &vhost) anope_override
{ {
size_t p = uid.find('!'); size_t p = uid.find('!');
if (p == Anope::string::npos) if (p == Anope::string::npos)
@@ -929,7 +929,11 @@ struct IRCDMessageNick : IRCDMessage
User::OnIntroduce(params[0], params[3], params[4], vhost, ip, s, params[10], user_ts, params[7], "", na ? *na->nc : NULL); User::OnIntroduce(params[0], params[3], params[4], vhost, ip, s, params[10], user_ts, params[7], "", na ? *na->nc : NULL);
} }
else else
source.GetUser()->ChangeNick(params[0]); {
User *u = source.GetUser();
if (u)
u->ChangeNick(params[0]);
}
} }
}; };
+7 -3
View File
@@ -374,7 +374,7 @@ class UnrealIRCdProto : public IRCDProto
UplinkSocket::Message(BotInfo::Find(message.source)) << "SASL " << message.target.substr(0, p) << " " << message.target << " " << message.type << " " << message.data << (message.ext.empty() ? "" : " " + message.ext); UplinkSocket::Message(BotInfo::Find(message.source)) << "SASL " << message.target.substr(0, p) << " " << message.target << " " << message.type << " " << message.data << (message.ext.empty() ? "" : " " + message.ext);
} }
void SendSVSLogin(const Anope::string &uid, const Anope::string &acc) anope_override void SendSVSLogin(const Anope::string &uid, const Anope::string &acc, const Anope::string &vident, const Anope::string &vhost) anope_override
{ {
size_t p = uid.find('!'); size_t p = uid.find('!');
if (p == Anope::string::npos) if (p == Anope::string::npos)
@@ -966,7 +966,11 @@ struct IRCDMessageNick : IRCDMessage
User::OnIntroduce(params[0], params[3], params[4], vhost, ip, s, params[10], user_ts, params[7], "", na ? *na->nc : NULL); User::OnIntroduce(params[0], params[3], params[4], vhost, ip, s, params[10], user_ts, params[7], "", na ? *na->nc : NULL);
} }
else else
source.GetUser()->ChangeNick(params[0]); {
User *u = source.GetUser();
if (u)
u->ChangeNick(params[0]);
}
} }
}; };
@@ -1279,7 +1283,7 @@ struct IRCDMessageUID : IRCDMessage
User *u = User::OnIntroduce(nickname, username, hostname, vhost, ip, source.GetServer(), info, user_ts, umodes, uid, na ? *na->nc : NULL); User *u = User::OnIntroduce(nickname, username, hostname, vhost, ip, source.GetServer(), info, user_ts, umodes, uid, na ? *na->nc : NULL);
if (!chost.empty() && chost != u->GetCloakedHost()) if (u && !chost.empty() && chost != u->GetCloakedHost())
u->SetCloakedHost(chost); u->SetCloakedHost(chost);
} }
}; };
+1
View File
@@ -67,6 +67,7 @@ class MemoServCore : public Module, public MemoServService
sender->lastmemosend = Anope::CurTime; sender->lastmemosend = Anope::CurTime;
Memo *m = new Memo(); Memo *m = new Memo();
m->mi = mi;
mi->memos->push_back(m); mi->memos->push_back(m);
m->owner = target; m->owner = target;
m->sender = source; m->sender = source;
+5
View File
@@ -97,7 +97,12 @@ class SQLineManager : public XLineManager
u->Kill(Config->GetClient("OperServ"), "Q-Lined: " + x->reason); u->Kill(Config->GetClient("OperServ"), "Q-Lined: " + x->reason);
} }
else if (x->mask[0] != '#' || IRCD->CanSQLineChannel) else if (x->mask[0] != '#' || IRCD->CanSQLineChannel)
{
IRCD->SendSQLine(u, x); IRCD->SendSQLine(u, x);
/* If it is an oper, assume they're walking it, otherwise kill for good measure */
if (u && !u->HasMode("OPER"))
u->Kill(Config->GetClient("OperServ"), "Q-Lined: " + x->reason);
}
} }
void SendDel(XLine *x) anope_override void SendDel(XLine *x) anope_override
+3 -4
View File
@@ -46,10 +46,9 @@ bool WebCPanel::NickServ::Alist::OnRequest(HTTPProvider *server, const Anope::st
replacements["NUMBERS"] = stringify(chan_count); replacements["NUMBERS"] = stringify(chan_count);
replacements["CHANNELS"] = (ci->HasExt("CS_NO_EXPIRE") ? "!" : "") + ci->name; replacements["CHANNELS"] = (ci->HasExt("CS_NO_EXPIRE") ? "!" : "") + ci->name;
Anope::string access_str;
for (unsigned i = 0; i < access.size(); ++i) const ChanAccess *highest = access.Highest();
access_str += ", " + access[i]->AccessSerialize(); replacements["ACCESSES"] = highest ? highest->AccessSerialize() : "";
replacements["ACCESSES"] = access_str.substr(2);
} }
TemplateFileServer page("nickserv/alist.html"); TemplateFileServer page("nickserv/alist.html");
+42 -51
View File
@@ -250,8 +250,10 @@ Serializable* ChanAccess::Unserialize(Serializable *obj, Serialize::Data &data)
return access; return access;
} }
bool ChanAccess::Matches(const User *u, const NickCore *acc, Path &p) const bool ChanAccess::Matches(const User *u, const NickCore *acc, ChannelInfo* &next) const
{ {
next = NULL;
if (this->nc) if (this->nc)
return this->nc == acc; return this->nc == acc;
@@ -276,28 +278,7 @@ bool ChanAccess::Matches(const User *u, const NickCore *acc, Path &p) const
if (IRCD->IsChannelValid(this->mask)) if (IRCD->IsChannelValid(this->mask))
{ {
ChannelInfo *tci = ChannelInfo::Find(this->mask); next = ChannelInfo::Find(this->mask);
if (tci)
{
for (unsigned i = 0; i < tci->GetAccessCount(); ++i)
{
ChanAccess *a = tci->GetAccess(i);
std::pair<const ChanAccess *, const ChanAccess *> pair = std::make_pair(this, a);
std::pair<Set::iterator, Set::iterator> range = p.first.equal_range(this);
for (; range.first != range.second; ++range.first)
if (range.first->first == pair.first && range.first->second == pair.second)
goto cont;
p.first.insert(pair);
if (a->Matches(u, acc, p))
p.second.insert(pair);
cont:;
}
return p.second.count(this) > 0;
}
} }
return false; return false;
@@ -347,37 +328,30 @@ bool ChanAccess::operator<=(const ChanAccess &other) const
return !(*this > other); return !(*this > other);
} }
AccessGroup::AccessGroup() : std::vector<ChanAccess *>() AccessGroup::AccessGroup()
{ {
this->ci = NULL; this->ci = NULL;
this->nc = NULL; this->nc = NULL;
this->super_admin = this->founder = false; this->super_admin = this->founder = false;
} }
static bool HasPriv(const AccessGroup &ag, const ChanAccess *access, const Anope::string &name) static bool HasPriv(const ChanAccess::Path &path, const Anope::string &name)
{ {
EventReturn MOD_RESULT; if (path.empty())
FOREACH_RESULT(OnCheckPriv, MOD_RESULT, (access, name)); return false;
if (MOD_RESULT == EVENT_ALLOW || access->HasPriv(name))
for (unsigned int i = 0; i < path.size(); ++i)
{ {
typedef std::multimap<const ChanAccess *, const ChanAccess *> path; ChanAccess *access = path[i];
std::pair<path::const_iterator, path::const_iterator> it = ag.path.second.equal_range(access);
if (it.first != it.second) EventReturn MOD_RESULT;
/* check all of the paths for this entry */ FOREACH_RESULT(OnCheckPriv, MOD_RESULT, (access, name));
for (; it.first != it.second; ++it.first)
{ if (MOD_RESULT != EVENT_ALLOW && !access->HasPriv(name))
const ChanAccess *a = it.first->second; return false;
/* if only one path fully matches then we are ok */
if (HasPriv(ag, a, name))
return true;
}
else
/* entry is the end of a chain, all entries match, ok */
return true;
} }
/* entry does not match or none of the chains fully match */ return true;
return false;
} }
bool AccessGroup::HasPriv(const Anope::string &name) const bool AccessGroup::HasPriv(const Anope::string &name) const
@@ -393,7 +367,7 @@ bool AccessGroup::HasPriv(const Anope::string &name) const
bool auto_mode = !name.find("AUTO"); bool auto_mode = !name.find("AUTO");
/* Only grant founder privilege if this isn't an auto mode or if they don't match any entries in this group */ /* Only grant founder privilege if this isn't an auto mode or if they don't match any entries in this group */
if ((!auto_mode || this->empty()) && this->founder) if ((!auto_mode || paths.empty()) && this->founder)
return true; return true;
EventReturn MOD_RESULT; EventReturn MOD_RESULT;
@@ -401,23 +375,40 @@ bool AccessGroup::HasPriv(const Anope::string &name) const
if (MOD_RESULT != EVENT_CONTINUE) if (MOD_RESULT != EVENT_CONTINUE)
return MOD_RESULT == EVENT_ALLOW; return MOD_RESULT == EVENT_ALLOW;
for (unsigned i = this->size(); i > 0; --i) for (unsigned int i = paths.size(); i > 0; --i)
{ {
ChanAccess *access = this->at(i - 1); const ChanAccess::Path &path = paths[i - 1];
if (::HasPriv(*this, access, name)) if (::HasPriv(path, name))
return true; return true;
} }
return false; return false;
} }
static ChanAccess *HighestInPath(const ChanAccess::Path &path)
{
ChanAccess *highest = NULL;
for (unsigned int i = 0; i < path.size(); ++i)
if (highest == NULL || *path[i] > *highest)
highest = path[i];
return highest;
}
const ChanAccess *AccessGroup::Highest() const const ChanAccess *AccessGroup::Highest() const
{ {
ChanAccess *highest = NULL; ChanAccess *highest = NULL;
for (unsigned i = 0; i < this->size(); ++i)
if (highest == NULL || *this->at(i) > *highest) for (unsigned int i = 0; i < paths.size(); ++i)
highest = this->at(i); {
ChanAccess *hip = HighestInPath(paths[i]);
if (highest == NULL || *hip > *highest)
highest = hip;
}
return highest; return highest;
} }
+7 -2
View File
@@ -168,8 +168,7 @@ void Channel::DeleteUser(User *user)
Log(LOG_DEBUG) << "Channel::DeleteUser() tried to delete non-existent channel " << this->name << " from " << user->nick << "'s channel list"; Log(LOG_DEBUG) << "Channel::DeleteUser() tried to delete non-existent channel " << this->name << " from " << user->nick << "'s channel list";
delete cu; delete cu;
if (std::find(deleting.begin(), deleting.end(), this) == deleting.end()) QueueForDeletion();
deleting.push_back(this);
} }
ChanUserContainer *Channel::FindUser(User *u) const ChanUserContainer *Channel::FindUser(User *u) const
@@ -938,6 +937,12 @@ Channel *Channel::FindOrCreate(const Anope::string &name, bool &created, time_t
return chan; return chan;
} }
void Channel::QueueForDeletion()
{
if (std::find(deleting.begin(), deleting.end(), this) == deleting.end())
deleting.push_back(this);
}
void Channel::DeleteChannels() void Channel::DeleteChannels()
{ {
for (unsigned int i = 0; i < deleting.size(); ++i) for (unsigned int i = 0; i < deleting.size(); ++i)
+1 -1
View File
@@ -117,7 +117,7 @@ void CommandSource::Reply(const Anope::string &message)
this->reply->SendMessage(this->service, tok); this->reply->SendMessage(this->service, tok);
} }
Command::Command(Module *o, const Anope::string &sname, size_t minparams, size_t maxparams) : Service(o, "Command", sname), max_params(maxparams), min_params(minparams), module(owner) Command::Command(Module *o, const Anope::string &sname, size_t minparams, size_t maxparams) : Service(o, "Command", sname), max_params(maxparams), min_params(minparams), module(o)
{ {
allow_unregistered = require_user = false; allow_unregistered = require_user = false;
} }
+8
View File
@@ -75,6 +75,10 @@ const char *Language::Translate(const NickCore *nc, const char *string)
#if GETTEXT_FOUND #if GETTEXT_FOUND
#ifdef __USE_GNU_GETTEXT
extern "C" int _nl_msg_cat_cntr;
#endif
const char *Language::Translate(const char *lang, const char *string) const char *Language::Translate(const char *lang, const char *string)
{ {
if (!string || !*string) if (!string || !*string)
@@ -83,6 +87,10 @@ const char *Language::Translate(const char *lang, const char *string)
if (!lang || !*lang) if (!lang || !*lang)
lang = Config->DefLanguage.c_str(); lang = Config->DefLanguage.c_str();
#ifdef __USE_GNU_GETTEXT
++_nl_msg_cat_cntr;
#endif
#ifdef _WIN32 #ifdef _WIN32
SetThreadLocale(MAKELCID(MAKELANGID(WindowsGetLanguage(lang), SUBLANG_DEFAULT), SORT_DEFAULT)); SetThreadLocale(MAKELCID(MAKELANGID(WindowsGetLanguage(lang), SUBLANG_DEFAULT), SORT_DEFAULT));
#else #else
+12 -3
View File
@@ -19,13 +19,12 @@
Memo::Memo() : Serializable("Memo") Memo::Memo() : Serializable("Memo")
{ {
mi = NULL;
unread = receipt = false; unread = receipt = false;
} }
Memo::~Memo() Memo::~Memo()
{ {
bool ischan;
MemoInfo *mi = MemoInfo::GetMemoInfo(this->owner, ischan);
if (mi) if (mi)
{ {
std::vector<Memo *>::iterator it = std::find(mi->memos->begin(), mi->memos->end(), this); std::vector<Memo *>::iterator it = std::find(mi->memos->begin(), mi->memos->end(), this);
@@ -60,7 +59,10 @@ Serializable* Memo::Unserialize(Serializable *obj, Serialize::Data &data)
if (obj) if (obj)
m = anope_dynamic_static_cast<Memo *>(obj); m = anope_dynamic_static_cast<Memo *>(obj);
else else
{
m = new Memo(); m = new Memo();
m->mi = mi;
}
m->owner = owner; m->owner = owner;
data["time"] >> m->time; data["time"] >> m->time;
@@ -99,7 +101,14 @@ void MemoInfo::Del(unsigned index)
{ {
if (index >= this->memos->size()) if (index >= this->memos->size())
return; return;
delete this->GetMemo(index);
Memo *m = this->GetMemo(index);
std::vector<Memo *>::iterator it = std::find(memos->begin(), memos->end(), m);
if (it != memos->end())
memos->erase(it);
delete m;
} }
bool MemoInfo::HasIgnore(User *u) bool MemoInfo::HasIgnore(User *u)
+1 -1
View File
@@ -162,7 +162,7 @@ void Join::SJoin(MessageSource &source, const Anope::string &chan, time_t ts, co
c->Sync(); c->Sync();
if (c->CheckDelete()) if (c->CheckDelete())
delete c; c->QueueForDeletion();
} }
} }
} }
+5 -1
View File
@@ -320,7 +320,7 @@ Anope::string Anope::Duration(time_t t, const NickCore *nc)
time_t minutes = (t / 60) % 60; time_t minutes = (t / 60) % 60;
time_t seconds = (t) % 60; time_t seconds = (t) % 60;
if (!days && !hours && !minutes) if (!years && !days && !hours && !minutes)
return stringify(seconds) + " " + (seconds != 1 ? Language::Translate(nc, _("seconds")) : Language::Translate(nc, _("second"))); return stringify(seconds) + " " + (seconds != 1 ? Language::Translate(nc, _("seconds")) : Language::Translate(nc, _("second")));
else else
{ {
@@ -632,7 +632,11 @@ Anope::string Anope::VersionShort()
Anope::string Anope::VersionBuildString() Anope::string Anope::VersionBuildString()
{ {
#ifdef REPRODUCIBLE_BUILD
Anope::string s = "build #" + stringify(BUILD);
#else
Anope::string s = "build #" + stringify(BUILD) + ", compiled " + Anope::compiled; Anope::string s = "build #" + stringify(BUILD) + ", compiled " + Anope::compiled;
#endif
Anope::string flags; Anope::string flags;
#ifdef DEBUG_BUILD #ifdef DEBUG_BUILD
+20 -8
View File
@@ -742,7 +742,7 @@ void ModeManager::StackerDel(Mode *m)
} }
} }
Entry::Entry(const Anope::string &m, const Anope::string &fh) : name(m), mask(fh), cidr_len(0) Entry::Entry(const Anope::string &m, const Anope::string &fh) : name(m), mask(fh), cidr_len(0), family(0)
{ {
Anope::string n, u, h; Anope::string n, u, h;
@@ -802,14 +802,13 @@ Entry::Entry(const Anope::string &m, const Anope::string &fh) : name(m), mask(fh
if (addr.valid() && cidr_range.is_pos_number_only()) if (addr.valid() && cidr_range.is_pos_number_only())
{ {
this->cidr_len = convertTo<unsigned short>(cidr_range); this->cidr_len = convertTo<unsigned short>(cidr_range);
/* If we got here, cidr_len is a valid number.
* If cidr_len is >32 (or 128) it is handled later in /* If we got here, cidr_len is a valid number. */
* cidr::match
*/
this->host = cidr_ip; this->host = cidr_ip;
this->family = addr.family();
Log(LOG_DEBUG) << "Ban " << m << " has cidr " << this->cidr_len; Log(LOG_DEBUG) << "Ban " << mask << " has cidr " << this->cidr_len;
} }
} }
catch (const ConvertException &) { } catch (const ConvertException &) { }
@@ -830,8 +829,21 @@ const Anope::string Entry::GetNUHMask() const
Anope::string n = nick.empty() ? "*" : nick, Anope::string n = nick.empty() ? "*" : nick,
u = user.empty() ? "*" : user, u = user.empty() ? "*" : user,
h = host.empty() ? "*" : host, h = host.empty() ? "*" : host,
r = real.empty() ? "" : "#" + real; r = real.empty() ? "" : "#" + real,
return n + "!" + u + "@" + h + r; c;
switch (family)
{
case AF_INET:
if (cidr_len <= 32)
c = "/" + stringify(cidr_len);
break;
case AF_INET6:
if (cidr_len <= 128)
c = "/" + stringify(cidr_len);
break;
}
return n + "!" + u + "@" + h + c + r;
} }
bool Entry::Matches(User *u, bool full) const bool Entry::Matches(User *u, bool full) const
+69 -35
View File
@@ -157,7 +157,7 @@ ChannelInfo::~ChannelInfo()
if (this->c) if (this->c)
{ {
if (this->c && this->c->CheckDelete()) if (this->c && this->c->CheckDelete())
delete this->c; this->c->QueueForDeletion();
this->c = NULL; this->c = NULL;
} }
@@ -384,6 +384,39 @@ ChanAccess *ChannelInfo::GetAccess(unsigned index) const
return acc; return acc;
} }
static void FindMatchesRecurse(ChannelInfo *ci, const User *u, const NickCore *account, unsigned int depth, std::vector<ChanAccess::Path> &paths, ChanAccess::Path &path)
{
if (depth > ChanAccess::MAX_DEPTH)
return;
for (unsigned int i = 0; i < ci->GetAccessCount(); ++i)
{
ChanAccess *a = ci->GetAccess(i);
ChannelInfo *next = NULL;
if (a->Matches(u, account, next))
{
ChanAccess::Path next_path = path;
next_path.push_back(a);
paths.push_back(next_path);
}
else if (next)
{
ChanAccess::Path next_path = path;
next_path.push_back(a);
FindMatchesRecurse(next, u, account, depth + 1, paths, next_path);
}
}
}
static void FindMatches(AccessGroup &group, ChannelInfo *ci, const User *u, const NickCore *account)
{
ChanAccess::Path path;
FindMatchesRecurse(ci, u, account, 0, group.paths, path);
}
AccessGroup ChannelInfo::AccessFor(const User *u, bool updateLastUsed) AccessGroup ChannelInfo::AccessFor(const User *u, bool updateLastUsed)
{ {
AccessGroup group; AccessGroup group;
@@ -404,20 +437,20 @@ AccessGroup ChannelInfo::AccessFor(const User *u, bool updateLastUsed)
group.ci = this; group.ci = this;
group.nc = nc; group.nc = nc;
for (unsigned i = 0, end = this->GetAccessCount(); i < end; ++i) FindMatches(group, this, u, u->Account());
{
ChanAccess *a = this->GetAccess(i);
if (a->Matches(u, u->Account(), group.path))
group.push_back(a);
}
if (group.founder || !group.empty()) if (group.founder || !group.paths.empty())
{ {
if (updateLastUsed) if (updateLastUsed)
this->last_used = Anope::CurTime; this->last_used = Anope::CurTime;
for (unsigned i = 0; i < group.size(); ++i) for (unsigned i = 0; i < group.paths.size(); ++i)
group[i]->last_seen = Anope::CurTime; {
ChanAccess::Path &p = group.paths[i];
for (unsigned int j = 0; j < p.size(); ++j)
p[j]->last_seen = Anope::CurTime;
}
} }
return group; return group;
@@ -431,14 +464,9 @@ AccessGroup ChannelInfo::AccessFor(const NickCore *nc, bool updateLastUsed)
group.ci = this; group.ci = this;
group.nc = nc; group.nc = nc;
for (unsigned i = 0, end = this->GetAccessCount(); i < end; ++i) FindMatches(group, this, NULL, nc);
{
ChanAccess *a = this->GetAccess(i);
if (a->Matches(NULL, nc, group.path))
group.push_back(a);
}
if (group.founder || !group.empty()) if (group.founder || !group.paths.empty())
if (updateLastUsed) if (updateLastUsed)
this->last_used = Anope::CurTime; this->last_used = Anope::CurTime;
@@ -452,28 +480,34 @@ unsigned ChannelInfo::GetAccessCount() const
return this->access->size(); return this->access->size();
} }
unsigned ChannelInfo::GetDeepAccessCount() const static unsigned int GetDeepAccessCount(const ChannelInfo *ci, std::set<const ChannelInfo *> &seen, unsigned int depth)
{ {
ChanAccess::Path path; if (depth > ChanAccess::MAX_DEPTH || seen.count(ci))
for (unsigned i = 0, end = this->GetAccessCount(); i < end; ++i) return 0;
seen.insert(ci);
unsigned int total = 0;
for (unsigned int i = 0; i < ci->GetAccessCount(); ++i)
{ {
ChanAccess *a = this->GetAccess(i); ChanAccess::Path path;
a->Matches(NULL, NULL, path); ChanAccess *a = ci->GetAccess(i);
ChannelInfo *next = NULL;
a->Matches(NULL, NULL, next);
++total;
if (next)
total += GetDeepAccessCount(ci, seen, depth + 1);
} }
unsigned count = this->GetAccessCount(); return total;
std::set<const ChannelInfo *> channels; }
channels.insert(this);
for (ChanAccess::Set::iterator it = path.first.begin(); it != path.first.end(); ++it) unsigned ChannelInfo::GetDeepAccessCount() const
{ {
const ChannelInfo *ci = it->first->ci; std::set<const ChannelInfo *> seen;
if (!channels.count(ci)) return ::GetDeepAccessCount(this, seen, 0);
{
channels.count(ci);
count += ci->GetAccessCount();
}
}
return count;
} }
ChanAccess *ChannelInfo::EraseAccess(unsigned index) ChanAccess *ChannelInfo::EraseAccess(unsigned index)
+5
View File
@@ -39,6 +39,11 @@ void sockaddrs::clear()
memset(this, 0, sizeof(*this)); memset(this, 0, sizeof(*this));
} }
int sockaddrs::family() const
{
return sa.sa_family;
}
size_t sockaddrs::size() const size_t sockaddrs::size() const
{ {
switch (sa.sa_family) switch (sa.sa_family)
+1 -1
View File
@@ -48,5 +48,5 @@ endif(NOT WIN32)
# On non-Windows platforms, if RUNGROUP is set, change the permissions of the tools directory # On non-Windows platforms, if RUNGROUP is set, change the permissions of the tools directory
if(NOT WIN32 AND RUNGROUP) if(NOT WIN32 AND RUNGROUP)
install(CODE "execute_process(COMMAND ${CHMOD} 2770 \"\$ENV{DESTDIR}${CMAKE_INSTALL_PREFIX}/bin\")") install(CODE "execute_process(COMMAND ${CHMOD} 2770 \"\$ENV{DESTDIR}\${CMAKE_INSTALL_PREFIX}/bin\")")
endif(NOT WIN32 AND RUNGROUP) endif(NOT WIN32 AND RUNGROUP)
+2
View File
@@ -507,6 +507,8 @@ void User::UpdateHost()
Anope::string last_realhost = this->GetIdent() + "@" + this->host; Anope::string last_realhost = this->GetIdent() + "@" + this->host;
na->last_usermask = last_usermask; na->last_usermask = last_usermask;
na->last_realhost = last_realhost; na->last_realhost = last_realhost;
// This is called on signon, and if users are introduced with an account it won't update
na->last_realname = this->realname;
} }
} }
+1 -1
View File
@@ -2,6 +2,6 @@
VERSION_MAJOR=2 VERSION_MAJOR=2
VERSION_MINOR=0 VERSION_MINOR=0
VERSION_PATCH=3 VERSION_PATCH=4
VERSION_EXTRA="" VERSION_EXTRA=""