diff options
69 files changed, 624 insertions, 236 deletions
diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 000000000..bb82add9b --- /dev/null +++ b/.travis.yml @@ -0,0 +1,13 @@ +compiler: + - clang + - gcc +dist: trusty +env: + - PURE_STATIC=1 + - +language: cpp +notifications: + email: false +script: + - sh ./tools/travis-ci.sh +sudo: required @@ -28,6 +28,7 @@ BEGIN { require 5.8.0; + push @INC, '.'; } use strict; @@ -268,10 +269,9 @@ if (defined $opt_cc) { $config{CC} = $opt_cc; } -our $exec = $config{CC} . " -dumpversion | cut -c 1"; -chomp($config{GCCVER} = `$exec`); # Major GCC Version -$exec = $config{CC} . " -dumpversion | cut -c 3"; -chomp($config{GCCMINOR} = `$exec`); +`$config{CC} -dumpversion` =~ /^(\d+)(?:\.(\d+))?/; +$config{GCCVER} = defined $1 ? $1 : ''; +$config{GCCMINOR} = defined $2 ? $2 : '0'; $config{MAXBUF} = "512"; # Max buffer size if ($config{HAS_OPENSSL} =~ /^([-[:digit:].]+)(?:[a-z])?(?:\-[a-z][0-9])?/) { @@ -347,57 +347,21 @@ print ($cache_loaded ? "found\n" : "not found\n"); $config{SYSTEM} = lc $^O; print "Checking operating system version... $config{SYSTEM}\n"; -$exec = $config{CC} . " -dumpversion | cut -c 1"; -chomp($config{GCCVER} = `$exec`); # Major GCC Version -$exec = $config{CC} . " -dumpversion | cut -c 3"; -chomp($config{GCCMINOR} = `$exec`); +`$config{CC} -dumpversion` =~ /^(\d+)(?:\.(\d+))?/; +$config{GCCVER} = defined $1 ? $1 : ''; +$config{GCCMINOR} = defined $2 ? $2 : '0'; printf "Checking if stdint.h exists... "; -$config{HAS_STDINT} = "true"; -our $fail = 0; -open(STDINT, "</usr/include/stdint.h") or $config{HAS_STDINT} = "false"; -if ($config{HAS_STDINT} eq "true") { - close(STDINT); -} -print "yes\n" if $config{HAS_STDINT} eq "true"; -print "no\n" if $config{HAS_STDINT} eq "false"; +$config{HAS_STDINT} = test_compile('stdint'); +print $config{HAS_STDINT} ? "yes\n" : "no\n"; printf "Checking if strlcpy exists... "; -# Perform the strlcpy() test.. -$config{HAS_STRLCPY} = "false"; -$fail = 0; -open(STRLCPY, "</usr/include/string.h") or $fail = 1; -if (!$fail) { - while (defined(my $line = <STRLCPY>)) { - chomp($line); - # try and find the delcaration of: - # size_t strlcpy(...) - if ($line =~ /size_t(\0x9|\s)+strlcpy/) { - $config{HAS_STRLCPY} = "true"; - } - } - close(STRLCPY); -} -print "yes\n" if $config{HAS_STRLCPY} eq "true"; -print "no\n" if $config{HAS_STRLCPY} eq "false"; +$config{HAS_STRLCPY} = test_compile('strlcpy'); +print $config{HAS_STRLCPY} ? "yes\n" : "no\n"; printf "Checking if kqueue exists... "; -$has_kqueue = 0; -$fail = 0; -open(KQUEUE, "</usr/include/sys/event.h") or $fail = 1; -if (!$fail) { - while (defined(my $line = <KQUEUE>)) { - chomp($line); - # try and find the delcaration of: - # int kqueue(void); - if ($line =~ /int(\0x9|\s)+kqueue/) { - $has_kqueue = 1; - } - } - close(KQUEUE); -} -print "yes\n" if $has_kqueue == 1; -print "no\n" if $has_kqueue == 0; +$has_kqueue = test_compile('kqueue'); +print $has_kqueue ? "yes\n" : "no\n"; printf "Checking for epoll support... "; $has_epoll = test_compile('epoll'); @@ -523,8 +487,9 @@ should NOT be used. You should probably specify a newer compiler.\n\n"; } chomp(my $foo = `$config{CC} -dumpversion | cut -c 1`); if ($foo ne "") { - chomp($config{GCCVER} = `$config{CC} -dumpversion | cut -c 1`); # we must redo these if we change compilers - chomp($config{GCCMINOR} = `$config{CC} -dumpversion | cut -c 3`); + `$config{CC} -dumpversion` =~ /^(\d+)(?:\.(\d+))?/; + $config{GCCVER} = defined $1 ? $1 : ''; + $config{GCCMINOR} = defined $2 ? $2 : '0'; print "Queried compiler: \e[1;32m$config{CC}\e[0m (version \e[1;32m$config{GCCVER}.$config{GCCMINOR}\e[0m)\n"; if ($config{GCCVER} < 3) { print "\e[1;32mGCC 2.x WILL NOT WORK!\e[0m. Let's try that again, shall we?\n"; @@ -874,8 +839,8 @@ sub writefiles { open(FILEHANDLE, ">include/inspircd_config.h.tmp"); print FILEHANDLE <<EOF; /* Auto generated by configure, do not modify! */ -#ifndef __CONFIGURATION_AUTO__ -#define __CONFIGURATION_AUTO__ +#ifndef INSPIRCD_CONFIG_H +#define INSPIRCD_CONFIG_H /* this is for windows support. */ #define CoreExport /**/ @@ -911,6 +876,10 @@ print FILEHANDLE "#define MAXBUF " . ($config{MAXBUF}+2) . "\n"; } if ($config{OSNAME} !~ /DARWIN/i) { print FILEHANDLE "#define HAS_CLOCK_GETTIME\n"; + } else { + print FILEHANDLE "#ifdef MAC_OS_X_VERSION_10_12\n"; + print FILEHANDLE "# define HAS_CLOCK_GETTIME\n"; + print FILEHANDLE "#endif\n"; } my $use_hiperf = 0; if (($has_kqueue) && ($config{USE_KQUEUE} eq "y")) { @@ -1000,6 +969,9 @@ EOF my @dotfiles = qw(main.mk inspircd); push @dotfiles, 'org.inspircd.plist' if $config{OSNAME} eq 'darwin'; + # HACK: we need to know if we are on GCC6 to disable the omission of `this` null pointer checks. + $config{GCC6} = `$config{CC} --version 2>/dev/null` =~ /gcc/i && $config{GCCVER} ge "6" ? "true" : "false"; + foreach my $file (@dotfiles) { open(FILEHANDLE, "make/template/$file") or die "Can't open make/template/$file: $!"; $_ = join '', <FILEHANDLE>; @@ -1009,7 +981,7 @@ EOF for my $var (qw( CC SYSTEM BASE_DIR CONFIG_DIR MODULE_DIR BINARY_DIR BUILD_DIR DATA_DIR UID - STARTSCRIPT DESTINATION SOCKETENGINE LOG_DIR + STARTSCRIPT DESTINATION SOCKETENGINE LOG_DIR GCC6 )) { s/\@$var\@/$config{$var}/g; } diff --git a/docs/conf/helpop-full.conf.example b/docs/conf/helpop-full.conf.example index a3529b9dc..ed82c6e02 100644 --- a/docs/conf/helpop-full.conf.example +++ b/docs/conf/helpop-full.conf.example @@ -381,6 +381,7 @@ Sets your name to the specified name."> OPERMOTD CHECK CLONES USERIP TLINE ALLTIME WALLOPS GLOBOPS MODENOTICE +CLOAK SETHOST SETIDENT CHGHOST CHGIDENT CHGNAME SETIDLE SWHOIS @@ -759,10 +760,9 @@ The duration may be specified in seconds, or in the format 1y2w3d4h5m6s - meaning one year, two weeks, three days, 4 hours, 5 minutes and 6 seconds. All fields in this format are optional."> -<helpop key="clearcache" value="/CLEARCACHE {servername} +<helpop key="clearcache" value="/CLEARCACHE -This command clears the DNS cache of the specified server. If no -server is specified, the local server's DNS cache will be cleared."> +This command clears the DNS cache of the local server."> <helpop key="close" value="/CLOSE @@ -774,6 +774,12 @@ Sends a notice to all users who have the given mode(s) set. If multiple mode letters are given, the notice is only sent to users who have all of them set."> +<helpop key="cloak" value="/CLOAK <host> + +Generate the cloak of a host or IP. This is useful for example when +trying to get the cloak of a user from /WHOWAS and they were not +using their cloak when they quit."> + ###################### # User/Channel Modes # ###################### @@ -809,6 +815,8 @@ who have all of them set."> hideoper module). I Hides a user's entire channel list in WHOIS from non-IRCops (requires hidechans module). + L Stops redirections done by m_redirect (mode must be + enabled in the config). R Blocks private messages from unregistered users (requires services account module). S Strips mIRC color/bold/underline codes out of private diff --git a/docs/conf/helpop.conf.example b/docs/conf/helpop.conf.example index 32884ea16..b4d3214f6 100644 --- a/docs/conf/helpop.conf.example +++ b/docs/conf/helpop.conf.example @@ -51,6 +51,7 @@ OPER"> OPERMOTD CHECK CLONES USERIP TLINE ALLTIME WALLOPS GLOBOPS MODENOTICE +CLOAK SETHOST SETIDENT CHGHOST CHGIDENT CHGNAME SETIDLE SWHOIS @@ -102,6 +103,8 @@ LOCKSERV UNLOCKSERV"> hideoper module). I Hides a user's entire channel list in WHOIS from non-IRCops (requires hidechans module). + L Stops redirections done by m_redirect (mode must be + enabled in the config). R Blocks private messages from unregistered users (requires services account module). S Strips mIRC color/bold/underline codes out of private diff --git a/docs/conf/inspircd.conf.example b/docs/conf/inspircd.conf.example index 9fd0adfd3..7099cefe2 100644 --- a/docs/conf/inspircd.conf.example +++ b/docs/conf/inspircd.conf.example @@ -695,6 +695,9 @@ # hidekills: If defined, replaces who set a /kill with a custom string. hidekills="" + # hideulinekills: Hide kills from clients of ulined servers from server notices. + hideulinekills="yes" + # hidesplits: If enabled, non-opers will not be able to see which # servers split in a netsplit, they will only be able to see that one # occurred (If their client has netsplit detection). diff --git a/docs/conf/modules.conf.example b/docs/conf/modules.conf.example index 364c30a14..003b4d04b 100644 --- a/docs/conf/modules.conf.example +++ b/docs/conf/modules.conf.example @@ -414,10 +414,16 @@ #-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-# # Channelban: Implements extended ban j:, which stops anyone already # in a channel matching a ban like +b j:#channel*mask from joining. +# Note that by default wildcard characters * and ? are allowed in +# channel names. To disallow them, load m_channames and add characters +# 42 and 63 to denyrange (see above). #<module name="m_channelban.so"> #-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-# # Chanprotect module: Gives +q and +a channel modes. +# +# IMPORTANT: This module has been removed in the next major version of +# InspIRCd. You should use m_customprefix instead. #<module name="m_chanprotect.so"> <chanprotect @@ -516,6 +522,10 @@ # key3, key4; the values must be less than 0x80000000 and should be # # picked at random. Prefix is mandatory, will default to network name # # if not specified, and will always have a "-" appended. # +# # +# IMPORTANT: The compat-host and compat-ip modes have been removed in # +# the next major version of InspIRCd. You should ONLY use them if you # +# need backwards compatibility with InspIRCd 1.2. # # #<cloak mode="half" # key="secret" @@ -668,6 +678,7 @@ # length - Default duration of entries in DCCALLOW list. # action - Default action to take if no action is # specified, can be 'block' or 'allow'. +# maxentries - Max number of nicks to allow on a DCCALLOW list. # # File configuration: # pattern - The glob pattern to match against. @@ -675,7 +686,7 @@ # that matches this pattern, can be 'block' or # 'allow'. # -#<dccallow blockchat="yes" length="5m" action="block"> +#<dccallow blockchat="yes" length="5m" action="block" maxentries="20"> #<banfile pattern="*.exe" action="block"> #<banfile pattern="*.txt" action="allow"> @@ -820,6 +831,9 @@ #-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-# # Halfop module: Provides the +h (halfops) channel status mode. +# +# IMPORTANT: This module has been removed in the next major version of +# InspIRCd. You should use m_customprefix instead. #<module name="m_halfop.so"> #-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-# @@ -995,7 +1009,8 @@ # binddn="cn=Manager,dc=brainbox,dc=cc" # # bindauth="mysecretpass" # # verbose="yes" # -# host="$uid.$ou.inspircd.org"> # +# host="$uid.$ou.inspircd.org" # +# useusername="no"> # # # # <ldapwhitelist cidr="10.42.0.0/16"> # # # @@ -1007,6 +1022,10 @@ # The attribute value indicates the attribute which is used to locate # # a user account by name. On POSIX systems this is usually 'uid'. # # # +# The useusername setting chooses whether the user's username or # +# nickname is used when locating a user account, if a username isn't # +# provided in PASS. # +# # # The server parameter indicates the LDAP server to connect to. The # # ldap:// style scheme before the hostname proper is MANDATORY. # # # @@ -1580,13 +1599,12 @@ # #-#-#-#-#-#-#-#-#-# SECURELIST CONFIGURATION -#-#-#-#-#-#-#-#-#-#-#-#-# # # -# Securelist can be harmful to some IRC search engines such as # -# netsplit.de and searchirc.com. To prevent securelist blocking these # -# sites from listing, define exception tags as shown below: # -#<securehost exception="*@*.searchirc.org"> +# Securelist can be harmful to some IRC search engines. To prevent # +# securelist blocking these sites from listing, define exception tags # +# as shown below: # #<securehost exception="*@*.netsplit.de"> -#<securehost exception="*@echo940.server4you.de"> #<securehost exception="*@*.ircdriven.com"> +#<securehost exception="*@*.irc-source.com"> # # # Define the following variable to change how long a user must wait # # before issuing a LIST. If not defined, defaults to 60 seconds. # @@ -1683,7 +1701,8 @@ # SSL channel mode module: Adds support for SSL-only channels via # channel mode +z and the 'z' extban which matches SSL client # certificate fingerprints. -# Does not do anything useful without a working SSL module (see below). +# Does not do anything useful without a working SSL module and the +# m_sslinfo module (see below). #<module name="m_sslmodes.so"> #-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-# diff --git a/include/base.h b/include/base.h index 0a4456f3a..19222a6f5 100644 --- a/include/base.h +++ b/include/base.h @@ -201,7 +201,7 @@ class CoreExport CoreException : public std::exception * Actually no, it does nothing. Never mind. * @throws Nothing! */ - virtual ~CoreException() throw() {}; + virtual ~CoreException() throw() {} /** Returns the reason for the exception. * The module should probably put something informative here as the user will see this upon failure. */ diff --git a/include/configreader.h b/include/configreader.h index b01a979a7..4a697d05c 100644 --- a/include/configreader.h +++ b/include/configreader.h @@ -438,6 +438,10 @@ class CoreExport ServerConfig */ std::string HideKillsServer; + /** Set to hide kills from clients of ulined servers in snotices. + */ + bool HideULineKills; + /** The full pathname and filename of the PID * file as defined in the configuration. */ diff --git a/include/dns.h b/include/dns.h index de4bcf422..05df6f69c 100644 --- a/include/dns.h +++ b/include/dns.h @@ -302,6 +302,10 @@ class CoreExport DNS : public EventHandler */ static const int MAX_REQUEST_ID = 0xFFFF; + /** Maximum number of entries in cache + */ + static const unsigned int MAX_CACHE_SIZE = 1000; + /** * Currently cached items */ diff --git a/include/inspircd.h b/include/inspircd.h index e2eaf8292..78348ed54 100644 --- a/include/inspircd.h +++ b/include/inspircd.h @@ -779,9 +779,10 @@ class CoreExport InspIRCd /** Attempt to write the process id to a given file * @param filename The PID file to attempt to write to + * @param exitonfail If true and the PID fail cannot be written log to stdout and exit, otherwise only log on failure * @return This function may bail if the file cannot be written */ - void WritePID(const std::string &filename); + void WritePID(const std::string& filename, bool exitonfail = true); /** This constructor initialises all the subsystems and reads the config file. * @param argc The argument count passed to main() diff --git a/include/modules.h b/include/modules.h index 9857012fc..4d4d0871f 100644 --- a/include/modules.h +++ b/include/modules.h @@ -116,7 +116,7 @@ struct ModResult { * and numerical comparisons in preprocessor macros if they wish to support * multiple versions of InspIRCd in one file. */ -#define INSPIRCD_VERSION_API 9 +#define INSPIRCD_VERSION_API 10 /** * This #define allows us to call a method in all diff --git a/make/calcdep.pl b/make/calcdep.pl index 4a759a24a..49506dd3b 100755 --- a/make/calcdep.pl +++ b/make/calcdep.pl @@ -160,7 +160,7 @@ END obj/ld-extra.cmd: $core_src \@\$(SOURCEPATH)/make/unit-cc.pl gen-ld\$(VERBOSE) \$\@ \$^ \$> -bin/inspircd: obj/ld-extra.cmd $core_mk +bin/inspircd: $core_mk obj/ld-extra.cmd \@\$(SOURCEPATH)/make/unit-cc.pl static-ld\$(VERBOSE) \$\@ \$^ \$> inspircd: bin/inspircd diff --git a/make/check_epoll.cpp b/make/check_epoll.cpp index 918d3907e..a5ed1c10b 100644 --- a/make/check_epoll.cpp +++ b/make/check_epoll.cpp @@ -1,6 +1,7 @@ /* * 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 diff --git a/make/check_eventfd.cpp b/make/check_eventfd.cpp index 980d04485..9b38b793b 100644 --- a/make/check_eventfd.cpp +++ b/make/check_eventfd.cpp @@ -1,6 +1,8 @@ /* * InspIRCd -- Internet Relay Chat Daemon * + * Copyright (C) 2012 William Pitcock <nenolod@dereferenced.org> + * Copyright (C) 2009-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 diff --git a/make/check_kqueue.cpp b/make/check_kqueue.cpp new file mode 100644 index 000000000..6034253df --- /dev/null +++ b/make/check_kqueue.cpp @@ -0,0 +1,26 @@ +/* + * InspIRCd -- Internet Relay Chat Daemon + * + * Copyright (C) 2015 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/>. + */ + + +#include <sys/types.h> +#include <sys/event.h> + +int main() { + int fd = kqueue(); + return (fd < 0); +} diff --git a/make/check_stdint.cpp b/make/check_stdint.cpp new file mode 100644 index 000000000..fbd01b80d --- /dev/null +++ b/make/check_stdint.cpp @@ -0,0 +1,25 @@ +/* + * InspIRCd -- Internet Relay Chat Daemon + * + * Copyright (C) 2015 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/>. + */ + + +#include <stdint.h> + +int main() { + uint32_t ret = 0; + return ret; +} diff --git a/make/check_strlcpy.cpp b/make/check_strlcpy.cpp new file mode 100644 index 000000000..e51d18d40 --- /dev/null +++ b/make/check_strlcpy.cpp @@ -0,0 +1,25 @@ +/* + * InspIRCd -- Internet Relay Chat Daemon + * + * Copyright (C) 2015 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/>. + */ + + +#include <string.h> + +int main() { + char test[5]; + strlcpy(test, "test", sizeof(test)); +} diff --git a/make/opensslcert.pm b/make/opensslcert.pm index 1bf27df15..20da704f7 100644 --- a/make/opensslcert.pm +++ b/make/opensslcert.pm @@ -46,6 +46,7 @@ sub make_openssl_cert() my $state = promptstring_s('What state are you located in?', 'Example State'); my $country = promptstring_s('What is the ISO 3166-1 code for the country you are located in?', 'XZ'); my $time = promptstring_s('How many days do you want your certificate to be valid for?', '365'); + my $use_1024 = promptstring_s('Do you want to generate less secure dhparams which are compatible with old versions of Java?', 'n'); print FH <<__END__; $country $state @@ -56,8 +57,9 @@ $commonname $email __END__ close(FH); -system("cat openssl.template | openssl req -x509 -nodes -newkey rsa:1024 -keyout key.pem -out cert.pem -days $time 2>/dev/null"); -system("openssl dhparam -out dhparams.pem 1024"); +my $dhbits = $use_1024 =~ /^(1|on|true|yes|y)$/ ? 1024 : 2048; +system("cat openssl.template | openssl req -x509 -nodes -newkey rsa:2048 -keyout key.pem -out cert.pem -days $time 2>/dev/null"); +system("openssl dhparam -out dhparams.pem $dhbits"); unlink("openssl.template"); } diff --git a/make/template/inspircd b/make/template/inspircd index 7cd83a8e1..b43ad60c9 100644 --- a/make/template/inspircd +++ b/make/template/inspircd @@ -135,7 +135,7 @@ sub cmd_rehash() sub cmd_cron() { - if (getstatus() == 0) { goto &cmd_start(); } + if (getstatus() == 0) { goto &cmd_start(@_); } exit(); } @@ -149,7 +149,7 @@ sub cmd_restart(@) { cmd_stop(); unlink($pidfile) if (-e $pidfile); - goto &cmd_start; + goto &cmd_start(@_); } sub hid_cheese_sandwich() diff --git a/make/template/main.mk b/make/template/main.mk index 1dff0fc20..23daa7efc 100644 --- a/make/template/main.mk +++ b/make/template/main.mk @@ -89,6 +89,11 @@ INSTMODE_LIB = 0644 D=0 @ENDIF +GCC6=@GCC6@ +@IFEQ $(GCC6) true + CXXFLAGS += -fno-delete-null-pointer-checks +@ENDIF + DBGOK=0 @IFEQ $(D) 0 CXXFLAGS += -O2 @@ -124,8 +129,8 @@ CXXFLAGS += -Iinclude @ELSE @GNU_ONLY MAKEFLAGS += --silent @BSD_ONLY MAKE += -s - RUNCC = perl $(SOURCEPATH)/make/run-cc.pl $(CC) - RUNLD = perl $(SOURCEPATH)/make/run-cc.pl $(CC) + RUNCC = perl "$(SOURCEPATH)/make/run-cc.pl" $(CC) + RUNLD = perl "$(SOURCEPATH)/make/run-cc.pl" $(CC) VERBOSE = @ENDIF @@ -160,7 +165,7 @@ all: $(FOOTER) target: $(HEADER) $(MAKEENV) perl make/calcdep.pl - cd $(BUILDPATH); $(MAKEENV) $(MAKE) -f real.mk $(TARGET) + cd "$(BUILDPATH)"; $(MAKEENV) $(MAKE) -f real.mk $(TARGET) debug: @${MAKE} D=1 all @@ -227,9 +232,9 @@ install: target @-$(INSTALL) -d -m $(INSTMODE_DIR) $(CONPATH)/examples/aliases @-$(INSTALL) -d -m $(INSTMODE_DIR) $(CONPATH)/examples/modules @-$(INSTALL) -d -m $(INSTMODE_DIR) $(MODPATH) - [ $(BUILDPATH)/bin/ -ef $(BINPATH) ] || $(INSTALL) -m $(INSTMODE_BIN) $(BUILDPATH)/bin/inspircd $(BINPATH) + [ "$(BUILDPATH)/bin/" -ef $(BINPATH) ] || $(INSTALL) -m $(INSTMODE_BIN) "$(BUILDPATH)/bin/inspircd" $(BINPATH) @IFNDEF PURE_STATIC - [ $(BUILDPATH)/modules/ -ef $(MODPATH) ] || $(INSTALL) -m $(INSTMODE_LIB) $(BUILDPATH)/modules/*.so $(MODPATH) + [ "$(BUILDPATH)/modules/" -ef $(MODPATH) ] || $(INSTALL) -m $(INSTMODE_LIB) "$(BUILDPATH)/modules/"*.so $(MODPATH) @ENDIF -$(INSTALL) -m $(INSTMODE_BIN) @STARTSCRIPT@ $(BASE) 2>/dev/null -$(INSTALL) -m $(INSTMODE_LIB) tools/gdbargs $(BASE)/.gdbargs 2>/dev/null @@ -258,16 +263,17 @@ GNUmakefile BSDmakefile: make/template/main.mk configure $(RCS_FILES) clean: @echo Cleaning... - -rm -f $(BUILDPATH)/bin/inspircd $(BUILDPATH)/include $(BUILDPATH)/real.mk - -rm -rf $(BUILDPATH)/obj $(BUILDPATH)/modules - @-rmdir $(BUILDPATH)/bin 2>/dev/null - @-rmdir $(BUILDPATH) 2>/dev/null + -rm -f "$(BUILDPATH)/bin/inspircd" "$(BUILDPATH)/include" "$(BUILDPATH)/real.mk" + -rm -rf "$(BUILDPATH)/obj" "$(BUILDPATH)/modules" + @-rmdir "$(BUILDPATH)/bin" 2>/dev/null + @-rmdir "$(BUILDPATH)" 2>/dev/null @echo Completed. deinstall: -rm -f $(BINPATH)/inspircd -rm -rf $(CONPATH)/examples - -rm -f $(MODPATH)/*.so + -rm -f $(MODPATH)/cmd_*.so + -rm -f $(MODPATH)/m_*.so -rm -f $(BASE)/.gdbargs -rm -f $(BASE)/org.inspircd.plist @@ -283,8 +289,8 @@ configureclean: -rm -f org.inspircd.plist distclean: clean configureclean - -rm -rf $(SOURCEPATH)/run - find $(SOURCEPATH)/src/modules -type l | xargs rm -f + -rm -rf "$(SOURCEPATH)/run" + find "$(SOURCEPATH)/src/modules" -type l | xargs rm -f help: @echo 'InspIRCd Makefile' @@ -314,4 +320,6 @@ help: @echo ' deinstall Removes the files created by "make install"' @echo +.NOTPARALLEL: + .PHONY: all target debug debug-header mod-header mod-footer std-header finishmessage install clean deinstall squeakyclean configureclean help diff --git a/make/utilities.pm b/make/utilities.pm index ae16ce3dc..baba584ad 100644 --- a/make/utilities.pm +++ b/make/utilities.pm @@ -29,6 +29,7 @@ use warnings FATAL => qw(all); use Exporter 'import'; use POSIX; +use File::Temp; use Getopt::Long; use Fcntl; our @EXPORT = qw(make_rpath pkgconfig_get_include_dirs pkgconfig_get_lib_dirs pkgconfig_check_version translate_functions promptstring); @@ -404,7 +405,7 @@ sub translate_functions($$) my $tmpfile; do { - $tmpfile = tmpnam(); + $tmpfile = File::Temp::tmpnam(); } until sysopen(TF, $tmpfile, O_RDWR|O_CREAT|O_EXCL|O_NOFOLLOW, 0700); print "(Created and executed \e[1;32m$tmpfile\e[0m)\n"; print TF $1; diff --git a/modulemanager b/modulemanager index af5bf113c..42566d3b1 100755 --- a/modulemanager +++ b/modulemanager @@ -22,9 +22,15 @@ use strict; use warnings FATAL => qw(all); -use make::configure; +BEGIN { + require 5.8.0; + push @INC, '.'; +} BEGIN { + # HACK: for some reason this needs to be in a second BEGIN block + # or it doesn't receive the updated @INC from above. + use make::configure; unless (module_installed("LWP::Simple")) { die "Your system is missing the LWP::Simple Perl module!"; } diff --git a/src/commands/cmd_kill.cpp b/src/commands/cmd_kill.cpp index 17c8a76a0..7bdf32c74 100644 --- a/src/commands/cmd_kill.cpp +++ b/src/commands/cmd_kill.cpp @@ -111,7 +111,8 @@ CmdResult CommandKill::Handle (const std::vector<std::string>& parameters, User if (!IS_LOCAL(u)) { // remote kill - ServerInstance->SNO->WriteToSnoMask('K', "Remote kill by %s: %s (%s)", user->nick.c_str(), u->GetFullRealHost().c_str(), parameters[1].c_str()); + if (!ServerInstance->Config->HideULineKills || !ServerInstance->ULine(user->server)) + ServerInstance->SNO->WriteToSnoMask('K', "Remote kill by %s: %s (%s)", user->nick.c_str(), u->GetFullRealHost().c_str(), parameters[1].c_str()); FOREACH_MOD(I_OnRemoteKill, OnRemoteKill(user, u, killreason, killreason)); } else @@ -121,10 +122,13 @@ CmdResult CommandKill::Handle (const std::vector<std::string>& parameters, User * XXX - this isn't entirely correct, servers A - B - C, oper on A, client on C. Oper kills client, A and B will get remote kill * snotices, C will get a local kill snotice. this isn't accurate, and needs fixing at some stage. -- w00t */ - if (IS_LOCAL(user)) - ServerInstance->SNO->WriteGlobalSno('k',"Local Kill by %s: %s (%s)", user->nick.c_str(), u->GetFullRealHost().c_str(), parameters[1].c_str()); - else - ServerInstance->SNO->WriteToSnoMask('k',"Local Kill by %s: %s (%s)", user->nick.c_str(), u->GetFullRealHost().c_str(), parameters[1].c_str()); + if (!ServerInstance->Config->HideULineKills || !ServerInstance->ULine(user->server)) + { + if (IS_LOCAL(user)) + ServerInstance->SNO->WriteGlobalSno('k',"Local Kill by %s: %s (%s)", user->nick.c_str(), u->GetFullRealHost().c_str(), parameters[1].c_str()); + else + ServerInstance->SNO->WriteToSnoMask('k',"Local Kill by %s: %s (%s)", user->nick.c_str(), u->GetFullRealHost().c_str(), parameters[1].c_str()); + } ServerInstance->Logs->Log("KILL",DEFAULT,"LOCAL KILL: %s :%s!%s!%s (%s)", u->nick.c_str(), ServerInstance->Config->ServerName.c_str(), user->dhost.c_str(), user->nick.c_str(), parameters[1].c_str()); /* Bug #419, make sure this message can only occur once even in the case of multiple KILL messages crossing the network, and change to show * hidekillsserver as source if possible @@ -134,7 +138,7 @@ CmdResult CommandKill::Handle (const std::vector<std::string>& parameters, User u->Write(":%s KILL %s :%s!%s!%s (%s)", ServerInstance->Config->HideKillsServer.empty() ? user->GetFullHost().c_str() : ServerInstance->Config->HideKillsServer.c_str(), u->nick.c_str(), ServerInstance->Config->ServerName.c_str(), - user->dhost.c_str(), + ServerInstance->Config->HideKillsServer.empty() ? user->dhost.c_str() : ServerInstance->Config->HideKillsServer.c_str(), ServerInstance->Config->HideKillsServer.empty() ? user->nick.c_str() : ServerInstance->Config->HideKillsServer.c_str(), parameters[1].c_str()); } diff --git a/src/commands/cmd_list.cpp b/src/commands/cmd_list.cpp index 2c420d1dd..eb28fb89c 100644 --- a/src/commands/cmd_list.cpp +++ b/src/commands/cmd_list.cpp @@ -49,8 +49,7 @@ CmdResult CommandList::Handle (const std::vector<std::string>& parameters, User user->WriteNumeric(321, "%s Channel :Users Name",user->nick.c_str()); - /* Work around mIRC suckyness. YOU SUCK, KHALED! */ - if (parameters.size() == 1) + if ((parameters.size() == 1) && (!parameters[0].empty())) { if (parameters[0][0] == '<') { diff --git a/src/commands/cmd_oper.cpp b/src/commands/cmd_oper.cpp index 1a5e7e178..95f6b98df 100644 --- a/src/commands/cmd_oper.cpp +++ b/src/commands/cmd_oper.cpp @@ -69,7 +69,7 @@ CmdResult CommandOper::HandleLocal(const std::vector<std::string>& parameters, L snprintf(TheIP, MAXBUF,"%s@%s",user->ident.c_str(),user->GetIPString()); OperIndex::iterator i = ServerInstance->Config->oper_blocks.find(parameters[0]); - if (i != ServerInstance->Config->oper_blocks.end()) + if ((i != ServerInstance->Config->oper_blocks.end()) && (i->second->oper_block)) { OperInfo* ifo = i->second; ConfigTag* tag = ifo->oper_block; diff --git a/src/commands/cmd_stats.cpp b/src/commands/cmd_stats.cpp index d547635ed..aa5bf44cd 100644 --- a/src/commands/cmd_stats.cpp +++ b/src/commands/cmd_stats.cpp @@ -39,7 +39,7 @@ class CommandStats : public Command public: /** Constructor for stats. */ - CommandStats ( Module* parent) : Command(parent,"STATS",1,2) { syntax = "<stats-symbol> [<servername>]"; } + CommandStats ( Module* parent) : Command(parent,"STATS",1,2) { allow_empty_last_param = false; syntax = "<stats-symbol> [<servername>]"; } /** Handle command. * @param parameters The parameters to the comamnd * @param pcnt The number of parameters passed to teh command diff --git a/src/commands/cmd_who.cpp b/src/commands/cmd_who.cpp index 90c26a974..8438f8cdd 100644 --- a/src/commands/cmd_who.cpp +++ b/src/commands/cmd_who.cpp @@ -58,13 +58,15 @@ class CommandWho : public Command }; -static Channel* get_first_visible_channel(User *u) +static Channel* get_first_visible_channel(User *source, User *u) { UCListIter i = u->chans.begin(); while (i != u->chans.end()) { Channel* c = *i++; - if (!c->IsModeSet('s')) + + /* XXX move the +I check into m_hidechans */ + if (source == u || !(c->IsModeSet('s') || c->IsModeSet('p') || u->IsModeSet('I')) || c->HasUser(source)) return c; } return NULL; @@ -189,7 +191,7 @@ bool CommandWho::CanView(Channel* chan, User* user) void CommandWho::SendWhoLine(User* user, const std::vector<std::string>& parms, const std::string &initial, Channel* ch, User* u, std::vector<std::string> &whoresults) { if (!ch) - ch = get_first_visible_channel(u); + ch = get_first_visible_channel(user, u); std::string wholine = initial + (ch ? ch->name : "*") + " " + u->ident + " " + (opt_showrealhost ? u->host : u->dhost) + " "; diff --git a/src/configparser.cpp b/src/configparser.cpp index 94192a71b..409ebdd39 100644 --- a/src/configparser.cpp +++ b/src/configparser.cpp @@ -388,19 +388,20 @@ bool ParseStack::ParseExec(const std::string& name, int flags, const std::string return ok; } -bool ConfigTag::readString(const std::string& key, std::string& value, bool allow_lf) -{ #ifdef __clang__ # pragma clang diagnostic push # pragma clang diagnostic ignored "-Wunknown-pragmas" # pragma clang diagnostic ignored "-Wundefined-bool-conversion" +#elif defined __GNUC__ +# pragma GCC diagnostic push +# pragma GCC diagnostic ignored "-Wpragmas" +# pragma GCC diagnostic ignored "-Wnonnull-compare" #endif +bool ConfigTag::readString(const std::string& key, std::string& value, bool allow_lf) +{ // TODO: this is undefined behaviour but changing the API is too risky for 2.0. if (!this) return false; -#ifdef __clang__ -# pragma clang diagnostic pop -#endif for(std::vector<KeyVal>::iterator j = items.begin(); j != items.end(); ++j) { if(j->first != key) @@ -418,6 +419,11 @@ bool ConfigTag::readString(const std::string& key, std::string& value, bool allo } return false; } +#ifdef __clang__ +# pragma clang diagnostic pop +#elif defined __GNUC__ +# pragma GCC diagnostic pop +#endif std::string ConfigTag::getString(const std::string& key, const std::string& def) { diff --git a/src/configreader.cpp b/src/configreader.cpp index bcee938d5..301db14e8 100644 --- a/src/configreader.cpp +++ b/src/configreader.cpp @@ -531,6 +531,7 @@ void ServerConfig::Fill() HideBans = security->getBool("hidebans"); HideWhoisServer = security->getString("hidewhois"); HideKillsServer = security->getString("hidekills"); + HideULineKills = security->getBool("hideulinekills"); RestrictBannedUsers = security->getBool("restrictbannedusers", true); GenericOper = security->getBool("genericoper"); NoUserDns = ConfValue("performance")->getBool("nouserdns"); @@ -728,7 +729,7 @@ void ServerConfig::Apply(ServerConfig* old, const std::string &useruid) // write once here, to try it out and make sure its ok if (valid) - ServerInstance->WritePID(this->PID); + ServerInstance->WritePID(this->PID, !old); if (old && valid) { diff --git a/src/dns.cpp b/src/dns.cpp index 14305ccab..3d3bc947f 100644 --- a/src/dns.cpp +++ b/src/dns.cpp @@ -121,7 +121,7 @@ class CacheTimer : public Timer DNS* dns; public: CacheTimer(DNS* thisdns) - : Timer(3600, ServerInstance->Time(), true), dns(thisdns) { } + : Timer(5*60, ServerInstance->Time(), true), dns(thisdns) { } virtual void Tick(time_t) { @@ -162,6 +162,8 @@ class RequestTimeout : public Timer CachedQuery::CachedQuery(const std::string &res, QueryType qt, unsigned int ttl) : data(res), type(qt) { + if (ttl > 5*60) + ttl = 5*60; expires = ServerInstance->Time() + ttl; } @@ -1058,7 +1060,11 @@ void DNS::HandleEvent(EventType, int) ServerInstance->stats->statsDnsGood++; if (!this->GetCache(res.original.c_str())) + { + if (cache->size() >= MAX_CACHE_SIZE) + cache->clear(); this->cache->insert(std::make_pair(res.original.c_str(), CachedQuery(res.result, res.type, res.ttl))); + } Classes[res.id]->OnLookupComplete(res.result, res.ttl, false); delete Classes[res.id]; diff --git a/src/inspircd.cpp b/src/inspircd.cpp index 766aeaf8e..0fa90fca5 100644 --- a/src/inspircd.cpp +++ b/src/inspircd.cpp @@ -294,7 +294,7 @@ bool InspIRCd::DaemonSeed() #endif } -void InspIRCd::WritePID(const std::string &filename) +void InspIRCd::WritePID(const std::string& filename, bool exitonfail) { #ifndef _WIN32 std::string fname(filename); @@ -307,10 +307,12 @@ void InspIRCd::WritePID(const std::string &filename) outfile.close(); } else - { - std::cout << "Failed to write PID-file '" << fname << "', exiting." << std::endl; - this->Logs->Log("STARTUP",DEFAULT,"Failed to write PID-file '%s', exiting.",fname.c_str()); - Exit(EXIT_STATUS_PID); + {
+ if (exitonfail)
+ std::cout << "Failed to write PID-file '" << fname << "', exiting." << std::endl; + this->Logs->Log("STARTUP",DEFAULT,"Failed to write PID-file '%s'%s",fname.c_str(), (exitonfail ? ", exiting." : ""));
+ if (exitonfail) + Exit(EXIT_STATUS_PID);
} #endif } @@ -814,11 +816,11 @@ int InspIRCd::Run() /* Allow a buffer of two seconds drift on this so that ntpdate etc dont harass admins */ if (TIME.tv_sec < OLDTIME - 2) { - SNO->WriteToSnoMask('d', "\002EH?!\002 -- Time is flowing BACKWARDS in this dimension! Clock drifted backwards %lu secs.", (unsigned long)OLDTIME-TIME.tv_sec); + SNO->WriteToSnoMask('d', "\002EH?!\002 -- Time is flowing BACKWARDS in this dimension! Clock drifted backwards %lu secs.", (unsigned long)(OLDTIME-TIME.tv_sec)); } else if (TIME.tv_sec > OLDTIME + 2) { - SNO->WriteToSnoMask('d', "\002EH?!\002 -- Time is jumping FORWARDS! Clock skipped %lu secs.", (unsigned long)TIME.tv_sec - OLDTIME); + SNO->WriteToSnoMask('d', "\002EH?!\002 -- Time is jumping FORWARDS! Clock skipped %lu secs.", (unsigned long)(TIME.tv_sec - OLDTIME)); } OLDTIME = TIME.tv_sec; diff --git a/src/mode.cpp b/src/mode.cpp index 89ff37fa1..0f5d45783 100644 --- a/src/mode.cpp +++ b/src/mode.cpp @@ -837,11 +837,19 @@ std::string ModeParser::GiveModeList(ModeMasks m) return type1 + "," + type2 + "," + type3 + "," + type4; } +struct PrefixModeSorter +{ + bool operator()(ModeHandler* lhs, ModeHandler* rhs) + { + return lhs->GetPrefixRank() < rhs->GetPrefixRank(); + } +}; + std::string ModeParser::BuildPrefixes(bool lettersAndModes) { std::string mletters; std::string mprefixes; - std::map<int,std::pair<char,char> > prefixes; + std::vector<ModeHandler*> prefixes; for (unsigned char mode = 'A'; mode <= 'z'; mode++) { @@ -849,15 +857,15 @@ std::string ModeParser::BuildPrefixes(bool lettersAndModes) if ((modehandlers[pos]) && (modehandlers[pos]->GetPrefix())) { - prefixes[modehandlers[pos]->GetPrefixRank()] = std::make_pair( - modehandlers[pos]->GetPrefix(), modehandlers[pos]->GetModeChar()); + prefixes.push_back(modehandlers[pos]); } } - for(std::map<int,std::pair<char,char> >::reverse_iterator n = prefixes.rbegin(); n != prefixes.rend(); n++) + std::sort(prefixes.begin(), prefixes.end(), PrefixModeSorter()); + for (std::vector<ModeHandler*>::const_reverse_iterator n = prefixes.rbegin(); n != prefixes.rend(); ++n) { - mletters = mletters + n->second.first; - mprefixes = mprefixes + n->second.second; + mletters += (*n)->GetPrefix(); + mprefixes += (*n)->GetModeChar(); } return lettersAndModes ? "(" + mprefixes + ")" + mletters : mletters; diff --git a/src/modules/extra/m_ldapauth.cpp b/src/modules/extra/m_ldapauth.cpp index 6c765fb2e..405bab082 100644 --- a/src/modules/extra/m_ldapauth.cpp +++ b/src/modules/extra/m_ldapauth.cpp @@ -310,36 +310,25 @@ public: } RAIILDAPMessage msg; - std::string what = (attribute + "=" + (useusername ? user->ident : user->nick)); - if ((res = ldap_search_ext_s(conn, base.c_str(), searchscope, what.c_str(), NULL, 0, NULL, NULL, NULL, 0, &msg)) != LDAP_SUCCESS) + std::string what; + std::string::size_type pos = user->password.find(':'); + // If a username is provided in PASS, use it, othewrise user their nick or ident + if (pos != std::string::npos) { - // Do a second search, based on password, if it contains a : - // That is, PASS <user>:<password> will work. - size_t pos = user->password.find(":"); - if (pos != std::string::npos) - { - // manpage says we must deallocate regardless of success or failure - // since we're about to do another query (and reset msg), first - // free the old one. - msg.dealloc(); - - std::string cutpassword = user->password.substr(0, pos); - res = ldap_search_ext_s(conn, base.c_str(), searchscope, cutpassword.c_str(), NULL, 0, NULL, NULL, NULL, 0, &msg); - - if (res == LDAP_SUCCESS) - { - // Trim the user: prefix, leaving just 'pass' for later password check - user->password = user->password.substr(pos + 1); - } - } + what = (attribute + "=" + user->password.substr(0, pos)); - // It may have found based on user:pass check above. - if (res != LDAP_SUCCESS) - { - if (verbose) - ServerInstance->SNO->WriteToSnoMask('c', "Forbidden connection from %s (LDAP search failed: %s)", user->GetFullRealHost().c_str(), ldap_err2string(res)); - return false; - } + // Trim the user: prefix, leaving just 'pass' for later password check + user->password = user->password.substr(pos + 1); + } + else + { + what = (attribute + "=" + (useusername ? user->ident : user->nick)); + } + if ((res = ldap_search_ext_s(conn, base.c_str(), searchscope, what.c_str(), NULL, 0, NULL, NULL, NULL, 0, &msg)) != LDAP_SUCCESS) + { + if (verbose) + ServerInstance->SNO->WriteToSnoMask('c', "Forbidden connection from %s (LDAP search failed: %s)", user->GetFullRealHost().c_str(), ldap_err2string(res)); + return false; } if (ldap_count_entries(conn, msg) > 1) { @@ -404,7 +393,7 @@ public: std::string dnPart; while (stream.GetToken(dnPart)) { - std::string::size_type pos = dnPart.find('='); + pos = dnPart.find('='); if (pos == std::string::npos) // malformed continue; diff --git a/src/modules/extra/m_sqlite3.cpp b/src/modules/extra/m_sqlite3.cpp index 1e3a65a18..47880c02c 100644 --- a/src/modules/extra/m_sqlite3.cpp +++ b/src/modules/extra/m_sqlite3.cpp @@ -90,8 +90,10 @@ class SQLConn : public SQLProvider std::string host = tag->getString("hostname"); if (sqlite3_open_v2(host.c_str(), &conn, SQLITE_OPEN_READWRITE, 0) != SQLITE_OK) { - ServerInstance->Logs->Log("m_sqlite3",DEFAULT, "WARNING: Could not open DB with id: " + tag->getString("id")); + // Even in case of an error conn must be closed + sqlite3_close(conn); conn = NULL; + ServerInstance->Logs->Log("m_sqlite3",DEFAULT, "WARNING: Could not open DB with id: " + tag->getString("id")); } } diff --git a/src/modules/extra/m_ssl_gnutls.cpp b/src/modules/extra/m_ssl_gnutls.cpp index 59ac1acb3..2f4acf3f0 100644 --- a/src/modules/extra/m_ssl_gnutls.cpp +++ b/src/modules/extra/m_ssl_gnutls.cpp @@ -28,7 +28,7 @@ #include "m_cap.h" #ifdef _WIN32 -# pragma comment(lib, "libgnutls-28.lib") +# pragma comment(lib, "libgnutls-30.lib") #endif /* $ModDesc: Provides SSL support for clients */ @@ -703,6 +703,9 @@ class ModuleSSLGnuTLS : public Module if (ret > 0) { recvq.append(buffer, ret); + // Schedule a read if there is still data in the GnuTLS buffer + if (gnutls_record_check_pending(session->sess) > 0) + ServerInstance->SE->ChangeEventMask(user, FD_ADD_TRIAL_READ); return 1; } else if (ret == GNUTLS_E_AGAIN || ret == GNUTLS_E_INTERRUPTED) diff --git a/src/modules/extra/m_ssl_openssl.cpp b/src/modules/extra/m_ssl_openssl.cpp index b21091d3f..aee7a5e34 100644 --- a/src/modules/extra/m_ssl_openssl.cpp +++ b/src/modules/extra/m_ssl_openssl.cpp @@ -405,12 +405,19 @@ class ModuleSSLOpenSSL : public Module #endif ERR_clear_error(); - if ((SSL_CTX_set_tmp_dh(ctx, ret) < 0) || (SSL_CTX_set_tmp_dh(clictx, ret) < 0)) + if (ret) { - ServerInstance->Logs->Log("m_ssl_openssl",DEFAULT, "m_ssl_openssl.so: Couldn't set DH parameters %s. SSL errors follow:", dhfile.c_str()); - ERR_print_errors_cb(error_callback, this); + if ((SSL_CTX_set_tmp_dh(ctx, ret) < 0) || (SSL_CTX_set_tmp_dh(clictx, ret) < 0)) + { + ServerInstance->Logs->Log("m_ssl_openssl", DEFAULT, "m_ssl_openssl.so: Couldn't set DH parameters %s. SSL errors follow:", dhfile.c_str()); + ERR_print_errors_cb(error_callback, this); + } + DH_free(ret); + } + else + { + ServerInstance->Logs->Log("m_ssl_openssl", DEFAULT, "m_ssl_openssl.so: Couldn't set DH parameters %s.", dhfile.c_str()); } - DH_free(ret); } #ifndef _WIN32 @@ -591,8 +598,15 @@ class ModuleSSLOpenSSL : public Module if (ret > 0) { recvq.append(buffer, ret); + + int mask = 0; + // Schedule a read if there is still data in the OpenSSL buffer + if (SSL_pending(session->sess) > 0) + mask |= FD_ADD_TRIAL_READ; if (session->data_to_write) - ServerInstance->SE->ChangeEventMask(user, FD_WANT_POLL_READ | FD_WANT_SINGLE_WRITE); + mask |= FD_WANT_POLL_READ | FD_WANT_SINGLE_WRITE; + if (mask != 0) + ServerInstance->SE->ChangeEventMask(user, mask); return 1; } else if (ret == 0) diff --git a/src/modules/m_callerid.cpp b/src/modules/m_callerid.cpp index 4147f0b16..2df6d7af0 100644 --- a/src/modules/m_callerid.cpp +++ b/src/modules/m_callerid.cpp @@ -68,7 +68,12 @@ struct CallerIDExtInfo : public ExtensionItem void unserialize(SerializeFormat format, Extensible* container, const std::string& value) { + void* old = get_raw(container); + if (old) + this->free(old); callerid_data* dat = new callerid_data; + set_raw(container, dat); + irc::commasepstream s(value); std::string tok; if (s.GetToken(tok)) @@ -89,10 +94,6 @@ struct CallerIDExtInfo : public ExtensionItem } } } - - void* old = set_raw(container, dat); - if (old) - this->free(old); } callerid_data* get(User* user, bool create) diff --git a/src/modules/m_cap.cpp b/src/modules/m_cap.cpp index e9f4dae90..6b4387fdd 100644 --- a/src/modules/m_cap.cpp +++ b/src/modules/m_cap.cpp @@ -66,23 +66,28 @@ class CommandCAP : public Command while (cap_stream.GetToken(cap_)) { - Data.wanted.push_back(cap_); + // Whilst the handling of extraneous spaces is not currently defined in the CAP specification + // every single other implementation ignores extraneous spaces. Lets copy them for + // compatibility purposes. + trim(cap_); + if (!cap_.empty()) + Data.wanted.push_back(cap_); } reghold.set(user, 1); Data.Send(); - if (Data.ack.size() > 0) + if (Data.wanted.empty()) { - std::string AckResult = irc::stringjoiner(" ", Data.ack, 0, Data.ack.size() - 1).GetJoined(); - user->WriteServ("CAP %s ACK :%s", user->nick.c_str(), AckResult.c_str()); + user->WriteServ("CAP %s ACK :%s", user->nick.c_str(), parameters[1].c_str()); + return CMD_SUCCESS; } - if (Data.wanted.size() > 0) - { - std::string NakResult = irc::stringjoiner(" ", Data.wanted, 0, Data.wanted.size() - 1).GetJoined(); - user->WriteServ("CAP %s NAK :%s", user->nick.c_str(), NakResult.c_str()); - } + // HACK: reset all of the caps which were enabled on this user because a cap request is atomic. + for (std::vector<std::pair<GenericCap*, int> >::iterator iter = Data.changed.begin(); iter != Data.changed.end(); ++iter) + iter->first->ext.set(user, iter->second); + + user->WriteServ("CAP %s NAK :%s", user->nick.c_str(), parameters[1].c_str()); } else if (subcommand == "END") { diff --git a/src/modules/m_cap.h b/src/modules/m_cap.h index 409671f48..23cf8cf69 100644 --- a/src/modules/m_cap.h +++ b/src/modules/m_cap.h @@ -21,6 +21,8 @@ #ifndef M_CAP_H #define M_CAP_H +class GenericCap; + class CapEvent : public Event { public: @@ -35,6 +37,7 @@ class CapEvent : public Event CapEventType type; std::vector<std::string> wanted; std::vector<std::string> ack; + std::vector<std::pair<GenericCap*, int> > changed; // HACK: clean this up before 2.2 User* user; CapEvent(Module* sender, User* u, CapEventType capevtype) : Event(sender, "cap_request"), type(capevtype), user(u) {} }; @@ -67,7 +70,7 @@ class GenericCap // we can handle this, so ACK it, and remove it from the wanted list data->ack.push_back(*it); data->wanted.erase(it); - ext.set(data->user, enablecap ? 1 : 0); + data->changed.push_back(std::make_pair(this, ext.set(data->user, enablecap ? 1 : 0))); break; } } diff --git a/src/modules/m_censor.cpp b/src/modules/m_censor.cpp index 50c8e22a7..65b965df2 100644 --- a/src/modules/m_censor.cpp +++ b/src/modules/m_censor.cpp @@ -101,7 +101,7 @@ class ModuleCensor : public Module { if (index->second.empty()) { - user->WriteNumeric(ERR_WORDFILTERED, "%s %s %s :Your message contained a censored word, and was blocked", user->nick.c_str(), ((Channel*)dest)->name.c_str(), index->first.c_str()); + user->WriteNumeric(ERR_WORDFILTERED, "%s %s %s :Your message contained a censored word, and was blocked", user->nick.c_str(), ((target_type == TYPE_CHANNEL) ? ((Channel*)dest)->name.c_str() : ((User*)dest)->nick.c_str()), index->first.c_str()); return MOD_RES_DENY; } diff --git a/src/modules/m_cgiirc.cpp b/src/modules/m_cgiirc.cpp index cce2e7855..09f6a4659 100644 --- a/src/modules/m_cgiirc.cpp +++ b/src/modules/m_cgiirc.cpp @@ -73,6 +73,7 @@ class CommandWebirc : public Command realhost("cgiirc_realhost", Creator), realip("cgiirc_realip", Creator), webirc_hostname("cgiirc_webirc_hostname", Creator), webirc_ip("cgiirc_webirc_ip", Creator) { + allow_empty_last_param = false; works_before_reg = true; this->syntax = "password client hostname ip"; } @@ -81,6 +82,14 @@ class CommandWebirc : public Command if(user->registered == REG_ALL) return CMD_FAILURE; + irc::sockets::sockaddrs ipaddr; + if (!irc::sockets::aptosa(parameters[3], 0, ipaddr)) + { + IS_LOCAL(user)->CommandFloodPenalty += 5000; + ServerInstance->SNO->WriteGlobalSno('a', "Connecting user %s tried to use WEBIRC but gave an invalid IP address.", user->GetFullRealHost().c_str()); + return CMD_FAILURE; + } + for(CGIHostlist::iterator iter = Hosts.begin(); iter != Hosts.end(); iter++) { if(InspIRCd::Match(user->host, iter->hostmask, ascii_case_insensitive_map) || InspIRCd::MatchCIDR(user->GetIPString(), iter->hostmask, ascii_case_insensitive_map)) @@ -108,6 +117,7 @@ class CommandWebirc : public Command } } + IS_LOCAL(user)->CommandFloodPenalty += 5000; ServerInstance->SNO->WriteGlobalSno('a', "Connecting user %s tried to use WEBIRC, but didn't match any configured webirc blocks.", user->GetFullRealHost().c_str()); return CMD_FAILURE; } diff --git a/src/modules/m_check.cpp b/src/modules/m_check.cpp index 9c5c414f1..5063368b8 100644 --- a/src/modules/m_check.cpp +++ b/src/modules/m_check.cpp @@ -174,7 +174,7 @@ class CommandCheck : public Command /* /check on a channel */ user->SendText(checkstr + " timestamp " + timestring(targchan->age)); - if (targchan->topic[0] != 0) + if (!targchan->topic.empty()) { /* there is a topic, assume topic related information exists */ user->SendText(checkstr + " topic " + targchan->topic); diff --git a/src/modules/m_cloaking.cpp b/src/modules/m_cloaking.cpp index 105d68833..f4cfdb54f 100644 --- a/src/modules/m_cloaking.cpp +++ b/src/modules/m_cloaking.cpp @@ -96,6 +96,10 @@ class CloakUser : public ModeHandler if (adding) { + // assume this is more correct + if (user->registered != REG_ALL && user->host != user->dhost) + return MODEACTION_DENY; + std::string* cloak = ext.get(user); if (!cloak) @@ -493,11 +497,14 @@ class ModuleCloaking : public Module { std::string chost; + irc::sockets::sockaddrs hostip; + bool host_is_ip = irc::sockets::aptosa(host, ip.port(), hostip) && hostip == ip; + switch (mode) { case MODE_COMPAT_HOST: { - if (ipstr != host) + if (!host_is_ip) { std::string tail = LastTwoDomainParts(host); @@ -520,7 +527,7 @@ class ModuleCloaking : public Module break; case MODE_HALF_CLOAK: { - if (ipstr != host) + if (!host_is_ip) chost = prefix + SegmentCloak(host, 1, 6) + LastTwoDomainParts(host); if (chost.empty() || chost.length() > 50) chost = SegmentIP(ip, false); diff --git a/src/modules/m_dccallow.cpp b/src/modules/m_dccallow.cpp index 829c1d337..05fff8937 100644 --- a/src/modules/m_dccallow.cpp +++ b/src/modules/m_dccallow.cpp @@ -58,6 +58,7 @@ SimpleExtItem<dccallowlist>* ext; class CommandDccallow : public Command { public: + unsigned int maxentries; CommandDccallow(Module* parent) : Command(parent, "DCCALLOW", 0) { syntax = "[(+|-)<nick> [<time>]]|[LIST|HELP]"; @@ -140,6 +141,12 @@ class CommandDccallow : public Command ul.push_back(user); } + if (dl->size() >= maxentries) + { + user->WriteNumeric(996, "%s %s :Too many nicks on DCCALLOW list", user->nick.c_str(), user->nick.c_str()); + return CMD_FAILURE; + } + for (dccallowlist::const_iterator k = dl->begin(); k != dl->end(); ++k) { if (k->nickname == target->nick) @@ -264,7 +271,7 @@ class ModuleDCCAllow : public Module ext = new SimpleExtItem<dccallowlist>("dccallow", this); ServerInstance->Modules->AddService(*ext); ServerInstance->Modules->AddService(cmd); - ReadFileConf(); + OnRehash(NULL); Implementation eventlist[] = { I_OnUserPreMessage, I_OnUserPreNotice, I_OnUserQuit, I_OnUserPostNick, I_OnRehash }; ServerInstance->Modules->Attach(eventlist, this, sizeof(eventlist)/sizeof(Implementation)); } @@ -272,6 +279,8 @@ class ModuleDCCAllow : public Module virtual void OnRehash(User* user) { ReadFileConf(); + ConfigTag* tag = ServerInstance->Config->ConfValue("dccallow"); + cmd.maxentries = tag->getInt("maxentries", 20); } virtual void OnUserQuit(User* user, const std::string &reason, const std::string &oper_message) @@ -331,29 +340,43 @@ class ModuleDCCAllow : public Module return MOD_RES_PASSTHRU; } - // tokenize - std::stringstream ss(text); - std::string buf; - std::vector<std::string> tokens; - - while (ss >> buf) - tokens.push_back(buf); - - if (tokens.size() < 2) + std::string buf = text.substr(5); + size_t s = buf.find(' '); + if (s == std::string::npos) return MOD_RES_PASSTHRU; - irc::string type = tokens[1].c_str(); + irc::string type = assign(buf.substr(0, s)); ConfigTag* conftag = ServerInstance->Config->ConfValue("dccallow"); bool blockchat = conftag->getBool("blockchat"); if (type == "SEND") { - if (tokens.size() < 3) + size_t first; + + buf = buf.substr(s + 1); + + if (!buf.empty() && buf[0] == '"') + { + s = buf.find('"', 1); + + if (s == std::string::npos || s <= 1) + return MOD_RES_PASSTHRU; + + --s; + first = 1; + } + else + { + s = buf.find(' '); + first = 0; + } + + if (s == std::string::npos) return MOD_RES_PASSTHRU; std::string defaultaction = conftag->getString("action"); - std::string filename = tokens[2]; + std::string filename = buf.substr(first, s); bool found = false; for (unsigned int i = 0; i < bfl.size(); i++) diff --git a/src/modules/m_dnsbl.cpp b/src/modules/m_dnsbl.cpp index d4101686a..3dea080ce 100644 --- a/src/modules/m_dnsbl.cpp +++ b/src/modules/m_dnsbl.cpp @@ -70,8 +70,8 @@ class DNSBLResolver : public Resolver int i = countExt.get(them); if (i) countExt.set(them, i - 1); - // Now we calculate the bitmask: 256*(256*(256*a+b)+c)+d - if(result.length()) + // All replies should be in 127.0.0.0/8 + if (result.compare(0, 4, "127.") == 0) { unsigned int bitmask = 0, record = 0; bool match = false; @@ -82,6 +82,7 @@ class DNSBLResolver : public Resolver switch (ConfEntry->type) { case DNSBLConfEntry::A_BITMASK: + // Now we calculate the bitmask: 256*(256*(256*a+b)+c)+d bitmask = resultip.s_addr >> 24; /* Last octet (network byte order) */ bitmask &= ConfEntry->bitmask; match = (bitmask != 0); @@ -196,7 +197,11 @@ class DNSBLResolver : public Resolver ConfEntry->stats_misses++; } else + { + if (!result.empty()) + ServerInstance->SNO->WriteGlobalSno('a', "DNSBL: %s returned address outside of acceptable subnet 127.0.0.0/8: %s", ConfEntry->domain.c_str(), result.c_str()); ConfEntry->stats_misses++; + } } } diff --git a/src/modules/m_hideoper.cpp b/src/modules/m_hideoper.cpp index 88b0c4cdf..32999d9f0 100644 --- a/src/modules/m_hideoper.cpp +++ b/src/modules/m_hideoper.cpp @@ -28,25 +28,43 @@ class HideOper : public SimpleUserModeHandler { public: + size_t opercount; + HideOper(Module* Creator) : SimpleUserModeHandler(Creator, "hideoper", 'H') + , opercount(0) { oper = true; } + + ModeAction OnModeChange(User* source, User* dest, Channel* channel, std::string& parameter, bool adding) + { + if (SimpleUserModeHandler::OnModeChange(source, dest, channel, parameter, adding) == MODEACTION_DENY) + return MODEACTION_DENY; + + if (adding) + opercount++; + else + opercount--; + + return MODEACTION_ALLOW; + } }; class ModuleHideOper : public Module { HideOper hm; + bool active; public: ModuleHideOper() : hm(this) + , active(false) { } void init() { ServerInstance->Modules->AddService(hm); - Implementation eventlist[] = { I_OnWhoisLine, I_OnSendWhoLine, I_OnStats }; + Implementation eventlist[] = { I_OnWhoisLine, I_OnSendWhoLine, I_OnStats, I_OnNumeric, I_OnUserQuit }; ServerInstance->Modules->Attach(eventlist, this, sizeof(eventlist)/sizeof(Implementation)); } @@ -60,6 +78,28 @@ class ModuleHideOper : public Module return Version("Provides support for hiding oper status with user mode +H", VF_VENDOR); } + void OnUserQuit(User* user, const std::string&, const std::string&) + { + if (user->IsModeSet('H')) + hm.opercount--; + } + + ModResult OnNumeric(User* user, unsigned int numeric, const std::string& text) + { + if (numeric != 252 || active || user->HasPrivPermission("users/auspex")) + return MOD_RES_PASSTHRU; + + // If there are no visible operators then we shouldn't send the numeric. + size_t opercount = ServerInstance->Users->all_opers.size() - hm.opercount; + if (opercount) + { + active = true; + user->WriteNumeric(252, "%s %lu :operator(s) online", user->nick.c_str(), static_cast<unsigned long>(opercount)); + active = false; + } + return MOD_RES_DENY; + } + ModResult OnWhoisLine(User* user, User* dest, int &numeric, std::string &text) { /* Dont display numeric 313 (RPL_WHOISOPER) if they have +H set and the diff --git a/src/modules/m_httpd_stats.cpp b/src/modules/m_httpd_stats.cpp index 2fc7ca7de..e17bf514f 100644 --- a/src/modules/m_httpd_stats.cpp +++ b/src/modules/m_httpd_stats.cpp @@ -213,7 +213,7 @@ class ModuleHttpStats : public Module data << "<server>"; data << "<servername>" << b->servername << "</servername>"; data << "<parentname>" << b->parentname << "</parentname>"; - data << "<gecos>" << b->gecos << "</gecos>"; + data << "<gecos>" << Sanitize(b->gecos) << "</gecos>"; data << "<usercount>" << b->usercount << "</usercount>"; // This is currently not implemented, so, commented out. // data << "<opercount>" << b->opercount << "</opercount>"; diff --git a/src/modules/m_ircv3.cpp b/src/modules/m_ircv3.cpp index da42d823d..b7dd0e81b 100644 --- a/src/modules/m_ircv3.cpp +++ b/src/modules/m_ircv3.cpp @@ -222,7 +222,7 @@ class ModuleIRCv3 : public Module { // Send the away notify line if the current member is local, has the away-notify cap and isn't excepted User* member = IS_LOCAL(it->first); - if ((member) && (cap_awaynotify.ext.get(member)) && (last_excepts.find(member) == last_excepts.end())) + if ((member) && (cap_awaynotify.ext.get(member)) && (last_excepts.find(member) == last_excepts.end()) && (it->second != memb)) { member->Write(line); } diff --git a/src/modules/m_jumpserver.cpp b/src/modules/m_jumpserver.cpp index dce8f0bd5..44c6fc0d9 100644 --- a/src/modules/m_jumpserver.cpp +++ b/src/modules/m_jumpserver.cpp @@ -161,7 +161,7 @@ class ModuleJumpServer : public Module user->WriteNumeric(10, "%s %s %d :Please use this Server/Port instead", user->nick.c_str(), js.redirect_to.c_str(), js.port); ServerInstance->Users->QuitUser(user, js.reason); - return MOD_RES_PASSTHRU; + return MOD_RES_DENY; } return MOD_RES_PASSTHRU; } diff --git a/src/modules/m_namedmodes.cpp b/src/modules/m_namedmodes.cpp index 4db1f70b9..46710946b 100644 --- a/src/modules/m_namedmodes.cpp +++ b/src/modules/m_namedmodes.cpp @@ -33,7 +33,12 @@ static void DisplayList(User* user, Channel* channel) continue; items << " +" << mh->name; if (mh->GetNumParams(true)) - items << " " << channel->GetModeParameter(letter); + { + if ((letter == 'k') && (!channel->HasUser(user)) && (!user->HasPrivPermission("channels/auspex"))) + items << " <key>"; + else + items << " " << channel->GetModeParameter(letter); + } } char pfx[MAXBUF]; snprintf(pfx, MAXBUF, ":%s 961 %s %s", ServerInstance->Config->ServerName.c_str(), user->nick.c_str(), channel->name.c_str()); @@ -65,6 +70,8 @@ class CommandProp : public Command while (i < parameters.size()) { std::string prop = parameters[i++]; + if (prop.empty()) + continue; bool plus = prop[0] != '-'; if (prop[0] == '+' || prop[0] == '-') prop.erase(prop.begin()); diff --git a/src/modules/m_operprefix.cpp b/src/modules/m_operprefix.cpp index 9f1f6cc5e..7d5e6d118 100644 --- a/src/modules/m_operprefix.cpp +++ b/src/modules/m_operprefix.cpp @@ -58,6 +58,39 @@ class OperPrefixMode : public ModeHandler } bool NeedsOper() { return true; } + + void RemoveMode(Channel* chan, irc::modestacker* stack) + { + irc::modestacker modestack(false); + const UserMembList* users = chan->GetUsers(); + for (UserMembCIter i = users->begin(); i != users->end(); ++i) + { + if (i->second->hasMode(mode)) + { + if (stack) + stack->Push(this->GetModeChar(), i->first->nick); + else + modestack.Push(this->GetModeChar(), i->first->nick); + } + } + + if (stack) + return; + + std::deque<std::string> stackresult; + std::vector<std::string> mode_junk; + mode_junk.push_back(chan->name); + while (modestack.GetStackedLine(stackresult)) + { + mode_junk.insert(mode_junk.end(), stackresult.begin(), stackresult.end()); + ServerInstance->SendMode(mode_junk, ServerInstance->FakeClient); + mode_junk.erase(mode_junk.begin() + 1, mode_junk.end()); + } + } + + void RemoveMode(User* user, irc::modestacker* stack) + { + } }; class ModuleOperPrefixMode; diff --git a/src/modules/m_permchannels.cpp b/src/modules/m_permchannels.cpp index e86b3cbf6..74a798356 100644 --- a/src/modules/m_permchannels.cpp +++ b/src/modules/m_permchannels.cpp @@ -298,6 +298,12 @@ public: ServerInstance->Logs->Log("m_permchannels", DEBUG, "Added %s with topic %s", channel.c_str(), topic.c_str()); + if (modes.find('P') == std::string::npos) + { + ServerInstance->Logs->Log("m_permchannels", DEFAULT, "%s (%s) does not have +P set in <permchannels:modes>; it will be deleted when empty!", + c->name.c_str(), tag->getTagLocation().c_str()); + } + if (modes.empty()) continue; diff --git a/src/modules/m_sakick.cpp b/src/modules/m_sakick.cpp index 7dfcd8904..afca49e25 100644 --- a/src/modules/m_sakick.cpp +++ b/src/modules/m_sakick.cpp @@ -63,14 +63,6 @@ class CommandSakick : public Command if (IS_LOCAL(dest)) { channel->KickUser(ServerInstance->FakeClient, dest, reason); - - Channel *n = ServerInstance->FindChan(parameters[1]); - if (n && n->HasUser(dest)) - { - /* Sort-of-bug: If the command was issued remotely, this message won't be sent */ - user->WriteServ("NOTICE %s :*** Unable to kick %s from %s", user->nick.c_str(), dest->nick.c_str(), parameters[0].c_str()); - return CMD_FAILURE; - } } if (IS_LOCAL(user)) diff --git a/src/modules/m_sasl.cpp b/src/modules/m_sasl.cpp index 32c9afc79..5afab9502 100644 --- a/src/modules/m_sasl.cpp +++ b/src/modules/m_sasl.cpp @@ -51,10 +51,63 @@ class SaslAuthenticator SaslResult result; bool state_announced; + /* taken from m_services_account */ + static bool ReadCGIIRCExt(const char* extname, User* user, std::string& out) + { + ExtensionItem* wiext = ServerInstance->Extensions.GetItem(extname); + if (!wiext) + return false; + + if (wiext->creator->ModuleSourceFile != "m_cgiirc.so") + return false; + + StringExtItem* stringext = static_cast<StringExtItem*>(wiext); + std::string* addr = stringext->get(user); + if (!addr) + return false; + + out = *addr; + return true; + } + + + void SendHostIP() + { + std::string host, ip; + + if (!ReadCGIIRCExt("cgiirc_webirc_hostname", user, host)) + { + host = user->host; + } + if (!ReadCGIIRCExt("cgiirc_webirc_ip", user, ip)) + { + ip = user->GetIPString(); + } + else + { + /* IP addresses starting with a : on irc are a Bad Thing (tm) */ + if (ip.c_str()[0] == ':') + ip.insert(ip.begin(),1,'0'); + } + + parameterlist params; + params.push_back(sasl_target); + params.push_back("SASL"); + params.push_back(user->uuid); + params.push_back("*"); + params.push_back("H"); + params.push_back(host); + params.push_back(ip); + + SendSASL(params); + } + public: SaslAuthenticator(User* user_, const std::string& method) : user(user_), state(SASL_INIT), state_announced(false) { + SendHostIP(); + parameterlist params; params.push_back(sasl_target); params.push_back("SASL"); @@ -147,7 +200,7 @@ class SaslAuthenticator SendSASL(params); - if (parameters[0][0] == '*') + if (parameters[0].c_str()[0] == '*') { this->Abort(); return false; @@ -189,6 +242,7 @@ class CommandAuthenticate : public Command : Command(Creator, "AUTHENTICATE", 1), authExt(ext), cap(Cap) { works_before_reg = true; + allow_empty_last_param = false; } CmdResult Handle (const std::vector<std::string>& parameters, User *user) @@ -199,6 +253,9 @@ class CommandAuthenticate : public Command if (!cap.ext.get(user)) return CMD_FAILURE; + if (parameters[0].find(' ') != std::string::npos || parameters[0][0] == ':') + return CMD_FAILURE; + SaslAuthenticator *sasl = authExt.get(user); if (!sasl) authExt.set(user, new SaslAuthenticator(user, parameters[0])); @@ -264,7 +321,7 @@ class ModuleSASL : public Module void init() { OnRehash(NULL); - Implementation eventlist[] = { I_OnEvent, I_OnUserRegister, I_OnRehash }; + Implementation eventlist[] = { I_OnEvent, I_OnUserConnect, I_OnRehash }; ServerInstance->Modules->Attach(eventlist, this, sizeof(eventlist)/sizeof(Implementation)); ServiceProvider* providelist[] = { &auth, &sasl, &authExt }; @@ -279,7 +336,7 @@ class ModuleSASL : public Module sasl_target = ServerInstance->Config->ConfValue("sasl")->getString("target", "*"); } - ModResult OnUserRegister(LocalUser *user) + void OnUserConnect(LocalUser *user) { SaslAuthenticator *sasl_ = authExt.get(user); if (sasl_) @@ -287,8 +344,6 @@ class ModuleSASL : public Module sasl_->Abort(); authExt.unset(user); } - - return MOD_RES_PASSTHRU; } Version GetVersion() diff --git a/src/modules/m_securelist.cpp b/src/modules/m_securelist.cpp index 6013d1fd7..5d11d27f7 100644 --- a/src/modules/m_securelist.cpp +++ b/src/modules/m_securelist.cpp @@ -76,7 +76,7 @@ class ModuleSecureList : public Module /* Not exempt, BOOK EM DANNO! */ user->WriteServ("NOTICE %s :*** You cannot list within the first %lu seconds of connecting. Please try again later.",user->nick.c_str(), (unsigned long) WaitTime); - /* Some crap clients (read: mIRC, various java chat applets) muck up if they don't + /* Some clients (e.g. mIRC, various java chat applets) muck up if they don't * receive these numerics whenever they send LIST, so give them an empty LIST to mull over. */ user->WriteNumeric(321, "%s Channel :Users Name",user->nick.c_str()); diff --git a/src/modules/m_spanningtree/capab.cpp b/src/modules/m_spanningtree/capab.cpp index 7b6435898..0ab815fef 100644 --- a/src/modules/m_spanningtree/capab.cpp +++ b/src/modules/m_spanningtree/capab.cpp @@ -27,6 +27,7 @@ #include "utils.h" #include "link.h" #include "main.h" +#include "../hash.h" std::string TreeSocket::MyModules(int filter) { @@ -134,7 +135,7 @@ void TreeSocket::SendCapabilities(int phase) std::string extra; /* Do we have sha256 available? If so, we send a challenge */ - if (Utils->ChallengeResponse && (ServerInstance->Modules->Find("m_sha256.so"))) + if (Utils->ChallengeResponse && (ServerInstance->Modules->FindDataService<HashProvider>("hash/sha256"))) { SetOurChallenge(ServerInstance->GenRandomStr(20)); extra = " CHALLENGE=" + this->GetOurChallenge(); @@ -320,7 +321,7 @@ bool TreeSocket::Capab(const parameterlist ¶ms) /* Challenge response, store their challenge for our password */ std::map<std::string,std::string>::iterator n = this->capab->CapKeys.find("CHALLENGE"); - if (Utils->ChallengeResponse && (n != this->capab->CapKeys.end()) && (ServerInstance->Modules->Find("m_sha256.so"))) + if (Utils->ChallengeResponse && (n != this->capab->CapKeys.end()) && (ServerInstance->Modules->FindDataService<HashProvider>("hash/sha256"))) { /* Challenge-response is on now */ this->SetTheirChallenge(n->second); diff --git a/src/modules/m_spanningtree/fjoin.cpp b/src/modules/m_spanningtree/fjoin.cpp index 47b394522..4ec6e1dbb 100644 --- a/src/modules/m_spanningtree/fjoin.cpp +++ b/src/modules/m_spanningtree/fjoin.cpp @@ -201,7 +201,7 @@ CmdResult CommandFJoin::Handle(const std::vector<std::string>& params, User *src } else { - ServerInstance->Logs->Log("m_spanningtree",SPARSE, "Ignored nonexistant user %s in fjoin to %s (probably quit?)", usr, channel.c_str()); + ServerInstance->Logs->Log("m_spanningtree",SPARSE, "Ignored nonexistent user %s in fjoin to %s (probably quit?)", usr, channel.c_str()); continue; } } diff --git a/src/modules/m_spanningtree/netburst.cpp b/src/modules/m_spanningtree/netburst.cpp index d508c092d..3bce90eda 100644 --- a/src/modules/m_spanningtree/netburst.cpp +++ b/src/modules/m_spanningtree/netburst.cpp @@ -140,25 +140,28 @@ void TreeSocket::SendFJoins(Channel* c) buffer.append(list).append("\r\n"); } - int linesize = 1; + unsigned int linesize = 1; for (BanList::iterator b = c->bans.begin(); b != c->bans.end(); b++) { - int size = b->data.length() + 2; - int currsize = linesize + size; - if (currsize <= 350) - { - modes.append("b"); - params.append(" ").append(b->data); - linesize += size; - } - if ((modes.length() >= ServerInstance->Config->Limits.MaxModes) || (currsize > 350)) + unsigned int size = b->data.length() + 2; // "b" and " " + unsigned int nextsize = linesize + size; + + if ((modes.length() >= ServerInstance->Config->Limits.MaxModes) || (nextsize > FMODE_MAX_LENGTH)) { - /* Wrap at MAXMODES */ + /* Wrap */ buffer.append(":").append(ServerInstance->Config->GetSID()).append(" FMODE ").append(c->name).append(" ").append(ConvToStr(c->age)).append(" +").append(modes).append(params).append("\r\n"); + modes.clear(); params.clear(); linesize = 1; } + + modes.push_back('b'); + + params.push_back(' '); + params.append(b->data); + + linesize += size; } /* Only send these if there are any */ diff --git a/src/modules/m_spanningtree/postcommand.cpp b/src/modules/m_spanningtree/postcommand.cpp index 471bbfcb9..3f5d427e1 100644 --- a/src/modules/m_spanningtree/postcommand.cpp +++ b/src/modules/m_spanningtree/postcommand.cpp @@ -73,7 +73,7 @@ void SpanningTreeUtilities::RouteCommand(TreeServer* origin, const std::string & TreeServer* sdest = FindServer(routing.serverdest); if (!sdest) { - ServerInstance->Logs->Log("m_spanningtree",DEFAULT,"Trying to route ENCAP to nonexistant server %s", + ServerInstance->Logs->Log("m_spanningtree",DEFAULT,"Trying to route ENCAP to nonexistent server %s", routing.serverdest.c_str()); return; } diff --git a/src/modules/m_spanningtree/protocolinterface.cpp b/src/modules/m_spanningtree/protocolinterface.cpp index 3ab5dae9d..ca4147fea 100644 --- a/src/modules/m_spanningtree/protocolinterface.cpp +++ b/src/modules/m_spanningtree/protocolinterface.cpp @@ -137,9 +137,6 @@ void SpanningTreeProtocolInterface::PushToClient(User* target, const std::string void SpanningTreeProtocolInterface::SendChannel(Channel* target, char status, const std::string &text) { - std::string cname = target->name; - if (status) - cname = status + cname; TreeServerList list; CUList exempt_list; Utils->GetListOfServersForChannel(target,list,status,exempt_list); @@ -154,12 +151,20 @@ void SpanningTreeProtocolInterface::SendChannel(Channel* target, char status, co void SpanningTreeProtocolInterface::SendChannelPrivmsg(Channel* target, char status, const std::string &text) { - SendChannel(target, status, ":" + ServerInstance->Config->GetSID()+" PRIVMSG "+target->name+" :"+text); + std::string cname = target->name; + if (status) + cname.insert(0, 1, status); + + SendChannel(target, status, ":" + ServerInstance->Config->GetSID()+" PRIVMSG "+cname+" :"+text); } void SpanningTreeProtocolInterface::SendChannelNotice(Channel* target, char status, const std::string &text) { - SendChannel(target, status, ":" + ServerInstance->Config->GetSID()+" NOTICE "+target->name+" :"+text); + std::string cname = target->name; + if (status) + cname.insert(0, 1, status); + + SendChannel(target, status, ":" + ServerInstance->Config->GetSID()+" NOTICE "+cname+" :"+text); } void SpanningTreeProtocolInterface::SendUserPrivmsg(User* target, const std::string &text) diff --git a/src/modules/m_spanningtree/treesocket.h b/src/modules/m_spanningtree/treesocket.h index abda28335..efcce5f7a 100644 --- a/src/modules/m_spanningtree/treesocket.h +++ b/src/modules/m_spanningtree/treesocket.h @@ -100,6 +100,8 @@ class TreeSocket : public BufferedSocket int proto_version; /* Remote protocol version */ bool ConnectionFailureShown; /* Set to true if a connection failure message was shown */ + static const unsigned int FMODE_MAX_LENGTH = 350; + /** Checks if the given servername and sid are both free */ bool CheckDuplicate(const std::string& servername, const std::string& sid); diff --git a/src/modules/m_sslinfo.cpp b/src/modules/m_sslinfo.cpp index 2bfe0e1c4..083ac0f04 100644 --- a/src/modules/m_sslinfo.cpp +++ b/src/modules/m_sslinfo.cpp @@ -180,6 +180,9 @@ class ModuleSSLInfo : public Module if (i != ServerInstance->Config->oper_blocks.end()) { OperInfo* ifo = i->second; + if (!ifo->oper_block) + return MOD_RES_PASSTHRU; + ssl_cert* cert = cmd.CertExt.get(user); if (ifo->oper_block->getBool("sslonly") && !cert) @@ -220,6 +223,9 @@ class ModuleSSLInfo : public Module for(OperIndex::iterator i = ServerInstance->Config->oper_blocks.begin(); i != ServerInstance->Config->oper_blocks.end(); i++) { OperInfo* ifo = i->second; + if (!ifo->oper_block) + continue; + std::string fp = ifo->oper_block->getString("fingerprint"); if (fp == cert->fingerprint && ifo->oper_block->getBool("autologin")) user->Oper(ifo); diff --git a/src/socketengines/socketengine_epoll.cpp b/src/socketengines/socketengine_epoll.cpp index f2837777a..d5f017347 100644 --- a/src/socketengines/socketengine_epoll.cpp +++ b/src/socketengines/socketengine_epoll.cpp @@ -25,7 +25,7 @@ #include "exitcodes.h" #include "socketengine.h" #include <sys/epoll.h> -#include <ulimit.h> +#include <sys/resource.h> #include <iostream> #define EP_DELAY 5 @@ -55,10 +55,11 @@ public: EPollEngine::EPollEngine() { CurrentSetSize = 0; - int max = ulimit(4, 0); - if (max > 0) + + struct rlimit limit; + if (!getrlimit(RLIMIT_NOFILE, &limit)) { - MAX_DESCRIPTORS = max; + MAX_DESCRIPTORS = limit.rlim_cur; } else { diff --git a/src/usermanager.cpp b/src/usermanager.cpp index 76446c5b5..2cb7ad511 100644 --- a/src/usermanager.cpp +++ b/src/usermanager.cpp @@ -143,6 +143,7 @@ void UserManager::AddUser(int socket, ListenSocket* via, irc::sockets::sockaddrs { ServerInstance->Logs->Log("USERS", DEBUG,"Internal error on new connection"); this->QuitUser(New, "Internal error handling connection"); + return; } /* NOTE: even if dns lookups are *off*, we still need to display this. diff --git a/src/users.cpp b/src/users.cpp index 418f2c9aa..4dbb73a1f 100644 --- a/src/users.cpp +++ b/src/users.cpp @@ -837,6 +837,7 @@ void LocalUser::FullConnect() void User::InvalidateCache() { /* Invalidate cache */ + cachedip.clear(); cached_fullhost.clear(); cached_hostip.clear(); cached_makehost.clear(); @@ -1001,8 +1002,7 @@ irc::sockets::cidr_mask User::GetCIDRMask() bool User::SetClientIP(const char* sip, bool recheck_eline) { - cachedip.clear(); - cached_hostip.clear(); + this->InvalidateCache(); return irc::sockets::aptosa(sip, 0, client_sa); } @@ -1398,6 +1398,8 @@ void User::DoHostCycle(const std::string &quitline) FOREACH_MOD(I_OnBuildNeighborList,OnBuildNeighborList(this, include_c, exceptions)); + // Users shouldn't see themselves quitting when host cycling + exceptions.erase(this); for (std::map<User*,bool>::iterator i = exceptions.begin(); i != exceptions.end(); ++i) { LocalUser* u = IS_LOCAL(i->first); diff --git a/src/version.sh b/src/version.sh index 8686e33ae..74a583759 100755 --- a/src/version.sh +++ b/src/version.sh @@ -1,2 +1,2 @@ #!/bin/sh -echo "InspIRCd-2.0.20" +echo "InspIRCd-2.0.23" diff --git a/tools/travis-ci.sh b/tools/travis-ci.sh new file mode 100755 index 000000000..42b07fa25 --- /dev/null +++ b/tools/travis-ci.sh @@ -0,0 +1,15 @@ +#!/bin/bash +set -v +if [ "$TRAVIS_OS_NAME" = "linux" ] +then + sudo apt-get update --assume-yes + sudo apt-get install --assume-yes libgeoip-dev libgnutls-dev libldap2-dev libmysqlclient-dev libpcre3-dev libpq-dev libsqlite3-dev libssl-dev libtre-dev +else + >&2 echo "'$TRAVIS_OS_NAME' is an unknown Travis CI environment!" + exit 1 +fi +set -e +./configure --enable-extras=m_geoip.cpp,m_ldapauth.cpp,m_ldapoper.cpp,m_mysql.cpp,m_pgsql.cpp,m_regex_pcre.cpp,m_regex_posix.cpp,m_regex_tre.cpp,m_sqlite3.cpp,m_ssl_gnutls.cpp,m_ssl_openssl.cpp +./configure --with-cc=$CXX +make -j4 install +./run/bin/inspircd --version diff --git a/win/CMakeLists.txt b/win/CMakeLists.txt index 10653cf74..7be08a3fc 100644 --- a/win/CMakeLists.txt +++ b/win/CMakeLists.txt @@ -85,6 +85,7 @@ file(MAKE_DIRECTORY ${LOG_PATH}) install(DIRECTORY ${LOG_PATH} DESTINATION .) if(EXISTS "${CMAKE_ROOT}/Modules/CPack.cmake") + set(CMAKE_INSTALL_SYSTEM_RUNTIME_DESTINATION ".") # place runtime libraries next to InspIRCd binary include(InstallRequiredSystemLibraries) set(CPACK_PACKAGE_NAME "InspIRCd IRC Daemon") diff --git a/win/inspircd_win32wrapper.h b/win/inspircd_win32wrapper.h index be437d4a3..d7ceb73aa 100644 --- a/win/inspircd_win32wrapper.h +++ b/win/inspircd_win32wrapper.h @@ -63,6 +63,7 @@ /* Disable the deprecation warnings.. it spams :P */ #define _CRT_SECURE_NO_DEPRECATE +#define _WINSOCK_DEPRECATED_NO_WARNINGS /* Normal windows (platform-specific) includes */ #include <winsock2.h> @@ -90,9 +91,11 @@ CoreExport const char * insp_inet_ntop(int af, const void * src, char * dst, soc #define inet_pton insp_inet_pton #define inet_ntop insp_inet_ntop -/* Safe printf functions aren't defined in VC++ */ +/* Safe printf functions aren't defined in VC++ releases older than v14 */ +#if _MSC_VER <= 1800 #define snprintf _snprintf #define vsnprintf _vsnprintf +#endif /* Unix-style sleep (argument is in seconds) */ __inline void sleep(int seconds) { Sleep(seconds * 1000); } @@ -136,11 +139,13 @@ struct DIR bool first; }; +#if _MSC_VER <= 1800 struct timespec { time_t tv_sec; long tv_nsec; }; +#endif CoreExport DIR * opendir(const char * path); CoreExport dirent * readdir(DIR * handle); |