--- /dev/null
+compiler:
+ - clang
+ - gcc
+dist: trusty
+env:
+ - PURE_STATIC=1
+ -
+language: cpp
+notifications:
+ email: false
+script:
+ - sh ./tools/travis-ci.sh
+sudo: required
BEGIN {
require 5.8.0;
+ push @INC, '.';
}
use strict;
{
$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])?/) {
$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');
}
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";
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 /**/
}
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")) {
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>;
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;
}
OPERMOTD CHECK CLONES USERIP TLINE
ALLTIME WALLOPS GLOBOPS MODENOTICE
+CLOAK
SETHOST SETIDENT CHGHOST CHGIDENT CHGNAME
SETIDLE SWHOIS
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
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 #
######################
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
OPERMOTD CHECK CLONES USERIP TLINE
ALLTIME WALLOPS GLOBOPS MODENOTICE
+CLOAK
SETHOST SETIDENT CHGHOST CHGIDENT CHGNAME
SETIDLE SWHOIS
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
# 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).
#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#
# 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
# 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"
# 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.
# 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">
#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#
# 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">
#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#
# 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"> #
# #
# 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. #
# #
#
#-#-#-#-#-#-#-#-#-# 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. #
# 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">
#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#
* 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.
*/
*/
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.
*/
*/
static const int MAX_REQUEST_ID = 0xFFFF;
+ /** Maximum number of entries in cache
+ */
+ static const unsigned int MAX_CACHE_SIZE = 1000;
+
/**
* Currently cached items
*/
/** 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()
* 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
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
/*
* 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
/*
* 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
--- /dev/null
+/*
+ * 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);
+}
--- /dev/null
+/*
+ * 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;
+}
--- /dev/null
+/*
+ * 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));
+}
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
$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");
}
sub cmd_cron()
{
- if (getstatus() == 0) { goto &cmd_start(); }
+ if (getstatus() == 0) { goto &cmd_start(@_); }
exit();
}
{
cmd_stop();
unlink($pidfile) if (-e $pidfile);
- goto &cmd_start;
+ goto &cmd_start(@_);
}
sub hid_cheese_sandwich()
D=0
@ENDIF
+GCC6=@GCC6@
+@IFEQ $(GCC6) true
+ CXXFLAGS += -fno-delete-null-pointer-checks
+@ENDIF
+
DBGOK=0
@IFEQ $(D) 0
CXXFLAGS += -O2
@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
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
@-$(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
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
-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'
@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
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);
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;
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!";
}
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
* 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
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());
}
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] == '<')
{
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;
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
};
-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;
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) + " ";
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)
}
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)
{
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");
// 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)
{
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)
{
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;
}
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];
#endif
}
-void InspIRCd::WritePID(const std::string &filename)
+void InspIRCd::WritePID(const std::string& filename, bool exitonfail)
{
#ifndef _WIN32
std::string fname(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);
+ {\r
+ if (exitonfail)\r
+ 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." : ""));\r
+ if (exitonfail)
+ Exit(EXIT_STATUS_PID);\r
}
#endif
}
/* 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));
}
\r
OLDTIME = TIME.tv_sec;
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++)
{
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;
}
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)
{
std::string dnPart;
while (stream.GetToken(dnPart))
{
- std::string::size_type pos = dnPart.find('=');
+ pos = dnPart.find('=');
if (pos == std::string::npos) // malformed
continue;
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"));
}
}
#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 */
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)
#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
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)
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))
}
}
}
-
- void* old = set_raw(container, dat);
- if (old)
- this->free(old);
}
callerid_data* get(User* user, bool create)
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")
{
#ifndef M_CAP_H
#define M_CAP_H
+class GenericCap;
+
class CapEvent : public Event
{
public:
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) {}
};
// 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;
}
}
{
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;
}
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";
}
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))
}
}
+ 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;
}
/* /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);
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)
{
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);
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);
class CommandDccallow : public Command
{
public:
+ unsigned int maxentries;
CommandDccallow(Module* parent) : Command(parent, "DCCALLOW", 0)
{
syntax = "[(+|-)<nick> [<time>]]|[LIST|HELP]";
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)
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));
}
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)
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++)
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;
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);
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++;
+ }
}
}
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));
}
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
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>";
{
// 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);
}
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;
}
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());
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());
}
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;
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;
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))
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");
SendSASL(params);
- if (parameters[0][0] == '*')
+ if (parameters[0].c_str()[0] == '*')
{
this->Abort();
return false;
: 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)
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]));
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 };
sasl_target = ServerInstance->Config->ConfValue("sasl")->getString("target", "*");
}
- ModResult OnUserRegister(LocalUser *user)
+ void OnUserConnect(LocalUser *user)
{
SaslAuthenticator *sasl_ = authExt.get(user);
if (sasl_)
sasl_->Abort();
authExt.unset(user);
}
-
- return MOD_RES_PASSTHRU;
}
Version GetVersion()
/* 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());
#include "utils.h"
#include "link.h"
#include "main.h"
+#include "../hash.h"
std::string TreeSocket::MyModules(int filter)
{
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();
/* 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);
}
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;
}
}
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 */
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;
}
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);
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)
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);
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)
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);
#include "exitcodes.h"
#include "socketengine.h"
#include <sys/epoll.h>
-#include <ulimit.h>
+#include <sys/resource.h>
#include <iostream>
#define EP_DELAY 5
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
{
{
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.
void User::InvalidateCache()
{
/* Invalidate cache */
+ cachedip.clear();
cached_fullhost.clear();
cached_hostip.clear();
cached_makehost.clear();
bool User::SetClientIP(const char* sip, bool recheck_eline)
{
- cachedip.clear();
- cached_hostip.clear();
+ this->InvalidateCache();
return irc::sockets::aptosa(sip, 0, client_sa);
}
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);
#!/bin/sh
-echo "InspIRCd-2.0.20"
+echo "InspIRCd-2.0.23"
--- /dev/null
+#!/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
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")
/* 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>
#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); }
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);