pax_global_header00006660000000000000000000000064135545504540014524gustar00rootroot0000000000000052 comment=f28161a652482717c57ecf7e2696c63833db6975 inspircd-3.4.0/000077500000000000000000000000001355455045400133435ustar00rootroot00000000000000inspircd-3.4.0/.gitattributes000066400000000000000000000000251355455045400162330ustar00rootroot00000000000000*.bat text eol=crlf inspircd-3.4.0/.github/000077500000000000000000000000001355455045400147035ustar00rootroot00000000000000inspircd-3.4.0/.github/ISSUE_TEMPLATE/000077500000000000000000000000001355455045400170665ustar00rootroot00000000000000inspircd-3.4.0/.github/ISSUE_TEMPLATE/BUG_REPORT.md000066400000000000000000000016171355455045400211250ustar00rootroot00000000000000--- name: Bug report about: Report a non-security issue with InspIRCd. --- **Description** **Steps to reproduce the issue:** 1. 2. 3. **Describe the results you received:** **Describe the results you expected:** **Additional information you deem important (e.g. issue happens only occasionally):** **Output of `./bin/inspircd --version`:** inspircd-3.4.0/.github/ISSUE_TEMPLATE/FEATURE_REQUEST.md000066400000000000000000000013701355455045400217140ustar00rootroot00000000000000--- name: Feature request about: Request that a new feature is added to InspIRCd. --- **Description** **Why this would be useful** inspircd-3.4.0/.github/PULL_REQUEST_TEMPLATE.md000066400000000000000000000014631355455045400205100ustar00rootroot00000000000000 ## Summary ## Rationale ## Testing Environment I have tested this pull request on: **Operating system name and version:** **Compiler name and version:** ## Checks I have ensured that: - [ ] This pull request does not introduce any incompatible API changes. - [ ] If ABI changes have been made I have incremented INSPIRCD_VERSION_API. - [ ] I have documented any features added by this pull request. inspircd-3.4.0/.github/SECURITY.md000066400000000000000000000015451355455045400165010ustar00rootroot00000000000000# Security Policy ## Supported Versions Currently the v2 (old stable) and v3 (stable) branches are actively receiving security fixes. Support for v2 will end on 2020-06-01. The v4 branch is still early in development and only receives security fixes when they are synced from the v3 branch. Version | Supported ------- | --------- 4.x.y | :warning: 3.x.y | :white_check_mark: 2.0.x | :white_check_mark: 1.2.y | :x: 1.1.y | :x: 1.0.y | :x: ## Reporting a Vulnerability Please do not report security vulnerabilities on GitHub. Instead, get the attention of a developer in our [development IRC channel](https://kiwiirc.com/nextclient/irc.inspircd.org:+6697/#inspircd.dev) at irc.inspircd.org #inspircd.dev and PM them the details. We will triage your issue as soon as possible and try to release a fixed version within a week of receiving your report. inspircd-3.4.0/.gitignore000066400000000000000000000010351355455045400153320ustar00rootroot00000000000000*~ *.pem *.swp .* !.git* /.configure /Makefile /GNUmakefile /build /docs/doxygen /run /include/config.h /src/modules/m_geo_maxmind.cpp /src/modules/m_ldap.cpp /src/modules/m_mysql.cpp /src/modules/m_pgsql.cpp /src/modules/m_regex_pcre.cpp /src/modules/m_regex_posix.cpp /src/modules/m_regex_re2.cpp /src/modules/m_regex_stdlib.cpp /src/modules/m_regex_tre.cpp /src/modules/m_sqlite3.cpp /src/modules/m_ssl_gnutls.cpp /src/modules/m_ssl_mbedtls.cpp /src/modules/m_ssl_openssl.cpp /src/modules/m_sslrehashsignal.cpp /win/Win32 /win/*.dir inspircd-3.4.0/.mailmap000066400000000000000000000101001355455045400147540ustar00rootroot00000000000000Adam Adam Adam Adam Attila Molnar Attila Molnar Attila Molnar attilamolnar Attila Molnar attilamolnar blitmap Pogs McPoggerson blitmap Sir Poggles blitmap Sir Pogsalot ChrisTX ChrisTX Craig Edwards (no author) <(no author)@e03df62e-2008-0410-955e-edbf42e46eb7> Craig Edwards brain Craig Edwards root Craig McLure frostycoolslug Daniel De Graaf danieldg Daniel Vassdal Daniel Vassdal Daniel Vassdal Daniel Vassdal Daniel Vassdal Daniel Vassdal Daniel Vassdal Daniel Vassdal Daniel Vassdal ShutterQuick Dennis Friis peavey DjSlash Rutger Geoff Bricker bricker iwalkalone iwalkalone jackmcbarn Jackmcbarn James Lu James Lu John Brooks special Justin Crawford Justasic linuxdaemon linuxdaemon linuxdaemon linuxdaemon Matt Smith dz md_5 md-5 Oliver Lupton om Pippijn van Steenhoven pippijn Robby Robby Robby Robby- Robby Robby- Robin Burchell Robin Burchell Robin Burchell w00t Thomas Stagner aquanight Uli Schlachter psychon William Pitcock nenolod # The identities of the following people could not be verified: # # burlex # eggy # fez # jamie # katsklaw # Philouuu / PhilSliderS # randomdan # typobox43 inspircd-3.4.0/.travis.yml000066400000000000000000000003031355455045400154500ustar00rootroot00000000000000compiler: - clang - gcc dist: xenial env: - CXXFLAGS=-std=gnu++98 - CXXFLAGS=-std=c++14 language: cpp notifications: email: false script: - sh ./tools/travis-ci.sh sudo: required inspircd-3.4.0/README.md000066400000000000000000000050441355455045400146250ustar00rootroot00000000000000## About InspIRCd is a modular C++ Internet Relay Chat (IRC) server for UNIX-like and Windows systems. ## Supported Platforms InspIRCd is supported on on the following platforms: - Most recent BSD variants using the Clang or GCC compilers and the GNU toolchains (Make, etc). - Most recent Linux distributions using the Clang or GCC compilers and the GNU toolchain. - The most recent three major releases of macOS using the AppleClang, Clang, or GCC (*not* LLVM-GCC) compilers and the GNU toolchains. - Windows 7 or newer using the MSVC 14 (Visual Studio 2015) compiler and CMake 2.8 or newer. Alternate platforms and toolchains may also work but are not officially supported by the InspIRCd team. Generally speaking if you are using a reasonably modern UNIX-like system you should be able to build InspIRCd on it. If you encounter any bugs then [please file an issue](https://github.com/inspircd/inspircd/issues/new/choose). ## Installation Most InspIRCd users running a UNIX-like system build from source. A guide about how to do this is available on [the InspIRCd docs site](https://docs.inspircd.org/3/installation/source). Building from source on Windows is generally not recommended but [a guide is available](https://github.com/inspircd/inspircd/blob/master/win/README.txt) if you wish to do this. If you are running on CentOS 7, Debian 7, or Windows binary packages are available from [the downloads page](https://github.com/inspircd/inspircd/releases/latest). A [Docker](https://www.docker.com) image is also available. See [the inspircd-docker repository](https://github.com/inspircd/inspircd-docker) for more information. Some distributions ship an InspIRCd package in their package managers. We generally do not recommend the use of such packages as in the past distributions have made broken modifications to InspIRCd and not kept their packages up to date with essential security updates. ## License InspIRCd is licensed under [version 2 of the GNU General Public License](https://www.gnu.org/licenses/old-licenses/gpl-2.0-standalone.html). ## External Links * [Website](https://www.inspircd.org) * [Documentation](https://docs.inspircd.org) * [GitHub](https://github.com/inspircd) * [Support IRC channel](https://kiwiirc.com/nextclient/irc.inspircd.org:+6697/#inspircd) — \#inspircd on irc.inspircd.org * [Development IRC channel](https://kiwiirc.com/nextclient/irc.inspircd.org:+6697/#inspircd.dev) — \#inspircd.dev on irc.inspircd.org * [InspIRCd test network](https://kiwiirc.com/nextclient/testnet.inspircd.org:+6697) — testnet.inspircd.org inspircd-3.4.0/configure000077500000000000000000000553501355455045400152620ustar00rootroot00000000000000#!/usr/bin/env perl # # InspIRCd -- Internet Relay Chat Daemon # # Copyright (C) 2012-2017 Peter Powell # Copyright (C) 2009-2010 Daniel De Graaf # Copyright (C) 2007, 2009 Dennis Friis # Copyright (C) 2003, 2006-2008 Craig Edwards # Copyright (C) 2006-2008 Robin Burchell # Copyright (C) 2008 Thomas Stagner # Copyright (C) 2007 John Brooks # Copyright (C) 2006 Oliver Lupton # Copyright (C) 2003-2006 Craig McLure # # 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 . # BEGIN { require 5.10.0; } use feature ':5.10'; use strict; use warnings FATAL => qw(all); use File::Basename qw(basename); use File::Copy (); use File::Spec::Functions qw(rel2abs); use FindBin qw($RealDir); use Getopt::Long qw(GetOptions); use POSIX qw(getgid getuid); use lib $RealDir; use make::common; use make::configure; use make::console; use make::directive; my ($opt_binary_dir, $opt_config_dir, $opt_data_dir, $opt_development, $opt_disable_auto_extras, $opt_disable_interactive, $opt_distribution_label, $opt_example_dir, $opt_gid, $opt_log_dir, $opt_manual_dir, $opt_module_dir, $opt_prefix, $opt_script_dir, $opt_socketengine, $opt_system, $opt_uid); sub list_extras (); sub enable_extras (@); sub disable_extras (@); my @opt_enableextras; my @opt_disableextras; exit 1 unless GetOptions( 'clean' => \&cmd_clean, 'help' => \&cmd_help, 'update' => \&cmd_update, 'binary-dir=s' => \$opt_binary_dir, 'config-dir=s' => \$opt_config_dir, 'data-dir=s' => \$opt_data_dir, 'development' => \$opt_development, 'disable-auto-extras' => \$opt_disable_auto_extras, 'disable-interactive' => \$opt_disable_interactive, 'distribution-label=s' => \$opt_distribution_label, 'example-dir=s' => \$opt_example_dir, 'gid=s' => \$opt_gid, 'log-dir=s' => \$opt_log_dir, 'manual-dir=s' => \$opt_manual_dir, 'module-dir=s' => \$opt_module_dir, 'prefix=s' => \$opt_prefix, 'script-dir=s' => \$opt_script_dir, 'socketengine=s' => \$opt_socketengine, 'system' => \$opt_system, 'uid=s' => \$opt_uid, # TODO: when the modulemanager rewrite is done these should be removed. 'disable-extras=s@' => \@opt_disableextras, 'enable-extras=s@' => \@opt_enableextras, 'list-extras' => sub { list_extras; exit 0; }, ); if (scalar(@opt_enableextras) + scalar(@opt_disableextras) > 0) { @opt_enableextras = split /,/, join(',', @opt_enableextras); @opt_disableextras = split /,/, join(',', @opt_disableextras); enable_extras(@opt_enableextras); disable_extras(@opt_disableextras); list_extras; print "Remember: YOU are responsible for making sure any libraries needed have been installed!\n"; exit 0; } our $interactive = !( !-t STDIN || !-t STDOUT || defined $opt_binary_dir || defined $opt_config_dir || defined $opt_data_dir || defined $opt_development || defined $opt_disable_auto_extras || defined $opt_disable_interactive || defined $opt_distribution_label || defined $opt_example_dir || defined $opt_gid || defined $opt_log_dir || defined $opt_manual_dir || defined $opt_module_dir || defined $opt_prefix || defined $opt_script_dir || defined $opt_socketengine || defined $opt_system || defined $opt_uid ); my %version = get_version $opt_distribution_label; print_format "<|BOLD Configuring InspIRCd $version{FULL} on $^O.|>\n"; my %config; if ($interactive) { %config = read_config_file(CONFIGURE_CACHE_FILE); run_test CONFIGURE_CACHE_FILE, %config; if (!defined $config{VERSION}) { $config{VERSION} = CONFIGURE_CACHE_VERSION; } elsif ($config{VERSION} != CONFIGURE_CACHE_VERSION) { print_warning "ignoring contents of ${\CONFIGURE_CACHE_FILE} as it was generated by an incompatible version of $0!"; %config = ('VERSION', CONFIGURE_CACHE_VERSION); } } $config{CXX} = find_compiler($config{CXX} // $ENV{CXX}); unless ($config{CXX}) { say 'A suitable C++ compiler could not be detected on your system!'; unless ($interactive) { say 'Set the CXX environment variable to the path to a C++ compiler binary if this is incorrect.'; exit 1; } until ($config{CXX}) { my $compiler_path = prompt_string 1, 'Please enter the path to a C++ compiler binary:', 'c++'; $config{CXX} = find_compiler $compiler_path; } } my %compiler = get_compiler_info($config{CXX}); $config{HAS_ARC4RANDOM_BUF} = run_test 'arc4random_buf()', test_file($config{CXX}, 'arc4random_buf.cpp'); $config{HAS_CLOCK_GETTIME} = run_test 'clock_gettime()', test_file($config{CXX}, 'clock_gettime.cpp', $^O eq 'darwin' ? undef : '-lrt'); $config{HAS_EVENTFD} = run_test 'eventfd()', test_file($config{CXX}, 'eventfd.cpp'); my @socketengines; push @socketengines, 'epoll' if run_test 'epoll', test_header $config{CXX}, 'sys/epoll.h'; push @socketengines, 'kqueue' if run_test 'kqueue', test_file $config{CXX}, 'kqueue.cpp'; push @socketengines, 'poll' if run_test 'poll', test_header $config{CXX}, 'poll.h'; push @socketengines, 'select'; if (defined $opt_socketengine) { unless (grep { $_ eq $opt_socketengine } @socketengines) { my $reason = -f "src/socketengines/socketengine_$opt_socketengine.cpp" ? 'is not available on this platform' : 'does not exist'; print_error "The socket engine you requested ($opt_socketengine) $reason!", 'Available socket engines are:', map { " * $_" } @socketengines; } } $config{SOCKETENGINE} = $opt_socketengine // $socketengines[0]; if (defined $opt_system) { $config{BASE_DIR} = $opt_prefix // '/var/lib/inspircd'; $config{BINARY_DIR} = $opt_binary_dir // '/usr/sbin'; $config{CONFIG_DIR} = $opt_config_dir // '/etc/inspircd'; $config{DATA_DIR} = $opt_data_dir // '/var/inspircd'; $config{EXAMPLE_DIR} = $opt_example_dir // '/usr/share/doc/inspircd'; $config{LOG_DIR} = $opt_log_dir // '/var/log/inspircd'; $config{MANUAL_DIR} = $opt_manual_dir // '/usr/share/man/man1'; $config{MODULE_DIR} = $opt_module_dir // '/usr/lib/inspircd'; $config{SCRIPT_DIR} = $opt_script_dir // '/usr/share/inspircd' } else { $config{BASE_DIR} = $opt_prefix // $config{BASE_DIR} // rel2abs 'run'; $config{BINARY_DIR} = $opt_binary_dir // $config{BINARY_DIR} // rel2abs $config{BASE_DIR} . '/bin'; $config{CONFIG_DIR} = $opt_config_dir // $config{CONFIG_DIR} // rel2abs $config{BASE_DIR} . '/conf'; $config{DATA_DIR} = $opt_data_dir // $config{DATA_DIR} // rel2abs $config{BASE_DIR} . '/data'; $config{EXAMPLE_DIR} = $opt_example_dir // $config{EXAMPLE_DIR} // $config{CONFIG_DIR} . '/examples'; $config{LOG_DIR} = $opt_log_dir // $config{LOG_DIR} // rel2abs $config{BASE_DIR} . '/logs'; $config{MANUAL_DIR} = $opt_manual_dir // $config{MANUAL_DIR} // rel2abs $config{BASE_DIR} . '/manuals'; $config{MODULE_DIR} = $opt_module_dir // $config{MODULE_DIR} // rel2abs $config{BASE_DIR} . '/modules'; $config{SCRIPT_DIR} = $opt_script_dir // $config{SCRIPT_DIR} // $config{BASE_DIR}; } # Parse --gid=123 or --gid=foo and extract the group id. my @group; if (defined $opt_gid) { @group = $opt_gid =~ /^\d+$/ ? getgrgid($opt_gid) : getgrnam($opt_gid); print_error "there is no '$opt_gid' group on this system!" unless @group; } else { @group = $opt_system ? getgrnam('irc') : getgrgid($config{GID} // getgid()); print_error "you need to specify a group to run as using '--gid [id|name]'!" unless @group; unless ($group[2]) { print_warning <<"EOW"; You are building as the privileged $group[0] group and have not specified an unprivileged group to run InspIRCd as. This is almost never what you should do. You should probably either create a new unprivileged user/group to build and run as or pass the '--gid [id|name]' flag to specify an unprivileged group to run as. EOW if (!prompt_bool $interactive, "Are you sure you want to build as the $group[0] group?", 0) { say STDERR "If you are sure you want to build as the $group[0] group pass the --gid $group[2] flag." unless $interactive; exit 1; } } } $config{GROUP} = $group[0]; $config{GID} = $group[2]; # Parse --uid=123 or --uid=foo and extract the user id. my @user; if (defined $opt_uid) { @user = $opt_uid =~ /^\d+$/ ? getpwuid($opt_uid) : getpwnam($opt_uid); print_error "there is no '$opt_uid' user on this system!" unless @user; } else { @user = $opt_system ? getpwnam('irc') : getpwuid($config{UID} // getuid()); print_error "you need to specify a user to run as using '--uid [id|name]'!" unless @user; unless ($user[2]) { print_warning <<"EOW"; You are building as the privileged $user[0] user and have not specified an unprivileged user to run InspIRCd as. This is almost never what you should do. You should probably either create a new unprivileged user/group to build and run as or pass the '--uid [id|name]' flag to specify an unprivileged user to run as. EOW if (!prompt_bool $interactive, "Are you sure you want to build as the $user[0] user?", 0) { say STDERR "If you are sure you want to build as the $user[0] user pass the --uid $user[2] flag." unless $interactive; exit 1; } } } $config{USER} = $user[0]; $config{UID} = $user[2]; # Warn the user about clock drifting when running on OpenVZ. if (-e '/proc/user_beancounters' || -e '/proc/vz/vzaquota') { print_warning <<'EOW'; You are building InspIRCd inside of an OpenVZ container. If you plan to use InspIRCd in this container then you should make sure that NTP is configured on the Hardware Node. Failure to do so may result in clock drifting! EOW } # Warn the user about OpenBSD shipping incredibly broken compilers/linkers. if ($^O eq 'openbsd') { print_warning <<'EOW'; You are building InspIRCd on OpenBSD. The C++ compilers and linkers that OpenBSD ship are incredibly broken. You may have strange linker errors and crashes. Please consider using a different OS like FreeBSD/NetBSD instead. EOW } # Check that the user actually wants this version. if (defined $version{REAL_LABEL}) { print_warning <<'EOW'; You are building a development version. This contains code which has not been tested as heavily and may contain various faults which could seriously affect the running of your server. It is recommended that you use a stable version instead. You can obtain the latest stable version from https://www.inspircd.org or by running `<|GREEN git checkout $(git describe --abbrev=0 --tags insp3)|>` if you are installing from Git. EOW if (!prompt_bool $interactive, 'I understand this warning and want to continue anyway.', $opt_development // 0) { say STDERR 'If you understand this warning and still want to continue pass the --development flag.' unless $interactive; exit 1; } } # Configure directory settings. my $question = <<"EOQ"; Currently, InspIRCd is configured with the following paths: <|BOLD Base:|> $config{BASE_DIR} <|BOLD Binary:|> $config{BINARY_DIR} <|BOLD Config:|> $config{CONFIG_DIR} <|BOLD Data:|> $config{DATA_DIR} <|BOLD Log:|> $config{LOG_DIR} <|BOLD Manual:|> $config{MANUAL_DIR} <|BOLD Module:|> $config{MODULE_DIR} <|BOLD Script:|> $config{SCRIPT_DIR} Do you want to change these settings? EOQ if (prompt_bool $interactive, $question, 0) { my $original_base_dir = $config{BASE_DIR}; $config{BASE_DIR} = prompt_dir $interactive, 'In what directory do you wish to install the InspIRCd base?', $config{BASE_DIR}; foreach my $key (qw(BINARY_DIR CONFIG_DIR DATA_DIR LOG_DIR MANUAL_DIR MODULE_DIR SCRIPT_DIR)) { $config{$key} =~ s/^\Q$original_base_dir\E/$config{BASE_DIR}/; } $config{BINARY_DIR} = prompt_dir $interactive, 'In what directory should the InspIRCd binary be placed?', $config{BINARY_DIR}; $config{CONFIG_DIR} = prompt_dir $interactive, 'In what directory are configuration files to be stored?', $config{CONFIG_DIR}; $config{DATA_DIR} = prompt_dir $interactive, 'In what directory are variable data files to be stored?', $config{DATA_DIR}; $config{LOG_DIR} = prompt_dir $interactive, 'In what directory are log files to be stored?', $config{LOG_DIR}; $config{MANUAL_DIR} = prompt_dir $interactive, 'In what directory are manual pages to be placed?', $config{MANUAL_DIR}; $config{MODULE_DIR} = prompt_dir $interactive, 'In what directory are modules to be placed?', $config{MODULE_DIR}; $config{SCRIPT_DIR} = prompt_dir $interactive, 'In what directory are scripts to be placed?', $config{SCRIPT_DIR}; $config{EXAMPLE_DIR} = $config{CONFIG_DIR} . '/examples'; } # Configure module settings. $question = <<'EOQ'; Currently, InspIRCd is configured to automatically enable all available extra modules. Would you like to enable extra modules manually? EOQ if (prompt_bool $interactive, $question, 0) { foreach my $extra () { my $module_name = basename $extra, '.cpp'; if (prompt_bool $interactive, "Would you like to enable $module_name?", 0) { enable_extras "$module_name.cpp"; } } } elsif (!defined $opt_disable_auto_extras) { # TODO: finish modulemanager rewrite and replace this code with: # system './modulemanager', 'enable', '--auto'; my %modules = ( # Missing: m_ldap, m_regex_stdlib, m_ssl_mbedtls 'm_geo_maxmind.cpp' => 'pkg-config --exists libmaxminddb', 'm_mysql.cpp' => 'mysql_config --version', 'm_pgsql.cpp' => 'pg_config --version', 'm_regex_pcre.cpp' => 'pcre-config --version', 'm_regex_posix.cpp' => undef, 'm_regex_re2.cpp' => 'pkg-config --exists re2', 'm_regex_tre.cpp' => 'pkg-config --exists tre', 'm_sqlite3.cpp' => 'pkg-config --exists sqlite3', 'm_ssl_gnutls.cpp' => 'pkg-config --exists gnutls', 'm_ssl_openssl.cpp' => 'pkg-config --exists openssl', 'm_sslrehashsignal.cpp' => undef, ); while (my ($module, $command) = each %modules) { unless (defined $command && system "$command 1>/dev/null 2>/dev/null") { enable_extras $module; } } } # Generate SSL certificates. $question = < be used on a production network. Note: you can get a <|BOLD free|> CA-signed certificate from Let's Encrypt. See https://letsencrypt.org/getting-started/ for more details. EOQ if () { if (prompt_bool $interactive, $question, $interactive) { system './tools/genssl', 'auto'; } } else { print_warning <<"EOM"; You are building without enabling any SSL modules. This is not recommended as SSL greatly enhances the security and privacy of your IRC server and in a future version will be <|BOLD required|> for linking servers. Please read the following documentation pages on how to enable SSL support: GnuTLS (recommended): https://docs.inspircd.org/3/modules/ssl_gnutls mbedTLS: https://docs.inspircd.org/3/modules/ssl_mbedtls OpenSSL: https://docs.inspircd.org/3/modules/ssl_openssl EOM } # Cache the distribution label so that its not lost when --update is run. $config{DISTRIBUTION} = $opt_distribution_label if $opt_distribution_label; write_configure_cache %config; parse_templates \%config, \%compiler, \%version; print_format <<"EOM"; Configuration is complete! You have chosen to build with the following settings: <|GREEN Compiler:|> <|GREEN Binary:|> $config{CXX} <|GREEN Name:|> $compiler{NAME} <|GREEN Version:|> $compiler{VERSION} <|GREEN Extra Modules:|> EOM for my $file () { my $module = basename $file, '.cpp'; say " * $module" if -l $file; } print_format <<"EOM"; <|GREEN Paths:|> <|GREEN Base:|> $config{BASE_DIR} <|GREEN Binary:|> $config{BINARY_DIR} <|GREEN Config:|> $config{CONFIG_DIR} <|GREEN Data:|> $config{DATA_DIR} <|GREEN Example:|> $config{EXAMPLE_DIR} <|GREEN Log:|> $config{LOG_DIR} <|GREEN Manual:|> $config{MANUAL_DIR} <|GREEN Module:|> $config{MODULE_DIR} <|GREEN Script:|> $config{SCRIPT_DIR} <|GREEN Execution Group:|> $config{GROUP} ($config{GID}) <|GREEN Execution User:|> $config{USER} ($config{UID}) <|GREEN Socket Engine:|> $config{SOCKETENGINE} To build with these settings run '<|GREEN make -j${\get_cpu_count} install|>' now. EOM # Routine to list out the extra/ modules that have been enabled. # Note: when getting any filenames out and comparing, it's important to lc it if the # file system is not case-sensitive (== Epoc, MacOS, OS/2 (incl DOS/DJGPP), VMS, Win32 # (incl NetWare, Symbian)). Cygwin may or may not be case-sensitive, depending on # configuration, however, File::Spec does not currently tell us (it assumes Unix behavior). sub list_extras () { use File::Spec; # @_ not used my $srcdir = File::Spec->catdir("src", "modules"); my $abs_srcdir = File::Spec->rel2abs($srcdir); local $_; my $dd; opendir $dd, File::Spec->catdir($abs_srcdir, "extra") or die (File::Spec->catdir($abs_srcdir, "extra") . ": $!\n"); my @extras = map { File::Spec->case_tolerant() ? lc($_) : $_ } (readdir($dd)); closedir $dd; undef $dd; opendir $dd, $abs_srcdir or die "$abs_srcdir: $!\n"; my @sources = map { File::Spec->case_tolerant() ? lc($_) : $_ } (readdir($dd)); closedir $dd; undef $dd; my $maxlen = (sort { $b <=> $a } (map {length($_)} (@extras)))[0]; my %extras = (); EXTRA: for my $extra (@extras) { next if (File::Spec->curdir() eq $extra || File::Spec->updir() eq $extra); my $abs_extra = File::Spec->catfile($abs_srcdir, "extra", $extra); my $abs_source = File::Spec->catfile($abs_srcdir, $extra); next unless ($extra =~ m/\.(cpp|h)$/ || (-d $abs_extra)); # C++ Source/Header, or directory if (-l $abs_source) { # Symlink, is it in the right place? my $targ = readlink($abs_source); my $abs_targ = File::Spec->rel2abs($targ, $abs_srcdir); if ($abs_targ eq $abs_extra) { $extras{$extra} = "\e[32;1menabled\e[0m"; } else { $extras{$extra} = sprintf("\e[31;1mwrong symlink target (%s)\e[0m", $abs_targ); } } elsif (-e $abs_source) { my ($devext, $inoext) = stat($abs_extra); my ($devsrc, $inosrc, undef, $lnksrc) = stat($abs_source); if ($lnksrc > 1) { if ($devsrc == $devext && $inosrc == $inoext) { $extras{$extra} = "\e[32;1menabled\e[0m"; } else { $extras{$extra} = sprintf("\e[31;1mwrong hardlink target (%d:%d)\e[0m", $devsrc, $inosrc); } } else { open my $extfd, "<", $abs_extra; open my $srcfd, "<", $abs_source; local $/ = undef; if (scalar(<$extfd>) eq scalar(<$srcfd>)) { $extras{$extra} = "\e[32;1menabled\e[0m"; } else { $extras{$extra} = sprintf("\e[31;1mout of synch (re-copy)\e[0m"); } } } else { $extras{$extra} = "\e[33;1mdisabled\e[0m"; } } # Now let's add dependency info for my $extra (keys(%extras)) { next unless $extras{$extra} =~ m/enabled/; # only process enabled extras. my $abs_extra = File::Spec->catfile($abs_srcdir, "extra", $extra); my @deps = split /\s+/, get_directive($abs_extra, 'ModDep', ''); for my $dep (@deps) { if (exists($extras{$dep})) { my $ref = \$extras{$dep}; # Take reference. if ($$ref !~ m/needed by/) { # First dependency found. if ($$ref =~ m/enabled/) { $$ref .= " (needed by \e[32;1m$extra\e[0m"; } else { $$ref =~ s/\e\[.*?m//g; # Strip out previous coloring. Will be set in bold+red+blink later. $$ref .= " (needed by \e[0;32;1;5m$extra\e[0;31;1;5m"; } } else { if ($$ref =~ m/enabled/) { $$ref .= ", \e[32;1m$extra\e[0m"; } else { $$ref .= ", \e[0;32;1;5m$extra\e[0;31;1;5m"; } } } } } for my $extra (sort {$a cmp $b} keys(%extras)) { my $text = $extras{$extra}; if ($text =~ m/needed by/ && $text !~ m/enabled/) { printf "\e[31;1;5m%-*s = %s%s\e[0m\n", $maxlen, $extra, $text, ($text =~ m/needed by/ ? ")" : ""); } else { printf "%-*s = %s%s\n", $maxlen, $extra, $text, ($text =~ m/needed by/ ? "\e[0m)" : ""); } } return keys(%extras) if wantarray; # Can be used by manage_extras. } sub enable_extras (@) { my (@extras) = @_; for my $extra (@extras) { my $extrapath = "src/modules/extra/$extra"; if (!-e $extrapath) { print STDERR "Cannot enable \e[32;1m$extra\e[0m : No such file or directory in src/modules/extra\n"; next; } my $source = "src/modules/$extra"; if (-e $source) { print STDERR "Cannot enable \e[32;1m$extra\e[0m : destination in src/modules exists (might already be enabled?)\n"; next; } # Get dependencies, and add them to be processed. my @deps = split /\s+/, get_directive($extrapath, 'ModDep', ''); for my $dep (@deps) { next if scalar(grep { $_ eq $dep } (@extras)) > 0; # Skip if we're going to be enabling it anyway. if (!-e "src/modules/$dep" && !-e "include/$dep") { if (-e "src/modules/extra/$dep") { print STDERR "Will also enable extra \e[32;1m$dep\e[0m (needed by \e[32;1m$extra\e[0m)\n"; push @extras, $dep; } else { print STDERR "\e[33;1mWARNING:\e[0m module \e[32;1m$extra\e[0m might be missing dependency \e[32;1m$dep\e[0m - YOU are responsible for satisfying it!\n"; } } } print "Enabling $extra ... \n"; symlink "extra/$extra", $source or print STDERR "$source: Cannot link to 'extra/$extra': $!\n"; } } sub disable_extras (@) { opendir my $dd, "src/modules/extra/"; my @files = readdir($dd); closedir $dd; my (@extras) = @_; EXTRA: for my $extra (@extras) { my $extrapath = "src/modules/extra/$extra"; my $source = "src/modules/$extra"; if (!-e $extrapath) { print STDERR "Cannot disable \e[32;1m$extra\e[0m : Is not an extra\n"; next; } if ((! -l $source) || readlink($source) ne "extra/$extra") { print STDERR "Cannot disable \e[32;1m$extra\e[0m : Source is not a link or doesn't refer to the right file. Remove manually if this is in error.\n"; next; } # Check if anything needs this. for my $file (@files) { my @deps = split /\s+/, get_directive("src/modules/extra/$file", 'ModDep', ''); # File depends on this extra... if (scalar(grep { $_ eq $extra } @deps) > 0) { # And is both enabled and not about to be disabled. if (-e "src/modules/$file" && scalar(grep { $_ eq $file } @extras) < 1) { print STDERR "Cannot disable \e[32;1m$extra\e[0m : is needed by \e[32;1m$file\e[0m\n"; next EXTRA; } } } # Now remove. print "Disabling $extra ... \n"; unlink "src/modules/$extra" or print STDERR "Cannot disable \e[32;1m$extra\e[0m : $!\n"; } } inspircd-3.4.0/docs/000077500000000000000000000000001355455045400142735ustar00rootroot00000000000000inspircd-3.4.0/docs/Doxyfile000066400000000000000000000174501355455045400160100ustar00rootroot00000000000000DOXYFILE_ENCODING = UTF-8 PROJECT_NAME = InspIRCd PROJECT_NUMBER = 3.0 PROJECT_BRIEF = PROJECT_LOGO = OUTPUT_DIRECTORY = docs/doxygen CREATE_SUBDIRS = NO ALLOW_UNICODE_NAMES = NO OUTPUT_LANGUAGE = English OUTPUT_TEXT_DIRECTION = None BRIEF_MEMBER_DESC = YES REPEAT_BRIEF = YES ABBREVIATE_BRIEF = ALWAYS_DETAILED_SEC = NO INLINE_INHERITED_MEMB = NO FULL_PATH_NAMES = YES STRIP_FROM_PATH = STRIP_FROM_INC_PATH = SHORT_NAMES = NO JAVADOC_AUTOBRIEF = NO JAVADOC_BANNER = NO QT_AUTOBRIEF = NO MULTILINE_CPP_IS_BRIEF = NO INHERIT_DOCS = YES SEPARATE_MEMBER_PAGES = NO TAB_SIZE = 8 ALIASES = TCL_SUBST = OPTIMIZE_OUTPUT_FOR_C = NO OPTIMIZE_OUTPUT_JAVA = NO OPTIMIZE_FOR_FORTRAN = NO OPTIMIZE_OUTPUT_VHDL = NO OPTIMIZE_OUTPUT_SLICE = NO EXTENSION_MAPPING = MARKDOWN_SUPPORT = YES TOC_INCLUDE_HEADINGS = 5 AUTOLINK_SUPPORT = YES BUILTIN_STL_SUPPORT = YES CPP_CLI_SUPPORT = NO SIP_SUPPORT = NO IDL_PROPERTY_SUPPORT = YES DISTRIBUTE_GROUP_DOC = NO GROUP_NESTED_COMPOUNDS = NO SUBGROUPING = YES INLINE_GROUPED_CLASSES = NO INLINE_SIMPLE_STRUCTS = NO TYPEDEF_HIDES_STRUCT = NO LOOKUP_CACHE_SIZE = 0 EXTRACT_ALL = NO EXTRACT_PRIVATE = NO EXTRACT_PRIV_VIRTUAL = NO EXTRACT_PACKAGE = NO EXTRACT_STATIC = NO EXTRACT_LOCAL_CLASSES = YES EXTRACT_LOCAL_METHODS = NO EXTRACT_ANON_NSPACES = NO HIDE_UNDOC_MEMBERS = NO HIDE_UNDOC_CLASSES = NO HIDE_FRIEND_COMPOUNDS = NO HIDE_IN_BODY_DOCS = NO INTERNAL_DOCS = NO CASE_SENSE_NAMES = NO HIDE_SCOPE_NAMES = NO HIDE_COMPOUND_REFERENCE= NO SHOW_INCLUDE_FILES = YES SHOW_GROUPED_MEMB_INC = NO FORCE_LOCAL_INCLUDES = NO INLINE_INFO = YES SORT_MEMBER_DOCS = YES SORT_BRIEF_DOCS = NO SORT_MEMBERS_CTORS_1ST = NO SORT_GROUP_NAMES = NO SORT_BY_SCOPE_NAME = NO STRICT_PROTO_MATCHING = NO GENERATE_TODOLIST = YES GENERATE_TESTLIST = YES GENERATE_BUGLIST = YES GENERATE_DEPRECATEDLIST= YES ENABLED_SECTIONS = MAX_INITIALIZER_LINES = 30 SHOW_USED_FILES = YES SHOW_FILES = YES SHOW_NAMESPACES = YES FILE_VERSION_FILTER = LAYOUT_FILE = CITE_BIB_FILES = QUIET = NO WARNINGS = NO WARN_IF_UNDOCUMENTED = NO WARN_IF_DOC_ERROR = YES WARN_NO_PARAMDOC = NO WARN_AS_ERROR = NO WARN_FORMAT = "$file:$line: $text" WARN_LOGFILE = INPUT = INPUT_ENCODING = UTF-8 FILE_PATTERNS = RECURSIVE = YES EXCLUDE = EXCLUDE_SYMLINKS = YES EXCLUDE_PATTERNS = */.git/* \ */doxygen/* \ */coremods/* \ */modules/* \ */vendor/* EXCLUDE_SYMBOLS = EXAMPLE_PATH = EXAMPLE_PATTERNS = EXAMPLE_RECURSIVE = NO IMAGE_PATH = INPUT_FILTER = FILTER_PATTERNS = FILTER_SOURCE_FILES = NO FILTER_SOURCE_PATTERNS = USE_MDFILE_AS_MAINPAGE = README.md SOURCE_BROWSER = NO INLINE_SOURCES = NO STRIP_CODE_COMMENTS = YES REFERENCED_BY_RELATION = NO REFERENCES_RELATION = NO REFERENCES_LINK_SOURCE = YES SOURCE_TOOLTIPS = YES USE_HTAGS = NO VERBATIM_HEADERS = YES ALPHABETICAL_INDEX = YES COLS_IN_ALPHA_INDEX = 5 IGNORE_PREFIX = GENERATE_HTML = YES HTML_OUTPUT = html HTML_FILE_EXTENSION = .html HTML_HEADER = HTML_FOOTER = HTML_STYLESHEET = HTML_EXTRA_STYLESHEET = HTML_EXTRA_FILES = HTML_COLORSTYLE_HUE = 220 HTML_COLORSTYLE_SAT = 100 HTML_COLORSTYLE_GAMMA = 80 HTML_TIMESTAMP = NO HTML_DYNAMIC_MENUS = YES HTML_DYNAMIC_SECTIONS = NO HTML_INDEX_NUM_ENTRIES = 100 GENERATE_DOCSET = YES DOCSET_FEEDNAME = "Doxygen generated documentation" DOCSET_BUNDLE_ID = org.doxygen.Project DOCSET_PUBLISHER_ID = org.doxygen.Publisher DOCSET_PUBLISHER_NAME = Publisher GENERATE_HTMLHELP = NO CHM_FILE = HHC_LOCATION = GENERATE_CHI = NO CHM_INDEX_ENCODING = BINARY_TOC = NO TOC_EXPAND = NO GENERATE_QHP = NO QCH_FILE = QHP_NAMESPACE = org.doxygen.Project QHP_VIRTUAL_FOLDER = doc QHP_CUST_FILTER_NAME = QHP_CUST_FILTER_ATTRS = QHP_SECT_FILTER_ATTRS = QHG_LOCATION = GENERATE_ECLIPSEHELP = NO ECLIPSE_DOC_ID = org.doxygen.Project DISABLE_INDEX = NO GENERATE_TREEVIEW = NO ENUM_VALUES_PER_LINE = 4 TREEVIEW_WIDTH = 250 EXT_LINKS_IN_WINDOW = NO FORMULA_FONTSIZE = 10 FORMULA_TRANSPARENT = YES USE_MATHJAX = NO MATHJAX_FORMAT = HTML-CSS MATHJAX_RELPATH = http://cdn.mathjax.org/mathjax/latest MATHJAX_EXTENSIONS = MATHJAX_CODEFILE = SEARCHENGINE = YES SERVER_BASED_SEARCH = NO EXTERNAL_SEARCH = NO SEARCHENGINE_URL = SEARCHDATA_FILE = searchdata.xml EXTERNAL_SEARCH_ID = EXTRA_SEARCH_MAPPINGS = GENERATE_LATEX = NO LATEX_OUTPUT = latex LATEX_CMD_NAME = latex MAKEINDEX_CMD_NAME = makeindex LATEX_MAKEINDEX_CMD = makeindex COMPACT_LATEX = NO PAPER_TYPE = a4 EXTRA_PACKAGES = LATEX_HEADER = LATEX_FOOTER = LATEX_EXTRA_STYLESHEET = LATEX_EXTRA_FILES = PDF_HYPERLINKS = YES USE_PDFLATEX = YES LATEX_BATCHMODE = NO LATEX_HIDE_INDICES = NO LATEX_SOURCE_CODE = NO LATEX_BIB_STYLE = plain LATEX_TIMESTAMP = NO LATEX_EMOJI_DIRECTORY = GENERATE_RTF = NO RTF_OUTPUT = rtf COMPACT_RTF = NO RTF_HYPERLINKS = NO RTF_STYLESHEET_FILE = RTF_EXTENSIONS_FILE = RTF_SOURCE_CODE = NO GENERATE_MAN = NO MAN_OUTPUT = man MAN_EXTENSION = .3 MAN_SUBDIR = MAN_LINKS = NO GENERATE_XML = NO XML_OUTPUT = xml XML_PROGRAMLISTING = YES XML_NS_MEMB_FILE_SCOPE = NO GENERATE_DOCBOOK = NO DOCBOOK_OUTPUT = docbook DOCBOOK_PROGRAMLISTING = NO GENERATE_AUTOGEN_DEF = NO GENERATE_PERLMOD = NO PERLMOD_LATEX = NO PERLMOD_PRETTY = YES PERLMOD_MAKEVAR_PREFIX = ENABLE_PREPROCESSING = YES MACRO_EXPANSION = YES EXPAND_ONLY_PREDEF = NO SEARCH_INCLUDES = YES INCLUDE_PATH = INCLUDE_FILE_PATTERNS = PREDEFINED = CoreExport=/**/ \ INSPIRCD_INTRUSIVE_LIST_NAME=intrusive_list EXPAND_AS_DEFINED = SKIP_FUNCTION_MACROS = YES TAGFILES = GENERATE_TAGFILE = ALLEXTERNALS = NO EXTERNAL_GROUPS = YES EXTERNAL_PAGES = YES CLASS_DIAGRAMS = YES DIA_PATH = HIDE_UNDOC_RELATIONS = YES HAVE_DOT = NO DOT_NUM_THREADS = 0 DOT_FONTNAME = Helvetica DOT_FONTSIZE = 10 DOT_FONTPATH = CLASS_GRAPH = YES COLLABORATION_GRAPH = YES GROUP_GRAPHS = YES UML_LOOK = NO UML_LIMIT_NUM_FIELDS = 10 TEMPLATE_RELATIONS = NO INCLUDE_GRAPH = YES INCLUDED_BY_GRAPH = YES CALL_GRAPH = NO CALLER_GRAPH = NO GRAPHICAL_HIERARCHY = YES DIRECTORY_GRAPH = YES DOT_IMAGE_FORMAT = png INTERACTIVE_SVG = NO DOT_PATH = DOTFILE_DIRS = MSCFILE_DIRS = DIAFILE_DIRS = PLANTUML_JAR_PATH = PLANTUML_CFG_FILE = PLANTUML_INCLUDE_PATH = DOT_GRAPH_MAX_NODES = 50 MAX_DOT_GRAPH_DEPTH = 0 DOT_TRANSPARENT = NO DOT_MULTI_TARGETS = NO GENERATE_LEGEND = YES DOT_CLEANUP = YES inspircd-3.4.0/docs/LICENSE.txt000066400000000000000000000437471355455045400161350ustar00rootroot00000000000000 NOTE: InspIRCd is licensed under GPL version 2 only. "Upgrading" to a later version of the GENERAL PUBLIC LICENSE is not permitted. For further information on this, please contact us at irc.inspircd.org on #inspircd. ---------------------------------------------------------------------- GNU GENERAL PUBLIC LICENSE Version 2, June 1991 Copyright (C) 1989, 1991 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This General Public License applies to most of the Free Software Foundation's software and to any other program whose authors commit to using it. (Some other Free Software Foundation software is covered by the GNU Lesser General Public License instead.) You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs; and that you know you can do these things. To protect your rights, we need to make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the software, or if you modify it. For example, if you distribute copies of such a program, whether gratis or for a fee, you must give the recipients all the rights that you have. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. We protect your rights with two steps: (1) copyright the software, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the software. Also, for each author's protection and ours, we want to make certain that everyone understands that there is no warranty for this free software. If the software is modified by someone else and passed on, we want its recipients to know that what they have is not the original, so that any problems introduced by others will not reflect on the original authors' reputations. Finally, any free program is threatened constantly by software patents. We wish to avoid the danger that redistributors of a free program will individually obtain patent licenses, in effect making the program proprietary. To prevent this, we have made it clear that any patent must be licensed for everyone's free use or not licensed at all. The precise terms and conditions for copying, distribution and modification follow. GNU GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License applies to any program or other work which contains a notice placed by the copyright holder saying it may be distributed under the terms of this General Public License. The "Program", below, refers to any such program or work, and a "work based on the Program" means either the Program or any derivative work under copyright law: that is to say, a work containing the Program or a portion of it, either verbatim or with modifications and/or translated into another language. (Hereinafter, translation is included without limitation in the term "modification".) Each licensee is addressed as "you". Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running the Program is not restricted, and the output from the Program is covered only if its contents constitute a work based on the Program (independent of having been made by running the Program). Whether that is true depends on what the Program does. 1. You may copy and distribute verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and give any other recipients of the Program a copy of this License along with the Program. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Program or any portion of it, thus forming a work based on the Program, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) You must cause the modified files to carry prominent notices stating that you changed the files and the date of any change. b) You must cause any work that you distribute or publish, that in whole or in part contains or is derived from the Program or any part thereof, to be licensed as a whole at no charge to all third parties under the terms of this License. c) If the modified program normally reads commands interactively when run, you must cause it, when started running for such interactive use in the most ordinary way, to print or display an announcement including an appropriate copyright notice and a notice that there is no warranty (or else, saying that you provide a warranty) and that users may redistribute the program under these conditions, and telling the user how to view a copy of this License. (Exception: if the Program itself is interactive but does not normally print such an announcement, your work based on the Program is not required to print an announcement.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Program, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Program, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Program. In addition, mere aggregation of another work not based on the Program with the Program (or with a work based on the Program) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may copy and distribute the Program (or a work based on it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you also do one of the following: a) Accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, b) Accompany it with a written offer, valid for at least three years, to give any third party, for a charge no more than your cost of physically performing source distribution, a complete machine-readable copy of the corresponding source code, to be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, c) Accompany it with the information you received as to the offer to distribute corresponding source code. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form with such an offer, in accord with Subsection b above.) The source code for a work means the preferred form of the work for making modifications to it. For an executable work, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the executable. However, as a special exception, the source code distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. If distribution of executable or object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place counts as distribution of the source code, even though third parties are not compelled to copy the source along with the object code. 4. You may not copy, modify, sublicense, or distribute the Program except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense or distribute the Program is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 5. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Program or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Program (or any work based on the Program), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Program or works based on it. 6. Each time you redistribute the Program (or any work based on the Program), the recipient automatically receives a license from the original licensor to copy, distribute or modify the Program subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties to this License. 7. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Program at all. For example, if a patent license would not permit royalty-free redistribution of the Program by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Program. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system, which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 8. If the distribution and/or use of the Program is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Program under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 9. The Free Software Foundation may publish revised and/or new versions of the General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of this License, you may choose any version ever published by the Free Software Foundation. 10. If you wish to incorporate parts of the Program into other free programs whose distribution conditions are different, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) This program 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; either version 2 of the License, or (at your option) any later version. 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, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. Also add information on how to contact you by electronic and paper mail. If the program is interactive, make it output a short notice like this when it starts in an interactive mode: Gnomovision version 69, Copyright (C) year name of author Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, the commands you use may be called something other than `show w' and `show c'; they could even be mouse-clicks or menu items--whatever suits your program. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the program, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the program `Gnomovision' (which makes passes at compilers) written by James Hacker. , 1 April 1989 Ty Coon, President of Vice This General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Lesser General Public License instead of this License. inspircd-3.4.0/docs/conf/000077500000000000000000000000001355455045400152205ustar00rootroot00000000000000inspircd-3.4.0/docs/conf/filter.conf.example000066400000000000000000000065411355455045400210140ustar00rootroot00000000000000# Configuration file for the filter module # The tags for this module are formatted as follows: # # # # Valid actions for 'action' are: # # warn This allows the line and sends out a notice to all opers # with +s. # # block This blocks the line, sends out a notice to all opers with # +s and informs the user that their message was blocked. # # silent This blocks the line only, and informs the user that their # message was blocked, but does not notify opers. # # none This action causes nothing to be done except logging. This # is the default action if none is specified. # # kill This disconnects the user, with the 'reason' parameter as # the kill reason. # # gline G-line the user for 'duration' length of time. Durations may # be specified using the notation 1y2w3d4h5m6s in a similar way to # other G-lines, omitting the duration or setting it to 0 makes # any G-lines set by this filter be permanent. # # zline Z-line the user for 'duration' length of time. Durations may # be specified using the notation 1y2w3d4h5m6s in a similar way to # other Z-lines, omitting the duration or setting it to 0 makes # any Z-lines set by this filter be permanent. # # shun Shun the user for 'duration' length of time. Durations may # be specified using the notation 1y2w3d4h5m6s in a similar way to # other X-lines, omitting the duration or setting it to 0 makes # any shuns set by this filter be permanent. # Requires the shun module to be loaded. # # You can add filters from IRC using the /FILTER command. If you do this, they # will be set globally to your entire network. # # Valid characters for 'flags' are one or more of: # # p: Block private and channel messages # n: Block private and channel notices # P: Block part messages # q: Block quit messages # o: Don't match against opers # r: Don't match against registered users # c: Strip color codes from text before trying to match # *: Represents all of the above flags except r # -: Does nothing, a no-op for when you do not want to specify any flags # Example filters: # # # # # An example regexp filter: # # # You may specify specific channels that are exempt from being filtered: # # # You can also exempt messages from being filtered if they are sent to # specific nicks. # Example that exempts all messages sent *to* NickServ: # # Note that messages *from* services are never subject to filtering; # tags are only for exempting messages sent *to* the # configured targets. inspircd-3.4.0/docs/conf/helpop.conf.example000066400000000000000000001337161355455045400210230ustar00rootroot00000000000000# Sample configuration file for the helpop module. # You can either copy this into your conf folder and set up the module to use it, # or you can customize the responses for your network and/or add more. # # The way the new helpop system works is simple. You use one or more helpop tags. # # key is what the user is looking for (i.e. /helpop moo), and value is what they get back # (note that it can span multiple lines!). # -- w00t 16/dec/2006 # inspircd-3.4.0/docs/conf/inspircd.conf.example000066400000000000000000001453141355455045400213440ustar00rootroot00000000000000######################################################################## # # # ___ ___ ____ ____ _ # # |_ _|_ __ ___ _ __|_ _| _ \ / ___|__| | # # | || '_ \/ __| '_ \| || |_) | | / _` | # # | || | | \__ \ |_) | || _ <| |__| (_| | # # |___|_| |_|___/ .__/___|_| \_\\____\__,_| # # |_| # # ____ __ _ _ _ # # / ___|___ _ __ / _(_) __ _ _ _ _ __ __ _| |_(_) ___ _ __ # # | | / _ \| '_ \| |_| |/ _` | | | | '__/ _` | __| |/ _ \| '_ \ # # | |__| (_) | | | | _| | (_| | |_| | | | (_| | |_| | (_) | | | | # # \____\___/|_| |_|_| |_|\__, |\__,_|_| \__,_|\__|_|\___/|_| |_| # # |___/ # # # ##################################||#################################### #||# ##################################||#################################### # # # This is an example of the config file for InspIRCd. # # Change the options to suit your network. # # # # # # ____ _ _____ _ _ ____ _ _ _ # # | _ \ ___ __ _ __| | |_ _| |__ (_)___ | __ )(_) |_| | # # | |_) / _ \/ _` |/ _` | | | | '_ \| / __| | _ \| | __| | # # | _ < __/ (_| | (_| | | | | | | | \__ \ | |_) | | |_|_| # # |_| \_\___|\__,_|\__,_| |_| |_| |_|_|___/ |____/|_|\__(_) # # # # Lines prefixed with READ THIS BIT, as shown above, are IMPORTANT # # lines, and you REALLY SHOULD READ THEM. Yes, THIS MEANS YOU. Even # # if you've configured InspIRCd before, these probably indicate # # something new or different to this version and you SHOULD READ IT. # # # ######################################################################## #-#-#-#-#-#-#-#-#-# CONFIGURATION FORMAT #-#-#-#-#-#-#-#-#-#-#-#-#-#- # # # In order to maintain compatibility with older configuration files, # # you can change the configuration parser to parse as it did in # # previous releases. When using the "compat" format, you need to use # # C++ escape sequences (e.g. \n) instead of XML ones (e.g. &nl;) and # # can not use to create macros. # # #-#-#-#-#-#-#-#-#-# INCLUDE CONFIGURATION #-#-#-#-#-#-#-#-#-#-#-#-#-# # # # This optional tag allows you to include another config file # # allowing you to keep your configuration tidy. The configuration # # file you include will be treated as part of the configuration file # # which includes it, in simple terms the inclusion is transparent. # # # # All paths to config files are relative to the directory that the # # process runs in. # # # # You may also include an executable file, in which case if you do so # # the output of the executable on the standard output will be added # # to your config at the point of the include tag. # # # # Syntax is as follows: # # # # # # # # # # Executable include example: # # # # #-#-#-#-#-#-#-#-#-#-#-# VARIABLE DEFINITIONS -#-#-#-#-#-#-#-#-#-#-#-# # # # You can define variables that will be substituted later in the # # configuration file. This can be useful to allow settings to be # # easily changed, or to parameterize a remote includes. # # # # Variables may be redefined and may reference other variables. # # Value expansion happens at the time the tag is read. # #-#-#-#-#-#-#-#-#-#-#-#- SERVER DESCRIPTION -#-#-#-#-#-#-#-#-#-#-#-#- # # # Here is where you enter the information about your server. # # # #-#-#-#-#-#-#-#-#-#-#-#- ADMIN INFORMATION -#-#-#-#-#-#-#-#-#-#-#-# # # # Describes the Server Administrator's real name (optionally), # # nick, and email address. # # # #-#-#-#-#-#-#-#-#-#-#-#- PORT CONFIGURATION -#-#-#-#-#-#-#-#-#-#-#- # # # Enter the port and address bindings here. # # # # # # ____ _ _____ _ _ ____ _ _ _ # # | _ \ ___ __ _ __| | |_ _| |__ (_)___ | __ )(_) |_| | # # | |_) / _ \/ _` |/ _` | | | | '_ \| / __| | _ \| | __| | # # | _ < __/ (_| | (_| | | | | | | | \__ \ | |_) | | |_|_| # # |_| \_\___|\__,_|\__,_| |_| |_| |_|_|___/ |____/|_|\__(_) # # # # If you want to link servers to InspIRCd you must load the # # spanningtree module! Please see the modules list for # # information on how to load this module! If you do not load this # # module, server ports will NOT work! # # Listener that binds on a TCP/IP endpoint: tag that you have defined or one # of "openssl", "gnutls", "mbedtls" if you have not defined any. See the # docs page for the SSL module you are using for more details. # # You will need to load the ssl_openssl module for OpenSSL, ssl_gnutls # for GnuTLS and ssl_mbedtls for mbedTLS. ssl="gnutls" # defer: When this is non-zero, connections will not be handed over to # the daemon from the operating system before data is ready. # In Linux, the value indicates the time period we'll wait for a # connection to come up with data. Don't set it too low! # In BSD the value is ignored; only zero and non-zero is possible. # Windows ignores this parameter completely. # Note: This does not take effect on rehash. # To change it on a running bind, you'll have to comment it out, # rehash, comment it in and rehash again. defer="0" # free: When this is enabled the listener will be created regardless of # whether the interface that provides the bind address is available. This # is useful for if you are starting InspIRCd on boot when the server may # not have brought the network interfaces up yet. free="no"> # Listener that binds on a UNIX endpoint (not supported on Windows): # # Listener accepting HTML5 WebSocket connections. # Requires the websocket module and SHA-1 hashing support (provided by the sha1 # module). # # You can define a custom tag which defines the SSL configuration # for this listener. See the docs page for the SSL module you are using for # more details. # # Alternatively, you can use one of the default SSL profiles which are created # when you have not defined any: # "openssl" (requires the ssl_openssl module) # "gnutls" (requires the ssl_gnutls module) # "mbedtls" (requires the ssl_mbedtls module) # # When linking servers, the OpenSSL, GnuTLS, and mbedTLS implementations are # completely link-compatible and can be used alongside each other on each end # of the link without any significant issues. #-#-#-#-#-#-#-#-#-#- CONNECTIONS CONFIGURATION -#-#-#-#-#-#-#-#-#-#-# # # # This is where you can configure which connections are allowed # # and denied access onto your server. The password is optional. # # You may have as many of these as you require. To allow/deny all # # connections, use a '*' or 0.0.0.0/0. # # # # -- It is important to note that connect tags are read from the -- # # TOP DOWN. This means that you should have more specific deny # # and allow tags at the top, progressively more general, followed # # by a (should you wish to have one). # # # # Connect blocks are searched twice for each user - once when the TCP # # connection is accepted, and once when the user completes their # # registration. Most of the information (hostname, ident response, # # password, SSL when using STARTTLS, etc) is only available during # # the second search, so if you are trying to make a closed server, # # you will probably need a connect block just for user registration. # # This can be done by using # # To enable IRCCloud on your network uncomment this: # # To enable KiwiIRC.com on your network uncomment this: # # A connect class with set denies connections from the specified host/IP range. # A connect class with set allows c from the specified host/IP range. #hash="bcrypt" # password: Password to use for this block/user(s) password="secret" # maxchans: Maximum number of channels a user in this class # be in at one time. maxchans="20" # timeout: How long the server will wait before disconnecting # a user if they do not do anything on connect. # (Note, this is a client-side thing, if the client does not # send /NICK, /USER or /PASS) timeout="20" # localmax: Maximum local connections per IP (or CIDR mask, see below). localmax="3" # globalmax: Maximum global (network-wide) connections per IP (or CIDR mask, see below). globalmax="3" # maxconnwarn: Enable warnings when localmax or globalmax are reached (defaults to on) maxconnwarn="off" # resolvehostnames: If disabled, no DNS lookups will be performed on connecting users # in this class. This can save a lot of resources on very busy servers. resolvehostnames="yes" # usednsbl: Defines whether or not users in this class are subject to DNSBL. Default is yes. # This setting only has effect when the dnsbl module is loaded. #usednsbl="yes" # useident: Defines if users in this class MUST respond to a ident query or not. useident="no" # usests: Whether a STS policy should be advertised to users in this class. # This setting only has effect when the ircv3_sts module is loaded. #usests="no" # webirc: Restricts usage of this class to the specified WebIRC gateway. # This setting only has effect when the cgiirc module is loaded. #webirc="name" # limit: How many users are allowed in this class limit="5000" # modes: User modes that are set on users in this block on connect. # Enabling this option requires that the conn_umodes module be loaded. # This entry is highly recommended to use for/with IP cloaking/masking. # For the example to work, this also requires that the cloaking # module be loaded as well. modes="+x" # requireident: Require that users of this block have a valid ident response. # Requires the ident module to be loaded. #requireident="yes" # requiressl: Require that users of this block use an SSL connection. # This can also be set to "trusted", as to only accept certificates # issued by a certificate authority that you can configure in the # settings of the SSL module that you're using. # Requires the sslinfo module to be loaded. #requiressl="yes" # requireaccount: Require that users of this block have authenticated to a # services account. # NOTE: You must complete the signon prior to full connection. Currently, # this is only possible by using SASL authentication; passforward # and PRIVMSG NickServ happen after your final connect block has been found. # Requires the services_account module to be loaded. #requireaccount="yes" # Alternate MOTD file for this connect class. The contents of this file are # specified using <files secretmotd="filename"> or <execfiles ...> # # NOTE: the following escape sequences for IRC formatting characters can be # used in your MOTD: # Bold: \b # Color: \c<fg>[,<bg>] # Italic: \i # Monospace: \m (not widely supported) # Reset: \x # Reverse: \r # Strikethrough: \s (not widely supported) # Underline: \u # See https://defs.ircdocs.horse/info/formatting.html for more information # on client support for formatting characters. motd="secretmotd" # port: What port range this user is allowed to connect on. (optional) # The ports MUST be set to listen in the bind blocks above. port="6697,9999"> <connect # name: Name to use for this connect block. Mainly used for # connect class inheriting. name="main" # allow: The IP address or hostname of clients that can use this # class. You can specify either an exact match, a glob match, or # a CIDR range here. allow="*" # maxchans: Maximum number of channels a user in this class # be in at one time. maxchans="20" # timeout: How long the server will wait before disconnecting # a user if they do not do anything on connect. # (Note, this is a client-side thing, if the client does not # send /NICK, /USER or /PASS) timeout="20" # pingfreq: How often the server tries to ping connecting clients. pingfreq="2m" # hardsendq: maximum amount of data allowed in a client's send queue # before they are dropped. Keep this value higher than the length of # your network's /LIST or /WHO output, or you will have lots of # disconnects from sendq overruns! # Setting this to "1M" is equivalent to "1048576", "8K" is 8192, etc. hardsendq="1M" # softsendq: amount of data in a client's send queue before the server # begins delaying their commands in order to allow the sendq to drain softsendq="10240" # recvq: amount of data allowed in a client's queue before they are dropped. # Entering "10K" is equivalent to "10240", see above. recvq="10K" # threshold: This specifies the amount of command penalty a user is allowed to have # before being quit or fakelagged due to flood. Normal commands have a penalty of 1, # ones such as /OPER have penalties up to 10. # # If you are not using fakelag, this should be at least 20 to avoid excess flood kills # from processing some commands. threshold="10" # commandrate: This specifies the maximum rate that commands can be processed. # If commands are sent more rapidly, the user's penalty will increase and they will # either be fakelagged or killed when they reach the threshold # # Units are millicommands per second, so 1000 means one line per second. commandrate="1000" # fakelag: Use fakelag instead of killing users for excessive flood # # Fake lag stops command processing for a user when a flood is detected rather than # immediately killing them; their commands are held in the recvq and processed later # as the user's command penalty drops. Note that if this is enabled, flooders will # quit with "RecvQ exceeded" rather than "Excess Flood". fakelag="on" # localmax: Maximum local connections per IP. localmax="3" # globalmax: Maximum global (network-wide) connections per IP. globalmax="3" # resolvehostnames: If disabled, no DNS lookups will be performed on connecting users # in this class. This can save a lot of resources on very busy servers. resolvehostnames="yes" # useident: Defines if users in this class must respond to a ident query or not. useident="no" # usests: Whether a STS policy should be advertised to users in this class. # This setting only has effect when the ircv3_sts module is loaded. #usests="no" # limit: How many users are allowed in this class limit="5000" # modes: User modes that are set on users in this block on connect. # Enabling this option requires that the conn_umodes module be loaded. # This entry is highly recommended to use for/with IP cloaking/masking. # For the example to work, this also requires that the cloaking # module be loaded as well. modes="+x"> #-#-#-#-#-#-#-#-#-#-#-#- CIDR CONFIGURATION -#-#-#-#-#-#-#-#-#-#-#- # # # CIDR configuration allows detection of clones and applying of # # throttle limits across a CIDR range. (A CIDR range is a group of # # IPs, for example, the CIDR range 192.168.1.0-192.168.1.255 may be # # represented as 192.168.1.0/24). This means that abuse across an ISP # # is detected and curtailed much easier. Here is a good chart that # # shows how many IPs the different CIDRs correspond to: # # https://en.wikipedia.org/wiki/IPv4_subnetting_reference # # https://en.wikipedia.org/wiki/IPv6_subnetting_reference # # # <cidr # ipv4clone: specifies how many bits of an IP address should be # looked at for clones. The default only looks for clones on a # single IP address of a user. You do not want to set this # extremely low. (Values are 0-32). ipv4clone="32" # ipv6clone: specifies how many bits of an IP address should be # looked at for clones. The default only looks for clones on a # single IP address of a user. You do not want to set this # extremely low. (Values are 0-128). ipv6clone="128"> # This file has all the information about oper classes, types and o:lines. # You *MUST* edit it. #<include file="examples/opers.conf.example"> # This file has all the information about server links and ulined servers. # You *MUST* edit it if you intend to link servers. #<include file="examples/links.conf.example"> #-#-#-#-#-#-#-#-#-#- MISCELLANEOUS CONFIGURATION -#-#-#-#-#-#-#-#-#-# # # # Files block - contains files whose contents are used by the ircd # # motd - displayed on connect and when a user executes /MOTD # Modules can also define their own files <files motd="examples/motd.txt.example"> # Example of an executable file include. Note this will be read on rehash, # not when the command is run. #<execfiles motd="wget -O - https://www.example.com/motd.txt"> #-#-#-#-#-#-#-#-#-#-#-#-#-#-# DNS SERVER -#-#-#-#-#-#-#-#-#-#-#-#-#-#-# # If these values are not defined, InspIRCd uses the default DNS resolver # of your system. <dns # server: DNS server to use to attempt to resolve IP's to hostnames. # in most cases, you won't need to change this, as inspircd will # automatically detect the nameserver depending on /etc/resolv.conf # (or, on Windows, your set nameservers in the registry.) # Note that this must be an IP address and not a hostname, because # there is no resolver to resolve the name until this is defined! # # server="127.0.0.1" # timeout: time to wait to try to resolve DNS/hostname. timeout="5"> # An example of using an IPv6 nameserver #<dns server="::1" timeout="5"> #-#-#-#-#-#-#-#-#-#-#-#-#-#-# PID FILE -#-#-#-#-#-#-#-#-#-#-#-#-#-#-# # # # Define the path to the PID file here. The PID file can be used to # # rehash the ircd from the shell or to terminate the ircd from the # # shell using shell scripts, perl scripts, etc... and to monitor the # # ircd's state via cron jobs. If this is a relative path, it will be # # relative to the configuration directory, and if it is not defined, # # the default of 'inspircd.pid' is used. # # # #<pid file="/path/to/inspircd.pid"> #-#-#-#-#-#-#-#-#-#-#-#-#- LIST MODE LIMITS #-#-#-#-#-#-#-#-#-#-#-#-#-# # # # The <maxlist> tag is used customise the maximum number of each list # # mode that can be set on a channel. # # The tags are read from top to bottom and the list mode limit from # # the first tag found which matches the channel name and mode type is # # applied to that channel. # # It is advisable to put an entry with the channel as '*' at the # # bottom of the list. If none are specified or no maxlist tag is # # matched, the banlist size defaults to 100 entries. # # # # Allows #largechan to have up to 200 ban entries. #<maxlist mode="ban" chan="#largechan" limit="200"> # Allows #largechan to have up to 200 ban exception entries. #<maxlist mode="e" chan="#largechan" limit="200"> # Allows all channels and list modes not previously matched to have # up to 100 entries. <maxlist chan="*" limit="100"> #-#-#-#-#-#-#-#-#-#-#-#-#- SERVER OPTIONS -#-#-#-#-#-#-#-#-#-#-#-#-# # # # Settings to define which features are usable on your server. # # # <options # prefixquit: What (if anything) users' quit messages # should be prefixed with. prefixquit="Quit: " # suffixquit: What (if anything) users' quit messages # should be suffixed with. suffixquit="" # prefixpart: What (if anything) users' part messages # should be prefixed with. prefixpart="&quot;" # NOTE: Use "\"" instead of "&quot;" if not using <config format="xml"> # suffixpart: What (if anything) users' part message # should be suffixed with. suffixpart="&quot;" # fixedquit: Set all users' quit messages to this value. #fixedquit="" # fixedpart: Set all users' part messages in all channels # to this value. #fixedpart="" # syntaxhints: If enabled, if a user fails to send the correct parameters # for a command, the ircd will give back some help text of what # the correct parameters are. syntaxhints="no" # casemapping: This sets the case mapping method to be used by the # server. This MUST be the same on all servers. Possible values are: # "ascii" (recommended) # "rfc1459" (default, required for linking to 2.0 servers) # NOTE: if you are using the nationalchars module this setting will be # ignored. You should use <nationalchars:casemapping> instead. casemapping="ascii" # cyclehostsfromuser: If enabled, the source of the mode change for # cyclehosts will be the user who cycled. This can look nicer, but # triggers anti-takeover mechanisms of some obsolete bots. cyclehostsfromuser="no" # announcets: If set to yes, when the timestamp on a channel changes, all users # in the channel will be sent a NOTICE about it. announcets="yes" # allowmismatch: Setting this option to yes will allow servers to link even # if they don't have the same "optionally common" modules loaded. Setting this to # yes may introduce some desyncs and unwanted behaviour. allowmismatch="no" # defaultbind: Sets the default for <bind> tags without an address. Choices are # ipv4 or ipv6; if not specified, IPv6 will be used if your system has support, # falling back to IPv4 otherwise. defaultbind="auto" # hostintopic: If enabled, channels will show the host of the topic setter # in the topic. If set to no, it will only show the nick of the topic setter. hostintopic="yes" # pingwarning: If a server does not respond to a ping within this period, # it will send a notice to opers with snomask +l informing that the server # is about to ping timeout. pingwarning="15" # serverpingfreq: How often pings are sent between servers. serverpingfreq="1m" # splitwhois: Whether to split private/secret channels from normal channels # in WHOIS responses. Possible values for this are: # 'no' - list all channels together in the WHOIS response regardless of type. # 'split' - split private/secret channels to a separate WHOIS response numeric. # 'splitmsg' - the same as split but also send a message explaining the split. splitwhois="no" # defaultmodes: What modes are set on a empty channel when a user # joins it and it is unregistered. defaultmodes="not" # xlinemessage: This is the text that is sent to a user when they are # banned from the server. xlinemessage="You're banned! Email irc@example.com with the ERROR line below for help." # allowzerolimit: If enabled then allow a limit of 0 to be set on channels. # This is non-standard behaviour and should only be enabled if you need to # link with servers running 2.0. Defaults to yes. allowzerolimit="no" # exemptchanops: Allows users with with a status mode to be exempt # from various channel restrictions. Possible restrictions are: # - anticaps Channel mode +B - blocks messages with too many capital # letters (requires the anticaps module). # - auditorium-see Permission required to see the full user list of # a +u channel (requires the auditorium module). # - auditorium-vis Permission required to be visible in a +u channel # (requires the auditorium module). # - blockcaps Channel mode +B - blocks messages with too many capital # letters (requires the blockcaps module). # - blockcolor Channel mode +c - blocks messages with formatting codes # (requires the blockcolor module). # - censor Channel mode +G - censors messages based on the network # configuration (requires the censor module). # - filter Channel mode +g - blocks messages containing the given # glob mask (requires the chanfilter module). # - flood Channel mode +f - kicks (and bans) on text flood of a # specified rate (requires the messageflood module). # - nickflood Channel mode +F - blocks nick changes after a specified # rate (requires the nickflood module). # - noctcp Channel mode +C - blocks any CTCPs to the channel # (requires the noctcp module). # - nonick Channel mode +N - prevents users on the channel from # changing nicks (requires the nonicks module). # - nonotice Channel mode +T - blocks /NOTICEs to the channel # (requires the nonotice module). # - regmoderated Channel mode +M - blocks unregistered users from # speaking (requires the services account module). # - stripcolor Channel mode +S - strips formatting codes from # messages (requires the stripcolor module). # - topiclock Channel mode +t - limits changing the topic to (half)ops # You can also configure this on a per-channel basis with a channel mode. # See m_exemptchanops in modules.conf.example for more details. exemptchanops="censor:o filter:o nickflood:o nonick:v regmoderated:o" # invitebypassmodes: This allows /INVITE to bypass other channel modes. # (Such as +k, +j, +l, etc.) invitebypassmodes="yes" # nosnoticestack: This prevents snotices from 'stacking' and giving you # the message saying '(last message repeated X times)'. Defaults to no. nosnoticestack="no"> #-#-#-#-#-#-#-#-#-#-#-# PERFORMANCE CONFIGURATION #-#-#-#-#-#-#-#-#-#-# # # <performance # netbuffersize: Size of the buffer used to receive data from clients. # The ircd may only read this amount of text in 1 go at any time. netbuffersize="10240" # somaxconn: The maximum number of connections that may be waiting # in the accept queue. This is *NOT* the total maximum number of # connections per server. Some systems may only allow this to be up # to 5, while others (such as Linux and *BSD) default to 128. # Setting this above the limit imposed by your OS can have undesired # effects. somaxconn="128" # softlimit: This optional feature allows a defined softlimit for # connections. If defined, it sets a soft max connections value. softlimit="12800" # clonesonconnect: If this is set to false, we won't check for clones # on initial connection, but only after the DNS check is done. # This can be useful where your main class is more restrictive # than some other class a user can be assigned after DNS lookup is complete. # Turning this option off will make the server spend more time on users we may # potentially not want. Normally this should be neglible, though. # Default value is true clonesonconnect="true" # timeskipwarn: The time period that a server clock can jump by before # operators will be warned that the server is having performance issues. timeskipwarn="2s" # quietbursts: When syncing or splitting from a network, a server # can generate a lot of connect and quit messages to opers with # +C and +Q snomasks. Setting this to yes squelches those messages, # which makes it easier for opers, but degrades the functionality of # bots like BOPM during netsplits. quietbursts="yes"> #-#-#-#-#-#-#-#-#-#-#-# SECURITY CONFIGURATION #-#-#-#-#-#-#-#-#-#-#-# # # <security # allowcoreunload: If this value is set to yes, Opers will be able to # unload core modules (e.g. core_privmsg). allowcoreunload="no" # announceinvites: This option controls which members of the channel # receive an announcement when someone is INVITEd. Available values: # 'none' - don't send invite announcements # 'all' - send invite announcements to all members # 'ops' - send invite announcements to ops and higher ranked users # 'dynamic' - send invite announcements to halfops (if available) and # higher ranked users. This is the recommended setting. announceinvites="dynamic" # hideulines: If this value is set to yes, U-lined servers will # be hidden from non-opers in /LINKS and /MAP. hideulines="no" # flatlinks: If this value is set to yes, /MAP and /LINKS will # be flattened when shown to non-opers. flatlinks="no" # hideserver: When defined, the given text will be used in place # of the server name in public messages. As with <server:name> this # does not need to resolve but does need to be a valid hostname. # # NOTE: enabling this will cause users' idle times to only be shown # when a remote whois (/WHOIS <nick> <nick>) is used. #hideserver="*.example.com" # hidebans: If this value is set to yes, when a user is banned ([KGZ]-lined) # only opers will see the ban message when the user is removed # from the server. hidebans="no" # hidekills: If defined, replaces who executed 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). hidesplits="no" # maxtargets: Maximum number of targets per command. # (Commands like /NOTICE, /PRIVMSG, /KICK, etc) maxtargets="20" # customversion: A custom message to be displayed in the comments field # of the VERSION command response. This does not hide the InspIRCd version. customversion="" # runasuser: If this is set, InspIRCd will attempt to switch # to run as this user, which allows binding of ports under 1024. # You should NOT set this unless you are starting as root. # NOT SUPPORTED/NEEDED UNDER WINDOWS. #runasuser="" # runasgroup: If this is set, InspIRCd will attempt to switch # to run as this group, which allows binding of ports under 1024. # You should NOT set this unless you are starting as root. # NOT SUPPORTED/NEEDED UNDER WINDOWS. #runasgroup="" # restrictbannedusers: If this is set to yes, InspIRCd will not allow users # banned on a channel to change nickname or message channels they are # banned on. This can also be set to silent to restrict the user but not # notify them. restrictbannedusers="yes" # genericoper: Setting this value to yes makes all opers on this server # appear as 'is a server operator' in their WHOIS, regardless of their # oper type, however oper types are still used internally. This only # affects the display in WHOIS. genericoper="no" # userstats: /STATS commands that users can run (opers can run all). userstats="Pu"> #-#-#-#-#-#-#-#-#-#-#-#-# LIMITS CONFIGURATION #-#-#-#-#-#-#-#-#-#-#-# # # # This configuration tag defines the maximum sizes of various types # # on IRC, such as the maximum length of a channel name, and the # # maximum length of a channel. Note that with the exception of the # # identmax value all values given here are the exact values you would # # expect to see on IRC. This contrasts with the older InspIRCd # # releases where these values would be one character shorter than # # defined to account for a null terminator on the end of the text. # # # # These values should match network-wide otherwise issues will occur. # # # # The highest safe value you can set any of these options to is 500, # # but it is recommended that you keep them somewhat # # near their defaults (or lower). # <limits # maxnick: Maximum length of a nickname. maxnick="30" # maxchan: Maximum length of a channel name. maxchan="64" # maxmodes: Maximum number of mode changes per line. maxmodes="20" # maxident: Maximum length of a ident/username. maxident="10" # maxhost: Maximum length of a hostname. maxhost="64" # maxquit: Maximum length of a quit message. maxquit="255" # maxtopic: Maximum length of a channel topic. maxtopic="307" # maxkick: Maximum length of a kick message. maxkick="255" # maxreal: Maximum length of a real name. maxreal="128" # maxaway: Maximum length of an away message. maxaway="200"> #-#-#-#-#-#-#-#-#-#-#-#-# PATHS CONFIGURATION #-#-#-#-#-#-#-#-#-#-#-#-# # # # This configuration tag defines the location that InspIRCd stores # # various types of files such as configuration files, log files and # # modules. You will probably not need to change these from the values # # set when InspIRCd was built unless you are using a binary package # # where you do not have the ability to set build time configuration. # #<path configdir="conf" datadir="data" logdir="logs" moduledir="modules"> #-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-# # Logging # ------- # # Logging is covered with the <log> tag, which you may use to change # the behaviour of the logging of the IRCd. # # An example log tag would be: # <log method="file" type="OPER" level="default" target="opers.log"> # which would log all information on /OPER (failed and successful) to # a file called opers.log. # # There are many different types which may be used, and modules may # generate their own. A list of useful types: # - USERS - information relating to user connection and disconnection # - OPER - succesful and failed oper attempts # - KILL - kill related messages # - FILTER - messages related to filter matches (filter module) # - CONFIG - configuration related messages # - COMMAND - die and restart messages, and messages related to unknown user types # - SOCKET - socket engine informational/error messages # - MODULE - module related messages # - STARTUP - messages related to starting up the server # # You may also log *everything* by using a type of *, and subtract things out # of that by using -TYPE - for example "* -USERINPUT -USEROUTPUT". # # Useful levels are: # - default (general messages, including errors) # - sparse (misc error messages) # - debug (debug messages) # # Some types only produce output in the debug level, those are: # - BANCACHE - ban cache debug messages # - CHANNELS - information relating to joining/creating channels # - CULLLIST - debug messages related to issues with removing users # - RESOLVER - DNS related debug messages # - CONNECTCLASS - Connection class debug messages # - USERINPUT # - USEROUTPUT # # If your server is producing a high levels of log messages you can also set the # flush="[positive number]" attribute to specify how many log messages should be # buffered before flushing to disk. You should probably not specify this unless # you are having problems. # # The following log tag is highly default and uncustomised. It is recommended you # sort out your own log tags. This is just here so you get some output. <log method="file" type="* -USERINPUT -USEROUTPUT" level="default" target="ircd.log"> #-#-#-#-#-#-#-#-#-#-#-#-#- WHOWAS OPTIONS -#-#-#-#-#-#-#-#-#-#-#-#-# # # # This tag lets you define the behaviour of the /WHOWAS command of # # your server. # # # <whowas # groupsize: Maximum entries per nick shown when performing # a /WHOWAS <nick>. groupsize="10" # maxgroups: Maximum number of nickgroups that can be added to # the list so that /WHOWAS does not use a lot of resources on # large networks. maxgroups="100000" # maxkeep: Maximum time a nick is kept in the whowas list # before being pruned. Time may be specified in seconds, # or in the following format: 1y2w3d4h5m6s. Minimum is # 1 hour. maxkeep="3d"> #-#-#-#-#-#-#-#-#-#-#-#-#-#- BAN OPTIONS -#-#-#-#-#-#-#-#-#-#-#-#-#-# # # # The ban tags define nick masks, host masks and ip ranges which are # # banned from your server. All details in these tags are local to # # Your server. # # # <badip # ipmask: IP range to ban. Wildcards and CIDR can be used. ipmask="192.0.2.69" # reason: Reason to display when user is disconnected. reason="No porn here thanks."> <badnick # nick: Nick to disallow. Wildcards are supported. nick="ChanServ" # reason: Reason to display on /NICK. reason="Reserved for a network service"> <badhost # host: ident@hostname to ban. # Wildcards and CIDR (if you specify an IP) can be used. host="*@banneduser.example.net" # reason: Reason to display when user is disconnected reason="Evading Bans"> <badhost host="root@*" reason="Don't IRC as root!"> <badhost host="*@198.51.100.0/24" reason="This subnet is bad."> # exception: Hosts that are exempt from [KGZ]-lines. <exception # host: ident@hostname to exempt. # Wildcards and CIDR (if you specify an IP) can be used. host="*@serverop.example.com" # reason: Reason for exception. Only shown in /STATS e. reason="Oper's hostname"> #-#-#-#-#-#-#-#-#-#-#- INSANE BAN OPTIONS -#-#-#-#-#-#-#-#-#-#-#-#-#-# # # # This optional tag allows you to specify how wide a G-line, E-line, # # K-line, Z-line or Q-line can be before it is forbidden from being # # set. By setting hostmasks="yes", you can allow all G-, K-, E-lines, # # no matter how many users the ban would cover. This is not # # recommended! By setting ipmasks="yes", you can allow all Z-lines, # # no matter how many users these cover too. Needless to say we # # don't recommend you do this, or, set nickmasks="yes", which will # # allow any Q-line. # # # <insane # hostmasks: Allow bans with insane hostmasks. (over-reaching bans) hostmasks="no" # ipmasks: Allow bans with insane ipmasks. (over-reaching bans) ipmasks="no" # nickmasks: Allow bans with insane nickmasks. (over-reaching bans) nickmasks="no" # trigger: What percentage of users on the network to trigger # specifying an insane ban as. The default is 95.5%, which means # if you have a 1000 user network, a ban will not be allowed if it # will be banning 955 or more users. trigger="95.5"> #-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-# MODULES #-#-#-#-#-#-#-#-#-#-#-#-#-#-# # ____ _ _____ _ _ ____ _ _ _ # # | _ \ ___ __ _ __| | |_ _| |__ (_)___ | __ )(_) |_| | # # | |_) / _ \/ _` |/ _` | | | | '_ \| / __| | _ \| | __| | # # | _ < __/ (_| | (_| | | | | | | | \__ \ | |_) | | |_|_| # # |_| \_\___|\__,_|\__,_| |_| |_| |_|_|___/ |____/|_|\__(_) # # # # Well done, you've reached the end of the basic configuration, your # # ircd should now start if you want to try it out! (./inspircd start) # # # # We now suggest you read and edit modules.conf, as modules are what # # provide almost all the features of InspIRCd. :) # # # # The default does nothing -- we include it for simplicity for you. # #<include file="examples/modules.conf.example"> #-#-#-#-#-#-#-#-#-#-#-# SERVICES CONFIGURATION #-#-#-#-#-#-#-#-#-#-#-# # # # If you use services you will probably want to include one of the # # following files which set up aliases, nick reservations and filter # # exemptions for services pseudoclients: # # # Anope users should uncomment this: #<include file="examples/services/anope.conf.example"> # # Atheme users should uncomment this: #<include file="examples/services/atheme.conf.example"> # # Users of other services should uncomment this: #<include file="examples/services/generic.conf.example"> ######################################################################### # # # - InspIRCd Development Team - # # https://www.inspircd.org # # # ######################################################################### ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/docs/conf/links.conf.example���������������������������������������������������������0000664�0000000�0000000�00000013116�13554550454�0020643�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������#-#-#-#-#-#-#-#-#-#-#- SERVER LINK CONFIGURATION -#-#-#-#-#-#-#-#-#-# # # # Defines which servers can link to this one, and which servers this # # server may create outbound links to. # # # # ____ _ _____ _ _ ____ _ _ _ # # | _ \ ___ __ _ __| | |_ _| |__ (_)___ | __ )(_) |_| | # # | |_) / _ \/ _` |/ _` | | | | '_ \| / __| | _ \| | __| | # # | _ < __/ (_| | (_| | | | | | | | \__ \ | |_) | | |_|_| # # |_| \_\___|\__,_|\__,_| |_| |_| |_|_|___/ |____/|_|\__(_) # # # # If you want to link servers to InspIRCd you must load the # # spanningtree module! # # # # # <link # name: The name of the remote server. This must match # the <server:name> value of the remote server. name="hub.example.org" # ipaddr: The IP address of the remote server. # Can also be a hostname, but hostname must resolve. ipaddr="penguin.example.org" # port: The port to connect to the server on. # It must be bound as a server port on the other server. port="7000" # allowmask: Range of IP addresses to allow for this link. # Can be a CIDR (see example). allowmask="203.0.113.0/24 127.0.0.0/8 2001:db8::/32" # timeout: If defined, this option defines how long the server # will wait to consider the connect attempt failed and try the # failover (see above). timeout="5m" # ssl: If defined, this states the SSL profile that will be used when # making an outbound connection to the server. Options are the name of an # <sslprofile> tag that you have defined or one of "openssl", "gnutls", # "mbedtls" if you have not defined any. See the docs page for the SSL # module you are using for more details. # # You will need to load the ssl_openssl module for OpenSSL, ssl_gnutls # for GnuTLS and ssl_mbedtls for mbedTLS. The server port that you # connect to must be capable of accepting this type of connection. ssl="gnutls" # fingerprint: If defined, this option will force servers to be # authenticated using SSL certificate fingerprints. See # https://docs.inspircd.org/3/modules/spanningtree for more information. # This will require an SSL link for both inbound and outbound connections. #fingerprint="" # bind: Local IP address to bind to. bind="1.2.3.4" # statshidden: Defines if IP is shown to opers when # /STATS c is invoked. statshidden="no" # hidden: If this is set to yes, this server and its "child" # servers will not be shown when users do a /MAP or /LINKS. hidden="no" # passwords: The passwords we send and receive. # The remote server will have these passwords reversed. # Passwords that contain a space character or begin with # a colon (:) are invalid and may not be used. sendpass="outgoing!password" recvpass="incoming!password"> # A duplicate of the first link block without comments, # if you like copying & pasting. <link name="hub.example.org" ipaddr="penguin.example.org" port="7000" allowmask="203.0.113.0/24 127.0.0.0/8 2001:db8::/32" timeout="5m" ssl="gnutls" bind="1.2.3.4" statshidden="no" hidden="no" sendpass="outgoing!password" recvpass="incoming!password"> # Link block for services. Options are the same as for the first # link block (depending on what your services package supports). <link name="services.example.com" ipaddr="localhost" port="7000" allowmask="127.0.0.0/8" sendpass="penguins" recvpass="polarbears"> # Simple autoconnect block. This enables automatic connections to a server. # Recommended setup is to have leaves connect to the hub, and have no # automatic connections started by the hub. <autoconnect period="10m" server="hub.example.org"> # Failover autoconnect block. If you have multiple hubs, or want your network # to automatically link even if the hub is down, you can specify multiple # space separated servers to autoconnect; they will be tried in a round # robin fashion until one succeeds. Period defines the time for restarting # a single loop. <autoconnect period="2m" server="hub.us.example.org hub.eu.example.org leaf.eu.example.org"> #-#-#-#-#-#-#-#-#-#-#-#-# U-LINES CONFIGURATION #-#-#-#-#-#-#-#-#-#-#-#-# # This tag defines a U-lined server. A U-lined server has special # # permissions, and should be used with caution. Services servers are # # usually U-lined in this manner. # # # # The 'silent' value, if set to yes, indicates that this server should # # not generate quit and connect notices, which can cut down on noise # # to opers on the network. # # # <uline server="services.example.com" silent="yes"> # Once you have edited this file you can remove this line. This is just to # ensure that you don't hastily include the file without reading it. <die reason="Using links.conf.example without editing it is a security risk"> ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/docs/conf/modules.conf.example�������������������������������������������������������0000664�0000000�0000000�00000351030�13554550454�0021173�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������#-#-#-#-#-#-#-#-#-#-#-#-#- MODULE OPTIONS -#-#-#-#-#-#-#-#-#-#-#-#-# # # # These tags define which modules will be loaded on startup by your # # server. Add modules without any paths. When you make your ircd # # using the 'make' command, all compiled modules will be moved into # # the folder you specified when you ran ./configure. The module tag # # automatically looks for modules in this location. # # If you attempt to load a module outside of this location, either # # in the config, or via /LOADMODULE, you will receive an error. # # # # By default, ALL modules are commented out. You must uncomment them # # or add lines to your config to load modules. Please refer to # # https://docs.inspircd.org/3/modules for a list of modules and # # each modules link for any additional conf tags they require. # # # # ____ _ _____ _ _ ____ _ _ _ # # | _ \ ___ __ _ __| | |_ _| |__ (_)___ | __ )(_) |_| | # # | |_) / _ \/ _` |/ _` | | | | '_ \| / __| | _ \| | __| | # # | _ < __/ (_| | (_| | | | | | | | \__ \ | |_) | | |_|_| # # |_| \_\___|\__,_|\__,_| |_| |_| |_|_|___/ |____/|_|\__(_) # # # # To link servers to InspIRCd, you MUST load the spanningtree module. # # If you don't do this, server links will NOT work at all. # # This is by design, to allow for the implementation of other linking # # protocols in modules in the future. This module is at the bottom of # # this file. # # # #-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-# # MD5 module: Allows other modules to generate MD5 hashes, usually for # cryptographic uses and security. # # IMPORTANT: # Other modules such as cloaking and password_hash may rely on # this module being loaded to function. # #<module name="md5"> #-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-# # SHA256 module: Allows other modules to generate SHA256 hashes, # usually for cryptographic uses and security. # # IMPORTANT: # Other modules such as password_hash may rely on this module being # loaded to function. Certain modules such as spanningtree will # function without this module but when it is loaded their features will # be enhanced (for example the addition of HMAC authentication). # #<module name="sha256"> #-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-# # Abbreviation module: Provides the ability to abbreviate commands a-la # BBC BASIC keywords. #<module name="abbreviation"> #-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-# # Alias module: Allows you to define server-side command aliases. #<module name="alias"> # # Set the 'prefix' for in-channel aliases (fantasy commands) to the # specified character. If not set, the default is "!". # If 'allowbots' is disabled, +B clients will not be able to use # fantasy commands. If not set, the default is no. #<fantasy prefix="!" allowbots="no"> # #-#-#-#-#-#-#-#-#-#-#- ALIAS DEFINITIONS -#-#-#-#-#-#-#-#-#-#-#-#-#-# # # # If you have the alias module loaded, you may also define aliases as # # shown below. They are commonly used to provide shortcut commands to # # services, however they are not limited to just this use. # # An alias tag requires the following values to be defined in it: # # # # text - The text to detect as the actual command line. # # Can't contain spaces, but case insensitive. # # You may have multiple aliases with the same # # command name (text="" value), however the first # # found will be executed if its format value is # # matched, or it has no format value. Aliases are # # read from the top of the file to the bottom. # # # # usercommand - If this is true, the alias can be run simply as # # /ALIASNAME. Defaults to true. # # # # channelcommand - If this is true, the alias can be used as an # # in-channel alias or 'fantasy command', prefixed # # by the fantasy prefix character, !aliasname by # # default. Defaults to false. # # # # format - If this is defined, the parameters of the alias # # must match this glob pattern. For example if you # # want the first parameter to start with a # for # # the alias to be executed, set format="#*" in the # # alias definition. Note that the :'s which are # # part of IRC formatted lines will be preserved # # for matching of this text. This value is # # optional. # # # # replace - The text to replace 'text' with. Usually this # # will be "PRIVMSG ServiceName :$2-" or similar. # # You may use the variables $1 through $9 in the # # replace string, which refer to the first through # # ninth word in the original string typed by the # # user. You may also use $1- through $9- which # # refer to the first word onwards, through to the # # ninth word onwards, e.g. if the user types the # # command "foo bar baz qux quz" then $3- will hold # # "baz qux quz" and $2 will contain "bar". You may # # also use the special variables: $nick, $ident, # # $host and $vhost, and you may separate multiple # # commands with a newline (which can be written in # # the file literally, or encoded as &nl; or \n # # depending on the config format setting). # # # # requires - If you provide a value for 'requires' this means # # the given nickname MUST be online for the alias # # to successfully trigger. If they are not, then # # the user receives a 'no such nick' 401 numeric. # # # # stripcolor - If this is true, the text from the user will be # # stripped of color and format codes before # # matching against 'text'. # # # # uline - Setting this to true will ensure that the user # # given in 'requires' is also on a U-lined server, # # as well as actually being on the network. If the # # user is online, but not on a U-lined server, # # then an oper alert is sent out as this is # # possibly a sign of a user trying to impersonate # # a service. # # # # operonly - If true, this will make the alias oper only. # # If a non-oper attempts to use the alias, it will # # appear to not exist. # # # # # An example of using the format value to create an alias with two # different behaviours depending on the format of the parameters. # #<alias text="ID" format="#*" replace="SQUERY ChanServ :IDENTIFY $2 $3" # requires="ChanServ" uline="yes"> # #<alias text="ID" replace="SQUERY NickServ :IDENTIFY $2" # requires="NickServ" uline="yes"> # # This alias fixes a glitch in xchat 2.6.x and above and the way it # assumes IDENTIFY must be prefixed by a colon (:) character. It should # be placed ABOVE the default NICKSERV alias. # #<alias text="NICKSERV" format=":IDENTIFY *" replace="SQUERY NickServ :IDENTIFY $3-" # requires="NickServ" uline="yes"> # # You may also add aliases to trigger based on something said in a # channel, aka 'fantasy' commands, configured in the same manner as any # other alias, with usercommand="no" and channelcommand="yes" The # command must be preceded by the fantasy prefix when used. # #<alias text="CS" usercommand="no" channelcommand="yes" # replace="SQUERY ChanServ :$1 $chan $2-" requires="ChanServ" uline="yes"> # # This would be used as "!cs <command> <options>", with the channel # being automatically inserted after the command in the message to # ChanServ, assuming the fantasy prefix is "!". #-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-# # Allowinvite module: Gives channel mode +A to allow all users to use # /INVITE, and extban A to deny invite from specific masks. #<module name="allowinvite"> #-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-# # Alltime module: Shows time on all connected servers at once. # This module is oper-only and provides /ALLTIME. # To use, ALLTIME must be in one of your oper class blocks. #<module name="alltime"> #-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-# # Anticaps module: Adds channel mode +B which allows you to punish # users that send overly capitalised messages to channels. Unlike the # blockcaps module this module is more flexible as it has more options # for punishment and allows channels to configure their own punishment # policies. #<module name="anticaps"> # # You may also configure the characters which anticaps considers to be # lower case and upper case. Any characters not listed here are assumed # to be punctuation and will be ignored when counting: # <anticaps lowercase="abcdefghijklmnopqrstuvwxyz" # uppercase="ABCDEFGHIJKLMNOPQRSTUVWXYZ"> #-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-# # Auditorium module: Adds channel mode +u which makes everyone else # except you in the channel invisible, used for large meetings etc. #<module name="auditorium"> # # Auditorium settings: # #<auditorium opvisible="no" opcansee="no" opercansee="yes"> # # opvisible (auditorium-vis in exemptchanops): # Show channel ops to all users # opcansee (auditorium-see in exemptchanops): # Allow ops to see all joins/parts/kicks in the channel # opercansee: # Allow opers (channels/auspex) to see see all joins/parts/kicks in the channel # # Exemptchanops can be used to adjust the level at which users become visible or # the level at which they can see the full member list of the channel. #-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-# # Autoop module: Adds basic channel access controls via the +w listmode. # For example +w o:*!Attila@127.0.0.1 will op anyone matching that mask # on join. This can be combined with extbans, for example +w o:R:Brain # will op anyone identified to the account "Brain". # Another useful combination is with SSL client certificate # fingerprints: +w h:z:72db600734bb9546c1bdd02377bc21d2a9690d48 will # give halfop to the user(s) having the given certificate. #<module name="autoop"> #-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-# # Ban except module: Adds support for channel ban exceptions (+e). #<module name="banexception"> #-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-# # Ban redirection module: Allows bans which redirect to a specified # channel. e.g. +b nick!ident@host#channelbanneduserissentto #<module name="banredirect"> #-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-# # bcrypt module: Allows other modules to generate bcrypt hashes, # usually for cryptographic uses and security. #<module name="bcrypt"> # # rounds: Defines how many rounds the bcrypt function will run when # generating new hashes. #<bcrypt rounds="10"> #-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-# # Block amsg module: Attempt to block all usage of /amsg and /ame. #<module name="blockamsg"> # #-#-#-#-#-#-#-#-#-#-#- BLOCKAMSG CONFIGURATION -#-#-#-#-#-#-#-#-#-#-# # # # If you have the blockamsg module loaded, you can configure it with # # the <blockamsg> tag: # # # # delay - How much time between two messages to force them # # to be recognised as unrelated. # # action - Any of 'notice', 'noticeopers', 'silent', 'kill' # # or 'killopers'. Define how to take action when # # a user uses /amsg or /ame. # # #<blockamsg delay="3" action="killopers"> #-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-# # Block CAPS module: Adds channel mode +B, blocks all-CAPS messages. # # NOTE: This module is deprecated and will be removed in a future version # of InspIRCd. You should use the anticaps module shown above instead. #<module name="blockcaps"> # #-#-#-#-#-#-#-#-#-#-#- BLOCKCAPS CONFIGURATION -#-#-#-#-#-#-#-#-#-#-# # # # percent - The percentage of a message which must be upper # # case before it will be blocked. # # # # minlen - The minimum length a message must be before it # # will be blocked. # # # # lowercase - The characters which will be considered lower # # case. # # # # uppercase - The characters which will be considered upper # # case. # # #<blockcaps percent="50" # minlen="5" # lowercase="abcdefghijklmnopqrstuvwxyz" # uppercase="ABCDEFGHIJKLMNOPQRSTUVWXYZ"> #-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-# # Block color module: Blocking color-coded messages with chan mode +c. #<module name="blockcolor"> #-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-# # Botmode module: Adds the user mode +B. If set on a user, it will # show that the user is a bot in /WHOIS. #<module name="botmode"> #-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-# # CallerID module: Adds user mode +g which activates hybrid-style # callerid: block all private messages unless you /ACCEPT first. #<module name="callerid"> # #-#-#-#-#-#-#-#-#-#-#- CALLERID CONFIGURATION -#-#-#-#-#-#-#-#-#-#-#-# # maxaccepts - Maximum number of entries a user can add to their # # /ACCEPT list. Default is 30 entries. # # tracknick - Preserve /ACCEPT entries when a user changes nick? # # If no (the default), the user is removed from # # everyone's accept list if their nickname changes. # # cooldown - Amount of time that must pass since the last # # notification sent to a user before they can be # # sent another. Default is 1 minute. # #<callerid maxaccepts="30" # tracknick="no" # cooldown="1m"> #-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-# # CAP module: Provides the CAP negotiation mechanism required by the # sasl, namesx, uhnames, and ircv3 modules. # It is also recommended for STARTTLS support in the starttls module. #<module name="cap"> #-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-# # CBAN module: Lets you disallow channels from being used at runtime. # This module is oper-only and provides /CBAN. # To use, CBAN must be in one of your oper class blocks. #<module name="cban"> #-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-# # Censor module: Adds channel and user mode +G which block phrases that # are listed in the server bad words list. #<module name="censor"> # #-#-#-#-#-#-#-#-#-#-#- CENSOR CONFIGURATION -#-#-#-#-#-#-#-#-#-#-#-# # # # If you have the censor module loaded you should specify one or more # # phrases to replace/block in user messages. The config for this is # # formatted as follows: # # # # Replaces "eggplant" with "aubergine" within messages: # # <badword text="eggplant" replace="aubergine"> # # # # Blocks messages that contain "fluffy capybaras": # #<badword text="fluffy capybaras"> # #-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-# # CGI:IRC module: Enables forwarding the real IP address of a user from # a gateway to the IRC server. #<module name="cgiirc"> # #-#-#-#-#-#-#-#-#-#-#-# CGIIRC CONFIGURATION #-#-#-#-#-#-#-#-#-#-#-#-# # # If you use the cgiirc module then you must specify the gateways which # are authorised to forward IP/host information to your server. There # are currently two ways to do this: # # The webirc method is the recommended way to allow gateways to forward # IP/host information. When using this method the gateway sends a WEBIRC # message to the server on connection. For more details please read the # IRCv3 WebIRC specification at: https://ircv3.net/specs/extensions/webirc.html # # When using this method you must specify a wildcard mask or CIDR range # to allow gateway connections from and at least one of either a SSL # client certificate fingerprint for the gateway or a password to be # sent in the WEBIRC command. # # <cgihost type="webirc" # fingerprint="bd90547b59c1942b85f382bc059318f4c6ca54c5" # mask="192.0.2.0/24"> # <cgihost type="webirc" # password="$2a$10$WEUpX9GweJiEF1WxBDSkeODBstIBMlVPweQTG9cKM8/Vd58BeM5cW" # hash="bcrypt" # mask="*.webirc.gateway.example.com"> # # Alternatively if your gateway does not support sending the WEBIRC # message then you can configure InspIRCd to look for the client IP # address in the ident sent by the user. This is not recommended as it # only works with IPv4 connections. # # When using this method you must specify a wildcard mask or CIDR range to allow # gateway connections from. You can also optionally configure the static value # that replaces the IP in the ident to avoid leaking the real IP address of # gateway clients (defaults to "gateway" if not set). # # <cgihost type="ident" # mask="198.51.100.0/24" # newident="wibble"> # <cgihost type="ident" # mask="*.ident.gateway.example.com" # newident="wobble"> # # By default gateway connections are logged to the +w snomask. If you # do not want this to happen then you can uncomment this to disable it. # <cgiirc opernotice="no"> # IMPORTANT NOTE: # --------------- # # When you connect gateway clients, there are two connect classes which # apply to these clients. When the client initially connects, the connect # class which matches the gateway site's host is checked. Therefore you # must raise the maximum local/global clients for this IP as high as you # want to allow gateway clients. After the client has connected and is # determined to be a gateway client, the class which matches the client's # real IP is then checked. You may set this class to a lower value, so that # the real IP of the client can still be restricted to, for example, 3 # sessions maximum. #-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-# # Channel create module: Adds snomask +j, which will notify opers of # any new channels that are created. # This module is oper-only. #<module name="chancreate"> #-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-# # Channel filter module: Allows channel-op defined message filtering # using simple string matches (channel mode +g). #<module name="chanfilter"> # # If hidemask is set to yes, the user will not be shown the mask when # their message is blocked. # # If maxlen is set then it defines the maximum length of a filter entry. # # If notifyuser is set to no, the user will not be notified when # their message is blocked. #<chanfilter hidemask="yes" maxlen="50" notifyuser="yes"> #-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-# # Channel history module: Displays the last 'X' lines of chat to a user # joining a channel with +H 'X:T' set; 'T' is the maximum time to keep # lines in the history buffer. Designed so that the new user knows what # the current topic of conversation is when joining the channel. #<module name="chanhistory"> # # Set the maximum number of lines allowed to be stored per channel below. # This is the hard limit for 'X'. # If notice is set to yes, joining users will get a NOTICE before playback # telling them about the following lines being the pre-join history. # If bots is set to yes, it will also send to users marked with +B #<chanhistory maxlines="50" notice="yes" bots="yes"> #-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-# # Channel logging module: Used to send snotice output to channels, to # allow staff to centrally monitor and discuss network activity. # # The "channel" field is where you want the messages to go, "snomasks" # is what snomasks you want to be sent to that channel. Multiple tags # are allowed. #<module name="chanlog"> #<chanlog snomasks="AOcC" channel="#opers"> #-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-# # Channel names module: Allows disabling channels which have certain # characters in the channel name such as bold, colorcodes, etc. which # can be quite annoying and allow users to on occasion have a channel # that looks like the name of another channel on the network. #<module name="channames"> #<channames # denyrange: characters or range of characters to deny in channel # names. #denyrange="2,3" # allowrange: characters or range of characters to specifically allow # in channel names. #allowrange=""> #-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-# # Channelban: Implements extended ban j:, which stops anyone already # in a channel matching a ban like +b j:#channel from joining. # It is also possible to ban based on their status in that channel, # like so: +b j:@#channel, this example prevents the ops from joining. # Note that by default wildcard characters * and ? are allowed in # channel names. To disallow them, load the channames module and # add characters 42 and 63 to denyrange (see above). #<module name="channelban"> #-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-# # Check module: Adds the /CHECK command. # Check is useful for looking up information on channels, users, # IP addresses and hosts. # This module is oper-only. # To use, CHECK must be in one of your oper class blocks. #<module name="check"> #-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-# # CHGHOST module: Adds the /CHGHOST command. # This module is oper-only. # To use, CHGHOST must be in one of your oper class blocks. # NOTE: Services will not be able to set vhosts on users if this module # isn't loaded. If you're planning on running services, you probably # want to load this. #<module name="chghost"> # #-#-#-#-#-#-#-#-# /CHGHOST - /SETHOST CONFIGURATION #-#-#-#-#-#-#-#-# # Optional - If you want to use special chars for hostnames you can # # specify your own custom list of chars with the <hostname> tag: # # # # charmap - A list of chars accepted as valid by the /CHGHOST # # and /SETHOST commands. Also note that the list is # # case-sensitive. # #<hostname charmap="abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ.-_/0123456789"> #-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-# # CHGIDENT module: Adds the /CHGIDENT command. # This module is oper-only. # To use, CHGIDENT must be in one of your oper class blocks. #<module name="chgident"> #-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-# # CHGNAME module: Adds the /CHGNAME command. # This module is oper-only. # To use, CHGNAME must be in one of your oper class blocks. #<module name="chgname"> # #-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-# # Connection class ban module: Adds support for extban 'n' which # matches against the class name of the user's connection. # This module assumes that connection classes are named in a uniform # way on all servers of the network. Wildcards are accepted. #<module name="classban"> #-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-# # Clear chan module: Allows opers to masskick, masskill or # mass G/Z-line all users on a channel using /CLEARCHAN. #<module name="clearchan"> #-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-# # Cloaking module: Adds user mode +x and cloaking support. # Relies on the md5 module being loaded. # To cloak users when they connect, load the conn_umodes module and set # <connect:modes> to include the +x mode. The example <connect> tag # shows this. See the conn_umodes module for more information. #<module name="cloaking"> # #-#-#-#-#-#-#-#-#-#-#- CLOAKING CONFIGURATION -#-#-#-#-#-#-#-#-#-#-#-# # # # To use cloaking, you must define a cloak key, and optionally a # # cloak prefix as shown below. The cloak key must be shared across # # the network for consistent cloaking and must be at least thirty # # characters long. # # # # There are two methods of cloaking: # # # # half Cloak only the "unique" portion of a host; by # # default show the last 2 parts of the domain, # # /16 subnet of IPv4 or /48 subnet of the IPv6 # # address. # # To change the number of shown parts, modify the # # domainparts option. # # # # full Cloak the users completely, using three slices for # # common CIDR bans (IPv4: /16, /24; IPv6: /48, /64). # # # # The methods use a single key that can be any length of text. # # An optional prefix may be specified to mark cloaked hosts. # # # # IMPORTANT: Changing these details will break all of your existing # # bans. If you do not want this to happen you can define multiple # # cloak tags. The first will be used for cloaking and the rest will # # be used for checking if a user is banned in a channel. # #-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-# # #<cloak mode="half" # key="changeme" # domainparts="3" # prefix="net-" # ignorecase="no"> # #<cloak mode="full" # key="changeme" # prefix="net-" # ignorecase="no"> #-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-# # Clones module: Adds an oper command /CLONES for detecting cloned # users. Warning: This command may be resource intensive when it is # issued, use with care. # This module is oper-only. # To use, CLONES must be in one of your oper class blocks. #<module name="clones"> #-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-# # Common channels module: Adds user mode +c, which, when set, requires # that users must share a common channel with you to PRIVMSG or NOTICE # you. #<module name="commonchans"> #-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-# # Auto join on connect module: Allows you to force users to join one # or more channels automatically upon connecting to the server, or # join them in case they aren't on any channels after being online # for X seconds. #<module name="conn_join"> # #-#-#-#-#-#-#-#-#-#-#-#- CONNJOIN CONFIGURATION -#-#-#-#-#-#-#-#-#-#-# # # If you have the conn_join module loaded, you can configure it below # or set autojoin="#chat,#help" in <connect> blocks. # # Join users immediately after connection to #one #two and #three. #<autojoin channel="#one,#two,#three"> # Join users to #chat after 15 seconds if they aren't on any channels. #<autojoin channel="#chat" delay="15"> #-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-# # Set modes on connect module: When this module is loaded <connect> # blocks may have an optional modes="" value, which contains modes to # add or remove from users when they connect to the server. #<module name="conn_umodes"> #-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-# # Wait for PONG on connect module: Send a PING to all connecting users # and don't let them connect until they reply with a PONG. # This is useful to stop certain kinds of bots and proxies. #<module name="conn_waitpong"> # #-#-#-#-#-#-#-#-#-#-#- WAITPONG CONFIGURATION -#-#-#-#-#-#-#-#-#-#-# # # # If you have the conn_waitpong module loaded, configure it with the # # <waitpong> tag: # # # # sendsnotice - Whether to send a helpful notice to users on # # connect telling them how to connect, should # # their client not reply PONG automatically. # # # # killonbadreply - Whether to kill the user if they send the wrong # # PONG reply. # # # #<waitpong sendsnotice="yes" killonbadreply="yes"> #-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-# # Channel cycle module: Adds the /CYCLE command which is a server-side # /HOP that bypasses restrictive modes. #<module name="cycle"> #-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-# # Connectban: Provides IP connection throttling. Any IP range that # connects too many times (configurable) in an hour is Z-lined for a # (configurable) duration, and their count resets to 0. #<module name="connectban"> # # ipv4cidr and ipv6cidr allow you to turn the comparison from # individual IP addresses (32 and 128 bits) into CIDR masks, to allow # for throttling over whole ISPs/blocks of IPs, which may be needed to # prevent attacks. # # This allows for 10 connections in an hour with a 10 minute ban if # that is exceeded. #<connectban threshold="10" duration="10m" ipv4cidr="32" ipv6cidr="128" # A custom ban message may optionally be specified. # banmessage="Your IP range has been attempting to connect too many times in too short a duration. Wait a while, and you will be able to connect."> #-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-# # Connection throttle module. #<module name="connflood"> # #-#-#-#-#-#-#-#-#-#-#- CONNTHROTTLE CONFIGURATION -#-#-#-#-#-#-#-#-#-# # period, maxconns - Amount of connections per <period>. # # timeout - Time to wait after the throttle was activated # before deactivating it. Be aware that the time # is seconds + timeout. # # quitmsg - The message that users get if they attempt to # connect while the throttle is active. # # bootwait - Amount of time in seconds to wait before enforcing # the throttling when the server just booted. # #<connflood period="30" maxconns="3" timeout="30" # quitmsg="Throttled" bootwait="2m"> #-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-# # Custom prefixes: Allows for channel prefixes to be configured. #<module name="customprefix"> # # name The name of the mode, must be unique from other modes. # letter The letter used for this mode. Required. # prefix The prefix used for nicks with this mode. Not required. # rank A numeric rank for this prefix, defining what permissions it gives. # The rank of voice, halfop and op is 10000, 20000, and 30000, # respectively. # ranktoset The numeric rank required to set this mode. Defaults to rank. # ranktounset The numeric rank required to unset this mode. Defaults to ranktoset. # depriv Can you remove the mode from yourself? Defaults to yes. #<customprefix name="founder" letter="q" prefix="~" rank="50000" ranktoset="50000"> #<customprefix name="admin" letter="a" prefix="&amp;" rank="40000" ranktoset="50000"> #<customprefix name="halfop" letter="h" prefix="%" rank="20000" ranktoset="30000"> # # You can also override the configuration of prefix modes added by both the core # and other modules by adding a customprefix tag with change="yes" specified. # <customprefix name="op" change="yes" rank="30000" ranktoset="30000"> # <customprefix name="voice" change="yes" rank="10000" ranktoset="20000" depriv="no"> # # Do /RELOADMODULE customprefix after changing the settings of this module. #-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-# # Custom title module: Adds the /TITLE command which allows for trusted # users to gain a custom whois line and an optional vhost can be # specified. #<module name="customtitle"> # #-#-#-#-#-#-#-#-#-#- CUSTOM TITLE CONFIGURATION -#-#-#-#-#-#-#-#-#-# # name - The username used to identify. # password - The password used to identify. # hash - The hash for the specific user's password (optional). # password_hash and a hashing module must be loaded # for this to work. # host - Allowed hostmask (optional). # title - Title shown in whois. # vhost - Displayed host (optional). # #<title name="foo" password="bar" title="Official Chat Helper"> #<title name="bar" password="foo" host="ident@test.org" title="Official Chat Helper" vhost="helper.test.org"> #<title name="foo" password="$2a$10$UYZ4OcO8NNTCCGyCdY9SK.2GHiqGgxZfHFPOPmWuxEVWVQTtoDC7C" hash="bcrypt" title="Official Chat Helper"> #-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-# # DCCALLOW module: Adds the /DCCALLOW command. #<module name="dccallow"> # #-#-#-#-#-#-#-#-#-#-#- DCCALLOW CONFIGURATION -#-#-#-#-#-#-#-#-#-#-# # blockchat - Whether to block DCC CHAT as well as DCC SEND. # 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. # action - Action to take if a user attempts to send a file # that matches this pattern, can be 'block' or # 'allow'. # #<dccallow blockchat="yes" length="5m" action="block" maxentries="20"> #<banfile pattern="*.exe" action="block"> #<banfile pattern="*.txt" action="allow"> #-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-# # Deaf module: Adds support for user modes +d and +D: # d - deaf to channel messages and notices. # D - deaf to user messages and notices. # The +D user mode is not enabled by default to enable link compatibility # with 2.0 servers. #<module name="deaf"> # #-#-#-#-#-#-#-#-#-#-#-#- DEAF CONFIGURATION -#-#-#-#-#-#-#-#-#-#-#-# # bypasschars - Characters that bypass deaf to a regular user. # bypasscharsuline - Characters that bypass deaf to a U-lined user (services). # Both of these take a list of characters that must match # the starting character of a message. # If 'bypasscharsuline' is empty, then 'bypasschars' will # match for both regular and U-lined users. # enableprivdeaf - Whether to enable user mode +D (privdeaf). # privdeafuline - Whether U-lined users bypass user mode +D (privdeaf). # #<deaf bypasschars="" bypasscharsuline="!" enableprivdeaf="no" privdeafuline="yes"> #-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-# # Delay join module: Adds the channel mode +D which delays all JOIN # messages from users until they speak. If they quit or part before # speaking, their quit or part message will not be shown to the channel # which helps cut down noise on large channels in a more friendly way # than the auditorium mode. Only channel ops may set the +D mode. #<module name="delayjoin"> #-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-# # Delay message module: Adds the channel mode +d which disallows a user # from talking in the channel unless they've been joined for X seconds. # Settable using /MODE #chan +d 30 #<module name="delaymsg"> # Set allownotice to no to disallow NOTICEs too. Defaults to yes. #<delaymsg allownotice="no"> #-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-# # Deny channels module: Deny channels from being used by users. #<module name="denychans"> # #-#-#-#-#-#-#-#-#-#-#- DENYCHAN DEFINITIONS -#-#-#-#-#-#-#-#-#-#-#-# # # # If you have the denychans module loaded, you need to specify the # # channels to deny: # # # # name - The channel name to deny (glob masks are ok). # # allowopers - If operators are allowed to override the deny. # # reason - Reason given for the deny. # # redirect - Redirect the user to a different channel. # # # #<badchan name="#gods*" allowopers="yes" reason="Tortoises!"> # #<badchan name="#chan1" redirect="#chan2" reason="Chan1 is closed"> # # # # Redirects will not work if the target channel is set +L. # # # # Additionally, you may specify channels which are allowed, even if # # a badchan tag specifies it would be denied: # #<goodchan name="#funtimes"> # # Glob masks are accepted here also. # #-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-# # Disable module: Provides support for disabling commands and modes. # #<module name="disable"> # #-#-#-#-#-#-#-#-#-#-#-#- DISABLE CONFIGURATION -#-#-#-#-#-#-#-#-#-#-#-# # # # If you have the disable module loaded then you need to specify the # # commands and modes that you want disabled. Users who have not fully # # connected yet are exempt from this module so you can e.g. disable # # the NICK command but still allow users to connect to the server. # # # # commands - A space-delimited list of commands that can not be used # # by users. You can exempt server operators from this with # # the servers/use-disabled-commands privilege. # # # # chanmodes - One or more channel modes that can not be added/removed # # by users. You can exempt server operators from this # # with the servers/use-disabled-modes privilege. # # # # usermodes - One or more user modes that can not be added/removed by # # users. You can exempt server operators from this with # # the servers/use-disabled-modes privilege. # # # # fakenonexistent - Whether to pretend that a disabled command/mode # # does not exist when executed/changed by a user. # # Defaults to no. # # # # notifyopers - Whether to send a notice to snomask `a` when a user # # is prevented from using a disabled command/mode. # # Defaults to no. # # # #<disabled commands="KICK TOPIC" # # chanmodes="kp" # # usermodes="iw" # # fakenonexistent="yes" # # notifyopers="no"> # #-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-# # DNS blacklist module: Provides support for looking up IPs on one or # # more blacklists. # #<module name="dnsbl"> # # # For configuration options please see the docs page for dnsbl at # # https://docs.inspircd.org/3/modules/dnsbl # #-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-# # Exempt channel operators module: Provides support for allowing # # users of a specified channel status to be exempt from some channel # # restriction modes. Supported restrictions are: # # anticaps, auditorium-see, auditorium-vis, blockcaps, blockcolor, # # censor, filter, flood, nickflood, noctcp, nonick, nonotice, # # regmoderated, stripcolor, and topiclock. # # See <options:exemptchanops> in inspircd.conf.example for a more # # detailed list of the restriction modes that can be exempted. # # These are settable using: /MODE #chan +X <restriction>:<status> # #<module name="exemptchanops"> #-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-# # Filter module: Provides message filtering, similar to SPAMFILTER. # #<module name="filter"> # # # This module depends upon a regex provider such as regex_pcre or # # regex_glob to function. You must specify which of these you want # # the filter module to use via the tag below. # # # # Valid engines are: # # # # glob - Glob patterns, provided via regex_glob. # # pcre - PCRE regexps, provided via regex_pcre, needs libpcre. # # tre - TRE regexps, provided via regex_tre, requires libtre. # # posix - POSIX regexps, provided via regex_posix, not available # # on Windows, no dependencies on other operating systems. # # stdlib - stdlib regexps, provided via regex_stdlib, see comment # # at the <module> tag for info on availability. # # # # If notifyuser is set to no, the user will not be notified when # # their message is blocked. # # # # If warnonselfmsg is set to yes when a user sends a message to # # themself that matches a filter the filter will be ignored and a # # warning will be sent to opers instead. This stops spambots which # # send their spam message to themselves first to check if it is being # # filtered by the server. # #<filteropts engine="glob" notifyuser="yes" warnonselfmsg="no"> # # # Your choice of regex engine must match on all servers network-wide. # # # # To learn more about the configuration of this module, read # # examples/filter.conf.example, which covers the various types of # # filters and shows how to add exemptions. # # # #-#-#-#-#-#-#-#-#-#-#- FILTER CONFIGURATION -#-#-#-#-#-#-#-#-#-#-#-# # # # Optional - If you specify to use the filter module, then # # specify below the path to the filter.conf file, or define some # # <keyword> tags. # # # #<include file="examples/filter.conf.example"> #-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-# # Flash Policy Daemon module: Allows Flash IRC clients (e.g. LightIRC)# # to connect. If no file is specified, it'll serve a default policy # # allowing all IPs to connect to all plaintext IRC ports # #<bind address="" port="8430" type="flashpolicyd"> # #<flashpolicyd timeout="5" file=""> # #<module name="flashpolicyd"> # #-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-# # Real name ban: Implements two extended bans: # # 'a', which matches a n!u@h+realname mask like +b a:*!*@host+*real* # # 'r', which matches a realname mask like +b r:*realname?here* # #<module name="gecosban"> #-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-# # Geolocation ban module: Adds support for extban 'G' which matches # # against the ISO 3166-1 alpha-2 codes for the countries that users # # are connecting from. Users connecting from unknown origins such as # # internal networks can be matched against using the XX alpha-2 code. # # A full list of ISO 3166-1 alpha-2 codes can be found at # # https://en.wikipedia.org/wiki/ISO_3166-1_alpha-2 # #<module name="geoban"> #-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-# # Geolocation connect class module: Adds support for limiting connect # # classes to users from specific countries. With this module you can # # specify a space-delimited list of two character the ISO 3166-1 # # alpha-2 codes in the "country" field of a connect class. e.g. to # # deny connections from users in Russia or Turkey: # # # # <connect deny="*" country="TR RU"> # # # # Users connecting from unknown origins such as internal networks can # # be matched against using the XX alpha-2 code. A full list of ISO # # 3166-1 alpha-2 codes can be found at # # https://en.wikipedia.org/wiki/ISO_3166-1_alpha-2 # #<module name="geoclass"> #-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-# # MaxMindDB geolocation module: Provides geolocation information for # # other modules that need it using the libMaxMindDB library. # # # # This module is in extras. Re-run configure with: # # ./configure --enable-extras=m_geo_maxmind.cpp # and run make install, then uncomment this module to enable it. # # # # This module requires libMaxMindDB to be installed on your system. # # Use your package manager to find the appropriate packages or check # # the InspIRCd documentation page for this module. # #<module name="geo_maxmind"> # # # If you use the geo_maxmind module you MUST provide a database file # # to look up geolocation information in. You can either purchase this # # from MaxMind at https://www.maxmind.com/en/geoip2-country-database # # or use the free CC-BY-SA licensed GeoLite2 Country database which # # can be downloaded at https://dev.maxmind.com/geoip/geoip2/geolite2/ # #<maxmind file="GeoLite2-Country.mmdb"> #-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-# # Globops module: Provides the /GLOBOPS command and snomask +g. # This module is oper-only. # To use, GLOBOPS must be in one of your oper class blocks. #<module name="globops"> #-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-# # Global load module: Allows loading and unloading of modules network- # wide (USE WITH EXTREME CAUTION!) # This module is oper-only and provides /GLOADMODULE, /GUNLOADMODULE # and /GRELOADMODULE. # To use, GLOADMODULE, GUNLOADMODULE and GRELOADMODULE # must be in one of your oper class blocks. #<module name="globalload"> #-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-# # HAProxy module: Adds support for the HAProxy PROXY v2 protocol. To # use this module specify hook="haproxy" in the <bind> tag that HAProxy # has been configured to connect to. #<module name="haproxy"> #-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-# # HELPOP module: Provides the /HELPOP command #<module name="helpop"> # #-#-#-#-#-#-#-#-#-#-#-#- HELPOP CONFIGURATION -#-#-#-#-#-#-#-#-#-#-# # # # If you specify to use the helpop module, then specify below the # # path to the helpop.conf file. # # # #<include file="examples/helpop.conf.example"> #-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-# # Hide chans module: Allows users to hide their channels list from non- # opers by setting user mode +I on themselves. #<module name="hidechans"> # # This mode can optionally prevent opers from seeing channels on a +I # user, for more privacy if set to true. # This setting is not recommended for most mainstream networks. #<hidechans affectsopers="false"> #-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-# # Hide list module: Allows for hiding the list of listmodes from users # who do not have sufficient channel rank. #<module name="hidelist"> # # Each <hidelist> tag configures one listmode to hide. # mode: Name of the listmode to hide. # rank: Minimum rank required to view the list. If set to 0, all # members of the channel may view the list, but non-members may not. # The rank of the built-in op and voice mode is 30000 and 10000, # respectively; the rank of other prefix modes is configurable. # Defaults to 20000. # # Hiding the ban list is not recommended because it may break some # clients. # # Hide filter (+g) list: #<hidelist mode="filter" rank="30000"> # Only show invite exceptions (+I) to channel members: #<hidelist mode="invex" rank="0"> #-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-# # Hide mode module: Allows for hiding mode changes from users who do not # have sufficient channel privileges. #<module name="hidemode"> # # Hide bans (+b) from people who are not voiced: #<hidemode mode="ban" rank="10000"> #-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-# # Hide oper module: Allows opers to hide their oper status from non- # opers by setting user mode +H on themselves. # This module is oper-only. #<module name="hideoper"> #-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-# # Hostchange module: Allows a different style of cloaking. #<module name="hostchange"> # #-#-#-#-#-#-#-#-#-#-#- HOSTCHANGE CONFIGURATION -#-#-#-#-#-#-#-#-#-# # # # See https://docs.inspircd.org/3/modules/hostchange for help. # # # #<hostchange mask="*@42.theanswer.example.org" action="addaccount" suffix=".users.example.com"> #<hostchange mask="*root@*" action="addnick" prefix="example/users/"> #<hostchange mask="a@example.com" action="set" value="foo.bar.baz"> #<hostchange mask="*@localhost" ports="7000,7001,7005-7007" action="set" value="blahblah.foo"> # hostcycle: If loaded, when a user gets a host or ident set, it will # cycle them in all their channels. If not loaded it will simply change # their host/ident without cycling them. # This module is compatible with the ircv3_chghost module. Clients # supporting the chghost extension will get the chghost message instead # of seeing a host cycle. #<module name="hostcycle"> #-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-# # httpd module: Provides HTTP server support for InspIRCd. #<module name="httpd"> # #-#-#-#-#-#-#-#-#-#-#-#- HTTPD CONFIGURATION -#-#-#-#-#-#-#-#-#-#-# # # If you choose to use the httpd module, then you will need to add # a <bind> tag with type "httpd", and load at least one of the other # httpd_* modules to provide pages to display. # <bind address="127.0.0.1" port="8067" type="httpd"> # <bind address="127.0.0.1" port="8097" type="httpd" ssl="gnutls"> # # You can adjust the timeout for HTTP connections below. All HTTP # connections will be closed after (roughly) this time period. #<httpd timeout="20"> #-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-# # HTTP ACL module: Provides access control lists for httpd dependent # modules. Use this module to restrict pages by IP address and by # password. #<module name="httpd_acl"> # #-#-#-#-#-#-#-#-#-#-#-#- HTTPD ACL CONFIGURATION -#-#-#-#-#-#-#-#-#-#-# # # Restrict access to the httpd_stats module to all but the local # network and when the correct password is specified: # <httpdacl path="/stats*" types="password,whitelist" # username="secrets" password="mypasshere" whitelist="127.0.0.*,10.*"> # # Deny all connections to all but the main index page: # <httpdacl path="/*" types="blacklist" blacklist="*"> #-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-# # HTTP config module: Allows the server configuration to be viewed over # HTTP via the /config path. Requires the httpd module to be loaded for # it to function. # # IMPORTANT: This module exposes extremely sensitive information about # your server and users so you *MUST* protect it using a local-only # <bind> tag and/or the httpd_acl module. See above for details. #<module name="httpd_config"> #-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-# # HTTP stats module: Provides server statistics over HTTP via the /stats # path. Requires the httpd module to be loaded for it to function. # # IMPORTANT: This module exposes extremely sensitive information about # your server and users so you *MUST* protect it using a local-only # <bind> tag and/or the httpd_acl module. See above for details. #<module name="httpd_stats"> #-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-# # Ident: Provides RFC 1413 ident lookup support. # When this module is loaded <connect:allow> tags may have an optional # useident="yes|no" boolean value, determining whether or not to lookup # ident on users matching that connect tag. #<module name="ident"> # #-#-#-#-#-#-#-#-#-#-#-#- IDENT CONFIGURATION -#-#-#-#-#-#-#-#-#-#-# # # # Optional - If you are using the ident module, then you can specify # # the timeout for ident lookups here. If not defined, it will default # # to 5 seconds. This is a non-blocking timeout which holds the user # # in a 'connecting' state until the lookup is complete. # # prefixunqueried: If on, the idents of users being in a connect class# # with ident lookups disabled (i.e. <connect useident="off">) will be # # prefixed with a "~". If off, the ident of those users will not be # # prefixed. Default is off. # # #<ident timeout="5" prefixunqueried="no"> #-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-# # Invite exception module: Adds support for channel invite exceptions # (+I). #<module name="inviteexception"> # bypasskey: If this is enabled, exceptions will bypass +k as well as +i #<inviteexception bypasskey="yes"> #-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-# # IRCv3 module: Provides the following IRCv3 extensions: # extended-join, away-notify and account-notify. These are optional # enhancements to the client-to-server protocol. An extension is only # active for a client when the client specifically requests it, so this # module needs the cap module to work. # # Further information on these extensions can be found at the IRCv3 # working group website: # https://ircv3.net/irc/ # #<module name="ircv3"> # The following block can be used to control which extensions are # enabled. Note that extended-join can be incompatible with delayjoin # and host cycling. #<ircv3 accountnotify="on" awaynotify="on" extendedjoin="on"> #-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-# # IRCv3 account-tag module. Adds the 'account' tag which contains the # services account name of the message sender. #<module name="ircv3_accounttag"> #-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-# # IRCv3 batch module: Provides the batch IRCv3 extension which allows # the server to inform a client that a group of messages are related to # each other. #<module name="ircv3_batch"> #-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-# # IRCv3 cap-notify module: Provides the cap-notify IRCv3 extension. # Required for IRCv3 conformance. #<module name="ircv3_capnotify"> #-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-# # IRCv3 chghost module: Provides the chghost IRCv3 extension which # allows capable clients to learn when the host/ident of another user # changes without cycling the user. This module is compatible with the # hostcycle module. If both are loaded, clients supporting the chghost # extension will get the chghost message and won't see host cycling. #<module name="ircv3_chghost"> #-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-# # IRCv3 client-to-client tags module: Provides the message-tags IRCv3 # extension which allows clients to add extra data to their messages. # This is used to support new IRCv3 features such as replies and ids. #<module name="ircv3_ctctags"> #-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-# # IRCv3 echo-message module: Provides the echo-message IRCv3 # extension which allows capable clients to get an acknowledgement when # their messages are delivered and learn what modifications, if any, # were applied to them. #<module name="ircv3_echomessage"> #-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-# # IRCv3 invite-notify module: Provides the invite-notify IRCv3 # extension which notifies supporting clients when a user invites # another user into a channel. This respects <options:announceinvites>. #<module name="ircv3_invitenotify"> #-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-# # IRCv3 message id module: Provides the msgid IRCv3 extension which # adds a unique identifier to each message when the message-tags cap # has been requested. This enables support for modern features such as # reactions and replies. #<module name="ircv3_msgid"> #-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-# # IRCv3 server-time module. Adds the 'time' tag which adds a timestamp # to all messages received from the server. #<module name="ircv3_servertime"> #-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-# # IRCv3 Strict Transport Security module: Provides the sts IRCv3 # extension which allows clients connecting insecurely to upgrade their # connections to TLS. #<module name="ircv3_sts"> # # If using the ircv3_sts module you MUST define a STS policy to send # to clients using the <sts> tag. This tag takes the following # attributes: # # host - A glob match for the SNI hostname to apply this policy to. # duration - The amount of time that the policy lasts for. Defaults to # approximately two months by default. # port - The port on which TLS connections to the server are being # accepted. You MUST have a CA-verified certificate on this # port. Self signed certificates are not acceptable. # preload - Whether client developers can include your certificate in # preload lists. # # <sts host="*.example.com" duration="60d" port="6697" preload="yes"> #-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-# # Join flood module: Adds support for join flood protection +j X:Y. # Closes the channel for N seconds if X users join in Y seconds. #<module name="joinflood"> # # The number of seconds to close the channel for: #<joinflood duration="1m"> #-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-# # Anti auto rejoin: Adds support for prevention of auto-rejoin (+J). #<module name="kicknorejoin"> #-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-# # Knock module: Adds the /KNOCK command and channel mode +K. #<module name="knock"> # # This setting specifies what to do when someone successfully /KNOCKs. # If set to "notice", then a NOTICE will be sent to the channel. # This is the default and the compatible setting, as it requires no # special support from the clients. # If set to "numeric" then a 710 numeric will be sent to the channel. # This allows easier scripting but not all clients support it. # If set to "both" then (surprise!) both will be sent. #<knock notify="notice"> #-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-# # LDAP module: Allows other SQL modules to access a LDAP database # through a unified API. # This modules is in extras. Re-run configure with: # ./configure --enable-extras=m_ldap.cpp # and run make install, then uncomment this module to enable it. # #<module name="ldap"> #<database module="ldap" id="ldapdb" server="ldap://localhost" binddn="cn=Manager,dc=inspircd,dc=org" bindauth="mysecretpass" searchscope="subtree"> # The server parameter indicates the LDAP server to connect to. The # # ldap:// style scheme before the hostname proper is MANDATORY. # # # # The binddn and bindauth indicate the DN to bind to for searching, # # and the password for the distinguished name. Some LDAP servers will # # allow anonymous searching in which case these two values do not # # need defining, otherwise they should be set similar to the examples # # above. # # # # The searchscope value indicates the subtree to search under. On our # # test system this is 'subtree'. Your mileage may vary. # #-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-# # LDAP authentication module: Adds the ability to authenticate users # # via LDAP. # #<module name="ldapauth"> # # # Configuration: # # # # <ldapauth dbid="ldapdb" # # baserdn="ou=People,dc=brainbox,dc=cc" # # attribute="uid" # # allowpattern="Guest* Bot*" # # killreason="Access denied" # # verbose="yes" # # host="$uid.$ou.inspircd.org" # # useusername="no"> # # # # <ldapwhitelist cidr="10.42.0.0/16"> # # # # <ldaprequire attribute="attr" value="val"> # # # # The baserdn indicates the base DN to search in for users. Usually # # this is 'ou=People,dc=yourdomain,dc=yourtld'. # # # # The attribute value indicates the attribute which is used to locate # # a user account by name. On POSIX systems this is usually 'uid'. # # # # The allowpattern value allows you to specify a space separated list # # of wildcard masks which will always be allowed to connect # # regardless of if they have an account, for example guest and bot # # users. # # # # 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. # # # # Killreason indicates the QUIT reason to give to users if they fail # # to authenticate. # # # # Setting the verbose value causes an oper notice to be sent out for # # every failed authentication to the server, with an error string. # # # # ldapwhitelist indicates that clients connecting from an IP in the # # provided CIDR do not need to authenticate against LDAP. It can be # # repeated to whitelist multiple CIDRs. # # # # ldaprequire allows further filtering on the LDAP user, by requiring # # certain LDAP attibutes to have a given value. It can be repeated, # # in which case the list will act as an OR list, that is, the # # authentication will succeed if any of the requirements in the list # # is satisfied. # # # # host allows you to change the displayed host of users connecting # # from ldap. The string supplied takes formatters which are replaced # # from the DN. For instance, if your DN looks like: # # uid=w00t,ou=people,dc=inspircd,dc=org, then the formatters uid, ou # # and dc will be available to you. If a key is given multiple times # # in the DN, the last appearance will take precedence. # #-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-# # LDAP oper configuration module: Adds the ability to authenticate # # opers via LDAP. # #<module name="ldapoper"> # # # Configuration: # # # # <ldapoper dbid="ldapdb" # baserdn="ou=People,dc=brainbox,dc=cc" # attribute="uid"> # # # Available configuration items are identical to the same items in # # ldapauth above (except for the verbose setting, that is only # # supported in ldapauth). # # Please always specify a password in your <oper> tags even if the # # opers are to be authenticated via LDAP, so in case this module is # # not loaded the oper accounts are still protected by a password. # #-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-# # Lock server module: Adds /LOCKSERV and /UNLOCKSERV commands that # # are used to temporarily close/open the server for new connections. # # These commands require that the /LOCKSERV and /UNLOCKSERV commands # # are specified in a <class> tag that the oper is part of. This is so # # you can control who has access to this possible dangerous command. # # If your server is locked and you get disconnected, do a REHASH from # # shell to open up again. # # This module is oper-only. #<module name="lockserv"> #-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-# # Map hiding module: replaces /MAP and /LINKS output to users with a # # message to see a website, set by maphide="https://test.org/map" in # # the <security> tag, instead. # #<module name="maphide"> #-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-# # Message flood module: Adds message/notice flood protection via # channel mode +f. #<module name="messageflood"> # # The weight to give each message type. TAGMSGs are considered to be # 1/5 of a NOTICE or PRIVMSG to avoid users being accidentally flooded # out of a channel by automatic client features such as typing # notifications. #<messageflood notice="1.0" privmsg="1.0" tagmsg="0.2"> #-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-# # MLOCK module: Adds support for server-side enforcement of services # side MLOCKs. Basically, this module suppresses any mode change that # would likely be immediately bounced by services. #<module name="mlock"> #-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-# # Modenotice module: Adds the /MODENOTICE command that allows opers to # send notices to all users having the given user mode(s) set. #<module name="modenotice"> #-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-# # Monitor module: Adds support for MONITOR which is used by clients to # maintain notify lists. #<module name="monitor"> # # Set the maximum number of entries on a user's monitor list below. #<monitor maxentries="30"> #-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-# # MySQL module: Allows other SQL modules to access MySQL databases # through a unified API. # This module is in extras. Re-run configure with: # ./configure --enable-extras=m_mysql.cpp # and run make install, then uncomment this module to enable it. #<module name="mysql"> # #-#-#-#-#-#-#-#-#-#-#-#- SQL CONFIGURATION -#-#-#-#-#-#-#-#-#-#-#-#-# # # # mysql is more complex than described here, see the docs for more # # info: https://docs.inspircd.org/3/modules/mysql # # #<database module="mysql" name="mydb" user="myuser" pass="mypass" host="localhost" id="my_database2"> #-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-# # Named modes module: Allows for the display and set/unset of channel # modes via long-form mode names via +Z and the /PROP command. # For example, to set a ban, do /MODE #channel +Z ban=foo!bar@baz or # /PROP #channel ban=foo!bar@baz #<module name="namedmodes"> #-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-# # NAMESX module: Provides support for the NAMESX extension which allows # clients to see all the prefixes set on a user without getting confused. # This is supported by mIRC, x-chat, klient, and maybe more. #<module name="namesx"> #-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-# # National characters module: # 1) Allows using national characters in nicknames. # 2) Allows using custom (national) casemapping over the network. #<module name="nationalchars"> # # file - Location of the file which contains casemapping rules. If this # is a relative path then it is relative to "<PWD>/../locales" # on UNIX and "<PWD>/locales" on Windows. # casemapping - The name of the casemapping sent to clients in the 005 # numeric. If this is not set then it defaults to the name # of the casemapping file unless the file name contains a # space in which case you will have to specify it manually. #<nationalchars file="bynets/russian-w1251-charlink" casemapping="ru_RU.cp1251-charlink"> #-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-# # Nickchange flood protection module: Provides channel mode +F X:Y # which allows up to X nick changes in Y seconds. #<module name="nickflood"> # # The number of seconds to prevent nick changes for: #<nickflood duration="1m"> #-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-# # Nicklock module: Let opers change a user's nick and then stop that # user from changing their nick again until unlocked. # This module is oper-only. # To use, NICKLOCK and NICKUNLOCK must be in one of your oper class blocks. #<module name="nicklock"> #-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-# # No CTCP module: Adds the channel mode +C and user mode +T to block # CTCPs and extban 'C' to block CTCPs sent by specific users. #<module name="noctcp"> # # The +T user mode is not enabled by default to enable link compatibility # with 2.0 servers. You can enable it by uncommenting this: #<noctcp enableumode="yes"> #-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-# # No kicks module: Adds the +Q channel mode and the Q: extban to deny # certain users from kicking. #<module name="nokicks"> #-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-# # No nicks module: Adds the +N channel mode, as well as the 'N' extban. # +N stops all users from changing their nick, the N extban stops # anyone from matching a +b N:nick!user@host mask from changing their # nick. #<module name="nonicks"> #-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-# # No part message module: Adds extban 'p' to block part messages from # # matching users. # #<module name="nopartmsg"> #-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-# # No notice module: Adds the channel mode +T and the extban 'T' to # block specific users from noticing the channel. #<module name="nonotice"> #-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-# # Network business join module: # Allows an oper to join a channel using /OJOIN, giving them +Y on the # channel which makes them immune to kicks. #<module name="ojoin"> # # Specify the prefix that +Y will grant here. # Leave 'prefix' empty if you do not wish +Y to grant a prefix. # If 'notice' is set to on, upon /OJOIN, the server will notice the # channel saying that the oper is joining on network business. # If 'op' is set to on, it will give them +o along with +Y. #<ojoin prefix="!" notice="yes" op="yes"> #-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-# # Oper channels mode: Adds the +O channel mode and extban O:<mask> # to ban, except, etc. specific oper types. For example # /MODE #channel +iI O:* is equivalent to channel mode +O, but you # may also set +iI O:AdminTypeOnly to only allow admins. # Modes +I and +e work in a similar fashion. #<module name="operchans"> #-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-# # Oper join module: Auto-joins opers to a channel upon oper-up. # This module is oper-only. For the user equivalent, see the conn_join # module. #<module name="operjoin"> # #-#-#-#-#-#-#-#-#-#-# OPERJOIN CONFIGURATION -#-#-#-#-#-#-#-#-#-#-# # # # If you are using the operjoin module, specify options here: # # # # channel - The channel name to join, can also be a comma # # separated list e.g. "#channel1,#channel2". # # # # override - If on, lets the oper join walking thru any modes # # that might be set, even bans. # # # #<operjoin channel="#channel" override="no"> # # Alternatively you can use the autojoin="channellist" in a <type> # # tag to set specific autojoins for a type of oper, for example: # # #<type name="Helper" autojoin="#help" classes="..."> #-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-# # Oper log module: Logs all oper commands to the server log (with log # type "m_operlog" at default loglevel), and optionally to the 'r' # snomask. # This module is oper-only. #<module name="operlog"> # # If the following option is on then all oper commands will be sent to # the snomask 'r'. The default is off. #<operlog tosnomask="off"> #-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-# # Oper prefixing module: Adds a channel prefix mode +y which is given # to all server operators automatically on all channels they are in. # This prefix mode is more powerful than channel op and other regular # prefix modes. # # Load this module if you want all your server operators to have # channel operator powers. #<module name="operprefix"> # # You may additionally customise the prefix character. #<operprefix prefix="!"> #-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-# # Oper MOTD module: Provides support for a separate message of the day # on oper-up. # This module is oper-only. #<module name="opermotd"> # #-#-#-#-#-#-#-#-#-#-# OPERMOTD CONFIGURATION -#-#-#-#-#-#-#-#-#-#-# # # # If you are using the opermotd module, specify the motd file here. # # # # onoper - If on, the message is sent on /OPER, otherwise it's # # only sent when /OPERMOTD is used. # # # #<opermotd file="examples/opermotd.txt.example" onoper="yes"> #-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-# # Override module: Adds support for oper override. # This module is oper-only. #<module name="override"> # #-#-#-#-#-#-#-#-#-#-# OVERRIDE CONFIGURATION -#-#-#-#-#-#-#-#-#-#-# # # # Much of override's configuration relates to your oper blocks. # # For more information on how to allow opers to override, see: # # https://docs.inspircd.org/3/modules/override # # # # noisy - If enabled, all oper overrides will be announced # # via channel notice. # # # # requirekey - If enabled, overriding on join requires a channel # # key of "override" to be specified. # # # # enableumode - If enabled, user mode +O is required for override. # # # #<override noisy="yes" requirekey="no" enableumode="true"> #-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-# # Oper levels module: Gives each oper a level and prevents actions # being taken by lower level opers against higher level opers. # Specify the level as the 'level' parameter of the <type> tag. # This module is oper-only. #<module name="operlevels"> #-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-# # Oper modes module: Allows you to specify modes to add/remove on oper. # Specify the modes as the 'modes' parameter of the <type> tag # and/or as the 'modes' parameter of the <oper> tag. # This module is oper-only. For the user equivalent, see the # conn_umodes module. #<module name="opermodes"> #-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-# # Password forwarding module: Forwards a password users can send on # connect to the specified client below. The client is usually NickServ # and this module is usually used to authenticate users with NickServ # using their connect password. #<module name="passforward"> <passforward # nick: nick to forward connect passwords to. nick="NickServ" # forwardmsg: Message to send to users using a connect password. # $nick will be the users' nick, $nickrequired will be the nick # of where the password is going (the nick above). # You can also use $user for the user ident string. forwardmsg="NOTICE $nick :*** Forwarding PASS to $nickrequired" # cmd: Command for the user to run when it receives a connect # password. cmd="SQUERY $nickrequired :IDENTIFY $pass"> #-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-# # Password hash module: Allows hashed passwords to be used. # To be useful, a hashing module like bcrypt also needs to be loaded. #<module name="password_hash"> # #-#-#-#-#-#-#-#-#-# PASSWORD HASH CONFIGURATION #-#-#-#-#-#-#-#-#-#-#-# # # To use this module, you must define a hash type for each oper's # password you want to hash. For example: # # <oper name="Brain" # host="ident@dialup15.isp.test.com" # hash="bcrypt" # password="$2a$10$Mss9AtHHslZTLBrXqM0FB.JBwD.UTSu8A48SfrY9exrpxbsRiRTbO" # type="NetAdmin"> # # If you are using a hash algorithm which does not perform salting you can use # HMAC to salt your passwords in order to prevent them from being looked up in # a rainbow table. # # hash="hmac-sha256" password="lkS1Nbtp$CyLd/WPQXizsbxFUTqFRoMvaC+zhOULEeZaQkUJj+Gg" # # Generate hashes using the /MKPASSWD command on the server. # Don't run it on a server you don't trust with your password. #-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-# # PBKDF2 module: Allows other modules to generate PBKDF2 hashes, # usually for cryptographic uses and security. # This module relies on other hash providers (e.g. SHA256). #<module name="pbkdf2"> # # iterations: Iterations the hashing function runs when generating new # hashes. # length: Length in bytes of the derived key. #<pbkdf2 iterations="12288" length="32"> # You can override these values with specific values # for specific providers if you want to. Example given for SHA256. #<pbkdf2prov hash="sha256" iterations="24576"> #-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-# # Permanent channels module: Channels with the permanent channel mode # will remain open even after everyone else has left the channel, and # therefore keep things like modes, ban lists and topic. Permanent # channels -may- need support from your Services package to function # properly with them. This adds channel mode +P. # This module is oper-only. #<module name="permchannels"> # # If you like, this module can write a config file of permanent channels # whenever +P is set, unset, or the topic/modes on a +P channel is changed. # If you want to do this, set the filename below, and uncomment the include. # # If 'listmodes' is true then all list modes (+b, +I, +e, +g...) will be # saved. Defaults to false. # # 'saveperiod' determines how often to check if the database needs to be # saved to disk. Defaults to every five seconds. #<permchanneldb filename="permchannels.conf" # listmodes="true" # saveperiod="5s"> #<include file="permchannels.conf"> # # You may also create channels on startup by using the <permchannels> block. #<permchannels channel="#opers" modes="isP" topic="Opers only."> #-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-# # PostgreSQL module: Allows other SQL modules to access PgSQL databases # through a unified API. # This module is in extras. Re-run configure with: # ./configure --enable-extras=m_pgsql.cpp # and run make install, then uncomment this module to enable it. #<module name="pgsql"> # #-#-#-#-#-#-#-#-#-#-#-#- SQL CONFIGURATION -#-#-#-#-#-#-#-#-#-#-#-#-# # # # pgsql is more complex than described here, see the docs for # # more: https://docs.inspircd.org/3/modules/pgsql # # #<database module="pgsql" name="mydb" user="myuser" pass="mypass" host="localhost" id="my_database" ssl="no"> #-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-# # Muteban: Implements extended ban 'm', which stops anyone matching # a mask like +b m:nick!user@host from speaking on channel. #<module name="muteban"> # # If notifyuser is set to no, the user will not be notified when # their message is blocked. #<muteban notifyuser="yes"> #-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-# # Random quote module: Provides a random quote on connect. # NOTE: Some of these may mimic fatal errors and confuse users and # opers alike - BEWARE! #<module name="randquote"> # #-#-#-#-#-#-#-#-#-#- RANDOMQUOTES CONFIGURATION -#-#-#-#-#-#-#-#-#-#-# # # # Optional - If you specify to use the randquote module, then specify # # below the path to the quotes file. # # # #<randquote file="quotes.txt"> #-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-# # Redirect module: Adds channel mode +L which redirects users to # # another channel when the channel has reached its user limit and # # user mode +L which stops redirection. # #<module name="redirect"> #-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-# # Regular expression provider for glob or wildcard (?/*) matching. # You must have at least 1 provider loaded to use the filter or R-line # modules. This module has no additional requirements, as it uses the # matching already present in InspIRCd core. #<module name="regex_glob"> #-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-# # Regular expression provider for PCRE (Perl-Compatible Regular # Expressions). You need libpcre installed to compile and load this # module. You must have at least 1 provider loaded to use the filter or # R-line modules. #<module name="regex_pcre"> #-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-# # Regular Expression Provider for RE2 Regular Expressions. # You need libre2 installed and in your include/library paths in order # to compile and load this module. #<module name="regex_re2"> #-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-# # Regular expression provider for POSIX regular expressions. # You shouldn't need any additional libraries on a POSIX-compatible # system (i.e.: any Linux, BSD, but not Windows). You must have at # least 1 provider loaded to use the filter or R-line modules. # On POSIX-compliant systems, regex syntax can be found by using the # command: 'man 7 regex'. #<module name="regex_posix"> #-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-# # Regular expression provider for C++11 std::regex regular expressions. # This module works on any fully compliant implementation of the C++11 # std::regex container. Examples for such are Visual C++ 2010 and newer # but not libstdc++ (which GCC uses). # You should verify that std::regex is supported by your setup before # using this module, as it may compile normally but won't do anything # on some implementations. #<module name="regex_stdlib"> # # Specify the regular expression engine to use here. Valid settings are # bre, ere, awk, grep, egrep, ecmascript (default if not specified). #<stdregex type="ecmascript"> #-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-# # Regular expression provider for TRE regular expressions. # This is the same regular expression engine used by UnrealIRCd, so # if you are most familiar with the syntax of /SPAMFILTER from there, # this is the provider you want. You need libtre installed in order # to compile and load this module. #<module name="regex_tre"> #-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-# # Remove module: Adds the /REMOVE command which is a peaceful # alternative to /KICK. It also provides the /FPART command which works # in the same way as /REMOVE. #<module name="remove"> # # supportnokicks: If true, /REMOVE is not allowed on channels where the # nokicks (+Q) mode is set. Defaults to false. # protectedrank: Members having this rank or above may not be /REMOVE'd # by anyone. Set to 0 to disable this feature. Defaults to 50000. #<remove supportnokicks="true" protectedrank="50000"> #-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-# # Repeat module: Allows to block, kick or ban upon similar messages # being uttered several times. Provides channel mode +E. # # Syntax: [~|*]<lines>:<sec>[:<difference>][:<backlog>] # ~ is to block, * is to ban, default is kick. # lines - In mode 1, the amount of lines that has to match consecutively. # In mode 2, the size of the backlog to keep for matching. # seconds - How old the message has to be before it's invalidated. # difference - Edit distance, in percent, between two strings to trigger on. # backlog - When set, the function goes into mode 2. In this mode the # function will trigger if this many of the last <lines> matches. # # As this module can be rather CPU-intensive, it comes with some options. # maxbacklog - Maximum size that can be specified for backlog. 0 disables # multiline matching. # maxdistance - Max percentage of difference between two lines we'll allow # to match. Set to 0 to disable edit-distance matching. # maxlines - Max lines of backlog to match against. # maxtime - Maximum period of time a user can set. 0 to allow any. # size - Maximum number of characters to check for, can be used to # truncate messages before they are checked, resulting in # less CPU usage. Increasing this beyond 512 doesn't have # any effect, as the maximum length of a message on IRC # cannot exceed that. #<repeat maxbacklog="20" maxdistance="50" maxlines="20" maxtime="0" size="512"> #<module name="repeat"> #-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-# # Restricted channels module: Allows only opers with the # channels/restricted-create priv and/or registered users to # create channels. # # You probably *DO NOT* want to load this module on a public network. # #<module name="restrictchans"> # # allowregistered: should registered users be allowed to bypass the restrictions? #<restrictchans allowregistered="no"> # # Allow any channel matching #user-* to be created, bypassing restrictchans checks #<allowchannel name="#user-*"> #-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-# # Restrict message module: Allows users to only message opers. # # You probably *DO NOT* want to load this module on a public network. # #<module name="restrictmsg"> #-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-# # R-line module: Ban users through regular expression patterns. #<module name="rline"> # #-#-#-#-#-#-#-#-#-#-#-#- RLINE CONFIGURATION -#-#-#-#-#-#-#-#-#-#-#-#-# # # If you wish to re-check a user when they change nickname (can be # useful under some situations, but *can* also use CPU with more users # on a server) then set 'matchonnickchange' to yes. # If you additionally want Z-lines to be added on matches, then # set 'zlineonmatch' to yes. # Also, this is where you set what Regular Expression engine is to be # used. If you ever change it while running, all of your R-lines will # be wiped. This is the regex engine used by all R-lines set, and # regex_<engine> must be loaded, or rline will be non-functional # until you load it or change the engine to one that is loaded. # #<rline matchonnickchange="yes" zlineonmatch="no" engine="pcre"> # # Generally, you will NOT want to use 'glob' here, as this turns an # R-line into just another G-line. The exceptions are that R-lines will # always use the full "nick!user@host realname" string, rather than only # user@host, but beware that only the ? and * wildcards are available, # and are the only way to specify where the space can occur if you do # use glob. For this reason, is recommended to use a real regex engine # so that at least \s or [[:space:]] is available. #-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-# # RMODE module: Adds the /RMODE command. # Allows channel operators to remove list modes en masse, optionally # matching a glob-based pattern. # Syntax: /RMODE <channel> <mode> [<pattern>] # E.g. '/RMODE #channel b m:*' will remove all mute extbans on the channel. #<module name="rmode"> #-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-# # SAJOIN module: Adds the /SAJOIN command which forcibly joins a user # to the given channel. # This module is oper-only. # To use, SAJOIN must be in one of your oper class blocks. # Opers need the users/sajoin-others priv to be able to /SAJOIN users # other than themselves. #<module name="sajoin"> #-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-# # SAKICK module: Adds the /SAKICK command which kicks a user from the # given channel. # This module is oper-only. # To use, SAKICK must be in one of your oper class blocks. #<module name="sakick"> #-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-# # SAMODE module: Adds the /SAMODE command which allows server operators # to change modes on a channel without requiring them to have any # channel priviliges. Also allows changing user modes for any user. # This module is oper-only. # To use, SAMODE must be in one of your oper class blocks. #<module name="samode"> #-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-# # SANICK module: Adds the /SANICK command which allows opers to change # users' nicks. # This module is oper-only. # To use, SANICK must be in one of your oper class blocks. #<module name="sanick"> #-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-# # SAPART module: Adds the /SAPART command which forcibly parts a user # from a channel. # This module is oper-only. # To use, SAPART must be in one of your oper class blocks. #<module name="sapart"> #-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-# # SAQUIT module: Adds the /SAQUIT command which forcibly quits a user. # This module is oper-only. # To use, SAQUIT must be in one of your oper class blocks. #<module name="saquit"> #-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-# # SATOPIC module: Adds the /SATOPIC command which allows changing the # topic on a channel without requiring any channel priviliges. # This module is oper-only. # To use, SATOPIC must be in one of your oper class blocks. #<module name="satopic"> #-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-# # SASL authentication module: Provides support for IRC Authentication # Layer via AUTHENTICATE. Note: You also need to have cap loaded # for SASL to work. #<module name="sasl"> # Define the following to your services server name to improve security # by ensuring the SASL messages are only sent to the services server # and not to all connected servers. This prevents a rogue server from # capturing SASL messages and disables the SASL cap when services is # down. #<sasl target="services.mynetwork.com"> #-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-# # Secure list module: Prevent /LIST in the first minute of connection, # crippling most spambots and trojan spreader bots. #<module name="securelist"> # #-#-#-#-#-#-#-#-#-# SECURELIST CONFIGURATION -#-#-#-#-#-#-#-#-#-#-#-#-# # # # 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="*@*.ircdriven.com"> #<securehost exception="*@*.ircs.me"> # # # Define the following variable to change how long a user must wait # # before issuing a LIST. If not defined, defaults to 60 seconds. # # # #<securelist waittime="1m"> # #-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-# # Servprotect module: Provides support for Austhex style +k / # UnrealIRCD +S services mode. #<module name="servprotect"> #-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-# # See nicks module: Adds snomask +n and +N which show local and remote # nick changes. # This module is oper-only. #<module name="seenicks"> #-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-# # Set idle module: Adds a command for opers to change their idle time. # This module is oper-only. # To use, SETIDLE must be in one of your oper class blocks. #<module name="setidle"> #-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-# # Services support module: Adds several user modes such as +R and +M. # This module implements the 'identified' state via account names, # and is similar in operation to the way asuka and ircu handle services. # # At the same time, this offers +r for users and channels to mark them # as identified separately from the idea of a master account, which # can be useful for services which are heavily nick-as-account centric. # # Also of note is that this module implements two extbans: # +b R: (stop matching account names from joining) # +b U:n!u@h (blocks matching unregistered users) # #<module name="services_account"> #-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-# # Sethost module: Adds the /SETHOST command. # This module is oper-only. # To use, SETHOST must be in one of your oper class blocks. # See the chghost module for how to customise valid chars for hostnames. #<module name="sethost"> #-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-# # Setident module: Adds the /SETIDENT command. # This module is oper-only. # To use, SETIDENT must be in one of your oper class blocks. #<module name="setident"> #-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-# # SETNAME module: Adds the /SETNAME command. #<module name="setname"> # #-#-#-#-#-#-#-#-#-#-#-#- SETNAME CONFIGURATION -#-#-#-#-#-#-#-#-#-#-#-# # # # operonly - Whether the SETNAME command should only be usable by # # server operators. Defaults to no. # # # # notifyopers - Whether to send a snotice to snomask `a` when a user # # changes their real name. Defaults to to yes if # # oper-only and no if usable by everyone. # # # #<setname notifyopers="yes" # operonly="no"> #-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-# # Serverban: Implements extended ban 's', which stops anyone connected # to a server matching a mask like +b s:server.mask.here from joining. # Wildcards are accepted. #<module name="serverban"> #-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-# # SHA1 module: Allows other modules to generate SHA1 hashes. # Required by the WebSocket module. #<module name="sha1"> #-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-# # Showfile: Provides support for showing a text file to users when # # they enter a command. # # This module adds one command for each <showfile> tag that shows the # # given file to the user as a series of messages or numerics. # #<module name="showfile"> # # #-#-#-#-#-#-#-#-#-#-# SHOWFILE CONFIGURATION -#-#-#-#-#-#-#-#-#-#-#-#-# # # # name - The name of the command which displays this file. This is # # the only mandatory setting, all others are optional. # # file - The text file to be shown to the user. # # By default same as the command name. # # method - How should the file be shown? # # * numeric: Send contents using a numeric # # (similar to /MOTD; the default). # # * notice: Send contents as a series of notices. # # * msg: Send contents as a series of private messages. # # # # When using the method "numeric", the following extra settings are # # available: # # # # introtext - Introductory line, "Showing <name>" by default. # # intronumeric - Numeric used for the introductory line. # # numeric - Numeric used for sending the text itself. # # endtext - Ending line, "End of <name>" by default. # # endnumeric - Numeric used for the ending line. # # # #<showfile name="RULES" # file="rules.txt" # introtext="Server rules:" # endtext="End of server rules."> #-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-# # Show whois module: Adds the +W user mode which allows opers to see # when they are /WHOIS'd. # This module is oper-only by default. #<module name="showwhois"> # # If you wish, you may also let users set this mode. Only opers with the # users/auspex priv will see real hosts of people, though. #<showwhois opersonly="yes" # # You may also set whether or not users should receive whois notices, # should they be /WHOIS'd by an oper. #showfromopers="yes"> #-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-# # Shun module: Provides the /SHUN command, which stops a user from # executing all except configured commands. # This module is oper-only. # To use, SHUN must be in one of your oper class blocks. #<module name="shun"> # # You may also configure which commands you wish a user to be able to # perform when shunned. It should be noted that if a shunned user # issues QUIT or PART then their message will be removed, as if they # did not issue one. # # You can optionally let the user know that their command was blocked. # # You may also let SHUN affect opers (defaults to no). #<shun enabledcommands="ADMIN PING PONG QUIT PART JOIN" notifyuser="yes" affectopers="no"> #-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-# # SSL mode module: Adds support for SSL-only channels via the '+z' # channel mode, SSL-only private messages via the '+z' user mode and # the 'z:' extban which matches SSL client certificate fingerprints. # # Does not do anything useful without a working SSL module and the # sslinfo module (see below). #<module name="sslmodes"> # # The +z user mode is not enabled by default to enable link compatibility # with 2.0 servers. You can enable it by uncommenting this: #<sslmodes enableumode="yes"> #-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-# # SSL rehash signal module: Allows the SSL modules to be rehashed by # sending SIGUSR1 to a running InspIRCd process. # This modules is in extras. Re-run configure with: # ./configure --enable-extras=m_sslrehashsignal.cpp # and run make install, then uncomment this module to enable it. #<module name="sslrehashsignal"> #-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-# # GnuTLS SSL module: Adds support for SSL/TLS connections using GnuTLS, # if enabled. You must answer 'yes' in ./configure when asked or # manually symlink the source for this module from the directory # src/modules/extra, if you want to enable this, or it will not load. #<module name="ssl_gnutls"> # #-#-#-#-#-#-#-#-#-#-#- GNUTLS CONFIGURATION -#-#-#-#-#-#-#-#-#-#-#-# # # # ssl_gnutls is too complex to describe here, see the docs: # # https://docs.inspircd.org/3/modules/ssl_gnutls # #-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-# # SSL info module: Allows users to retrieve information about other # users' peer SSL certificates and keys via the SSLINFO command. # This can be used by client scripts to validate users. For this to # work, one of ssl_gnutls, ssl_mbedtls or ssl_openssl must be loaded. # This module also adds the "<user> is using a secure connection" # and "<user> has client certificate fingerprint <fingerprint>" # WHOIS lines, the ability for opers to use SSL cert fingerprints to # verify their identity and the ability to force opers to use SSL # connections in order to oper up. It is highly recommended to load # this module if you use SSL on your network. # For how to use the oper features, please see the first # example <oper> tag in opers.conf.example. # #<module name="sslinfo"> # # If you want to prevent users from viewing SSL certificate information # and fingerprints of other users, set operonly to yes. #<sslinfo operonly="no"> #-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-# # mbedTLS SSL module: Adds support for SSL/TLS connections using mbedTLS. #<module name="ssl_mbedtls"> # #-#-#-#-#-#-#-#-#-#-#- MBEDTLS CONFIGURATION -#-#-#-#-#-#-#-#-#-#-#-# # # # ssl_mbedtls is too complex to describe here, see the docs: # # https://docs.inspircd.org/3/modules/ssl_mbedtls # #-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-# # OpenSSL SSL module: Adds support for SSL/TLS connections using OpenSSL, # if enabled. You must answer 'yes' in ./configure when asked or symlink # the source for this module from the directory src/modules/extra, if # you want to enable this, or it will not load. #<module name="ssl_openssl"> # #-#-#-#-#-#-#-#-#-#-#- OPENSSL CONFIGURATION -#-#-#-#-#-#-#-#-#-#-#-# # # # ssl_openssl is too complex to describe here, see the docs: # # https://docs.inspircd.org/3/modules/ssl_openssl # #-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-# # Strip color module: Adds channel mode +S that strips color codes and # all control codes except CTCP from all messages sent to the channel. #<module name="stripcolor"> #-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-# # Silence module: Adds support for the /SILENCE command, which allows # users to have a server-side ignore list for their client. #<module name="silence"> # # Set the maximum number of entries allowed on a user's silence list. #<silence maxentries="32" # # Whether messages from U-lined servers will bypass silence masks. #exemptuline="yes"> #-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-# # SQLite3 module: Allows other SQL modules to access SQLite3 # # databases through a unified API. # # This module is in extras. Re-run configure with: # # ./configure --enable-extras=m_sqlite3.cpp # and run make install, then uncomment this module to enable it. # # #<module name="sqlite3"> # #-#-#-#-#-#-#-#-#-#-#-#- SQL CONFIGURATION -#-#-#-#-#-#-#-#-#-#-#-#-# # # # sqlite is more complex than described here, see the docs for more # # info: https://docs.inspircd.org/3/modules/sqlite3 # # #<database module="sqlite" hostname="/full/path/to/database.db" id="anytext"> #-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-# # SQL authentication module: Allows IRCd connections to be tied into # a database table (for example a forum). # #<module name="sqlauth"> # #-#-#-#-#-#-#-#-#-#-#- SQLAUTH CONFIGURATION -#-#-#-#-#-#-#-#-#-#-#-# # # # sqlauth is too complex to describe here, see the docs: # # https://docs.inspircd.org/3/modules/sqlauth # #-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-# # SQL oper module: Allows you to store oper credentials in an SQL # table. You can add additional table columns like you would config # tags in opers.conf. Opers in opers.conf will override opers from # this module. # #<module name="sqloper"> # #-#-#-#-#-#-#-#-#-#-#- SQLOPER CONFIGURATION -#-#-#-#-#-#-#-#-#-#-#-# # # # dbid - Database ID to use (see SQL modules). # # # # See also: https://docs.inspircd.org/3/modules/sqloper # # # #<sqloper dbid="1"> #-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-# # StartTLS module: Implements STARTTLS, which allows clients # # connected to non SSL enabled ports to enable SSL, if a proper SSL # # module is loaded (either ssl_gnutls, ssl_mbedtls or ssl_openssl). # #<module name="starttls"> #-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-# # SVSHold module: Implements SVSHOLD. Like Q-lines, but can only be # # added/removed by Services. # #<module name="svshold"> # SVSHOLD does not generate server notices by default, you can turn # notices on by uncommenting the next line. #<svshold silent="false"> #-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-# # SWHOIS module: Allows you to add arbitrary lines to user WHOIS. # This module is oper-only. # To use, SWHOIS must be in one of your oper class blocks. #<module name="swhois"> #-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-# # Timed bans module: Adds timed channel bans with the /TBAN command. #<module name="timedbans"> #-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-# # Test line module: Adds the /TLINE command, used to test how many # users a /GLINE or /ZLINE etc. would match. # This module is oper-only. # To use, TLINE must be in one of your oper class blocks. #<module name="tline"> #-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-# # Topiclock module: implements server-side topic locking to achieve deeper # integration with services packages. #<module name="topiclock"> #-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-# # UHNAMES support module: Adds support for the IRCX style UHNAMES # extension, which displays ident and hostname in the names list for # each user, saving clients from doing a WHO on the channel. # If a client does not support UHNAMES it will not enable it, this will # not break incompatible clients. #<module name="uhnames"> #-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-# # Uninvite module: Adds the /UNINVITE command which lets users remove # pending invites from channels without waiting for the user to join. #<module name="uninvite"> #-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-# # Userip module: Adds the /USERIP command. # Allows users to query their own IP, also allows opers to query the IP # of anyone else. #<module name="userip"> #-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-# # Vhost module: Adds the VHOST command which allows for adding virtual # hosts which are accessible using a username and password in the config. #<module name="vhost"> # #-#-#-#-#-#-#-#-#-#-#- VHOST CONFIGURATION -#-#-#-#-#-#-#-#-#-#-#-#-# # # # user - Username for the vhost. # # # # pass - Password for the vhost. # # # # hash - The hash for the specific user (optional) # # password_hash and a hashing module must be loaded for # # this to work. # # # # host - Vhost to set. # # #<vhost user="some_username" pass="some_password" host="some.host.test.cc"> #<vhost user="foo" password="$2a$10$iTuYLT6BRhRlOgzfsW9oPe62etW.oXwSpyKw5rJit64SGZanLXghO" hash="bcrypt" host="some.other.host.example.com"> #-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-# # Watch module: Adds the WATCH command, which is used by clients to # maintain notify lists. #<module name="watch"> # # Set the maximum number of entries on a user's watch list below. #<watch maxentries="32"> #-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-# # WebSocket module: Adds HTML5 WebSocket support. # Specify hook="websocket" in a <bind> tag to make that port accept # WebSocket connections. Compatible with SSL/TLS. # Requires SHA-1 hash support available in the sha1 module. #<module name="websocket"> # # Whether to re-encode messages as UTF-8 before sending to WebSocket # clients. This is recommended as the WebSocket protocol requires all # text frames to be sent as UTF-8. If you do not have this enabled # messages will be sent as binary frames instead. #<websocket sendastext="yes"> # # If you use the websocket module you MUST specify one or more origins # which are allowed to connect to the server. You should set this as # strict as possible to prevent malicious webpages from connecting to # your server. # <wsorigin allow="https://*.example.com"> #-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-# # X-line database: Stores all *-lines (G/Z/K/R/any added by other modules) # in a file which is re-loaded on restart. This is useful # for two reasons: it keeps bans so users may not evade them, and on # bigger networks, server connections will take less time as there will # be a lot less bans to apply - as most of them will already be there. #<module name="xline_db"> # Specify the filename for the xline database and how often to check whether # the database needs to be saved here. #<xlinedb filename="xline.db" saveperiod="5s"> #-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-# # ____ _ _____ _ _ ____ _ _ _ # # | _ \ ___ __ _ __| | |_ _| |__ (_)___ | __ )(_) |_| | # # | |_) / _ \/ _` |/ _` | | | | '_ \| / __| | _ \| | __| | # # | _ < __/ (_| | (_| | | | | | | | \__ \ | |_) | | |_|_| # # |_| \_\___|\__,_|\__,_| |_| |_| |_|_|___/ |____/|_|\__(_) # # # # To link servers to InspIRCd, you MUST load the spanningtree module. # # If you don't do this, server links will NOT work at all. # # This is by design, to allow for the implementation of other linking # # protocols in modules in the future. # #-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-# # Spanning tree module: Allows linking of servers using the spanning # tree protocol (see the READ THIS BIT section above). # You will almost always want to load this. # #<module name="spanningtree"> ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/docs/conf/motd.txt.example�����������������������������������������������������������0000664�0000000�0000000�00000003473�13554550454�0020365�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������ _____ _____ _____ _____ _ |_ _| |_ _| | __ \ / ____| | | | | _ __ ___ _ __ | | | |__) || | __| | | | | '_ \ / __| | '_ \ | | | _ / | | / _` | _| |_ | | | | \__ \ | |_) | _| |_ | | \ \ | |____ | (_| | |_____| |_| |_| |___/ | .__/ |_____| |_| \_\ \_____| \__,_| __________________| |_______________________________ |__________________|_|_______________________________| Putting the ricer in IRCer since 2007 //\ V \ WELCOME TO AN INSPIRCD NETWORK \ \_ If you see this, I am probably new. \,'.`-. If I'm not new, my owner is lazy. |\ `. `. ( \ `. `-. _,.-:\ \ \ `. `-._ __..--' ,-';/ \ `. `-. `-..___..---' _.--' ,'/ `. `. `-._ __..--' ,' / `. `-_ ``--..'' _.-' ,' `-_ `-.___ __,--' ,' `-.__ `----""" __.-' `--..____..--' ---- To change, see motd.txt.example ----- / \ / * Web: https://www.inspircd.org \ | * IRC: irc.inspircd.org #inspircd | | * Docs: https://docs.inspircd.org | | * Bugs: https://inspircd.org/bugs | | | | We hope you like this software. Please do | | make sure you put some effort into | | your configuration, though, so you love it.| | Enjoy. | | | \ -- The InspIRCd Team / ------------------------------------------- �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/docs/conf/opermotd.txt.example�������������������������������������������������������0000664�0000000�0000000�00000003473�13554550454�0021253�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������ _____ _____ _____ _____ _ |_ _| |_ _| | __ \ / ____| | | | | _ __ ___ _ __ | | | |__) || | __| | | | | '_ \ / __| | '_ \ | | | _ / | | / _` | _| |_ | | | | \__ \ | |_) | _| |_ | | \ \ | |____ | (_| | |_____| |_| |_| |___/ | .__/ |_____| |_| \_\ \_____| \__,_| __________________| |_______________________________ |__________________|_|_______________________________| Putting the ricer in IRCer since 2007 //\ V \ WELCOME TO AN INSPIRCD NETWORK \ \_ If you see this, I am probably new. \,'.`-. If I'm not new, my owner is lazy. |\ `. `. ( \ `. `-. _,.-:\ \ \ `. `-._ __..--' ,-';/ \ `. `-. `-..___..---' _.--' ,'/ `. `. `-._ __..--' ,' / `. `-_ ``--..'' _.-' ,' `-_ `-.___ __,--' ,' `-.__ `----""" __.-' `--..____..--' -- To change, see opermotd.txt.example --- / \ / * Web: https://www.inspircd.org \ | * IRC: irc.inspircd.org #inspircd | | * Docs: https://docs.inspircd.org | | * Bugs: https://inspircd.org/bugs | | | | We hope you like this software. Please do | | make sure you put some effort into | | your configuration, though, so you love it.| | Enjoy. | | | \ -- The InspIRCd Team / ------------------------------------------- �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/docs/conf/opers.conf.example���������������������������������������������������������0000664�0000000�0000000�00000024265�13554550454�0020662�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������#-#-#-#-#-#-#-#-#-#-#-#-# CLASS CONFIGURATION #-#-#-#-#-#-#-#-#-#-#-# # # # Classes are a group of commands which are grouped together and # # given a unique name. They're used to define which commands # # are available to certain types of Operators. # # # # # # Note: It is possible to make a class which covers all available # # commands. To do this, specify commands="*". This is not really # # recommended, as it negates the whole purpose of the class system, # # however it is provided for fast configuration (e.g. in test nets). # # # <class name="Shutdown" # commands: Oper-only commands that opers of this class can run. commands="DIE RESTART REHASH LOADMODULE UNLOADMODULE RELOADMODULE GLOADMODULE GUNLOADMODULE GRELOADMODULE" # privs: Special privileges that users with this class may utilise. # VIEWING: # - channels/auspex: allows opers with this priv to see more details about channels than normal users. # - users/auspex: allows opers with this priv to view more details about users than normal users, e.g. real host and IP. # - users/channel-spy: allows opers with this priv to view the private/secret channels that a user is on. # - servers/auspex: allows opers with this priv to see more details about server information than normal users. # ACTIONS: # - users/mass-message: allows opers with this priv to PRIVMSG and NOTICE to a server mask (e.g. NOTICE $*). # - users/samode-usermodes: allows opers with this priv to change the user modes of any other user using /SAMODE. # PERMISSIONS: # - channels/ignore-noctcp: allows opers with this priv to send a CTCP to a +C channel. # - channels/ignore-nonicks: allows opers with this priv to change their nick when on a +N channel. # - channels/restricted-create: allows opers with this priv to create channels if the restrictchans module is loaded. # - users/flood/increased-buffers: allows opers with this priv to send and receive data without worrying about being disconnected for exceeding limits (*NOTE). # - users/flood/no-fakelag: prevents opers from being penalized with fake lag for flooding (*NOTE). # - users/flood/no-throttle: allows opers with this priv to send commands without being throttled (*NOTE). # - users/ignore-callerid: allows opers with this priv to message people using callerid without being on their callerid list. # - users/ignore-commonchans: allows opers with this priv to send a message to a +c user without sharing common channels. # - users/ignore-noctcp: allows opers with this priv to send a CTCP to a +T user. # - users/ignore-privdeaf: allows opers with this priv to message users with +D set. # - users/sajoin-others: allows opers with this priv to /SAJOIN users other than themselves. # - servers/use-disabled-commands: allows opers with this priv to use disabled commands. # - servers/use-disabled-modes: allows opers with this priv to use disabled modes. # # *NOTE: These privs are potentially dangerous, as they grant users with them the ability to hammer your server's CPU/RAM as much as they want, essentially. privs="users/auspex channels/auspex servers/auspex users/mass-message users/flood/no-throttle users/flood/increased-buffers" # usermodes: Oper-only user modes that opers with this class can use. usermodes="*" # chanmodes: Oper-only channel modes that opers with this class can use. chanmodes="*"> <class name="SACommands" commands="SAJOIN SAPART SANICK SAQUIT SATOPIC SAKICK SAMODE OJOIN"> <class name="ServerLink" commands="CONNECT SQUIT RCONNECT RSQUIT MKPASSWD ALLTIME SWHOIS LOCKSERV UNLOCKSERV" usermodes="*" chanmodes="*" privs="servers/auspex"> <class name="BanControl" commands="KILL GLINE KLINE ZLINE QLINE ELINE TLINE RLINE CHECK NICKLOCK NICKUNLOCK SHUN CLONES CBAN" usermodes="*" chanmodes="*"> <class name="OperChat" commands="WALLOPS GLOBOPS" usermodes="*" chanmodes="*" privs="users/mass-message"> <class name="HostCloak" commands="SETHOST SETIDENT SETIDLE CHGNAME CHGHOST CHGIDENT" usermodes="*" chanmodes="*" privs="users/auspex"> #-#-#-#-#-#-#-#-#-#-#-#- OPERATOR COMPOSITION -#-#-#-#-#-#-#-#-#-#-# # # # This is where you specify which types of operators you have on # # your server, as well as the commands they are allowed to use. # # This works alongside with the classes specified above. # # # <type # name: Name of the type. Used in actual server operator accounts below. name="NetAdmin" # classes: Classes (blocks above) that this type belongs to. classes="SACommands OperChat BanControl HostCloak Shutdown ServerLink" # vhost: Host that opers of this type get when they log in (oper up). This is optional. vhost="netadmin.omega.example.org" # maxchans: Maximum number of channels opers of this type can be in at once. maxchans="60" # modes: User modes besides +o that are set on an oper of this type # when they oper up. Used for snomasks and other things. # Requires the opermodes module to be loaded. modes="+s +cCqQ"> <type name="GlobalOp" classes="SACommands OperChat BanControl HostCloak ServerLink" vhost="serverop.omega.example.org"> <type name="Helper" classes="HostCloak" vhost="helper.omega.example.org"> #-#-#-#-#-#-#-#-#-#-#- OPERATOR CONFIGURATION -#-#-#-#-#-#-#-#-#-#-# # # # Opers are defined here. This is a very important section. # # Remember to only make operators out of trustworthy people. # # # # Operator account with a plaintext password. <oper # name: Oper login that is used to oper up (/OPER <username> <password>). # Remember: This is case sensitive. name="Attila" # password: Case-sensitive, unhashed (plaintext). password="s3cret" # host: What hostnames and IPs are allowed to use this operator account. # Multiple options can be separated by spaces and CIDRs are allowed. # You can use just * or *@* for this section, but it is not recommended # for security reasons. host="attila@inspircd.org *@2001:db8::/32" # ** ADVANCED ** This option is disabled by default. # fingerprint: When using the sslinfo module, you may specify # a key fingerprint here. This can be obtained by using the /SSLINFO # command while the module is loaded, and is also noticed on connect. # This enhances security by verifying that the person opering up has # a matching SSL client certificate, which is very difficult to # forge (impossible unless preimage attacks on the hash exist). # If the sslinfo module isn't loaded, this option will be ignored. #fingerprint="67cb9dc013248a829bb2171ed11becd4" # autologin: If an SSL certificate fingerprint for this oper is specified, # you can have the oper block automatically log in. This moves all security # of the oper block to the protection of the client certificate, so be sure # that the private key is well-protected! Requires the sslinfo module. #autologin="on" # sslonly: If on, this oper can only oper up if they're using an SSL connection. # Setting this option adds a decent bit of security. Highly recommended # if the oper is on wifi, or specifically, unsecured wifi. Note that it # is redundant to specify this option if you specify a fingerprint. # This setting only takes effect if the sslinfo module is loaded. #sslonly="yes" # vhost: Overrides the vhost in the type block. Class and modes may also # be overridden. vhost="attila.example.org" # type: Which type of operator this person is; see the block # above for the list of types. NOTE: This is case-sensitive as well. type="NetAdmin"> # Operator with a plaintext password and no comments, for easy copy & paste. <oper name="Brain" password="youshouldhashthis" host="brain@dialup15.isp.test.com *@localhost *@example.com *@2001:db8::/32" #fingerprint="67cb9dc013248a829bb2171ed11becd4" type="NetAdmin"> # Operator with a hashed password. It is highly recommended to use hashed passwords. <oper # name: Oper login that is used to oper up (/OPER <username> <password>). # Remember: This is case sensitive. name="Adam" # hash: The hash function this password is hashed with. Requires the # module for the selected function (bcrypt, md5, sha1, or sha256) and # the password hashing module (password_hash) to be loaded. # # You may also use any of the above other than bcrypt prefixed with # either "hmac-" or "pbkdf2-hmac-" (requires the pbkdf2 module). # Create hashed passwords with: /MKPASSWD <hashtype> <plaintext>. hash="bcrypt" # password: A hash of the password (see above option) hashed # with /MKPASSWD <hashtype> <plaintext>. See the password_hash module # in modules.conf for more information about password hashing. password="qQmv3LcF$Qh63wzmtUqWp9OXnLwe7yv1GcBwHpq59k2a0UrY8xe0" # host: What hostnames and IPs are allowed to use this operator account. # Multiple options can be separated by spaces and CIDRs are allowed. # You can use just * or *@* for this section, but it is not recommended # for security reasons. host="*@127.0.0.1 *@192.0.2.40 *@198.51.100.4" # type: Which type of operator this person is; see the block # above for the list of types. NOTE: This is case-sensitive as well. type="Helper"> # Once you have edited this file you can remove this line. This is just to # ensure that you don't hastily include the file without reading it. <die reason="Using opers.conf.example without editing it is a security risk"> �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/docs/conf/providers/�����������������������������������������������������������������0000775�0000000�0000000�00000000000�13554550454�0017235�5����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/docs/conf/providers/irccloud.conf.example��������������������������������������������0000664�0000000�0000000�00000002127�13554550454�0023344�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������# This file contains connect classes which are used by IRCCloud users. # See https://www.irccloud.com for more information on IRCCloud and # https://www.irccloud.com/networks for more information on supporting # IRCloud on your network. <connect name="IRCCloud" parent="main" globalmax="100" localmax="100"> <connect name="IRCCloud-Brockwell" parent="IRCCloud" allow="192.184.10.118"> <connect name="IRCCloud-Charlton" parent="IRCCloud" allow="192.184.9.112"> <connect name="IRCCloud-Ealing" parent="IRCCloud" allow="192.184.9.110"> <connect name="IRCCloud-Hathersage" parent="IRCCloud" allow="192.184.8.73"> <connect name="IRCCloud-Highgate" parent="IRCCloud" allow="192.184.9.108"> <connect name="IRCCloud-Stonehaven" parent="IRCCloud" allow="192.184.8.103"> <connect name="IRCCloud-Tooting" parent="IRCCloud" allow="192.184.10.9"> # This is not typically needed as each user has their own IPv6 but if you have # <cidr:ipv6clone> set to a value lower than 128 you will need to enable this. #<connect name="IRCCloud-IPv6" parent="IRCCloud" allow="2001:67c:2f08::/48"> �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/docs/conf/providers/kiwiirc-com.conf.example�����������������������������������������0000664�0000000�0000000�00000001412�13554550454�0023751�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������# This file contains connect classes which are used by KiwiIRC.com users. # See https://kiwiirc.com for more information on KiwiIRC.com. <connect name="KiwiIRC.com" parent="main" globalmax="100" localmax="100" registered="no" resolvehostnames="no" usednsbl="no" useident="no"> <connect name="KiwiIRC.com-1" parent="KiwiIRC.com" allow="107.161.19.53"> <connect name="KiwiIRC.com-2" parent="KiwiIRC.com" allow="107.161.19.109"> <connect name="KiwiIRC.com-3" parent="KiwiIRC.com" allow="109.169.31.4"> <exception host="*@107.161.19.53" reason="KiwiIRC.com WebIRC Gateway"> <exception host="*@107.161.19.109" reason="KiwiIRC.com WebIRC Gateway"> <exception host="*@107.169.31.4" reason="KiwiIRC.com WebIRC Gateway"> ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/docs/conf/quotes.txt.example���������������������������������������������������������0000664�0000000�0000000�00000027531�13554550454�0020743�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������Men are from Mars. Women are from Venus. Computers are from hell Computer /nm./: a device designed to speed and automate errors Hardware /nm./: the part of the computer that you can kick. Maniac /n./ An early computer built by nuts. RAM /abr./: Rarely Adequate Memory. Programmer /n./ A red-eyed, mumbling mammal capable of conversing with inanimate objects Multitasking /adj./ 3 PCs and a chair with wheels Plonk /excl./: The sound a newbie makes as he falls to the bottom of a kill file hURL /n./: a link to a web site that makes you want to puke SUPERCOMPUTER: what it sounded like before you bought it. If it's really a supercomputer, how come the bullets don't bounce off when I shoot it? . The Covert Comic. A computer is like an Old Testament god, with a lot of rules and no mercy. . Joseph Campbell I dropped my computer on my foot! That Megahurtz!! A computer's attention span is as long as it's power cord 586: The average IQ needed to understand a PC Memory is like an orgasm. It's a lot better if you don't have to fake it If it jams, force it. If it breaks, it needed replacing anyway. A bus station is where a bus stops. A train station is where a train stops. On my desk I have a workstation.. Want to come see my HARD DRIVE ? I promise it isn't 3.5 inches and it ain't floppy. . Geek pick-up line. If you torture the data enough, it will confess. . Ronald Coase If you give someone a program, you will frustrate them for a day; if you teach them how to program, you will frustrate them for a lifetime ASCII stupid question, get a stupid ANSI! Use the source, Luke... Programming is an art form that fights back MacOS, Windows, BeOS: they're all just Xerox copies Whenever you think you have a clever programming trick... forget it! Managing senior programmers is like herding cats. . Dave Platt Your program is sick ! Shoot it and put it out of its memory /* You are not expected to understand this */ To define recursion, we must first define recursion ERROR: Computer possessed; Load EXOR.SYS ? [Y/N] Linux is only free if your time is worthless Linux: find out what you've been missing while you've been rebooting Windows NT unzip; strip; touch; finger; mount; fsck; more; yes; unmount; sleep Profanity is the one language all programmers know best It's 5.50 a.m.... Do you know where your stack pointer is? #define QUESTION ((bb) || !(bb)) . Shakespeare The more I C, the less I see. Confucius say: He who play in root, eventually kill tree. Unix is the answer, but only if you phrase the question very carefully C++: Hard to learn and built to stay that way Java is, in many ways, C++-- . Michael Feldman. They don't make bugs like Bunny anymore . Olav Mjelde If debugging is the process of removing software bugs, then programming must be the process of putting them in When the only tool you own is a hammer, every problem you encounter resembles a nail System Error: press F13 to continue... To err is human, but for a real disaster you need a computer Computers make very fast, very accurate mistakes Life would be so much easier if we only had the source code Who is this 'General Failure' and why is he reading my disk? hAS aNYONE sEEN MY cAPSLOCK kEY? InspIRCd, now with excessive ammounts of Cheeze I'm in the computer business, I make Out-Of-Order signs Kevorkian Virus: helps your computer shut down whenever it wants to. [OUT OF QUOTES, PLEASE ORDER MORE] Insert Something Funkeh.. err.. There! --> Cannot delete tmp150---3.tmp: There is not enough free disk space. Delete one or more files to free disk space, and then try again File not found. Should I fake it ? (Y/N) The definition of an upgrade: Take old bugs out, put new ones in If it's not on fire, it's a software problem It's a little-known fact that the Y1K problem caused the Dark Ages Artificial Intelligence usually beats natural stupidity Making fun of AOL users is like making fun of the kid in the wheel chair Daddy, why doesn't this magnet pick up this floppy disk? Daddy, what does FORMATTING DRIVE C mean? See daddy ? All the keys are in alphabetical order now. Enter any 11-digit prime number to continue... ASCII and ye shall receive. The web is a dominatrix. Every where I turn, I see little buttons ordering me to Submit. <FrostyCoolSlug> NO, You cannot dial 999, I'm downloading my mail ;/ 640K ought to be enough for anybody. . Bill Gates, 1981 Windows not found, [P]arty, [C]elebrate, [D]rink? English, the Microsoft of languages... It's been said that Bill Gates named his company after his dick... Ever notice how fast Windows runs ? -- Neither did I If at first you don't succeed, work for Microsoft We are Microsoft. Resistance Is Futile. You Will Be Assimilated "Microsoft Works." . Oxymoron Windows isn't a virus, viruses do something PANIC! buffer = :NickServ WRITE_DB(3). <-- JUST KIDDING! It just keeps going and going and going and going and goi <BANG> All that I know is that nukes are comming from 127.0.0.1 I know all about the irc and the mirc cops. M re ink n ed d, ple s r fil Please refrain from feeding the server operators. Thank you. I know all about mirc stuff, hmm.. I think this channel is experiencing packet loss.. MacDonalds claims Macintosh stole their next idea of the iMac I can't hold her any longer, captain, she's gonna bl.. sorry, got caught up in the moment I recommend purchasing a Cyrix CPU for testing nuclear meltdowns Is it an international rule to have the worst picture possible on your driver license? Have you hugged your services coder, today? Ever wonder why they make the colon flash on alarm clocks? Whats this?.. blue screen with a VXD error?!.. I'VE BEEN NUKED! do-do-bop-doo-doo-do-do-doo.. For those of you who know that song, you have problems.. be wery wery quiet... hunting wabbit... I've been IRC Nuked"Great warrior? War does not make one great." - Yoda "I find your lack of faith.....disturbing." - Darth Vader "I have a bad feeling about this.."--All of the Star Wars characters. Can I upgrade my Hard Drive to a WARP drive? Canadian DOS prompt: EH?\> Canadian DOS: "Yer sure, eh?" [y/n] CONGRESS.SYS Corrupted: Re-boot Washington D.C (Y/n)? I don't have a solution but I admire the problem. Famous Last Words: Trust me. I know what I'm doing. Hey Captain, I just created a black ho-p!%$ NO CARRIER Access denied--nah nah na nah nah! Bad command. Bad, bad command! Sit! Stay! Staaay.. Error: Keyboard not attached. Press F1 to continue. *grumble* "You're just supposed to sit here?" "Hey, what's this button d..<BOOM>" -W. Crusher "He has become One with Himself!" "He's passed out!" "That too."-B5 For a funny quote, call back later. Famous last words: 'You saw a WHAT around the corner?!' I like work ... I can sit and watch it for hours. Copywight 1994 Elmer Fudd. All wights wesewved. Cannot find REALITY.SYS. Universe halted. BUFFERS=20 FILES=15 2nd down, 4th quarter, 5 yards to go! My software never has bugs. It just develops random features. Why doesn't DOS ever say 'EXCELLENT command or filename!? Shell to DOS... Come in DOS, do you copy? Shell to DOS... Computing Definition - Network-Admin: Primary person who just got set up for the blame of the system crash. An expert is a person who has made all the mistakes which can be made in a very narrow field. Famous last words: This is the safe way to do it....... Famous Last Words: Trust me. I know what I'm doing. Clinton, "I didn't say that - er, well - yes, but I didn't mean..." CLINTON LEGACY??...even Pharaoh had only ten plagues... IBM I Bought McIntosh IBM I Bring Manuals IBM I've Been Moved IBM Idolized By Management IBM Impenetrable Brain Matter IBM Imperialism By Marketing IBM Incorrigible Boisterous Mammoth IBM Inertia Breeds Mediocrity IBM Ingenuity Becomes Mysterious IBM Ingrained Batch Mentality IBM Innovation By Management IBM Insipid Belligerent Mossbacks IBM Insipidly Bankrolling Millions IBM Inspect Before Multiusing IBM Install Bigger Memory IBM Institution By Machiavelli IBM Insultingly Boring Merchandisers IBM Intellectuals Being Moronized IBM Intelligence Belittling Meaning IBM Intimidated, Buffaloed Management IBM Into Building Money IBM Intolerant of Beards & Moustaches IBM Invest Before Multi-tasking IBM Investigate Baffling Malodor IBM Irresponsible Behave Multinational IBM It Beats Mattel IBM It's a Big Mess IBM It's Better Manually IBM Itty Bitty Machine IBM Institute for Black Magic 100,000 lemmings can't be wrong. Murphy's Eighth Law: If everything seems to be going well, you have obviously overlooked something. Rules of the game: Do not believe in miracles - rely on them. Rules of the game: Any given program, once running, is obsolete. Computing Definition - Error: What someone else has made when they disagree with your computer output. Backup not found: (A)bort (R)etry (P)anic WinErr 653: Multitasking attempted - system confused. Cannot join #real_life (invite only) "Unfortunatly, no one can be told what the Matrix is. You have to see it for yourself." - Matrix "Reality is a thing of the past" - Matrix "The future will not be user friendly" - Matrix "The general idea in chat is to make yourself understandable... ..." - Peer "heh i am talkin to someone...she's not dead...yet anyways" - Stinky "He who must die, must die in the dark, even though he sells candles" "If at first you don't succeed, skydiving is not for you." "Friendship is like peeing on yourself: everyone can see it, but only you get the warm feeling that it brings." "France sucks, but Paris swallows" "A computer once beat me at chess, but it was no match for me at kick boxing. "Ever wonder why the SAME PEOPLE make up ALL the conspiracy theories? "Don't think of it as being outnumbered. Think of it as having a wide target selection." "Sysadmins can't be sued for malpractice, but surgeons don't have to deal with patients who install new versions of their own innards." "FACE!" "Dirka Dirka Mohammed JIHAD!" We can learn much from wise words, little from wisecracks, and less from wise guys. "Blessed are the young, for they shall inherit the national debt." - Herbert Hoover If you have five dollars and Chuck Norris has five dollars, Chuck Norris has more money than you. Apple pays Chuck Norris 99 cents every time he listens to a song. If Chuck Norris and InspIRCd met in a dark alley, Chuck Norris would get his first black eye. Ever. Chuck Norris can sneeze with his eyes open. Chuck Norris can kill two stones with one bird. There is no theory of evolution. Just a list of animals Chuck Norris allows to live. The Great Wall of China was originally created to keep Chuck Norris out. It failed miserably. Chuck Norris can win a game of Connect Four in only three moves. Chuck Norris is not hung like a horse... horses are hung like Chuck Norris. Chuck Norris is currently suing NBC, claiming Law and Order are trademarked names for his left and right legs. Chuck Norris CAN believe it's not butter. Chuck Norris is so fast, he can run around the world and punch himself in the back of the head. When the Boogeyman goes to sleep every night, he checks his closet for Chuck Norris. Outer space exists because it's afraid to be on the same planet with Chuck Norris. Chuck Norris counted to infinity - twice. Chuck Norris only fears one thing in this world, and that is InspIRCd. InspIRCd's core is ran by donated Chuck Norris DNA. Chuck Norris exists because InspIRCd allows him to. Chuck Norris CAN punch you in the face over the internet. When Chuck Norris uses InspIRCd, he doesn't use the /kill command, he uses the /ROUND-HOUSE-TO-THE-FACE command. A developer only classifies oneself as such if they consider themselves as such. "While hunting in Africa, I shot an elephant in my pajamas. How an elephant got into my pajamas I'll never know." -- Groucho Marx �����������������������������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/docs/conf/services/������������������������������������������������������������������0000775�0000000�0000000�00000000000�13554550454�0017043�5����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/docs/conf/services/anope.conf.example������������������������������������������������0000664�0000000�0000000�00000000654�13554550454�0022453�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������# This file contains aliases and nickname reservations which are used # by Anope. See https://www.anope.org for more information on Anope. # This file inherits from the generic config to avoid repetition. <include file="examples/services/generic.conf.example"> # /GLOBAL <message> # Sends a global notice. <alias text="GLOBAL" format="*" replace="SQUERY $requirement :GLOBAL $2-" requires="Global" uline="yes" operonly="yes"> ������������������������������������������������������������������������������������inspircd-3.4.0/docs/conf/services/atheme.conf.example�����������������������������������������������0000664�0000000�0000000�00000006265�13554550454�0022620�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������# This file contains aliases and nickname reservations which are used # by Atheme. See https://atheme.github.io/atheme.html for more # information on Atheme. # This file inherits from the generic config to avoid repetition. <include file="examples/services/generic.conf.example"> # Long hand aliases for services pseudoclients. <alias text="ALIS" replace="SQUERY $requirement :$2-" requires="ALIS" uline="yes"> <alias text="CHANFIX" replace="SQUERY $requirement :$2-" requires="ChanFix" uline="yes"> <alias text="GAMESERV" replace="SQUERY $requirement :$2-" requires="GameServ" uline="yes"> <alias text="GLOBAL" replace="SQUERY $requirement :$2-" requires="Global" uline="yes" operonly="yes"> <alias text="GROUPSERV" replace="SQUERY $requirement :$2-" requires="GroupServ" uline="yes"> <alias text="HELPSERV" replace="SQUERY $requirement :$2-" requires="HelpServ" uline="yes"> <alias text="INFOSERV" replace="SQUERY $requirement :$2-" requires="InfoServ" uline="yes"> <alias text="PROXYSCAN" replace="SQUERY $requirement :$2-" requires="Proxyscan" uline="yes" operonly="yes"> <alias text="RPGSERV" replace="SQUERY $requirement :$2-" requires="RPGServ" uline="yes"> # Short hand aliases for services pseudoclients. <alias text="CF" replace="SQUERY $requirement :$2-" requires="ChanFix" uline="yes"> <alias text="GL" replace="SQUERY $requirement :$2-" requires="Global" uline="yes" operonly="yes"> <alias text="GS" replace="SQUERY $requirement :$2-" requires="GroupServ" uline="yes"> <alias text="IS" replace="SQUERY $requirement :$2-" requires="InfoServ" uline="yes"> <alias text="LS" replace="SQUERY $requirement :$2-" requires="ALIS" uline="yes"> <alias text="PS" replace="SQUERY $requirement :$2-" requires="Proxyscan" uline="yes" operonly="yes"> <alias text="RS" replace="SQUERY $requirement :$2-" requires="RPGServ" uline="yes"> # These short hand aliases conflict with other pseudoclients. You can enable # them but you will need to comment out the uncommented ones above first, #<alias text="GS" replace="SQUERY $requirement :$2-" requires="GameServ" uline="yes"> #<alias text="HS" replace="SQUERY $requirement :$2-" requires="HelpServ" uline="yes"> # Prevent clients from using the nicknames of services pseudoclients. <badnick nick="ALIS" reason="Reserved for a network service"> <badnick nick="ChanFix" reason="Reserved for a network service"> <badnick nick="GameServ" reason="Reserved for a network service"> <badnick nick="GroupServ" reason="Reserved for a network service"> <badnick nick="HelpServ" reason="Reserved for a network service"> <badnick nick="InfoServ" reason="Reserved for a network service"> <badnick nick="Proxyscan" reason="Reserved for a network service"> <badnick nick="RPGServ" reason="Reserved for a network service"> <badnick nick="SaslServ" reason="Reserved for a network service"> # Exempt services pseudoclients from filters. <exemptfromfilter target="ALIS"> <exemptfromfilter target="ChanFix"> <exemptfromfilter target="GameServ"> <exemptfromfilter target="GroupServ"> <exemptfromfilter target="HelpServ"> <exemptfromfilter target="InfoServ"> <exemptfromfilter target="Proxyscan"> <exemptfromfilter target="RPGServ"> <exemptfromfilter target="SaslServ"> �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/docs/conf/services/generic.conf.example����������������������������������������������0000664�0000000�0000000�00000005241�13554550454�0022762�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������# This file contains aliases and nickname reservations which are used # by all common services implementations. <module name="alias"> # Long hand aliases for services pseudoclients. <alias text="BOTSERV" replace="SQUERY $requirement :$2-" requires="BotServ" uline="yes"> <alias text="CHANSERV" replace="SQUERY $requirement :$2-" requires="ChanServ" uline="yes"> <alias text="HOSTSERV" replace="SQUERY $requirement :$2-" requires="HostServ" uline="yes"> <alias text="MEMOSERV" replace="SQUERY $requirement :$2-" requires="MemoServ" uline="yes"> <alias text="NICKSERV" replace="SQUERY $requirement :$2-" requires="NickServ" uline="yes"> <alias text="OPERSERV" replace="SQUERY $requirement :$2-" requires="OperServ" uline="yes" operonly="yes"> <alias text="STATSERV" replace="SQUERY $requirement :$2-" requires="StatServ" uline="yes"> # Short hand aliases for services pseudoclients. <alias text="BS" replace="SQUERY $requirement :$2-" requires="BotServ" uline="yes"> <alias text="CS" replace="SQUERY $requirement :$2-" requires="ChanServ" uline="yes"> <alias text="HS" replace="SQUERY $requirement :$2-" requires="HostServ" uline="yes"> <alias text="MS" replace="SQUERY $requirement :$2-" requires="MemoServ" uline="yes"> <alias text="NS" replace="SQUERY $requirement :$2-" requires="NickServ" uline="yes"> <alias text="OS" replace="SQUERY $requirement :$2-" requires="OperServ" uline="yes" operonly="yes"> <alias text="SS" replace="SQUERY $requirement :$2-" requires="StatServ" uline="yes"> # /ID [account] <password> # Identifies to a services account. <alias text="ID" format="*" replace="SQUERY $requirement :IDENTIFY $2-" requires="NickServ" uline="yes"> <alias text="IDENTIFY" format="*" replace="SQUERY $requirement :IDENTIFY $2-" requires="NickServ" uline="yes"> # Prevent clients from using the nicknames of services pseudoclients. <badnick nick="BotServ" reason="Reserved for a network service"> <badnick nick="ChanServ" reason="Reserved for a network service"> <badnick nick="Global" reason="Reserved for a network service"> <badnick nick="HostServ" reason="Reserved for a network service"> <badnick nick="MemoServ" reason="Reserved for a network service"> <badnick nick="NickServ" reason="Reserved for a network service"> <badnick nick="OperServ" reason="Reserved for a network service"> <badnick nick="StatServ" reason="Reserved for a network service"> # Exempt services pseudoclients from filters. <exemptfromfilter target="BotServ"> <exemptfromfilter target="ChanServ"> <exemptfromfilter target="Global"> <exemptfromfilter target="HostServ"> <exemptfromfilter target="MemoServ"> <exemptfromfilter target="NickServ"> <exemptfromfilter target="OperServ"> <exemptfromfilter target="StatServ"> ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/docs/sql/����������������������������������������������������������������������������0000775�0000000�0000000�00000000000�13554550454�0015072�5����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/docs/sql/sqloper.mysql.sql�����������������������������������������������������������0000664�0000000�0000000�00000000470�13554550454�0020445�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������CREATE TABLE ircd_opers ( id bigint(20) NOT NULL auto_increment, name text NOT NULL, password text NOT NULL, hash text, host text NOT NULL, type text NOT NULL, fingerprint text, autologin tinyint(1) NOT NULL DEFAULT 0, active tinyint(1) NOT NULL DEFAULT 1, PRIMARY KEY (id) ) ENGINE=MyISAM; ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/docs/sql/sqloper.pgsql.sql�����������������������������������������������������������0000664�0000000�0000000�00000000563�13554550454�0020431�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������CREATE TABLE ircd_opers ( "id" serial NOT NULL, "name" text NOT NULL, "password" text NOT NULL, "hash" text, "host" text NOT NULL, "type" text NOT NULL, "fingerprint" text, "autologin" smallint NOT NULL DEFAULT 0, "active" smallint NOT NULL DEFAULT 1 ); ALTER TABLE ONLY ircd_opers ADD CONSTRAINT ircd_opers_pkey PRIMARY KEY (id); ���������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/docs/sql/sqloper.sqlite3.sql���������������������������������������������������������0000664�0000000�0000000�00000000355�13554550454�0020666�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������CREATE TABLE ircd_opers ( id integer primary key, name text NOT NULL, password text NOT NULL, hash text, host text NOT NULL, type text NOT NULL, fingerprint text, autologin integer NOT NULL DEFAULT 0, active integer NOT NULL DEFAULT 1); �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/include/�����������������������������������������������������������������������������0000775�0000000�0000000�00000000000�13554550454�0014766�5����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/include/aligned_storage.h������������������������������������������������������������0000664�0000000�0000000�00000002236�13554550454�0020271�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * InspIRCd -- Internet Relay Chat Daemon * * Copyright (C) 2014 Attila Molnar <attilamolnar@hush.com> * * This file is part of InspIRCd. InspIRCd is free software: you can * redistribute it and/or modify it under the terms of the GNU General Public * License as published by the Free Software Foundation, version 2. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once namespace insp { template <typename T> class aligned_storage; } template <typename T> class insp::aligned_storage { mutable typename TR1NS::aligned_storage<sizeof(T), TR1NS::alignment_of<T>::value>::type data; public: aligned_storage() { } aligned_storage(const aligned_storage& other) { } T* operator->() const { return static_cast<T*>(static_cast<void*>(&data)); } operator T*() const { return operator->(); } }; ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/include/bancache.h�������������������������������������������������������������������0000664�0000000�0000000�00000005427�13554550454�0016673�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * InspIRCd -- Internet Relay Chat Daemon * * Copyright (C) 2008 Craig Edwards <craigedwards@brainbox.cc> * Copyright (C) 2007 Robin Burchell <robin+git@viroteck.net> * * This file is part of InspIRCd. InspIRCd is free software: you can * redistribute it and/or modify it under the terms of the GNU General Public * License as published by the Free Software Foundation, version 2. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once /** Stores a cached ban entry. * Each ban has one of these hashed in a hash_map to make for faster removal * of already-banned users in the case that they try to reconnect. As no wildcard * matching is done on these IPs, the speed of the system is improved. These cache * entries expire every few hours, which is a reasonable expiry for any reasonable * sized network. */ class CoreExport BanCacheHit { public: /** Type of cached ban */ std::string Type; /** Reason, shown as quit message */ std::string Reason; /** Time that the ban expires at */ time_t Expiry; BanCacheHit(const std::string& type, const std::string& reason, time_t seconds); bool IsPositive() const { return (!Reason.empty()); } }; /** A manager for ban cache, which allocates and deallocates and checks cached bans. */ class CoreExport BanCacheManager { /** A container of ban cache items. */ typedef TR1NS::unordered_map<std::string, BanCacheHit*, TR1NS::hash<std::string> > BanCacheHash; BanCacheHash BanHash; bool RemoveIfExpired(BanCacheHash::iterator& it); public: /** Creates and adds a Ban Cache item. * @param ip The IP the item is for. * @param type The type of ban cache item. std::string. .empty() means it's a negative match (user is allowed freely). * @param reason The reason for the ban. Left .empty() if it's a negative match. * @param seconds Number of seconds before nuking the bancache entry, the default is a day. This might seem long, but entries will be removed as G-lines/etc expire. */ BanCacheHit *AddHit(const std::string &ip, const std::string &type, const std::string &reason, time_t seconds = 0); BanCacheHit *GetHit(const std::string &ip); /** Removes all entries of a given type, either positive or negative. Returns the number of hits removed. * @param type The type of bancache entries to remove (e.g. 'G') * @param positive Remove either positive (true) or negative (false) hits. */ void RemoveEntries(const std::string& type, bool positive); ~BanCacheManager(); }; �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/include/base.h�����������������������������������������������������������������������0000664�0000000�0000000�00000020026�13554550454�0016051�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * InspIRCd -- Internet Relay Chat Daemon * * Copyright (C) 2009 Daniel De Graaf <danieldg@inspircd.org> * Copyright (C) 2006-2007 Oliver Lupton <oliverlupton@gmail.com> * Copyright (C) 2007 Dennis Friis <peavey@inspircd.org> * Copyright (C) 2003-2005, 2007 Craig Edwards <craigedwards@brainbox.cc> * * This file is part of InspIRCd. InspIRCd is free software: you can * redistribute it and/or modify it under the terms of the GNU General Public * License as published by the Free Software Foundation, version 2. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <map> #include <deque> #include <string> #include <list> /** Dummy class to help enforce culls being parent-called up to classbase */ class CullResult { CullResult(); friend class classbase; }; /** The base class for all inspircd classes with a well-defined lifetime. * Classes that inherit from this may be destroyed through GlobalCulls, * and may rely on cull() being called prior to their deletion. */ class CoreExport classbase { public: classbase(); /** * Called just prior to destruction via cull list. */ virtual CullResult cull(); virtual ~classbase(); private: // uncopyable classbase(const classbase&); void operator=(const classbase&); }; /** The base class for inspircd classes that provide a wrapping interface, and * should only exist while being used. Prevents heap allocation. */ class CoreExport interfacebase { public: interfacebase() {} static inline void* operator new(size_t, void* m) { return m; } private: interfacebase(const interfacebase&); void operator=(const interfacebase&); static void* operator new(size_t); static void operator delete(void*); }; /** The base class for inspircd classes that support reference counting. * Any objects that do not have a well-defined lifetime should inherit from * this, and should be assigned to a reference<type> object to establish their * lifetime. * * Reference objects should not hold circular references back to themselves, * even indirectly; this will cause a memory leak because the count will never * drop to zero. * * Using a normal pointer for the object is recommended if you can assure that * at least one reference<> will remain as long as that pointer is used; this * will avoid the slight overhead of changing the reference count. */ class CoreExport refcountbase { mutable unsigned int refcount; public: refcountbase(); virtual ~refcountbase(); inline unsigned int GetReferenceCount() const { return refcount; } static inline void* operator new(size_t, void* m) { return m; } static void* operator new(size_t); static void operator delete(void*); inline void refcount_inc() const { refcount++; } inline bool refcount_dec() const { refcount--; return !refcount; } private: // uncopyable refcountbase(const refcountbase&); void operator=(const refcountbase&); }; /** Base class for use count tracking. Uses reference<>, but does not * cause object deletion when the last user is removed. * * Safe for use as a second parent class; will not add a second vtable. */ class CoreExport usecountbase { mutable unsigned int usecount; public: usecountbase() : usecount(0) { } ~usecountbase(); inline unsigned int GetUseCount() const { return usecount; } inline void refcount_inc() const { usecount++; } inline bool refcount_dec() const { usecount--; return false; } private: // uncopyable usecountbase(const usecountbase&); void operator=(const usecountbase&); }; template <typename T> class reference { T* value; public: reference() : value(0) { } reference(T* v) : value(v) { if (value) value->refcount_inc(); } reference(const reference<T>& v) : value(v.value) { if (value) value->refcount_inc(); } reference<T>& operator=(const reference<T>& other) { if (other.value) other.value->refcount_inc(); this->reference::~reference(); value = other.value; return *this; } ~reference() { if (value && value->refcount_dec()) delete value; } inline reference<T>& operator=(T* other) { if (value != other) { if (value && value->refcount_dec()) delete value; value = other; if (value) value->refcount_inc(); } return *this; } inline operator bool() const { return (value != NULL); } inline operator T*() const { return value; } inline T* operator->() const { return value; } inline T& operator*() const { return *value; } inline bool operator<(const reference<T>& other) const { return value < other.value; } inline bool operator>(const reference<T>& other) const { return value > other.value; } static inline void* operator new(size_t, void* m) { return m; } private: #ifndef _WIN32 static void* operator new(size_t); static void operator delete(void*); #endif }; /** This class can be used on its own to represent an exception, or derived to represent a module-specific exception. * When a module whishes to abort, e.g. within a constructor, it should throw an exception using ModuleException or * a class derived from ModuleException. If a module throws an exception during its constructor, the module will not * be loaded. If this happens, the error message returned by ModuleException::GetReason will be displayed to the user * attempting to load the module, or dumped to the console if the ircd is currently loading for the first time. */ class CoreExport CoreException : public std::exception { protected: /** Holds the error message to be displayed */ const std::string err; /** Source of the exception */ const std::string source; public: /** This constructor can be used to specify an error message before throwing. * @param message Human readable error message */ CoreException(const std::string &message) : err(message), source("The core") {} /** This constructor can be used to specify an error message before throwing, * and to specify the source of the exception. * @param message Human readable error message * @param src Source of the exception */ CoreException(const std::string &message, const std::string &src) : err(message), source(src) {} /** This destructor solves world hunger, cancels the world debt, and causes the world to end. * Actually no, it does nothing. Never mind. * @throws Nothing! */ virtual ~CoreException() throw() {} /** Returns the reason for the exception. * @return Human readable description of the error */ const std::string& GetReason() const { return err; } /** Returns the source of the exception * @return Source of the exception */ const std::string& GetSource() const { return source; } }; class Module; class CoreExport ModuleException : public CoreException { public: /** This constructor can be used to specify an error message before throwing. */ ModuleException(const std::string &message, Module* me = NULL); }; typedef const reference<Module> ModuleRef; enum ServiceType { /** is a Command */ SERVICE_COMMAND, /** is a ModeHandler */ SERVICE_MODE, /** is a metadata descriptor */ SERVICE_METADATA, /** is a data processing provider (MD5, SQL) */ SERVICE_DATA, /** is an I/O hook provider (SSL) */ SERVICE_IOHOOK, /** Service managed by a module */ SERVICE_CUSTOM }; /** A structure defining something that a module can provide */ class CoreExport ServiceProvider : public classbase { public: /** Module that is providing this service */ ModuleRef creator; /** Name of the service being provided */ const std::string name; /** Type of service (must match object type) */ const ServiceType service; ServiceProvider(Module* Creator, const std::string& Name, ServiceType Type); virtual ~ServiceProvider(); /** Register this service in the appropriate registrar */ virtual void RegisterService(); /** If called, this ServiceProvider won't be registered automatically */ void DisableAutoRegister(); }; ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/include/channels.h�������������������������������������������������������������������0000664�0000000�0000000�00000027475�13554550454�0016751�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * InspIRCd -- Internet Relay Chat Daemon * * Copyright (C) 2009 Daniel De Graaf <danieldg@inspircd.org> * Copyright (C) 2007 Robin Burchell <robin+git@viroteck.net> * Copyright (C) 2007 Dennis Friis <peavey@inspircd.org> * Copyright (C) 2003-2007 Craig Edwards <craigedwards@brainbox.cc> * * This file is part of InspIRCd. InspIRCd is free software: you can * redistribute it and/or modify it under the terms of the GNU General Public * License as published by the Free Software Foundation, version 2. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include "membership.h" #include "mode.h" #include "parammode.h" /** Holds an entry for a ban list, exemption list, or invite list. * This class contains a single element in a channel list, such as a banlist. */ /** Holds all relevent information for a channel. * This class represents a channel, and contains its name, modes, topic, topic set time, * etc, and an instance of the BanList type. */ class CoreExport Channel : public Extensible { public: /** A map of Memberships on a channel keyed by User pointers */ typedef std::map<User*, insp::aligned_storage<Membership> > MemberMap; private: /** Set default modes for the channel on creation */ void SetDefaultModes(); /** Modes for the channel. * It is a bitset where each item in it represents if a mode is set. * To see if a mode is set, inspect modes[mh->modeid] */ std::bitset<ModeParser::MODEID_MAX> modes; /** Remove the given membership from the channel's internal map of * memberships and destroy the Membership object. * This function does not remove the channel from User::chanlist. * Since the parameter is an iterator to the target, the complexity * of this function is constant. * @param membiter The MemberMap iterator to remove, must be valid */ void DelUser(const MemberMap::iterator& membiter); public: /** Creates a channel record and initialises it with default values * @param name The name of the channel * @param ts The creation time of the channel * @throw CoreException if this channel name is in use */ Channel(const std::string &name, time_t ts); /** Checks whether the channel should be destroyed, and if yes, begins * the teardown procedure. * * If there are users on the channel or a module vetoes the deletion * (OnPreChannelDelete hook) then nothing else happens. * Otherwise, first the OnChannelDelete event is fired, then the channel is * removed from the channel list. All pending invites are destroyed and * finally the channel is added to the cull list. */ void CheckDestroy(); /** The channel's name. */ std::string name; /** Time that the object was instantiated (used for TS calculation etc) */ time_t age; /** User list. */ MemberMap userlist; /** Channel topic. * If this is an empty string, no channel topic is set. */ std::string topic; /** Time topic was set. * If no topic was ever set, this will be equal to Channel::created */ time_t topicset; /** The last user to set the topic. * If this member is an empty string, no topic was ever set. */ std::string setby; /* 128 */ /** Sets or unsets a custom mode in the channels info * @param mode The mode character to set or unset * @param value True if you want to set the mode or false if you want to remove it */ void SetMode(ModeHandler* mode, bool value); /** Returns true if a mode is set on a channel * @param mode The mode character you wish to query * @return True if the custom mode is set, false if otherwise */ bool IsModeSet(ModeHandler* mode) { return ((mode->GetId() != ModeParser::MODEID_MAX) && (modes[mode->GetId()])); } bool IsModeSet(ModeHandler& mode) { return IsModeSet(&mode); } bool IsModeSet(ChanModeReference& mode); /** Returns the parameter for a custom mode on a channel. * @param mode The mode character you wish to query * * For example if "+L #foo" is set, and you pass this method * 'L', it will return '\#foo'. If the mode is not set on the * channel, or the mode has no parameters associated with it, * it will return an empty string. * * @return The parameter for this mode is returned, or an empty string */ std::string GetModeParameter(ModeHandler* mode); std::string GetModeParameter(ChanModeReference& mode); std::string GetModeParameter(ParamModeBase* pm); /** Sets the channel topic. * @param user The user setting the topic. * @param topic The topic to set it to. * @param topicts Timestamp of the new topic. * @param setter Setter string, may be used when the original setter is no longer online. * If omitted or NULL, the setter string is obtained from the user. */ void SetTopic(User* user, const std::string& topic, time_t topicts, const std::string* setter = NULL); /** Obtain the channel "user counter" * This returns the number of users on this channel * * @return The number of users on this channel */ size_t GetUserCounter() const { return userlist.size(); } /** Add a user pointer to the internal reference list * @param user The user to add * * The data inserted into the reference list is a table as it is * an arbitary pointer compared to other users by its memory address, * as this is a very fast 32 or 64 bit integer comparison. */ Membership* AddUser(User* user); /** Delete a user pointer to the internal reference list * @param user The user to delete * @return number of users left on the channel after deletion of the user */ void DelUser(User* user); /** Obtain the internal reference list * The internal reference list contains a list of User*. * These are used for rapid comparison to determine * channel membership for PRIVMSG, NOTICE, QUIT, PART etc. * The resulting pointer to the vector should be considered * readonly and only modified via AddUser and DelUser. * * @return This function returns pointer to a map of User pointers (CUList*). */ const MemberMap& GetUsers() const { return userlist; } /** Returns true if the user given is on the given channel. * @param user The user to look for * @return True if the user is on this channel */ bool HasUser(User* user); Membership* GetUser(User* user); /** Make src kick user from this channel with the given reason. * @param src The source of the kick * @param victimiter Iterator to the user being kicked, must be valid * @param reason The reason for the kick */ void KickUser(User* src, const MemberMap::iterator& victimiter, const std::string& reason); /** Make src kick user from this channel with the given reason. * @param src The source of the kick * @param user The user being kicked * @param reason The reason for the kick */ void KickUser(User* src, User* user, const std::string& reason) { MemberMap::iterator it = userlist.find(user); if (it != userlist.end()) KickUser(src, it, reason); } /** Part a user from this channel with the given reason. * If the reason field is NULL, no reason will be sent. * @param user The user who is parting (must be on this channel) * @param reason The part reason * @return True if the user was on the channel and left, false if they weren't and nothing happened */ bool PartUser(User* user, std::string& reason); /** Join a local user to a channel, with or without permission checks. May be a channel that doesn't exist yet. * @param user The user to join to the channel. * @param channame The channel name to join to. Does not have to exist. * @param key The key of the channel, if given * @param override If true, override all join restrictions such as +bkil * @return A pointer to the Channel the user was joined to. A new Channel may have * been created if the channel did not exist before the user was joined to it. * If the user could not be joined to a channel, the return value is NULL. */ static Channel* JoinUser(LocalUser* user, std::string channame, bool override = false, const std::string& key = ""); /** Join a user to an existing channel, without doing any permission checks * @param user The user to join to the channel * @param privs Priviliges (prefix mode letters) to give to this user, may be NULL * @param bursting True if this join is the result of a netburst (passed to modules in the OnUserJoin hook) * @param created_by_local True if this channel was just created by a local user (passed to modules in the OnUserJoin hook) * @return A newly created Membership object, or NULL if the user was already inside the channel or if the user is a server user */ Membership* ForceJoin(User* user, const std::string* privs = NULL, bool bursting = false, bool created_by_local = false); /** Write to all users on a channel except some users * @param protoev Event to send, may contain any number of messages. * @param status The status of the users to write to, e.g. '@' or '%'. Use a value of 0 to write to everyone * @param except_list List of users not to send to */ void Write(ClientProtocol::Event& protoev, char status = 0, const CUList& except_list = CUList()); /** Write to all users on a channel except some users. * @param protoevprov Protocol event provider for the message. * @param msg Message to send. * @param status The status of the users to write to, e.g. '@' or '%'. Use a value of 0 to write to everyone * @param except_list List of users not to send to */ void Write(ClientProtocol::EventProvider& protoevprov, ClientProtocol::Message& msg, char status = 0, const CUList& except_list = CUList()); /** Return the channel's modes with parameters. * @param showsecret If this is set to true, the value of secret parameters * are shown, otherwise they are replaced with '&lt;name&gt;'. * @return The channel mode string */ const char* ChanModes(bool showsecret); /** Get the value of a users prefix on this channel. * @param user The user to look up * @return The module or core-defined value of the users prefix. * The values for op, halfop and voice status are constants in * mode.h, and are OP_VALUE, HALFOP_VALUE, and VOICE_VALUE respectively. * If the value you are given does not match one of these three, it is * a module-defined mode, and it should be compared in proportion to * these three constants. For example a value greater than OP_VALUE * is a prefix of greater 'worth' than ops, and a value less than * VOICE_VALUE is of lesser 'worth' than a voice. */ unsigned int GetPrefixValue(User* user); /** Check if a user is banned on this channel * @param user A user to check against the banlist * @returns True if the user given is banned */ bool IsBanned(User* user); /** Check a single ban for match */ bool CheckBan(User* user, const std::string& banmask); /** Get the status of an "action" type extban */ ModResult GetExtBanStatus(User *u, char type); /** Write a NOTICE to all local users on the channel * @param text Text to send */ void WriteNotice(const std::string& text); }; inline bool Channel::HasUser(User* user) { return (userlist.find(user) != userlist.end()); } inline std::string Channel::GetModeParameter(ChanModeReference& mode) { if (!mode) return ""; return GetModeParameter(*mode); } inline std::string Channel::GetModeParameter(ModeHandler* mh) { std::string out; ParamModeBase* pm = mh->IsParameterMode(); if (pm && this->IsModeSet(pm)) pm->GetParameter(this, out); return out; } inline std::string Channel::GetModeParameter(ParamModeBase* pm) { std::string out; if (this->IsModeSet(pm)) pm->GetParameter(this, out); return out; } inline bool Channel::IsModeSet(ChanModeReference& mode) { if (!mode) return false; return IsModeSet(*mode); } ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/include/clientprotocol.h�������������������������������������������������������������0000664�0000000�0000000�00000056723�13554550454�0020214�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * InspIRCd -- Internet Relay Chat Daemon * * Copyright (C) 2016 Attila Molnar <attilamolnar@hush.com> * * This file is part of InspIRCd. InspIRCd is free software: you can * redistribute it and/or modify it under the terms of the GNU General Public * License as published by the Free Software Foundation, version 2. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include "event.h" namespace ClientProtocol { class EventHook; class MessageSource; struct RFCEvents; struct ParseOutput; class TagSelection; } /** Contains a message parsed from wire format. * Used by Serializer::Parse(). */ struct ClientProtocol::ParseOutput { /** Command name, must not be empty. */ std::string cmd; /** Parameter list, may be empty. */ ClientProtocol::ParamList params; /** Message tags, may be empty. */ ClientProtocol::TagMap tags; }; /** A selection of zero or more tags in a TagMap. */ class ClientProtocol::TagSelection { std::bitset<64> selection; public: /** Check if a tag is selected. * @param tags TagMap the tag is in. The TagMap must contain the same tags as it had when the tag * was selected with Select(), otherwise the result is not meaningful. * @param it Iterator to the tag to check. * @return True if the tag is selected, false otherwise. */ bool IsSelected(const TagMap& tags, TagMap::const_iterator it) const { const size_t index = std::distance(tags.begin(), it); return ((index < selection.size()) && (selection[index])); } /** Select a tag. * @param tags TagMap the tag is in. This parameter must be the same every time the method is called. * The TagMap must not be altered otherwise the results of IsSelected() is not meaningful. * @param it Iterator to the tag to mark as selected. */ void Select(const TagMap& tags, TagMap::const_iterator it) { const size_t index = std::distance(tags.begin(), it); if (index < selection.size()) selection[index] = true; } /** Check if a TagSelection is equivalent to this object. * @param other Other TagSelection object to compare this with. * @return True if the objects are equivalent, false if they aren't. */ bool operator==(const TagSelection& other) const { return (this->selection == other.selection); } }; class ClientProtocol::MessageSource { User* sourceuser; const std::string* sourcestr; public: /** Constructor, sets the source to be the full host of a user or sets it to be nothing. * The actual source string when serializing will be obtained from User::GetFullHost() if the user is non-NULL. * @param Sourceuser User to set as source of the message. If NULL, the message won't have a source when serialized. * Optional, defaults to NULL. */ MessageSource(User* Sourceuser = NULL) { SetSourceUser(Sourceuser); } /** Constructor, sets the source to the supplied string and optionally sets the source user. * @param Sourcestr String to use as message source for serialization purposes. Must remain valid * as long as this object is alive. * @param Sourceuser User to set as source. Optional, defaults to NULL. It will not be used for serialization but * if provided it may be used internally, for example to create message tags. * Useful when the source string is synthesized but it is still related to a User. */ MessageSource(const std::string& Sourcestr, User* Sourceuser = NULL) { SetSource(Sourcestr, Sourceuser); } /** Get the source of this message as a string. * @return Pointer to the message source string or NULL if there is no source. */ const std::string* GetSource() const { // Return string if there's one explicitly set if (sourcestr) return sourcestr; if (sourceuser) return &sourceuser->GetFullHost(); return NULL; } /** Get the source User. * This shouldn't be used for serialization, use GetSource() for that. * @return User pointer if the message has a source user, NULL otherwise. */ User* GetSourceUser() const { return sourceuser; } /** Set the source of this message to a User. * See the one parameter constructor for a more detailed description. * @param Sourceuser User to set as source. */ void SetSourceUser(User* Sourceuser) { sourceuser = Sourceuser; sourcestr = NULL; } /** Set the source string and optionally source user. * See the two parameter constructor for a more detailed description. * @param Sourcestr String source, to be used for serialization purposes. Must remain valid as long * as this object is alive. * @param Sourceuser Source user to set, optional. */ void SetSource(const std::string& Sourcestr, User* Sourceuser = NULL) { sourcestr = &Sourcestr; sourceuser = Sourceuser; } /** Copy the source from a MessageSource object. * @param other MessageSource object to copy from. */ void SetSource(const MessageSource& other) { sourcestr = other.sourcestr; sourceuser = other.sourceuser; } }; /** Outgoing client protocol message. * Represents a high level client protocol message which is turned into raw or wire format * by a Serializer. Messages can be serialized into different format by different serializers. * * Messages are created on demand and are disposed of after they have been sent. * * All messages have a command name, a list of parameters and a map of tags, the last two can be empty. * They also always have a source, see class MessageSource. */ class ClientProtocol::Message : public ClientProtocol::MessageSource { public: /** Contains information required to identify a specific version of a serialized message. */ struct SerializedInfo { const Serializer* serializer; TagSelection tagwl; /** Constructor. * @param Ser Serializer used to serialize the message. * @param Tagwl Tag whitelist used to serialize the message. */ SerializedInfo(const Serializer* Ser, const TagSelection& Tagwl) : serializer(Ser) , tagwl(Tagwl) { } /** Check if a SerializedInfo object is equivalent to this object. * @param other Other SerializedInfo object. * @return True if other is equivalent to this object, false otherwise. */ bool operator==(const SerializedInfo& other) const { return ((serializer == other.serializer) && (tagwl == other.tagwl)); } }; class Param { const std::string* ptr; insp::aligned_storage<std::string> str; bool owned; void InitFrom(const Param& other) { owned = other.owned; if (owned) new(str) std::string(*other.str); else ptr = other.ptr; } public: operator const std::string&() const { return (owned ? *str : *ptr); } Param() : ptr(NULL) , owned(false) { } Param(const std::string& s) : ptr(&s) , owned(false) { } Param(int, const char* s) : owned(true) { new(str) std::string(s); } Param(int, const std::string& s) : owned(true) { new(str) std::string(s); } Param(const Param& other) { InitFrom(other); } ~Param() { using std::string; if (owned) str->~string(); } Param& operator=(const Param& other) { if (&other == this) return *this; using std::string; if (owned) str->~string(); InitFrom(other); return *this; } bool IsOwned() const { return owned; } }; typedef std::vector<Param> ParamList; private: typedef std::vector<std::pair<SerializedInfo, SerializedMessage> > SerializedList; ParamList params; TagMap tags; std::string command; bool msginit_done; mutable SerializedList serlist; bool sideeffect; protected: /** Set command string. * @param cmd Command string to set. */ void SetCommand(const char* cmd) { command.clear(); if (cmd) command = cmd; } public: /** Constructor. * @param cmd Command name, e.g. "JOIN", "NICK". May be NULL. If NULL, the command must be set * with SetCommand() before the message is serialized. * @param Sourceuser See the one parameter constructor of MessageSource for description. */ Message(const char* cmd, User* Sourceuser = NULL) : ClientProtocol::MessageSource(Sourceuser) , command(cmd ? cmd : std::string()) , msginit_done(false) , sideeffect(false) { params.reserve(8); serlist.reserve(8); } /** Constructor. * @param cmd Command name, e.g. "JOIN", "NICK". May be NULL. If NULL, the command must be set * with SetCommand() before the message is serialized. * @param Sourcestr See the two parameter constructor of MessageSource for description. * Must remain valid as long as this object is alive. * @param Sourceuser See the two parameter constructor of MessageSource for description. */ Message(const char* cmd, const std::string& Sourcestr, User* Sourceuser = NULL) : ClientProtocol::MessageSource(Sourcestr, Sourceuser) , command(cmd ? cmd : std::string()) , msginit_done(false) , sideeffect(false) { params.reserve(8); serlist.reserve(8); } /** Get the parameters of this message. * @return List of parameters. */ const ParamList& GetParams() const { return params; } /** Get a map of tags attached to this message. * The map contains the tag providers that attached the tag to the message. * @return Map of tags. */ const TagMap& GetTags() const { return tags; } /** Get the command string. * @return Command string, e.g. "NICK", "001". */ const char* GetCommand() const { return command.c_str(); } /** Add a parameter to the parameter list. * @param str String to add, will be copied. */ void PushParam(const char* str) { params.push_back(Param(0, str)); } /** Add a parameter to the parameter list. * @param str String to add, will be copied. */ void PushParam(const std::string& str) { params.push_back(Param(0, str)); } /** Add a parameter to the parameter list. * @param str String to add. * The string will NOT be copied, it must remain alive until ClearParams() is called or until the object is destroyed. */ void PushParamRef(const std::string& str) { params.push_back(str); } /** Add a placeholder parameter to the parameter list. * Placeholder parameters must be filled in later with actual parameters using ReplaceParam() or ReplaceParamRef(). */ void PushParamPlaceholder() { params.push_back(Param()); } /** Replace a parameter or a placeholder that is already in the parameter list. * @param index Index of the parameter to replace. Must be less than GetParams().size(). * @param str String to replace the parameter or placeholder with, will be copied. */ void ReplaceParam(unsigned int index, const char* str) { params[index] = Param(0, str); } /** Replace a parameter or a placeholder that is already in the parameter list. * @param index Index of the parameter to replace. Must be less than GetParams().size(). * @param str String to replace the parameter or placeholder with, will be copied. */ void ReplaceParam(unsigned int index, const std::string& str) { params[index] = Param(0, str); } /** Replace a parameter or a placeholder that is already in the parameter list. * @param index Index of the parameter to replace. Must be less than GetParams().size(). * @param str String to replace the parameter or placeholder with. * The string will NOT be copied, it must remain alive until ClearParams() is called or until the object is destroyed. */ void ReplaceParamRef(unsigned int index, const std::string& str) { params[index] = Param(str); } /** Add a tag. * @param tagname Raw name of the tag to use in the protocol. * @param tagprov Provider of the tag. * @param val Tag value. If empty no value will be sent with the tag. * @param tagdata Tag provider specific data, will be passed to MessageTagProvider::ShouldSendTag(). Optional, defaults to NULL. */ void AddTag(const std::string& tagname, MessageTagProvider* tagprov, const std::string& val, void* tagdata = NULL) { tags.insert(std::make_pair(tagname, MessageTagData(tagprov, val, tagdata))); } /** Add all tags in a TagMap to the tags in this message. Existing tags will not be overwritten. * @param newtags New tags to add. */ void AddTags(const ClientProtocol::TagMap& newtags) { tags.insert(newtags.begin(), newtags.end()); } /** Get the message in a serialized form. * @param serializeinfo Information about which exact serialized form of the message is the caller asking for * (which serializer to use and which tags to include). * @return Serialized message according to serializeinfo. The returned reference remains valid until the * next call to this method. */ const SerializedMessage& GetSerialized(const SerializedInfo& serializeinfo) const; /** Clear the parameter list and tags. */ void ClearParams() { msginit_done = false; params.clear(); tags.clear(); InvalidateCache(); } /** Remove all serialized messages. * If a parameter is changed after the message has been sent at least once, this method must be called before * serializing the message again to ensure the cache won't contain stale data. */ void InvalidateCache() { serlist.clear(); } void CopyAll() { size_t j = 0; for (ParamList::iterator i = params.begin(); i != params.end(); ++i, j++) { Param& curr = *i; if (!curr.IsOwned()) ReplaceParam(j, curr); } } void SetSideEffect(bool Sideeffect) { sideeffect = Sideeffect; } bool IsSideEffect() const { return sideeffect; } friend class Serializer; }; /** Client protocol event class. * All messages sent to a user must be part of an event. A single event may result in more than one protocol message * being sent, for example a join event may result in a JOIN and a MODE protocol message sent to members of the channel * if the joining user has some prefix modes set. * * Event hooks attached to a specific event can alter the messages sent for that event. */ class ClientProtocol::Event { EventProvider* event; Message* initialmsg; const MessageList* initialmsglist; bool eventinit_done; public: /** Constructor. * @param protoeventprov Protocol event provider the event is an instance of. */ Event(EventProvider& protoeventprov) : event(&protoeventprov) , initialmsg(NULL) , initialmsglist(NULL) , eventinit_done(false) { } /** Constructor. * @param protoeventprov Protocol event provider the event is an instance of. * @param msg Message to include in this event by default. */ Event(EventProvider& protoeventprov, ClientProtocol::Message& msg) : event(&protoeventprov) , initialmsg(&msg) , initialmsglist(NULL) , eventinit_done(false) { } /** Set a single message as the initial message in the event. * Modules may alter this later. */ void SetMessage(Message* msg) { initialmsg = msg; initialmsglist = NULL; } /** Set a list of messages as the initial messages in the event. * Modules may alter this later. */ void SetMessageList(const MessageList& msglist) { initialmsg = NULL; initialmsglist = &msglist; } /** Get a list of messages to send to a user. * The exact messages sent to a user are determined by the initial message(s) set and hooks. * @param user User to get the messages for. * @param messagelist List to fill in with messages to send to the user for the event */ void GetMessagesForUser(LocalUser* user, MessageList& messagelist); }; /** Base class for message tag providers. * All message tags belong to a message tag provider. Message tag providers can populate messages * with tags before the message is sent and they have the job of determining whether a user should * get a message tag or be allowed to send one. */ class ClientProtocol::MessageTagProvider : public Events::ModuleEventListener { public: /** Constructor. * @param mod Module owning the provider. */ MessageTagProvider(Module* mod) : Events::ModuleEventListener(mod, "event/messagetag") { } /** Called when a message is ready to be sent to give the tag provider a chance to add tags to the message. * To add tags call Message::AddTag(). If the provided tag or tags have been added already elsewhere or if the * provider doesn't want its tag(s) to be on the message, the implementation doesn't have to do anything special. * The default implementation does nothing. * @param msg Message to be populated with tags. */ virtual void OnPopulateTags(ClientProtocol::Message& msg) { } /** Called for each tag that the server receives from a client in a message. * @param user User that sent the tag. * @param tagname Name of the tag. * @param tagvalue Value of the tag, empty string if the tag has no value. May be modified. * @return MOD_RES_ALLOW to accept the tag with the value in 'value', MOD_RES_DENY to reject the tag and act as if it wasn't sent, * MOD_RES_PASSTHRU to make no decision. If no hooks accept a tag, the tag is rejected. * The default implementation returns MOD_RES_PASSTHRU. */ virtual ModResult OnProcessTag(User* user, const std::string& tagname, std::string& tagvalue) { return MOD_RES_PASSTHRU; } /** Called whenever a user is about to receive a message that has a tag attached which is provided by this provider * to determine whether or not the user should get the tag. * @param user User in question. * @param tagdata Tag in question. * @return True if the tag should be sent to the user, false otherwise. */ virtual bool ShouldSendTag(LocalUser* user, const MessageTagData& tagdata) = 0; }; /** Base class for client protocol event hooks. * A protocol event hook is attached to a single event type. It has the ability to alter or block messages * sent to users which belong to the event the hook is attached to. */ class ClientProtocol::EventHook : public Events::ModuleEventListener { public: static std::string GetEventName(const std::string& name) { return "event/protoevent_" + name; } /** Constructor. * @param mod Owner of the hook. * @param name Name of the event to hook. * @param priority Priority of the hook. Determines the order in which hooks for the same event get called. * Optional. */ EventHook(Module* mod, const std::string& name, unsigned int priority = Events::ModuleEventListener::DefaultPriority) : Events::ModuleEventListener(mod, GetEventName(name), priority) { } /** Called exactly once before an event is sent to any user. * The default implementation doesn't do anything. * @param ev Event being sent to one or more users. */ virtual void OnEventInit(const ClientProtocol::Event& ev) { } /** Called for each user that may receive the event. * The hook may alter the messages sent to the user and decide whether further hooks should be executed. * @param user User the message list is being prepared to be sent to. * @param ev Event associated with the messages. * @param messagelist List of messages to send to the user. The hook can alter this in any way it sees fit, for example it can replace messages, * add new messages, etc. The list must not be empty when the method returns. * @return MOD_RES_PASSTHRU to run hooks after the called hook or if no hooks are after the called hook, send the messages in messagelist to the user. * MOD_RES_DENY to not send any messages to the user and to not run other hooks, * MOD_RES_ALLOW to send the messages in messagelist to the user and to not run other hooks. */ virtual ModResult OnPreEventSend(LocalUser* user, const ClientProtocol::Event& ev, ClientProtocol::MessageList& messagelist) = 0; }; /** Event provider for client protocol events. * Protocol event hooks can be attached to the instances of these providers. The core has event * providers for most common IRC events defined in RFC1459. */ class ClientProtocol::EventProvider : public Events::ModuleEventProvider { public: /** Constructor. * @param Mod Module that owns the event provider. * @param eventname Name of the event this provider is for, e.g. "JOIN", "PART", "NUMERIC". * Should match command name if applicable. */ EventProvider(Module* Mod, const std::string& eventname) : Events::ModuleEventProvider(Mod, ClientProtocol::EventHook::GetEventName(eventname)) { } }; /** Commonly used client protocol events. * Available via InspIRCd::GetRFCEvents(). */ struct ClientProtocol::RFCEvents { EventProvider numeric; EventProvider join; EventProvider part; EventProvider kick; EventProvider quit; EventProvider nick; EventProvider mode; EventProvider topic; EventProvider privmsg; EventProvider invite; EventProvider ping; EventProvider pong; EventProvider error; RFCEvents() : numeric(NULL, "NUMERIC") , join(NULL, "JOIN") , part(NULL, "PART") , kick(NULL, "KICK") , quit(NULL, "QUIT") , nick(NULL, "NICK") , mode(NULL, "MODE") , topic(NULL, "TOPIC") , privmsg(NULL, "PRIVMSG") , invite(NULL, "INVITE") , ping(NULL, "PING") , pong(NULL, "PONG") , error(NULL, "ERROR") { } }; /** Base class for client protocol serializers. * A serializer has to implement serialization and parsing of protocol messages to/from wire format. */ class CoreExport ClientProtocol::Serializer : public DataProvider { Events::ModuleEventProvider evprov; /** Make a white list containing which tags a user should get. * @param user User in question. * @param tagmap Tag map that contains all possible tags. * @return Whitelist of tags to send to the user. */ TagSelection MakeTagWhitelist(LocalUser* user, const TagMap& tagmap) const; public: /** Constructor. * @param mod Module owning the serializer. * @param Name Name of the serializer, e.g. "rfc". */ Serializer(Module* mod, const char* Name); /** Handle a tag in a message being parsed. Call this method for each parsed tag. * @param user User sending the tag. * @param tagname Name of the tag. * @param tagvalue Tag value, may be empty. * @param tags TagMap to place the tag into, if it gets accepted. * @return True if no error occured, false if the tag name is invalid or if this tag already exists. */ bool HandleTag(LocalUser* user, const std::string& tagname, std::string& tagvalue, TagMap& tags) const; /** Serialize a message for a user. * @param user User to serialize the message for. * @param msg Message to serialize. * @return Raw serialized message, only containing the appropriate tags for the user. * The reference is guaranteed to be valid as long as the Message object is alive and until the same * Message is serialized for another user. */ const SerializedMessage& SerializeForUser(LocalUser* user, Message& msg); /** Serialize a high level protocol message into wire format. * @param msg High level message to serialize. Contains all necessary information about the message, including all possible tags. * @param tagwl Message tags to include in the serialized message. Tags attached to the message but not included in the whitelist must not * appear in the output. This is because each user may get a different set of tags for the same message. * @return Protocol message in wire format. Must contain message delimiter as well, if any (e.g. CRLF for RFC1459). */ virtual std::string Serialize(const Message& msg, const TagSelection& tagwl) const = 0; /** Parse a protocol message from wire format. * @param user Source of the message. * @param line Raw protocol message. * @param parseoutput Output of the parser. * @return True if the message was parsed successfully into parseoutput and should be processed, false to drop the message. */ virtual bool Parse(LocalUser* user, const std::string& line, ParseOutput& parseoutput) = 0; }; inline ClientProtocol::MessageTagData::MessageTagData(MessageTagProvider* prov, const std::string& val, void* data) : tagprov(prov) , value(val) , provdata(data) { } ���������������������������������������������inspircd-3.4.0/include/clientprotocolevent.h��������������������������������������������������������0000664�0000000�0000000�00000005036�13554550454�0021245�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * InspIRCd -- Internet Relay Chat Daemon * * Copyright (C) 2016 Attila Molnar <attilamolnar@hush.com> * * This file is part of InspIRCd. InspIRCd is free software: you can * redistribute it and/or modify it under the terms of the GNU General Public * License as published by the Free Software Foundation, version 2. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once namespace ClientProtocol { namespace Events { struct Join; class Mode; } } struct ClientProtocol::Events::Join : public ClientProtocol::Messages::Join, public ClientProtocol::Event { Join() : ClientProtocol::Event(ServerInstance->GetRFCEvents().join, *this) { } Join(Membership* Memb) : ClientProtocol::Messages::Join(Memb) , ClientProtocol::Event(ServerInstance->GetRFCEvents().join, *this) { } Join(Membership* Memb, const std::string& Sourcestr) : ClientProtocol::Messages::Join(Memb, Sourcestr) , ClientProtocol::Event(ServerInstance->GetRFCEvents().join, *this) { } }; class ClientProtocol::Events::Mode : public ClientProtocol::Event { std::list<ClientProtocol::Messages::Mode> modelist; std::vector<Message*> modemsgplist; const Modes::ChangeList& modechanges; public: static void BuildMessages(User* source, Channel* Chantarget, User* Usertarget, const Modes::ChangeList& changelist, std::list<ClientProtocol::Messages::Mode>& modelist, std::vector<Message*>& modemsgplist) { // Build as many MODEs as necessary for (Modes::ChangeList::List::const_iterator i = changelist.getlist().begin(); i != changelist.getlist().end(); i = modelist.back().GetEndIterator()) { modelist.push_back(ClientProtocol::Messages::Mode(source, Chantarget, Usertarget, changelist, i)); modemsgplist.push_back(&modelist.back()); } } Mode(User* source, Channel* Chantarget, User* Usertarget, const Modes::ChangeList& changelist) : ClientProtocol::Event(ServerInstance->GetRFCEvents().mode) , modechanges(changelist) { BuildMessages(source, Chantarget, Usertarget, changelist, modelist, modemsgplist); SetMessageList(modemsgplist); } const Modes::ChangeList& GetChangeList() const { return modechanges; } const std::list<ClientProtocol::Messages::Mode>& GetMessages() const { return modelist; } }; ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/include/clientprotocolmsg.h����������������������������������������������������������0000664�0000000�0000000�00000051537�13554550454�0020721�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * InspIRCd -- Internet Relay Chat Daemon * * Copyright (C) 2016 Attila Molnar <attilamolnar@hush.com> * * This file is part of InspIRCd. InspIRCd is free software: you can * redistribute it and/or modify it under the terms of the GNU General Public * License as published by the Free Software Foundation, version 2. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once namespace ClientProtocol { namespace Messages { class Numeric; class Join; struct Part; struct Kick; struct Quit; struct Nick; class Mode; struct Topic; class Privmsg; struct Invite; struct Ping; struct Pong; struct Error; } } /** Numeric message. * Doesn't have a fixed command name, it's always a 3 digit number padded with zeroes if necessary. * The first parameter is the target of the numeric which is almost always the nick of the user * the numeric will be sent to. */ class ClientProtocol::Messages::Numeric : public ClientProtocol::Message { char numericstr[4]; void InitCommand(unsigned int number) { snprintf(numericstr, sizeof(numericstr), "%03u", number); SetCommand(numericstr); } void InitFromNumeric(const ::Numeric::Numeric& numeric) { InitCommand(numeric.GetNumeric()); for (std::vector<std::string>::const_iterator i = numeric.GetParams().begin(); i != numeric.GetParams().end(); ++i) PushParamRef(*i); } public: /** Constructor, target is a User. * @param num Numeric object to send. Must remain valid as long as this object is alive and must not be modified. * @param user User to send the numeric to. May be unregistered, must remain valid as long as this object is alive. */ Numeric(const ::Numeric::Numeric& num, User* user) : ClientProtocol::Message(NULL, (num.GetServer() ? num.GetServer()->GetName() : ServerInstance->Config->ServerName)) { if (user->registered & REG_NICK) PushParamRef(user->nick); else PushParam("*"); InitFromNumeric(num); } /** Constructor, target is a string. * @param num Numeric object to send. Must remain valid as long as this object is alive and must not be modified. * @param target Target string, must stay valid as long as this object is alive. */ Numeric(const ::Numeric::Numeric& num, const std::string& target) : ClientProtocol::Message(NULL, (num.GetServer() ? num.GetServer()->GetName() : ServerInstance->Config->ServerName)) { PushParamRef(target); InitFromNumeric(num); } /** Constructor. Only the numeric number has to be specified. * @param num Numeric number. */ Numeric(unsigned int num) : ClientProtocol::Message(NULL, ServerInstance->Config->ServerName) { InitCommand(num); PushParam("*"); } }; /** JOIN message. * Sent when a user joins a channel. */ class ClientProtocol::Messages::Join : public ClientProtocol::Message { Membership* memb; public: /** Constructor. Does not populate parameters, call SetParams() before sending the message. */ Join() : ClientProtocol::Message("JOIN") , memb(NULL) { } /** Constructor. * @param Memb Membership of the joining user. */ Join(Membership* Memb) : ClientProtocol::Message("JOIN", Memb->user) { SetParams(Memb); } /** Constructor. * @param Memb Membership of the joining user. * @param sourcestrref Message source string, must remain valid as long as this object is alive. */ Join(Membership* Memb, const std::string& sourcestrref) : ClientProtocol::Message("JOIN", sourcestrref, Memb->user) { SetParams(Memb); } /** Populate parameters from a Membership * @param Memb Membership of the joining user. */ void SetParams(Membership* Memb) { memb = Memb; PushParamRef(memb->chan->name); } /** Get the Membership of the joining user. * @return Membership of the joining user. */ Membership* GetMember() const { return memb; } }; /** PART message. * Sent when a user parts a channel. */ struct ClientProtocol::Messages::Part : public ClientProtocol::Message { /** Constructor. * @param memb Member parting. * @param reason Part reason, may be empty. If non-empty, must remain valid as long as this object is alive. */ Part(Membership* memb, const std::string& reason) : ClientProtocol::Message("PART", memb->user) { PushParamRef(memb->chan->name); if (!reason.empty()) PushParamRef(reason); } }; /** KICK message. * Sent when a user is kicked from a channel. */ struct ClientProtocol::Messages::Kick : public ClientProtocol::Message { /** Constructor. * @param source User that does the kick. * @param memb Membership of the user being kicked. * @param reason Kick reason. Must remain valid as long as this object is alive. */ Kick(User* source, Membership* memb, const std::string& reason) : ClientProtocol::Message("KICK", source) { PushParamRef(memb->chan->name); PushParamRef(memb->user->nick); PushParamRef(reason); } }; /** QUIT message. * Sent when a user quits. */ struct ClientProtocol::Messages::Quit : public ClientProtocol::Message { /** Constructor. * @param source User quitting. * @param reason Quit reason, may be empty. Must remain valid as long as this object is alive. */ Quit(User* source, const std::string& reason) : ClientProtocol::Message("QUIT", source) { if (!reason.empty()) PushParamRef(reason); } }; /** NICK message. * Sent when a user changes their nickname. */ struct ClientProtocol::Messages::Nick : public ClientProtocol::Message { /** Constructor. * @param source User changing nicks. * @param newnick New nickname. Must remain valid as long as this object is alive. */ Nick(User* source, const std::string& newnick) : ClientProtocol::Message("NICK", source) { PushParamRef(newnick); } }; /** MODE message. * Sent when modes are changed on a user or channel. */ class ClientProtocol::Messages::Mode : public ClientProtocol::Message { Channel* chantarget; User* usertarget; Modes::ChangeList::List::const_iterator beginit; Modes::ChangeList::List::const_iterator lastit; /** Convert a range of a mode change list to mode letters and '+', '-' symbols. * @param list Mode change list. * @param maxlinelen Maximum output length. * @param beginit Iterator to the first element in 'list' to process. * @param lastit Iterator which is set to the first element not processed due to length limitations by the method. */ static std::string ToModeLetters(const Modes::ChangeList::List& list, std::string::size_type maxlinelen, Modes::ChangeList::List::const_iterator beginit, Modes::ChangeList::List::const_iterator& lastit) { std::string ret; std::string::size_type paramlength = 0; char output_pm = '\0'; // current output state, '+' or '-' Modes::ChangeList::List::const_iterator i; for (i = beginit; i != list.end(); ++i) { const Modes::Change& item = *i; const char needed_pm = (item.adding ? '+' : '-'); if (needed_pm != output_pm) { output_pm = needed_pm; ret.push_back(output_pm); } if (!item.param.empty()) paramlength += item.param.length() + 1; if (ret.length() + 1 + paramlength > maxlinelen) { // Mode sequence is getting too long const char c = *ret.rbegin(); if ((c == '+') || (c == '-')) ret.erase(ret.size()-1); break; } ret.push_back(item.mh->GetModeChar()); } lastit = i; return ret; } /** Push mode parameters for modes that have one, starting at beginit to lastit (not including lastit). */ void PushModeParams() { for (Modes::ChangeList::List::const_iterator i = beginit; i != lastit; ++i) { const Modes::Change& item = *i; if (!item.param.empty()) PushParamRef(item.param); } } public: /** Convert an entire mode change list into mode letters and '+' and '-' characters. * @param changelist Mode change list to convert into mode letters. * @return Mode letters. */ static std::string ToModeLetters(const Modes::ChangeList& changelist) { // TODO: This assumes that std::string::max_size() >= UINT_MAX Modes::ChangeList::List::const_iterator dummy; return ToModeLetters(changelist.getlist(), UINT_MAX, changelist.getlist().begin(), dummy); } /** Constructor, populate parameters starting from a given position in a mode change list. * @param source User doing the mode change. * @param Chantarget Channel target of the mode change. May be NULL if Usertarget is non-NULL. * @param Usertarget User target of the mode change. May be NULL if Chantarget is non-NULL. * @param changelist Mode change list. Must remain valid and unchanged as long as this object is alive or until the next SetParams() call. * @param beginiter Starting position of mode changes in 'changelist'. */ Mode(User* source, Channel* Chantarget, User* Usertarget, const Modes::ChangeList& changelist, Modes::ChangeList::List::const_iterator beginiter) : ClientProtocol::Message("MODE", source) , chantarget(Chantarget) , usertarget(Usertarget) , beginit(beginiter) { PushParamRef(GetStrTarget()); PushParam(ToModeLetters(changelist.getlist(), 450, beginit, lastit)); PushModeParams(); } /** Constructor, populate parameters starting from the beginning of a mode change list. * @param source User doing the mode change. * @param Chantarget Channel target of the mode change. May be NULL if Usertarget is non-NULL. * @param Usertarget User target of the mode change. May be NULL if Chantarget is non-NULL. * @param changelist Mode change list. Must remain valid and unchanged as long as this object is alive or until the next SetParams() call. */ Mode(User* source, Channel* Chantarget, User* Usertarget, const Modes::ChangeList& changelist) : ClientProtocol::Message("MODE", source) , chantarget(Chantarget) , usertarget(Usertarget) , beginit(changelist.getlist().begin()) { PushParamRef(GetStrTarget()); PushParam(ToModeLetters(changelist.getlist(), 450, beginit, lastit)); PushModeParams(); } /** Constructor. Does not populate parameters, call SetParams() before sending the message. * The message source is set to the local server. */ Mode() : ClientProtocol::Message("MODE", ServerInstance->FakeClient) , chantarget(NULL) , usertarget(NULL) { } /** Set parameters * @param Chantarget Channel target of the mode change. May be NULL if Usertarget is non-NULL. * @param Usertarget User target of the mode change. May be NULL if Chantarget is non-NULL. * @param changelist Mode change list. Must remain valid and unchanged as long as this object is alive or until the next SetParams() call. */ void SetParams(Channel* Chantarget, User* Usertarget, const Modes::ChangeList& changelist) { ClearParams(); chantarget = Chantarget; usertarget = Usertarget; beginit = changelist.getlist().begin(); PushParamRef(GetStrTarget()); PushParam(ToModeLetters(changelist.getlist(), 450, beginit, lastit)); PushModeParams(); } /** Get first mode change included in this MODE message. * @return Iterator to the first mode change that is included in this MODE message. */ Modes::ChangeList::List::const_iterator GetBeginIterator() const { return beginit; } /** Get first mode change not included in this MODE message. * @return Iterator to the first mode change that is not included in this MODE message. */ Modes::ChangeList::List::const_iterator GetEndIterator() const { return lastit; } /** Get mode change target as a string. * This is the name of the channel if the mode change targets a channel or the nickname of the user * if the target is a user. * @return Name of target as a string. */ const std::string& GetStrTarget() const { return (chantarget ? chantarget->name : usertarget->nick); } /** Get user target. * @return User target or NULL if the mode change targets a channel. */ User* GetUserTarget() const { return usertarget; } /** Get channel target. * @return Channel target or NULL if the mode change targets a user. */ Channel* GetChanTarget() const { return chantarget; } }; /** TOPIC message. */ struct ClientProtocol::Messages::Topic : public ClientProtocol::Message { /** Constructor. * @param source User changing the topic. * @param chan Channel the topic is being changed on. * @param newtopic New topic. May be empty, must remain valid as long as this object is alive. */ Topic(User* source, const Channel* chan, const std::string& newtopic) : ClientProtocol::Message("TOPIC", source) { PushParamRef(chan->name); PushParamRef(newtopic); } }; /** PRIVMSG and NOTICE message. */ class ClientProtocol::Messages::Privmsg : public ClientProtocol::Message { void PushTargetChan(char status, const Channel* targetchan) { if (status) { std::string rawtarget(1, status); rawtarget.append(targetchan->name); PushParam(rawtarget); } else { PushParamRef(targetchan->name); } } void PushTargetUser(const User* targetuser) { if (targetuser->registered & REG_NICK) PushParamRef(targetuser->nick); else PushParam("*"); } public: /** Used to differentiate constructors that copy the text from constructors that do not. */ enum NoCopy { nocopy }; /** Get command name from MessageType. * @param mt Message type to get command name for. * @return Command name for the message type. */ static const char* CommandStrFromMsgType(MessageType mt) { return ((mt == MSG_PRIVMSG) ? "PRIVMSG" : "NOTICE"); } /** Constructor, user source, string target, copies text. * @param source Source user. * @param target Privmsg target string. * @param text Privmsg text, will be copied. * @param mt Message type. */ Privmsg(User* source, const std::string& target, const std::string& text, MessageType mt = MSG_PRIVMSG) : ClientProtocol::Message(CommandStrFromMsgType(mt), source) { PushParam(target); PushParam(text); } /** Constructor, user source, user target, copies text. * @param source Source user. * @param targetchan Target channel. * @param text Privmsg text, will be copied. * @param mt Message type. * @param status Prefix character for status messages. If non-zero the message is a status message. Optional, defaults to 0. */ Privmsg(User* source, const Channel* targetchan, const std::string& text, MessageType mt = MSG_PRIVMSG, char status = 0) : ClientProtocol::Message(CommandStrFromMsgType(mt), source) { PushTargetChan(status, targetchan); PushParam(text); } /** Constructor, user source, user target, copies text. * @param source Source user. * @param targetuser Target user. * @param text Privmsg text, will be copied. * @param mt Message type. */ Privmsg(User* source, const User* targetuser, const std::string& text, MessageType mt = MSG_PRIVMSG) : ClientProtocol::Message(CommandStrFromMsgType(mt), source) { PushTargetUser(targetuser); PushParam(text); } /** Constructor, string source, string target, copies text. * @param source Source user. * @param target Target string. * @param text Privmsg text, will be copied. * @param mt Message type. */ Privmsg(const std::string& source, const std::string& target, const std::string& text, MessageType mt = MSG_PRIVMSG) : ClientProtocol::Message(CommandStrFromMsgType(mt), source) { PushParam(target); PushParam(text); } /** Constructor, string source, channel target, copies text. * @param source Source string. * @param targetchan Target channel. * @param text Privmsg text, will be copied. * @param status Prefix character for status messages. If non-zero the message is a status message. Optional, defaults to 0. * @param mt Message type. */ Privmsg(const std::string& source, const Channel* targetchan, const std::string& text, MessageType mt = MSG_PRIVMSG, char status = 0) : ClientProtocol::Message(CommandStrFromMsgType(mt), source) { PushTargetChan(status, targetchan); PushParam(text); } /** Constructor, string source, user target, copies text. * @param source Source string. * @param targetuser Target user. * @param text Privmsg text, will be copied. * @param mt Message type. */ Privmsg(const std::string& source, const User* targetuser, const std::string& text, MessageType mt = MSG_PRIVMSG) : ClientProtocol::Message(CommandStrFromMsgType(mt), source) { PushTargetUser(targetuser); PushParam(text); } /** Constructor, user source, string target, copies text. * @param source Source user. * @param target Target string. * @param text Privmsg text, will not be copied. * @param mt Message type. */ Privmsg(NoCopy, User* source, const std::string& target, const std::string& text, MessageType mt = MSG_PRIVMSG) : ClientProtocol::Message(CommandStrFromMsgType(mt), source) { PushParam(target); PushParamRef(text); } /** Constructor, user source, channel target, does not copy text. * @param source Source user. * @param targetchan Target channel. * @param text Privmsg text, will not be copied. * @param status Prefix character for status messages. If non-zero the message is a status message. Optional, defaults to 0. * @param mt Message type. */ Privmsg(NoCopy, User* source, const Channel* targetchan, const std::string& text, MessageType mt = MSG_PRIVMSG, char status = 0) : ClientProtocol::Message(CommandStrFromMsgType(mt), source) { PushTargetChan(status, targetchan); PushParamRef(text); } /** Constructor, user source, user target, does not copy text. * @param source Source user. * @param targetuser Target user. * @param text Privmsg text, will not be copied. * @param mt Message type. */ Privmsg(NoCopy, User* source, const User* targetuser, const std::string& text, MessageType mt = MSG_PRIVMSG) : ClientProtocol::Message(CommandStrFromMsgType(mt), source) { PushTargetUser(targetuser); PushParamRef(text); } /** Constructor, string source, string target, does not copy text. * @param source Source string. * @param target Target string. * @param text Privmsg text, will not be copied. * @param mt Message type. */ Privmsg(NoCopy, const std::string& source, const std::string& target, const std::string& text, MessageType mt = MSG_PRIVMSG) : ClientProtocol::Message(CommandStrFromMsgType(mt), source) { PushParam(target); PushParamRef(text); } /** Constructor, string source, channel target, does not copy text. * @param source Source string. * @param targetchan Target channel. * @param text Privmsg text, will not be copied. * @param status Prefix character for status messages. If non-zero the message is a status message. Optional, defaults to 0. * @param mt Message type. */ Privmsg(NoCopy, const std::string& source, const Channel* targetchan, const std::string& text, MessageType mt = MSG_PRIVMSG, char status = 0) : ClientProtocol::Message(CommandStrFromMsgType(mt), source) { PushTargetChan(status, targetchan); PushParamRef(text); } /** Constructor, string source, user target, does not copy text. * @param source Source string. * @param targetuser Target user. * @param text Privmsg text, will not be copied. * @param mt Message type. */ Privmsg(NoCopy, const std::string& source, const User* targetuser, const std::string& text, MessageType mt = MSG_PRIVMSG) : ClientProtocol::Message(CommandStrFromMsgType(mt), source) { PushTargetUser(targetuser); PushParamRef(text); } }; /** INVITE message. * Sent when a user is invited to join a channel. */ struct ClientProtocol::Messages::Invite : public ClientProtocol::Message { /** Constructor. * @param source User inviting the target user. * @param target User being invited by source. * @param chan Channel the target user is being invited to. */ Invite(User* source, User* target, Channel* chan) : ClientProtocol::Message("INVITE", source) { PushParamRef(target->nick); PushParamRef(chan->name); } }; /** PING message. * Used to check if a connection is still alive. */ struct ClientProtocol::Messages::Ping : public ClientProtocol::Message { /** Constructor. * The ping cookie is the name of the local server. */ Ping() : ClientProtocol::Message("PING") { PushParamRef(ServerInstance->Config->ServerName); } /** Constructor. * @param cookie Ping cookie. Must remain valid as long as this object is alive. */ Ping(const std::string& cookie) : ClientProtocol::Message("PING") { PushParamRef(cookie); } }; /** PONG message. * Sent as a reply to PING. */ struct ClientProtocol::Messages::Pong : public ClientProtocol::Message { /** Constructor. * @param cookie Ping cookie. Must remain valid as long as this object is alive. */ Pong(const std::string& cookie) : ClientProtocol::Message("PONG", ServerInstance->Config->ServerName) { PushParamRef(ServerInstance->Config->ServerName); PushParamRef(cookie); } }; /** ERROR message. * Sent to clients upon disconnection. */ struct ClientProtocol::Messages::Error : public ClientProtocol::Message { /** Constructor. * @param text Error text. */ Error(const std::string& text) : ClientProtocol::Message("ERROR") { PushParam(text); } }; �����������������������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/include/command_parse.h��������������������������������������������������������������0000664�0000000�0000000�00000017113�13554550454�0017752�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * InspIRCd -- Internet Relay Chat Daemon * * Copyright (C) 2009-2010 Daniel De Graaf <danieldg@inspircd.org> * Copyright (C) 2007 Robin Burchell <robin+git@viroteck.net> * Copyright (C) 2007 Dennis Friis <peavey@inspircd.org> * Copyright (C) 2005-2007 Craig Edwards <craigedwards@brainbox.cc> * * This file is part of InspIRCd. InspIRCd is free software: you can * redistribute it and/or modify it under the terms of the GNU General Public * License as published by the Free Software Foundation, version 2. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once /** This class handles command management and parsing. * It allows you to add and remove commands from the map, * call command handlers by name, and chop up comma seperated * parameters into multiple calls. */ class CoreExport CommandParser { public: typedef TR1NS::unordered_map<std::string, Command*, irc::insensitive, irc::StrHashComp> CommandMap; private: /** Process a command from a user. * @param user The user to parse the command for. * @param command The name of the command. * @param parameters The parameters to the command. */ void ProcessCommand(LocalUser* user, std::string& command, CommandBase::Params& parameters); /** Command list, a hash_map of command names to Command* */ CommandMap cmdlist; public: /** Default constructor. */ CommandParser(); /** Get a command name -> Command* map containing all client to server commands * @return A map of command handlers keyed by command names */ const CommandMap& GetCommands() const { return cmdlist; } /** Calls the handler for a given command. * @param commandname The command to find. This should be in uppercase. * @param parameters Parameter list * @param user The user to call the handler on behalf of * @param cmd If non-NULL and the command was executed it is set to the command handler, * otherwise it isn't written to. * @return This method will return CMD_SUCCESS if the command handler was found and called, * and the command completeld successfully. It will return CMD_FAILURE if the command handler was found * and called, but the command did not complete successfully, and it will return CMD_INVALID if the * command simply did not exist at all or the wrong number of parameters were given, or the user * was not privilaged enough to execute the command. */ CmdResult CallHandler(const std::string& commandname, const CommandBase::Params& parameters, User* user, Command** cmd = NULL); /** Get the handler function for a command. * @param commandname The command required. Always use uppercase for this parameter. * @return a pointer to the command handler, or NULL */ Command* GetHandler(const std::string &commandname); /** LoopCall is used to call a command handler repeatedly based on the contents of a comma seperated list. * There are two ways to call this method, either with one potential list or with two potential lists. * We need to handle two potential lists for JOIN, because a JOIN may contain two lists of items at once: * the channel names and their keys as follows: * * JOIN \#chan1,\#chan2,\#chan3 key1,,key3 * * Therefore, we need to deal with both lists concurrently. If there are two lists then the method reads * them both together until the first runs out of tokens. * With one list it is much simpler, and is used in NAMES, WHOIS, PRIVMSG etc. * * If there is only one list and there are duplicates in it, then the command handler is only called for * unique items. Entries are compared using "irc comparison". * If the usemax parameter is true (the default) the function only parses until it reaches * ServerInstance->Config->MaxTargets number of targets, to stop abuse via spam. * * The OnPostCommand hook is executed for each item after it has been processed by the handler, with the * original line parameter being empty (to indicate that the command in that form was created by this function). * This only applies if the user executing the command is local. * * If there are two lists and the second list runs out of tokens before the first list then parameters[extra] * will be an EMPTY string when Handle() is called for the remaining tokens in the first list, even if it is * in the middle of parameters[]! Moreover, empty tokens in the second list are allowed, and those will also * result in the appropiate entry being empty in parameters[]. * This is different than what command handlers usually expect; the command parser only allows an empty param * as the last item in the vector. * * @param user The user who sent the command * @param handler The command handler to call for each parameter in the list * @param parameters Parameter list as a vector of strings * @param splithere The first parameter index to split as a comma seperated list * @param extra The second parameter index to split as a comma seperated list, or -1 (the default) if there is only one list * @param usemax True to limit the command to MaxTargets targets (default), or false to process all tokens * @return This function returns true when it identified a list in the given parameter and finished calling the * command handler for each entry on the list. When this occurs, the caller should return without doing anything, * otherwise it should continue into its main section of code. */ static bool LoopCall(User* user, Command* handler, const CommandBase::Params& parameters, unsigned int splithere, int extra = -1, bool usemax = true); /** Take a raw input buffer from a recvq, and process it on behalf of a user. * @param buffer The buffer line to process * @param user The user to whom this line belongs */ void ProcessBuffer(LocalUser* user, const std::string& buffer); /** Add a new command to the commands hash * @param f The new Command to add to the list * @return True if the command was added */ bool AddCommand(Command *f); /** Removes a command. */ void RemoveCommand(Command* x); /** Translate a single item based on the TranslationType given. * @param to The translation type to use for the process * @param item The input string * @param dest The output string. The translation result will be appended to this string * @param custom_translator Used to translate the parameter if the translation type is TR_CUSTOM, if NULL, TR_CUSTOM will act like TR_TEXT * @param paramnumber The index of the parameter we are translating. */ static void TranslateSingleParam(TranslateType to, const std::string& item, std::string& dest, CommandBase* custom_translator = NULL, unsigned int paramnumber = 0); /** Translate nicknames in a list of strings into UIDs, based on the TranslateTypes given. * @param to The translation types to use for the process. If this list is too short, TR_TEXT is assumed for the rest. * @param source The strings to translate * @param prefix_final True if the final source argument should have a colon prepended (if it could contain a space) * @param custom_translator Used to translate the parameter if the translation type is TR_CUSTOM, if NULL, TR_CUSTOM will act like TR_TEXT * @return dest The output string */ static std::string TranslateUIDs(const std::vector<TranslateType>& to, const CommandBase::Params& source, bool prefix_final = false, CommandBase* custom_translator = NULL); }; �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/include/commands/��������������������������������������������������������������������0000775�0000000�0000000�00000000000�13554550454�0016567�5����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/include/commands/cmd_whowas.h��������������������������������������������������������0000664�0000000�0000000�00000012620�13554550454�0021074�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * InspIRCd -- Internet Relay Chat Daemon * * Copyright (C) 2009 Daniel De Graaf <danieldg@inspircd.org> * Copyright (C) 2007 Dennis Friis <peavey@inspircd.org> * Copyright (C) 2006 Craig Edwards <craigedwards@brainbox.cc> * * This file is part of InspIRCd. InspIRCd is free software: you can * redistribute it and/or modify it under the terms of the GNU General Public * License as published by the Free Software Foundation, version 2. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include "modules.h" namespace WhoWas { /** One entry for a nick. There may be multiple entries for a nick. */ struct Entry { /** Real host */ const std::string host; /** Displayed host */ const std::string dhost; /** Ident */ const std::string ident; /** Server name */ const std::string server; /** Real name */ const std::string real; /** Signon time */ const time_t signon; /** Initialize this Entry with a user */ Entry(User* user); }; /** Everything known about one nick */ struct Nick : public insp::intrusive_list_node<Nick> { /** A group of users related by nickname */ typedef std::deque<Entry*> List; /** Container where each element has information about one occurrence of this nick */ List entries; /** Time this nick was added to the database */ const time_t addtime; /** Nickname whose information is stored in this class */ const std::string nick; /** Constructor to initialize fields */ Nick(const std::string& nickname); /** Destructor, deallocates all elements in the entries container */ ~Nick(); }; class Manager { public: struct Stats { /** Number of currently existing WhoWas::Entry objects */ size_t entrycount; }; /** Add a user to the whowas database. Called when a user quits. * @param user The user to add to the database */ void Add(User* user); /** Retrieves statistics about the whowas database * @return Whowas statistics as a WhoWas::Manager::Stats struct */ Stats GetStats() const; /** Expires old entries */ void Maintain(); /** Updates the current configuration which may result in the database being pruned if the * new values are lower than the current ones. * @param NewGroupSize Maximum number of nicks allowed in the database. In case there are this many nicks * in the database and one more is added, the oldest one is removed (FIFO). * @param NewMaxGroups Maximum number of entries per nick * @param NewMaxKeep Seconds how long each nick should be kept */ void UpdateConfig(unsigned int NewGroupSize, unsigned int NewMaxGroups, unsigned int NewMaxKeep); /** Retrieves all data known about a given nick * @param nick Nickname to find, case insensitive (IRC casemapping) * @return A pointer to a WhoWas::Nick if the nick was found, NULL otherwise */ const Nick* FindNick(const std::string& nick) const; /** Returns true if WHOWAS is enabled according to the current configuration * @return True if WHOWAS is enabled according to the configuration, false if WHOWAS is disabled */ bool IsEnabled() const; /** Constructor */ Manager(); /** Destructor */ ~Manager(); private: /** Order in which the users were added into the map, used to remove oldest nick */ typedef insp::intrusive_list_tail<Nick> FIFO; /** Sets of users in the whowas system */ typedef TR1NS::unordered_map<std::string, WhoWas::Nick*, irc::insensitive, irc::StrHashComp> whowas_users; /** Primary container, links nicknames tracked by WHOWAS to a list of records */ whowas_users whowas; /** List of nicknames in the order they were inserted into the map */ FIFO whowas_fifo; /** Max number of WhoWas entries per user. */ unsigned int GroupSize; /** Max number of cumulative user-entries in WhoWas. * When max reached and added to, push out oldest entry FIFO style. */ unsigned int MaxGroups; /** Max seconds a user is kept in WhoWas before being pruned. */ unsigned int MaxKeep; /** Shrink all data structures to honor the current settings */ void Prune(); /** Remove a nick (and all entries belonging to it) from the database * @param it Iterator to the nick to purge */ void PurgeNick(whowas_users::iterator it); /** Remove a nick (and all entries belonging to it) from the database * @param nick Nick to purge */ void PurgeNick(WhoWas::Nick* nick); }; } /** Handle /WHOWAS. These command handlers can be reloaded by the core, * and handle basic RFC1459 commands. Commands within modules work * the same way, however, they can be fully unloaded, where these * may not. */ class CommandWhowas : public Command { public: /** Manager handling all whowas database related tasks */ WhoWas::Manager manager; CommandWhowas(Module* parent); /** Handle command. * @param parameters The parameters to the comamnd * @param user The user issuing the command * @return A value from CmdResult to indicate command success or failure. */ CmdResult Handle(User* user, const Params& parameters) CXX11_OVERRIDE; }; ����������������������������������������������������������������������������������������������������������������inspircd-3.4.0/include/compat.h���������������������������������������������������������������������0000664�0000000�0000000�00000006263�13554550454�0016431�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * InspIRCd -- Internet Relay Chat Daemon * * Copyright (C) 2013 Peter Powell <petpow@saberuk.com> * Copyright (C) 2008 Thomas Stagner <aquanight@inspircd.org> * Copyright (C) 2007 Robin Burchell <robin+git@viroteck.net> * * This file is part of InspIRCd. InspIRCd is free software: you can * redistribute it and/or modify it under the terms of the GNU General Public * License as published by the Free Software Foundation, version 2. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once /** * Some implementations of the C++11 standard library are incomplete so we use * the implementation of the same types from C++ Technical Report 1 instead. */ #if defined _LIBCPP_VERSION || defined _WIN32 # define TR1NS std # include <array> # include <functional> # include <unordered_map> # include <type_traits> #else # define TR1NS std::tr1 # include <tr1/array> # include <tr1/functional> # include <tr1/unordered_map> # include <tr1/type_traits> #endif /** * This macro enables the compile-time checking of printf format strings. This * makes the compiler show a warning if the format of a printf arguments are * incorrect. */ #if defined __clang__ || defined __GNUC__ # define CUSTOM_PRINTF(stringpos, firstpos) __attribute__((format(printf, stringpos, firstpos))) #else # define CUSTOM_PRINTF(stringpos, firstpos) #endif /** * These macros enable the use of the C++11 override control keywords in * compilers which support them. */ #if __cplusplus >= 201103L # define HAS_CXX11_FINAL_OVERRIDE #elif defined __clang__ # if __has_feature(cxx_override_control) # define HAS_CXX11_FINAL_OVERRIDE # endif #elif (__GNUC__ > 4) || (__GNUC__ == 4 && __GNUC_MINOR__ >= 7) # if defined __GXX_EXPERIMENTAL_CXX0X__ # define HAS_CXX11_FINAL_OVERRIDE # endif #elif _MSC_VER >= 1700 # define HAS_CXX11_FINAL_OVERRIDE #endif #if defined HAS_CXX11_FINAL_OVERRIDE # define CXX11_FINAL final # define CXX11_OVERRIDE override #else # define CXX11_FINAL # define CXX11_OVERRIDE #endif /** * This macro allows methods to be marked as deprecated. To use this, wrap the * method declaration in the header file with the macro. */ #if defined __clang__ || defined __GNUC__ # define DEPRECATED_METHOD(function) function __attribute__((deprecated)) #elif defined _MSC_VER # define DEPRECATED_METHOD(function) __declspec(deprecated) function #else # define DEPRECATED_METHOD(function) function #endif /** * Windows is very different to UNIX so we have to wrap certain features in * order to build on Windows correctly. */ #if defined _WIN32 # include "inspircd_win32wrapper.h" # include "threadengines/threadengine_win32.h" #else # define ENTRYPOINT int main(int argc, char** argv) # define DllExport __attribute__ ((visibility ("default"))) # define CoreExport __attribute__ ((visibility ("default"))) # include <unistd.h> # include "threadengines/threadengine_pthread.h" #endif ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/include/configparser.h���������������������������������������������������������������0000664�0000000�0000000�00000002615�13554550454�0017625�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * InspIRCd -- Internet Relay Chat Daemon * * Copyright (C) 2009 Daniel De Graaf <danieldg@inspircd.org> * * This file is part of InspIRCd. InspIRCd is free software: you can * redistribute it and/or modify it under the terms of the GNU General Public * License as published by the Free Software Foundation, version 2. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once struct ParseStack { std::vector<std::string> reading; insp::flat_map<std::string, std::string, irc::insensitive_swo> vars; ConfigDataHash& output; ConfigFileCache& FilesOutput; std::stringstream& errstr; ParseStack(ServerConfig* conf) : output(conf->config_data), FilesOutput(conf->Files), errstr(conf->errstr) { vars["amp"] = "&"; vars["quot"] = "\""; vars["newline"] = vars["nl"] = "\n"; } bool ParseFile(const std::string& name, int flags, const std::string& mandatory_tag = std::string(), bool isexec = false); void DoInclude(ConfigTag* includeTag, int flags); void DoReadFile(const std::string& key, const std::string& file, int flags, bool exec); }; �������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/include/configreader.h���������������������������������������������������������������0000664�0000000�0000000�00000035601�13554550454�0017574�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * InspIRCd -- Internet Relay Chat Daemon * * Copyright (C) 2009 Daniel De Graaf <danieldg@inspircd.org> * Copyright (C) 2007, 2009 Dennis Friis <peavey@inspircd.org> * Copyright (C) 2006-2008 Craig Edwards <craigedwards@brainbox.cc> * Copyright (C) 2006-2008 Robin Burchell <robin+git@viroteck.net> * Copyright (C) 2006 Oliver Lupton <oliverlupton@gmail.com> * * This file is part of InspIRCd. InspIRCd is free software: you can * redistribute it and/or modify it under the terms of the GNU General Public * License as published by the Free Software Foundation, version 2. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <sstream> #include <string> #include <vector> #include <map> #include "inspircd.h" #include "modules.h" #include "socketengine.h" #include "socket.h" #include "token_list.h" /** Structure representing a single \<tag> in config */ class CoreExport ConfigTag : public refcountbase { ConfigItems items; public: const std::string tag; const std::string src_name; const int src_line; /** Get the value of an option, using def if it does not exist */ std::string getString(const std::string& key, const std::string& def, const TR1NS::function<bool(const std::string&)>& validator); /** Get the value of an option, using def if it does not exist */ std::string getString(const std::string& key, const std::string& def = "", size_t minlen = 0, size_t maxlen = UINT32_MAX); /** Get the value of an option, using def if it does not exist */ long getInt(const std::string& key, long def, long min = LONG_MIN, long max = LONG_MAX); /** Get the value of an option, using def if it does not exist */ unsigned long getUInt(const std::string& key, unsigned long def, unsigned long min = 0, unsigned long max = ULONG_MAX); /** Get the value of an option, using def if it does not exist */ double getFloat(const std::string& key, double def, double min = DBL_MIN, double max = DBL_MAX); /** Get the value of an option, using def if it does not exist */ bool getBool(const std::string& key, bool def = false); /** Get the value in seconds of a duration that is in the user-friendly "1h2m3s" format, * using a default value if it does not exist or is out of bounds. * @param key The config key name * @param def Default value (optional) * @param min Minimum acceptable value (optional) * @param max Maximum acceptable value (optional) * @return The duration in seconds */ unsigned long getDuration(const std::string& key, unsigned long def, unsigned long min = 0, unsigned long max = ULONG_MAX); /** Get the value of an option * @param key The option to get * @param value The location to store the value (unmodified if does not exist) * @param allow_newline Allow newlines in the option (normally replaced with spaces) * @return true if the option exists */ bool readString(const std::string& key, std::string& value, bool allow_newline = false); std::string getTagLocation(); inline const ConfigItems& getItems() const { return items; } /** Create a new ConfigTag, giving access to the private ConfigItems item list */ static ConfigTag* create(const std::string& Tag, const std::string& file, int line, ConfigItems*& Items); private: ConfigTag(const std::string& Tag, const std::string& file, int line); }; /** Defines the server's length limits on various length-limited * items such as topics, nicknames, channel names etc. */ class ServerLimits { public: /** Maximum nickname length */ size_t NickMax; /** Maximum channel length */ size_t ChanMax; /** Maximum number of modes per line */ size_t MaxModes; /** Maximum length of ident, not including ~ etc */ size_t IdentMax; /** Maximum length of a quit message */ size_t MaxQuit; /** Maximum topic length */ size_t MaxTopic; /** Maximum kick message length */ size_t MaxKick; /** Maximum real name length */ size_t MaxReal; /** Maximum away message length */ size_t MaxAway; /** Maximum line length */ size_t MaxLine; /** Maximum hostname length */ size_t MaxHost; /** Read all limits from a config tag. Limits which aren't specified in the tag are set to a default value. * @param tag Configuration tag to read the limits from */ ServerLimits(ConfigTag* tag); /** Maximum length of a n!u\@h mask */ size_t GetMaxMask() const { return NickMax + 1 + IdentMax + 1 + MaxHost; } }; struct CommandLineConf { /** If this value is true, the owner of the * server specified -nofork on the command * line, causing the daemon to stay in the * foreground. */ bool nofork; /** If this value if true then all log * messages will be output, regardless of * the level given in the config file. * This is set with the -debug commandline * option. */ bool forcedebug; /** If this is true then log output will be * written to the logfile. This is the default. * If you put -nolog on the commandline then * the logfile will not be written. * This is meant to be used in conjunction with * -debug for debugging without filling up the * hard disk. */ bool writelog; /** If this is true, a PID file will be written * to the file given in the "file" variable of * the \<pid> tag in the config file. This is * the default. * Passing --nopid as a command line argument * sets this to false; in this case, a PID file * will not be written, even the default PID * file that is usually written when the \<pid> * tag is not defined in the config file. */ bool writepid; /** Saved argc from startup */ int argc; /** Saved argv from startup */ char** argv; }; class CoreExport OperInfo : public refcountbase { public: TokenList AllowedOperCommands; TokenList AllowedPrivs; /** Allowed user modes from oper classes. */ std::bitset<64> AllowedUserModes; /** Allowed channel modes from oper classes. */ std::bitset<64> AllowedChanModes; /** \<oper> block used for this oper-up. May be NULL. */ reference<ConfigTag> oper_block; /** \<type> block used for this oper-up. Valid for local users, may be NULL on remote */ reference<ConfigTag> type_block; /** \<class> blocks referenced from the \<type> block. These define individual permissions */ std::vector<reference<ConfigTag> > class_blocks; /** Name of the oper type; i.e. the one shown in WHOIS */ std::string name; /** Creates a new OperInfo with the specified oper type name. * @param Name The name of the oper type. */ OperInfo(const std::string& Name); /** Get a configuration item, searching in the oper, type, and class blocks (in that order) */ std::string getConfig(const std::string& key); void init(); }; /** This class holds the bulk of the runtime configuration for the ircd. * It allows for reading new config values, accessing configuration files, * and storage of the configuration data needed to run the ircd, such as * the servername, connect classes, /ADMIN data, MOTDs and filenames etc. */ class CoreExport ServerConfig { private: void CrossCheckOperClassType(); void CrossCheckConnectBlocks(ServerConfig* current); public: /** How to treat a user in a channel who is banned. */ enum BannedUserTreatment { /** Don't treat a banned user any different to normal. */ BUT_NORMAL, /** Restrict the actions of a banned user. */ BUT_RESTRICT_SILENT, /** Restrict the actions of a banned user and notify them of their treatment. */ BUT_RESTRICT_NOTIFY }; class ServerPaths { public: /** Config path */ std::string Config; /** Data path */ std::string Data; /** Log path */ std::string Log; /** Module path */ std::string Module; ServerPaths(ConfigTag* tag); std::string PrependConfig(const std::string& fn) const { return FileSystem::ExpandPath(Config, fn); } std::string PrependData(const std::string& fn) const { return FileSystem::ExpandPath(Data, fn); } std::string PrependLog(const std::string& fn) const { return FileSystem::ExpandPath(Log, fn); } std::string PrependModule(const std::string& fn) const { return FileSystem::ExpandPath(Module, fn); } }; /** Holds a complete list of all connect blocks */ typedef std::vector<reference<ConnectClass> > ClassVector; /** Index of valid oper blocks and types */ typedef insp::flat_map<std::string, reference<OperInfo> > OperIndex; /** Get a configuration tag by name. If one or more tags are present then the first is returned. * @param tag The name of the tag to get. * @returns Either a tag from the config or EmptyTag. */ ConfigTag* ConfValue(const std::string& tag); /** Get a list of configuration tags by name. * @param tag The name of the tags to get. * @returns Either a list of tags from the config or an empty ConfigTagList. */ ConfigTagList ConfTags(const std::string& tag); /** An empty configuration tag. */ ConfigTag* EmptyTag; /** Error stream, contains error output from any failed configuration parsing. */ std::stringstream errstr; /** True if this configuration is valid enough to run with */ bool valid; /** Bind to IPv6 by default */ bool WildcardIPv6; /** This holds all the information in the config file, * it's indexed by tag name to a vector of key/values. */ ConfigDataHash config_data; /** This holds all extra files that have been read in the configuration * (for example, MOTD and RULES files are stored here) */ ConfigFileCache Files; /** Length limits, see definition of ServerLimits class */ ServerLimits Limits; /** Locations of various types of file (config, module, etc). */ ServerPaths Paths; /** Configuration parsed from the command line. */ CommandLineConf cmdline; /** Clones CIDR range for ipv4 (0-32) * Defaults to 32 (checks clones on all IPs seperately) */ unsigned char c_ipv4_range; /** Clones CIDR range for ipv6 (0-128) * Defaults to 128 (checks on all IPs seperately) */ unsigned char c_ipv6_range; /** Holds the server name of the local server * as defined by the administrator. */ std::string ServerName; /** Notice to give to users when they are banned by an XLine */ std::string XLineMessage; /* Holds the network name the local server * belongs to. This is an arbitary field defined * by the administrator. */ std::string Network; /** Holds the description of the local server * as defined by the administrator. */ std::string ServerDesc; /** How to treat a user in a channel who is banned. */ BannedUserTreatment RestrictBannedUsers; /** The size of the read() buffer in the user * handling code, used to read data into a user's * recvQ. */ int NetBufferSize; /** The value to be used for listen() backlogs * as default. */ int MaxConn; /** If we should check for clones during CheckClass() in AddUser() * Setting this to false allows to not trigger on maxclones for users * that may belong to another class after DNS-lookup is complete. * It does, however, make the server spend more time on users we may potentially not want. */ bool CCOnConnect; /** The soft limit value assigned to the irc server. * The IRC server will not allow more than this * number of local users. */ unsigned int SoftLimit; /** Maximum number of targets for a multi target command * such as PRIVMSG or KICK */ unsigned int MaxTargets; /** The number of seconds that the server clock can skip by before server operators are warned. */ time_t TimeSkipWarn; /** True if we're going to hide ban reasons for non-opers (e.g. G-lines, * K-lines, Z-lines) */ bool HideBans; /** True if raw I/O is being logged */ bool RawLog; /** Set to a non-empty string to obfuscate server names. */ std::string HideServer; /** The full pathname and filename of the PID * file as defined in the configuration. */ std::string PID; /** The connect classes in use by the IRC server. */ ClassVector Classes; /** Default channel modes */ std::string DefaultModes; /** Custom version string, which if defined can replace the system info in VERSION. */ std::string CustomVersion; /** If set to true, provide syntax hints for unknown commands */ bool SyntaxHints; /** The name of the casemapping method used by this server. */ std::string CaseMapping; /** If set to true, the full nick!user\@host will be shown in the TOPIC command * for who set the topic last. If false, only the nick is shown. */ bool FullHostInTopic; /** Oper blocks keyed by their name */ OperIndex oper_blocks; /** Oper types keyed by their name */ OperIndex OperTypes; /** Default value for <connect:maxchans>, deprecated in 3.0 */ unsigned int MaxChans; /** Default value for <oper:maxchans>, deprecated in 3.0 */ unsigned int OperMaxChans; /** TS6-like server ID. * NOTE: 000...999 are usable for InspIRCd servers. This * makes code simpler. 0AA, 1BB etc with letters are reserved * for services use. */ std::string sid; /** Construct a new ServerConfig */ ServerConfig(); ~ServerConfig(); /** Get server ID as string with required leading zeroes */ const std::string& GetSID() const { return sid; } /** Read the entire configuration into memory * and initialize this class. All other methods * should be used only by the core. */ void Read(); /** Apply configuration changes from the old configuration. */ void Apply(ServerConfig* old, const std::string &useruid); void ApplyModules(User* user); void Fill(); /** Escapes a value for storage in a configuration key. * @param str The string to escape. * @param xml Are we using the XML config format? */ static std::string Escape(const std::string& str, bool xml = true); /** If this value is true, snotices will not stack when repeats are sent */ bool NoSnoticeStack; }; /** The background thread for config reading, so that reading from executable includes * does not block. */ class CoreExport ConfigReaderThread : public Thread { ServerConfig* Config; volatile bool done; public: const std::string TheUserUID; ConfigReaderThread(const std::string &useruid) : Config(new ServerConfig), done(false), TheUserUID(useruid) { } virtual ~ConfigReaderThread() { delete Config; } void Run() CXX11_OVERRIDE; /** Run in the main thread to apply the configuration */ void Finish(); bool IsDone() { return done; } }; /** Represents the status of a config load. */ class CoreExport ConfigStatus { public: /** Whether this is the initial config load. */ bool const initial; /** The user who initiated the config load or NULL if not initiated by a user. */ User* const srcuser; /** Initializes a new instance of the ConfigStatus class. * @param user The user who initiated the config load or NULL if not initiated by a user. * @param isinitial Whether this is the initial config load. */ ConfigStatus(User* user = NULL, bool isinitial = false) : initial(isinitial) , srcuser(user) { } }; �������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/include/consolecolors.h��������������������������������������������������������������0000664�0000000�0000000�00000005502�13554550454�0020025�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * InspIRCd -- Internet Relay Chat Daemon * * This file is part of InspIRCd. InspIRCd is free software: you can * redistribute it and/or modify it under the terms of the GNU General Public * License as published by the Free Software Foundation, version 2. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <ostream> #include <stdio.h> #ifdef _WIN32 # include <io.h> # define isatty(x) _isatty((x)) # define fileno(x) _fileno((x)) #else # include <unistd.h> #endif namespace { inline bool CanUseColors() { #ifdef INSPIRCD_DISABLE_COLORS return false; #else return isatty(fileno(stdout)); #endif } } #ifdef _WIN32 #include <windows.h> extern WORD g_wOriginalColors; extern WORD g_wBackgroundColor; extern HANDLE g_hStdout; inline std::ostream& con_green(std::ostream &s) { if (CanUseColors()) SetConsoleTextAttribute(g_hStdout, FOREGROUND_GREEN|FOREGROUND_INTENSITY|g_wBackgroundColor); return s; } inline std::ostream& con_red(std::ostream &s) { if (CanUseColors()) SetConsoleTextAttribute(g_hStdout, FOREGROUND_RED|FOREGROUND_INTENSITY|g_wBackgroundColor); return s; } inline std::ostream& con_white(std::ostream &s) { if (CanUseColors()) SetConsoleTextAttribute(g_hStdout, FOREGROUND_RED|FOREGROUND_BLUE|FOREGROUND_GREEN|g_wBackgroundColor); return s; } inline std::ostream& con_white_bright(std::ostream &s) { if (CanUseColors()) SetConsoleTextAttribute(g_hStdout, FOREGROUND_RED|FOREGROUND_BLUE|FOREGROUND_GREEN|FOREGROUND_INTENSITY|g_wBackgroundColor); return s; } inline std::ostream& con_bright(std::ostream &s) { if (CanUseColors()) SetConsoleTextAttribute(g_hStdout, FOREGROUND_INTENSITY|g_wBackgroundColor); return s; } inline std::ostream& con_reset(std::ostream &s) { if (CanUseColors()) SetConsoleTextAttribute(g_hStdout, g_wOriginalColors); return s; } #else inline std::ostream& con_green(std::ostream &s) { if (!CanUseColors()) return s; return s << "\033[1;32m"; } inline std::ostream& con_red(std::ostream &s) { if (!CanUseColors()) return s; return s << "\033[1;31m"; } inline std::ostream& con_white(std::ostream &s) { if (!CanUseColors()) return s; return s << "\033[0m"; } inline std::ostream& con_white_bright(std::ostream &s) { if (!CanUseColors()) return s; return s << "\033[1m"; } inline std::ostream& con_bright(std::ostream &s) { if (!CanUseColors()) return s; return s << "\033[1m"; } inline std::ostream& con_reset(std::ostream &s) { if (!CanUseColors()) return s; return s << "\033[0m"; } #endif ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/include/convto.h���������������������������������������������������������������������0000664�0000000�0000000�00000005600�13554550454�0016450�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * InspIRCd -- Internet Relay Chat Daemon * * Copyright (C) 2014 Attila Molnar <attilamolnar@hush.com> * Copyright (C) 2006 Craig Edwards <craigedwards@brainbox.cc> * * This file is part of InspIRCd. InspIRCd is free software: you can * redistribute it and/or modify it under the terms of the GNU General Public * License as published by the Free Software Foundation, version 2. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once /** Template function to convert any input type to std::string */ template<typename T> inline std::string ConvNumeric(const T& in) { if (in == 0) return "0"; T quotient = in; std::string out; while (quotient) { out += "0123456789"[std::abs((long)quotient % 10)]; quotient /= 10; } if (in < 0) out += '-'; std::reverse(out.begin(), out.end()); return out; } /** Template function to convert any input type to std::string */ inline std::string ConvToStr(const int in) { return ConvNumeric(in); } /** Template function to convert any input type to std::string */ inline std::string ConvToStr(const long in) { return ConvNumeric(in); } /** Template function to convert any input type to std::string */ inline std::string ConvToStr(const char* in) { return in; } /** Template function to convert any input type to std::string */ inline std::string ConvToStr(const bool in) { return (in ? "1" : "0"); } /** Template function to convert any input type to std::string */ inline std::string ConvToStr(char in) { return std::string(1, in); } inline const std::string& ConvToStr(const std::string& in) { return in; } /** Template function to convert any input type to std::string */ template <class T> inline std::string ConvToStr(const T& in) { std::stringstream tmp; if (!(tmp << in)) return std::string(); return tmp.str(); } /** Template function to convert a std::string to any numeric type. */ template<typename TOut> inline TOut ConvToNum(const std::string& in) { TOut ret; std::istringstream tmp(in); if (!(tmp >> ret)) return 0; return ret; } template<> inline char ConvToNum<char>(const std::string& in) { // We specialise ConvToNum for char to avoid istringstream treating // the input as a character literal. uint16_t num = ConvToNum<uint16_t>(in); return num <= UINT8_MAX ? num : 0; } template<> inline unsigned char ConvToNum<unsigned char>(const std::string& in) { // We specialise ConvToNum for unsigned char to avoid istringstream // treating the input as a character literal. int16_t num = ConvToNum<int16_t>(in); return num >= INT8_MIN && num <= INT8_MAX ? num : 0; } ��������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/include/ctables.h��������������������������������������������������������������������0000664�0000000�0000000�00000023172�13554550454�0016561�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * InspIRCd -- Internet Relay Chat Daemon * * Copyright (C) 2009 Daniel De Graaf <danieldg@inspircd.org> * Copyright (C) 2008 Robin Burchell <robin+git@viroteck.net> * Copyright (C) 2008 Thomas Stagner <aquanight@inspircd.org> * Copyright (C) 2007 Dennis Friis <peavey@inspircd.org> * Copyright (C) 2003, 2007 Craig Edwards <craigedwards@brainbox.cc> * * This file is part of InspIRCd. InspIRCd is free software: you can * redistribute it and/or modify it under the terms of the GNU General Public * License as published by the Free Software Foundation, version 2. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once /** Used to indicate the result of trying to execute a command. */ enum CmdResult { /** The command exists but its execution failed. */ CMD_FAILURE = 0, /** The command exists and its execution succeeded. */ CMD_SUCCESS = 1, /* The command does not exist. */ CMD_INVALID = 2 }; /** Flag for commands that are only allowed from servers */ const char FLAG_SERVERONLY = 7; // technically anything nonzero below 'A' works /** Translation types for translation of parameters to UIDs. * This allows the core commands to not have to be aware of how UIDs * work (making it still possible to write other linking modules which * do not use UID (but why would you want to?) */ enum TranslateType { TR_TEXT, /* Raw text, leave as-is */ TR_NICK, /* Nickname, translate to UUID for server->server */ TR_CUSTOM /* Custom translation handled by EncodeParameter/DecodeParameter */ }; /** Routing types for a command. Any command which is created defaults * to having its command broadcasted on success. This behaviour may be * overridden to one of the route types shown below (see the #defines * below for more information on each one's behaviour) */ enum RouteType { ROUTE_TYPE_LOCALONLY, ROUTE_TYPE_BROADCAST, ROUTE_TYPE_UNICAST, ROUTE_TYPE_MESSAGE, ROUTE_TYPE_OPT_BCAST, ROUTE_TYPE_OPT_UCAST }; /** Defines routing information for a command, containing a destination * server id (if applicable) and a routing type from the enum above. */ struct RouteDescriptor { /** Routing type from the enum above */ RouteType type; /** For unicast, the destination server's name */ std::string serverdest; /** For unicast, the destination Server */ Server* server; /** Create a RouteDescriptor */ RouteDescriptor(RouteType t, const std::string &d) : type(t), serverdest(d), server(NULL) { } RouteDescriptor(RouteType t, Server* srv) : type(t), server(srv) { } }; /** Do not route this command */ #define ROUTE_LOCALONLY (RouteDescriptor(ROUTE_TYPE_LOCALONLY, "")) /** Route this command to all servers, fail if not understood */ #define ROUTE_BROADCAST (RouteDescriptor(ROUTE_TYPE_BROADCAST, "")) /** Route this command to a single server (do nothing if own server name specified) */ #define ROUTE_UNICAST(x) (RouteDescriptor(ROUTE_TYPE_UNICAST, x)) /** Route this command as a message with the given target (any of user, #channel, @#channel, $servermask) */ #define ROUTE_MESSAGE(x) (RouteDescriptor(ROUTE_TYPE_MESSAGE, x)) /** Route this command to all servers wrapped via ENCAP, so ignored if not understood */ #define ROUTE_OPT_BCAST (RouteDescriptor(ROUTE_TYPE_OPT_BCAST, "")) /** Route this command to a single server wrapped via ENCAP, so ignored if not understood */ #define ROUTE_OPT_UCAST(x) (RouteDescriptor(ROUTE_TYPE_OPT_UCAST, x)) /** A structure that defines a command. Every command available * in InspIRCd must be defined as derived from Command. */ class CoreExport CommandBase : public ServiceProvider { public: /** Encapsulates parameters to a command. */ class Params : public std::vector<std::string> { private: /* IRCv3 message tags. */ ClientProtocol::TagMap tags; public: /** Initializes a new instance from parameter and tag references. * @param paramsref Message parameters. * @param tagsref IRCv3 message tags. */ Params(const std::vector<std::string>& paramsref, const ClientProtocol::TagMap& tagsref) : std::vector<std::string>(paramsref) , tags(tagsref) { } /** Initializes a new instance from parameter iterators. * @param first The first element in the parameter array. * @param last The last element in the parameter array. */ template<typename Iterator> Params(Iterator first, Iterator last) : std::vector<std::string>(first, last) { } /** Initializes a new empty instance. */ Params() { } /** Retrieves the IRCv3 message tags. */ const ClientProtocol::TagMap& GetTags() const { return tags; } }; /** User flags needed to execute the command or 0 */ unsigned char flags_needed; /** Minimum number of parameters command takes */ const unsigned int min_params; /** Maximum number of parameters command takes. * This is used by the command parser to join extra parameters into one last param. * If not set, no munging is done to this command. */ const unsigned int max_params; /** used by /stats m */ unsigned long use_count; /** True if the command can be issued before registering */ bool works_before_reg; /** True if the command allows an empty last parameter. * When false and the last parameter is empty, it's popped BEFORE * checking there are enough params, etc. (i.e. the handler won't * be called if there aren't enough params after popping the empty * param). * True by default */ bool allow_empty_last_param; /** Syntax string for the command, displayed if non-empty string. * This takes place of the text in the 'not enough parameters' numeric. */ std::string syntax; /** Translation type list for possible parameters, used to tokenize * parameters into UIDs and SIDs etc. */ std::vector<TranslateType> translation; /** How many seconds worth of penalty does this command have? */ unsigned int Penalty; /** Create a new command. * @param me The module which created this command. * @param cmd Command name. This must be UPPER CASE. * @param minpara Minimum parameters required for the command. * @param maxpara Maximum number of parameters this command may have - extra parameters * will be tossed into one last space-seperated param. */ CommandBase(Module* me, const std::string& cmd, unsigned int minpara = 0, unsigned int maxpara = 0); virtual RouteDescriptor GetRouting(User* user, const CommandBase::Params& parameters); /** Encode a parameter for server->server transmission. * Used for parameters for which the translation type is TR_CUSTOM. * @param parameter The parameter to encode. Can be modified in place. * @param index The parameter index (0 == first parameter). */ virtual void EncodeParameter(std::string& parameter, unsigned int index); /** @return true if the command works before registration. */ bool WorksBeforeReg() { return works_before_reg; } virtual ~CommandBase(); }; class CoreExport Command : public CommandBase { public: /** If true, the command will not be forwarded by the linking module even if it comes via ENCAP. * Can be used to forward commands before their effects. */ bool force_manual_route; Command(Module* me, const std::string& cmd, unsigned int minpara = 0, unsigned int maxpara = 0); /** Handle the command from a user. * @param parameters The parameters for the command. * @param user The user who issued the command. * @return Return CMD_SUCCESS on success, or CMD_FAILURE on failure. */ virtual CmdResult Handle(User* user, const Params& parameters) = 0; /** Register this object in the CommandParser */ void RegisterService() CXX11_OVERRIDE; /** Destructor * Removes this command from the command parser */ ~Command(); }; class CoreExport SplitCommand : public Command { public: SplitCommand(Module* me, const std::string &cmd, unsigned int minpara = 0, unsigned int maxpara = 0) : Command(me, cmd, minpara, maxpara) {} CmdResult Handle(User* user, const Params& parameters) CXX11_OVERRIDE; virtual CmdResult HandleLocal(LocalUser* user, const Params& parameters); virtual CmdResult HandleRemote(RemoteUser* user, const Params& parameters); virtual CmdResult HandleServer(FakeUser* user, const Params& parameters); }; /** Shortcut macros for defining translation lists */ #define TRANSLATE1(x1) translation.push_back(x1); #define TRANSLATE2(x1,x2) translation.push_back(x1);translation.push_back(x2); #define TRANSLATE3(x1,x2,x3) translation.push_back(x1);translation.push_back(x2);translation.push_back(x3); #define TRANSLATE4(x1,x2,x3,x4) translation.push_back(x1);translation.push_back(x2);translation.push_back(x3);translation.push_back(x4); #define TRANSLATE5(x1,x2,x3,x4,x5) translation.push_back(x1);translation.push_back(x2);translation.push_back(x3);translation.push_back(x4);\ translation.push_back(x5); #define TRANSLATE6(x1,x2,x3,x4,x5,x6) translation.push_back(x1);translation.push_back(x2);translation.push_back(x3);translation.push_back(x4);\ translation.push_back(x5);translation.push_back(x6); #define TRANSLATE7(x1,x2,x3,x4,x5,x6,x7) translation.push_back(x1);translation.push_back(x2);translation.push_back(x3);translation.push_back(x4);\ translation.push_back(x5);translation.push_back(x6);translation.push_back(x7); #define TRANSLATE8(x1,x2,x3,x4,x5,x6,x7,x8) translation.push_back(x1);translation.push_back(x2);translation.push_back(x3);translation.push_back(x4);\ translation.push_back(x5);translation.push_back(x6);translation.push_back(x7);translation.push_back(x8); ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/include/cull_list.h������������������������������������������������������������������0000664�0000000�0000000�00000003501�13554550454�0017130�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * InspIRCd -- Internet Relay Chat Daemon * * Copyright (C) 2009 Daniel De Graaf <danieldg@inspircd.org> * Copyright (C) 2008 Robin Burchell <robin+git@viroteck.net> * Copyright (C) 2007 Dennis Friis <peavey@inspircd.org> * Copyright (C) 2005, 2007 Craig Edwards <craigedwards@brainbox.cc> * * This file is part of InspIRCd. InspIRCd is free software: you can * redistribute it and/or modify it under the terms of the GNU General Public * License as published by the Free Software Foundation, version 2. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once /** * The CullList class is used to delete objects at the end of the main loop to * avoid problems with references to deleted pointers if an object were deleted * during execution. */ class CoreExport CullList { std::vector<classbase*> list; std::vector<LocalUser*> SQlist; public: /** Adds an item to the cull list */ void AddItem(classbase* item) { list.push_back(item); } void AddSQItem(LocalUser* item) { SQlist.push_back(item); } /** Applies the cull list (deletes the contents) */ void Apply(); }; /** Represents an action which is executable by an action list */ class CoreExport ActionBase : public classbase { public: /** Executes this action. */ virtual void Call() = 0; }; class CoreExport ActionList { std::vector<ActionBase*> list; public: /** Adds an item to the list */ void AddAction(ActionBase* item) { list.push_back(item); } /** Runs the items */ void Run(); }; �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/include/dynamic.h��������������������������������������������������������������������0000664�0000000�0000000�00000003716�13554550454�0016572�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * InspIRCd -- Internet Relay Chat Daemon * * Copyright (C) 2009 Daniel De Graaf <danieldg@inspircd.org> * Copyright (C) 2007, 2009 Dennis Friis <peavey@inspircd.org> * Copyright (C) 2007 Oliver Lupton <oliverlupton@gmail.com> * Copyright (C) 2003-2004, 2007 Craig Edwards <craigedwards@brainbox.cc> * * This file is part of InspIRCd. InspIRCd is free software: you can * redistribute it and/or modify it under the terms of the GNU General Public * License as published by the Free Software Foundation, version 2. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once /** The DLLManager class is able to load a module file by filename, * and locate its init_module symbol. */ class CoreExport DLLManager : public classbase { protected: /** The last error string */ std::string err; /** Sets the last error string */ void RetrieveLastError(); public: /** This constructor loads the module using dlopen() * @param fname The filename to load. This should be within * the modules dir. */ DLLManager(const char *fname); virtual ~DLLManager(); /** Get the last error from dlopen() or dlsym(). */ const std::string& LastError() { return err; } /** The module library handle. */ void *h; /** Return a module by calling the init function */ Module* CallInit(); /** Retrieves the value of the specified symbol. * @param name The name of the symbol to retrieve. * @return Either the value of the specified symbol or or NULL if it does not exist. */ void* GetSymbol(const char* name); /** Get detailed version information from the module file */ std::string GetVersion(); }; ��������������������������������������������������inspircd-3.4.0/include/dynref.h���������������������������������������������������������������������0000664�0000000�0000000�00000006143�13554550454�0016432�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * InspIRCd -- Internet Relay Chat Daemon * * Copyright (C) 2013 Attila Molnar <attilamolnar@hush.com> * Copyright (C) 2009 Daniel De Graaf <danieldg@inspircd.org> * * This file is part of InspIRCd. InspIRCd is free software: you can * redistribute it and/or modify it under the terms of the GNU General Public * License as published by the Free Software Foundation, version 2. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include "base.h" class CoreExport dynamic_reference_base : public interfacebase, public insp::intrusive_list_node<dynamic_reference_base> { public: class CaptureHook { public: /** Called when the target of the dynamic_reference has been acquired */ virtual void OnCapture() = 0; }; private: std::string name; CaptureHook* hook; void resolve(); protected: ServiceProvider* value; public: ModuleRef creator; dynamic_reference_base(Module* Creator, const std::string& Name); ~dynamic_reference_base(); inline const std::string& GetProvider() { return name; } void SetProvider(const std::string& newname); /** Set handler to call when the target object becomes available * @param h Handler to call */ void SetCaptureHook(CaptureHook* h) { hook = h; } void check(); operator bool() { return (value != NULL); } static void reset_all(); }; inline void dynamic_reference_base::check() { if (!value) throw ModuleException("Dynamic reference to '" + name + "' failed to resolve"); } template<typename T> class dynamic_reference : public dynamic_reference_base { public: dynamic_reference(Module* Creator, const std::string& Name) : dynamic_reference_base(Creator, Name) {} inline T* operator->() { check(); return static_cast<T*>(value); } T* operator*() { return operator->(); } const T* operator->() const { return static_cast<T*>(value); } const T* operator*() const { return operator->(); } }; template<typename T> class dynamic_reference_nocheck : public dynamic_reference_base { public: dynamic_reference_nocheck(Module* Creator, const std::string& Name) : dynamic_reference_base(Creator, Name) {} T* operator->() { return static_cast<T*>(value); } T* operator*() { return operator->(); } const T* operator->() const { return static_cast<T*>(value); } const T* operator*() const { return operator->(); } }; class ModeHandler; class ChanModeReference : public dynamic_reference_nocheck<ModeHandler> { public: ChanModeReference(Module* mod, const std::string& modename) : dynamic_reference_nocheck<ModeHandler>(mod, "mode/" + modename) {} }; class UserModeReference : public dynamic_reference_nocheck<ModeHandler> { public: UserModeReference(Module* mod, const std::string& modename) : dynamic_reference_nocheck<ModeHandler>(mod, "umode/" + modename) {} }; �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/include/event.h����������������������������������������������������������������������0000664�0000000�0000000�00000014561�13554550454�0016267�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * InspIRCd -- Internet Relay Chat Daemon * * Copyright (C) 2015 Attila Molnar <attilamolnar@hush.com> * * This file is part of InspIRCd. InspIRCd is free software: you can * redistribute it and/or modify it under the terms of the GNU General Public * License as published by the Free Software Foundation, version 2. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once namespace Events { class ModuleEventListener; class ModuleEventProvider; } /** Provider of one or more cross-module events. * Modules who wish to provide events for other modules create instances of this class and use * one of the macros below to fire the event, passing the instance of the event provider class * to the macro. * Event providers are identified using a unique identifier string. */ class Events::ModuleEventProvider : public ServiceProvider, private dynamic_reference_base::CaptureHook { public: struct Comp { bool operator()(ModuleEventListener* one, ModuleEventListener* two) const; }; typedef insp::flat_multiset<ModuleEventListener*, Comp, std::less<ModuleEventListener*> > SubscriberList; /** Constructor * @param mod Module providing the event(s) * @param eventid Identifier of the event or event group provided, must be unique */ ModuleEventProvider(Module* mod, const std::string& eventid) : ServiceProvider(mod, eventid, SERVICE_DATA) , prov(mod, eventid) { prov.SetCaptureHook(this); } /** Get list of objects subscribed to this event * @return List of subscribed objects */ const SubscriberList& GetSubscribers() const { return prov->subscribers; } /** Subscribes a listener to this event. * @param subscriber The listener to subscribe. */ void Subscribe(ModuleEventListener* subscriber) { subscribers.insert(subscriber); OnSubscribe(subscriber); } /** Unsubscribes a listener from this event. * @param subscriber The listener to unsubscribe. */ void Unsubscribe(ModuleEventListener* subscriber) { subscribers.erase(subscriber); OnUnsubscribe(subscriber); } private: void OnCapture() CXX11_OVERRIDE { // If someone else holds the list from now on, clear mine. See below for more info. if (*prov != this) subscribers.clear(); } /** Called when a listener subscribes to this event. * @param subscriber The listener which subscribed. */ virtual void OnSubscribe(ModuleEventListener* subscriber) { } /** Called when a listener unsubscribes from this event. * @param subscriber The listener which unsubscribed. */ virtual void OnUnsubscribe(ModuleEventListener* subscriber) { } /** Reference to the active provider for this event. In case multiple event providers * exist for the same event, only one of them contains the list of subscribers. * To handle the case when we are not the ones with the list, we get it from the provider * where the dynref points to. */ dynamic_reference_nocheck<ModuleEventProvider> prov; /** List of objects subscribed to the event(s) provided by us, or empty if multiple providers * exist with the same name and we are not the ones holding the list. */ SubscriberList subscribers; }; /** Base class for abstract classes describing cross-module events. * Subscribers should NOT inherit directly from this class. */ class Events::ModuleEventListener : private dynamic_reference_base::CaptureHook { /** Reference to the provider, can be NULL if none of the provider modules are loaded */ dynamic_reference_nocheck<ModuleEventProvider> prov; const unsigned int eventpriority; /** Called by the dynref when the event provider becomes available */ void OnCapture() CXX11_OVERRIDE { prov->Subscribe(this); } public: static const unsigned int DefaultPriority = 100; /** Constructor * @param mod Module subscribing * @param eventid Identifier of the event to subscribe to * @param eventprio The priority to give this event listener */ ModuleEventListener(Module* mod, const std::string& eventid, unsigned int eventprio = DefaultPriority) : prov(mod, eventid) , eventpriority(eventprio) { prov.SetCaptureHook(this); // If the dynamic_reference resolved at construction our capture handler wasn't called if (prov) ModuleEventListener::OnCapture(); } ~ModuleEventListener() { if (prov) prov->Unsubscribe(this); } /** Retrieves the module which created this listener. */ const Module* GetModule() const { return prov.creator; } friend struct ModuleEventProvider::Comp; }; inline bool Events::ModuleEventProvider::Comp::operator()(Events::ModuleEventListener* one, Events::ModuleEventListener* two) const { return (one->eventpriority < two->eventpriority); } /** * Run the given hook provided by a module * * FOREACH_MOD_CUSTOM(accountevprov, AccountEventListener, OnAccountChange, MOD_RESULT, (user, newaccount)) */ #define FOREACH_MOD_CUSTOM(prov, listenerclass, func, params) do { \ const ::Events::ModuleEventProvider::SubscriberList& _handlers = (prov).GetSubscribers(); \ for (::Events::ModuleEventProvider::SubscriberList::const_iterator _i = _handlers.begin(); _i != _handlers.end(); ++_i) \ { \ listenerclass* _t = static_cast<listenerclass*>(*_i); \ const Module* _m = _t->GetModule(); \ if (_m && !_m->dying) \ _t->func params ; \ } \ } while (0); /** * Run the given hook provided by a module until some module returns MOD_RES_ALLOW or MOD_RES_DENY. * If no module does that, result is set to MOD_RES_PASSTHRU. * * Example: ModResult MOD_RESULT; * FIRST_MOD_RESULT_CUSTOM(httpevprov, HTTPRequestEventListener, OnHTTPRequest, MOD_RESULT, (request)); */ #define FIRST_MOD_RESULT_CUSTOM(prov, listenerclass, func, result, params) do { \ result = MOD_RES_PASSTHRU; \ const ::Events::ModuleEventProvider::SubscriberList& _handlers = (prov).GetSubscribers(); \ for (::Events::ModuleEventProvider::SubscriberList::const_iterator _i = _handlers.begin(); _i != _handlers.end(); ++_i) \ { \ listenerclass* _t = static_cast<listenerclass*>(*_i); \ const Module* _m = _t->GetModule(); \ if (!_m || _m->dying) \ continue; \ result = _t->func params ; \ if (result != MOD_RES_PASSTHRU) \ break; \ } \ } while (0); �����������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/include/exitcodes.h������������������������������������������������������������������0000664�0000000�0000000�00000003210�13554550454�0017122�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * InspIRCd -- Internet Relay Chat Daemon * * Copyright (C) 2006-2008 Craig Edwards <craigedwards@brainbox.cc> * Copyright (C) 2007 Dennis Friis <peavey@inspircd.org> * Copyright (C) 2007 Robin Burchell <robin+git@viroteck.net> * * This file is part of InspIRCd. InspIRCd is free software: you can * redistribute it and/or modify it under the terms of the GNU General Public * License as published by the Free Software Foundation, version 2. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once /** Valid exit codes to be used with InspIRCd::Exit() */ enum ExitStatus { EXIT_STATUS_NOERROR = 0, /* No error */ EXIT_STATUS_DIE = 1, /* Operator issued DIE */ EXIT_STATUS_CONFIG = 2, /* Config error */ EXIT_STATUS_LOG = 3, /* Log file error */ EXIT_STATUS_FORK = 4, /* fork() failed */ EXIT_STATUS_ARGV = 5, /* Invalid program arguments */ EXIT_STATUS_PID = 6, /* Couldn't write PID file */ EXIT_STATUS_SOCKETENGINE = 7, /* Couldn't start socket engine */ EXIT_STATUS_ROOT = 8, /* Refusing to start as root */ EXIT_STATUS_MODULE = 9, /* Couldn't load a required module */ EXIT_STATUS_SIGTERM = 10 /* Received SIGTERM */ }; /** Array that maps exit codes (ExitStatus types) to * human-readable strings to be shown on shutdown. */ extern const char * ExitCodes[]; ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/include/extensible.h�����������������������������������������������������������������0000664�0000000�0000000�00000022706�13554550454�0017310�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * InspIRCd -- Internet Relay Chat Daemon * * Copyright (C) 2009 Daniel De Graaf <danieldg@inspircd.org> * * This file is part of InspIRCd. InspIRCd is free software: you can * redistribute it and/or modify it under the terms of the GNU General Public * License as published by the Free Software Foundation, version 2. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once /** DEPRECATED: use {To,From}{Human,Internal,Network} instead. */ enum SerializeFormat { FORMAT_USER, FORMAT_INTERNAL, FORMAT_NETWORK, FORMAT_PERSIST }; /** Base class for logic that extends an Extensible object. */ class CoreExport ExtensionItem : public ServiceProvider, public usecountbase { public: /** Types of Extensible that an ExtensionItem can apply to. */ enum ExtensibleType { /** The ExtensionItem applies to a User object. */ EXT_USER, /** The ExtensionItem applies to a Channel object. */ EXT_CHANNEL, /** The ExtensionItem applies to a Membership object. */ EXT_MEMBERSHIP }; /** The type of Extensible that this ExtensionItem applies to. */ const ExtensibleType type; /** Initializes an instance of the ExtensionItem class. * @param key The name of the extension item (e.g. ssl_cert). * @param exttype The type of Extensible that this ExtensionItem applies to. * @param owner The module which created this ExtensionItem */ ExtensionItem(const std::string& key, ExtensibleType exttype, Module* owner); /** Destroys an instance of the ExtensionItem class. */ virtual ~ExtensionItem(); /** Sets an ExtensionItem using a value in the internal format. * @param container A container the ExtensionItem should be set on. * @param value A value in the internal format. */ virtual void FromInternal(Extensible* container, const std::string& value); /** Sets an ExtensionItem using a value in the network format. * @param container A container the ExtensionItem should be set on. * @param value A value in the network format. */ virtual void FromNetwork(Extensible* container, const std::string& value); /** Gets an ExtensionItem's value in a human-readable format. * @param container The container the ExtensionItem is set on. * @param item The value to convert to a human-readable format. * @return The value specified in \p item in a human readable format. */ virtual std::string ToHuman(const Extensible* container, void* item) const; /** Gets an ExtensionItem's value in the internal format. * @param container The container the ExtensionItem is set on. * @param item The value to convert to the internal format. * @return The value specified in \p item in the internal format. */ virtual std::string ToInternal(const Extensible* container, void* item) const ; /** Gets an ExtensionItem's value in the network format. * @param container The container the ExtensionItem is set on. * @param item The value to convert to the network format. * @return The value specified in \p item in the network format. */ virtual std::string ToNetwork(const Extensible* container, void* item) const; /** Deallocates the specified ExtensionItem value. * @param container The container that the ExtensionItem is set on. * @param item The item to deallocate. */ virtual void free(Extensible* container, void* item) = 0; /** Registers this object with the ExtensionManager. */ void RegisterService() CXX11_OVERRIDE; /** DEPRECATED: use To{Human,Internal,Network} instead. */ DEPRECATED_METHOD(virtual std::string serialize(SerializeFormat format, const Extensible* container, void* item) const); /** DEPRECATED: use From{Internal,Network} instead. */ DEPRECATED_METHOD(virtual void unserialize(SerializeFormat format, Extensible* container, const std::string& value)); protected: /** Retrieves the value for this ExtensionItem from the internal map. * @param container The container that the ExtensionItem is set on. * @return Either the value of this ExtensionItem or NULL if it is not set. */ void* get_raw(const Extensible* container) const; /** Stores a value for this ExtensionItem in the internal map and returns the old value if one was set. * @param container A container the ExtensionItem should be set on. * @param value The value to set on the specified container. * @return Either the old value or NULL if one is not set. */ void* set_raw(Extensible* container, void* value); /** Removes the value for this ExtensionItem from the internal map and returns it. * @param container A container the ExtensionItem should be removed from. * @return Either the old value or NULL if one is not set. */ void* unset_raw(Extensible* container); }; /** class Extensible is the parent class of many classes such as User and Channel. * class Extensible implements a system which allows modules to 'extend' the class by attaching data within * a map associated with the object. In this way modules can store their own custom information within user * objects, channel objects and server objects, without breaking other modules (this is more sensible than using * a flags variable, and each module defining bits within the flag as 'theirs' as it is less prone to conflict and * supports arbitary data storage). */ class CoreExport Extensible : public classbase , public Serializable { public: typedef insp::flat_map<reference<ExtensionItem>, void*> ExtensibleStore; // Friend access for the protected getter/setter friend class ExtensionItem; private: /** Private data store. * Holds all extensible metadata for the class. */ ExtensibleStore extensions; /** True if this Extensible has been culled. * A warning is generated if false on destruction. */ unsigned int culled:1; public: /** * Get the extension items for iteraton (i.e. for metadata sync during netburst) */ inline const ExtensibleStore& GetExtList() const { return extensions; } Extensible(); CullResult cull() CXX11_OVERRIDE; virtual ~Extensible(); void doUnhookExtensions(const std::vector<reference<ExtensionItem> >& toRemove); /** * Free all extension items attached to this Extensible */ void FreeAllExtItems(); /** @copydoc Serializable::Deserialize. */ bool Deserialize(Data& data) CXX11_OVERRIDE; /** @copydoc Serializable::Deserialize. */ bool Serialize(Serializable::Data& data) CXX11_OVERRIDE; }; class CoreExport ExtensionManager { public: typedef std::map<std::string, reference<ExtensionItem> > ExtMap; bool Register(ExtensionItem* item); void BeginUnregister(Module* module, std::vector<reference<ExtensionItem> >& list); ExtensionItem* GetItem(const std::string& name); /** Get all registered extensions keyed by their names * @return Const map of ExtensionItem pointers keyed by their names */ const ExtMap& GetExts() const { return types; } private: ExtMap types; }; /** DEPRECATED: use ExtensionItem instead. */ typedef ExtensionItem LocalExtItem; template <typename T, typename Del = stdalgo::defaultdeleter<T> > class SimpleExtItem : public ExtensionItem { public: SimpleExtItem(const std::string& Key, ExtensibleType exttype, Module* parent) : ExtensionItem(Key, exttype, parent) { } virtual ~SimpleExtItem() { } inline T* get(const Extensible* container) const { return static_cast<T*>(get_raw(container)); } inline void set(Extensible* container, const T& value) { T* ptr = new T(value); T* old = static_cast<T*>(set_raw(container, ptr)); free(container, old); } inline void set(Extensible* container, T* value) { T* old = static_cast<T*>(set_raw(container, value)); free(container, old); } inline void unset(Extensible* container) { T* old = static_cast<T*>(unset_raw(container)); free(container, old); } void free(Extensible* container, void* item) CXX11_OVERRIDE { Del del; del(static_cast<T*>(item)); } }; class CoreExport LocalStringExt : public SimpleExtItem<std::string> { public: LocalStringExt(const std::string& key, ExtensibleType exttype, Module* owner); virtual ~LocalStringExt(); std::string ToInternal(const Extensible* container, void* item) const CXX11_OVERRIDE; void FromInternal(Extensible* container, const std::string& value) CXX11_OVERRIDE; }; class CoreExport LocalIntExt : public ExtensionItem { public: LocalIntExt(const std::string& key, ExtensibleType exttype, Module* owner); virtual ~LocalIntExt(); std::string ToInternal(const Extensible* container, void* item) const CXX11_OVERRIDE; void FromInternal(Extensible* container, const std::string& value) CXX11_OVERRIDE; intptr_t get(const Extensible* container) const; intptr_t set(Extensible* container, intptr_t value); void unset(Extensible* container) { set(container, 0); } void free(Extensible* container, void* item) CXX11_OVERRIDE; }; class CoreExport StringExtItem : public ExtensionItem { public: StringExtItem(const std::string& key, ExtensibleType exttype, Module* owner); virtual ~StringExtItem(); std::string* get(const Extensible* container) const; std::string ToNetwork(const Extensible* container, void* item) const CXX11_OVERRIDE; void FromNetwork(Extensible* container, const std::string& value) CXX11_OVERRIDE; void set(Extensible* container, const std::string& value); void unset(Extensible* container); void free(Extensible* container, void* item) CXX11_OVERRIDE; }; ����������������������������������������������������������inspircd-3.4.0/include/filelogger.h�����������������������������������������������������������������0000664�0000000�0000000�00000002172�13554550454�0017260�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * InspIRCd -- Internet Relay Chat Daemon * * Copyright (C) 2008 Thomas Stagner <aquanight@inspircd.org> * Copyright (C) 2007 Dennis Friis <peavey@inspircd.org> * * This file is part of InspIRCd. InspIRCd is free software: you can * redistribute it and/or modify it under the terms of the GNU General Public * License as published by the Free Software Foundation, version 2. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include "logger.h" /** A logging class which logs to a streamed file. */ class CoreExport FileLogStream : public LogStream { private: FileWriter *f; public: FileLogStream(LogLevel loglevel, FileWriter *fw); virtual ~FileLogStream(); void OnLog(LogLevel loglevel, const std::string& type, const std::string& msg) CXX11_OVERRIDE; }; ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/include/fileutils.h������������������������������������������������������������������0000664�0000000�0000000�00000006340�13554550454�0017142�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * InspIRCd -- Internet Relay Chat Daemon * * Copyright (C) 2013 Peter Powell <petpow@saberuk.com> * * This file is part of InspIRCd. InspIRCd is free software: you can * redistribute it and/or modify it under the terms of the GNU General Public * License as published by the Free Software Foundation, version 2. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once /** Provides an easy method of reading a text file into memory. */ class CoreExport FileReader { /** The lines of text in the file. */ std::vector<std::string> lines; /** File size in bytes. */ unsigned long totalSize; public: /** Initializes a new file reader. */ FileReader() : totalSize(0) { } /** Initializes a new file reader and reads the specified file. * @param filename The file to read into memory. */ FileReader(const std::string& filename); /** Loads a text file from disk. * @param filename The file to read into memory. * @throw CoreException The file can not be loaded. */ void Load(const std::string& filename); /** Retrieves the entire contents of the file cache as a single string. */ std::string GetString() const; /** Retrieves the entire contents of the file cache as a vector of strings. */ const std::vector<std::string>& GetVector() const { return lines; } /** Retrieves the total size in bytes of the file. */ unsigned long TotalSize() const { return totalSize; } }; /** Implements methods for file system access */ class CoreExport FileSystem { private: FileSystem() { } public: /** Expands a path fragment to a full path. * @param base The base path to expand from * @param fragment The path fragment to expand on top of base. */ static std::string ExpandPath(const std::string& base, const std::string& fragment); /** * Checks whether a file with the specified name exists on the filesystem. * @param path The path to a file. * @return True if the file exists; otherwise, false. */ static bool FileExists(const std::string& path); /** Gets the file name segment of a path. * @param path The path to extract the file name from. * @return The file name segment of a path. */ static std::string GetFileName(const std::string& path); /** Gets a list of files which exist in the specified directory. * @param directory The directory to retrieve files from. * @param entries A vector which entries will be added to. * @param match If defined then a glob match for files to be matched against. * @return True if the directory could be opened; otherwise false. */ static bool GetFileList(const std::string& directory, std::vector<std::string>& entries, const std::string& match = "*"); /** Determines whether the given path starts with a Windows drive letter. * @param path The path to validate. * @returns True if the path begins with a Windows drive letter; otherwise, false. */ static bool StartsWithWindowsDriveLetter(const std::string& path); }; ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/include/flat_map.h�������������������������������������������������������������������0000664�0000000�0000000�00000022463�13554550454�0016731�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * InspIRCd -- Internet Relay Chat Daemon * * Copyright (C) 2014 Attila Molnar <attilamolnar@hush.com> * * This file is part of InspIRCd. InspIRCd is free software: you can * redistribute it and/or modify it under the terms of the GNU General Public * License as published by the Free Software Foundation, version 2. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vector> namespace insp { namespace detail { template <typename T, typename Comp> class map_pair_compare : public Comp { typedef T value_type; typedef typename value_type::first_type key_type; public: bool operator()(const value_type& x, const value_type& y) const { return Comp::operator()(x.first, y.first); } bool operator()(const value_type& x, const key_type& y) const { return Comp::operator()(x.first, y); } bool operator()(const key_type& x, const value_type& y) const { return Comp::operator()(x, y.first); } }; template <typename Val, typename Comp> class map_value_compare : public std::binary_function<Val, Val, bool> { public: // Constructor should be private bool operator()(const Val& x, const Val& y) const { Comp c; return c(x.first, y.first); } }; template <typename T, typename Comp, typename Key = T, typename ElementComp = Comp> class flat_map_base { protected: typedef std::vector<T> storage_type; storage_type vect; public: typedef typename storage_type::iterator iterator; typedef typename storage_type::const_iterator const_iterator; typedef typename storage_type::reverse_iterator reverse_iterator; typedef typename storage_type::const_reverse_iterator const_reverse_iterator; typedef typename storage_type::size_type size_type; typedef typename storage_type::difference_type difference_type; typedef Key key_type; typedef T value_type; typedef Comp key_compare; typedef ElementComp value_compare; flat_map_base() { } flat_map_base(const flat_map_base& other) : vect(other.vect) { } size_type size() const { return vect.size(); } bool empty() const { return vect.empty(); } size_type capacity() const { return vect.capacity(); } size_type max_size() const { return vect.max_size(); } void clear() { vect.clear(); } void reserve(size_type n) { vect.reserve(n); } iterator begin() { return vect.begin(); } iterator end() { return vect.end(); } reverse_iterator rbegin() { return vect.rbegin(); } reverse_iterator rend() { return vect.rend(); } const_iterator begin() const { return vect.begin(); } const_iterator end() const { return vect.end(); } const_reverse_iterator rbegin() const { return vect.rbegin(); } const_reverse_iterator rend() const { return vect.rend(); } key_compare key_comp() const { return Comp(); } iterator erase(iterator it) { return vect.erase(it); } iterator erase(iterator first, iterator last) { return vect.erase(first, last); } size_type erase(const key_type& x) { size_type n = vect.size(); std::pair<iterator, iterator> itpair = equal_range(x); vect.erase(itpair.first, itpair.second); return n - vect.size(); } iterator find(const key_type& x) { value_compare c; iterator it = std::lower_bound(vect.begin(), vect.end(), x, c); if ((it != vect.end()) && (!c(x, *it))) return it; return vect.end(); } const_iterator find(const key_type& x) const { // Same as above but this time we return a const_iterator value_compare c; const_iterator it = std::lower_bound(vect.begin(), vect.end(), x, c); if ((it != vect.end()) && (!c(x, *it))) return it; return vect.end(); } std::pair<iterator, iterator> equal_range(const key_type& x) { return std::equal_range(vect.begin(), vect.end(), x, value_compare()); } std::pair<const_iterator, const_iterator> equal_range(const key_type& x) const { return std::equal_range(vect.begin(), vect.end(), x, value_compare()); } iterator lower_bound(const key_type& x) { return std::lower_bound(vect.begin(), vect.end(), x, value_compare()); } const_iterator lower_bound(const key_type& x) const { return std::lower_bound(vect.begin(), vect.end(), x, value_compare()); } iterator upper_bound(const key_type& x) { return std::upper_bound(vect.begin(), vect.end(), x, value_compare()); } const_iterator upper_bound(const key_type& x) const { return std::upper_bound(vect.begin(), vect.end(), x, value_compare()); } size_type count(const key_type& x) const { std::pair<const_iterator, const_iterator> itpair = equal_range(x); return std::distance(itpair.first, itpair.second); } protected: std::pair<iterator, bool> insert_single(const value_type& x) { bool inserted = false; value_compare c; iterator it = std::lower_bound(vect.begin(), vect.end(), x, c); if ((it == vect.end()) || (c(x, *it))) { inserted = true; it = vect.insert(it, x); } return std::make_pair(it, inserted); } iterator insert_multi(const value_type& x) { iterator it = std::lower_bound(vect.begin(), vect.end(), x, value_compare()); return vect.insert(it, x); } }; } // namespace detail template <typename T, typename Comp = std::less<T>, typename ElementComp = Comp> class flat_set : public detail::flat_map_base<T, Comp, T, ElementComp> { typedef detail::flat_map_base<T, Comp, T, ElementComp> base_t; public: typedef typename base_t::iterator iterator; typedef typename base_t::value_type value_type; flat_set() { } template <typename InputIterator> flat_set(InputIterator first, InputIterator last) { this->insert(first, last); } flat_set(const flat_set& other) : base_t(other) { } std::pair<iterator, bool> insert(const value_type& x) { return this->insert_single(x); } template <typename InputIterator> void insert(InputIterator first, InputIterator last) { for (; first != last; ++first) this->insert_single(*first); } void swap(flat_set& other) { base_t::vect.swap(other.vect); } }; template <typename T, typename Comp = std::less<T>, typename ElementComp = Comp> class flat_multiset : public detail::flat_map_base<T, Comp, T, ElementComp> { typedef detail::flat_map_base<T, Comp, T, ElementComp> base_t; public: typedef typename base_t::iterator iterator; typedef typename base_t::value_type value_type; flat_multiset() { } template <typename InputIterator> flat_multiset(InputIterator first, InputIterator last) { this->insert(first, last); } flat_multiset(const flat_multiset& other) : base_t(other) { } iterator insert(const value_type& x) { return this->insert_multi(x); } template <typename InputIterator> void insert(InputIterator first, InputIterator last) { for (; first != last; ++first) insert_multi(*first); } void swap(flat_multiset& other) { base_t::vect.swap(other.vect); } }; template <typename T, typename U, typename Comp = std::less<T>, typename ElementComp = Comp > class flat_map : public detail::flat_map_base<std::pair<T, U>, Comp, T, detail::map_pair_compare<std::pair<T, U>, ElementComp> > { typedef detail::flat_map_base<std::pair<T, U>, Comp, T, detail::map_pair_compare<std::pair<T, U>, ElementComp> > base_t; public: typedef typename base_t::iterator iterator; typedef typename base_t::key_type key_type; typedef typename base_t::value_type value_type; typedef U mapped_type; typedef typename base_t::value_compare value_compare; flat_map() { } template <typename InputIterator> flat_map(InputIterator first, InputIterator last) { insert(first, last); } flat_map(const flat_map& other) : base_t(other) { } std::pair<iterator, bool> insert(const value_type& x) { return this->insert_single(x); } template <typename InputIterator> void insert(InputIterator first, InputIterator last) { for (; first != last; ++first) this->insert_single(*first); } void swap(flat_map& other) { base_t::vect.swap(other.vect); } mapped_type& operator[](const key_type& x) { return insert(std::make_pair(x, mapped_type())).first->second; } value_compare value_comp() const { return value_compare(); } }; template <typename T, typename U, typename Comp = std::less<T>, typename ElementComp = Comp > class flat_multimap : public detail::flat_map_base<std::pair<T, U>, Comp, T, detail::map_pair_compare<std::pair<T, U>, ElementComp> > { typedef detail::flat_map_base<std::pair<T, U>, Comp, T, detail::map_pair_compare<std::pair<T, U>, ElementComp> > base_t; public: typedef typename base_t::iterator iterator; typedef typename base_t::value_type value_type; typedef U mapped_type; typedef typename base_t::value_compare value_compare; flat_multimap() { } template <typename InputIterator> flat_multimap(InputIterator first, InputIterator last) { this->insert(first, last); } flat_multimap(const flat_multimap& other) : base_t(other) { } iterator insert(const value_type& x) { return this->insert_multi(x); } template <typename InputIterator> void insert(InputIterator first, InputIterator last) { for (; first != last; ++first) this->insert_multi(*first); } void swap(flat_multimap& other) { base_t::vect.swap(other.vect); } value_compare value_comp() const { return value_compare(); } }; } // namespace insp �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/include/hashcomp.h�������������������������������������������������������������������0000664�0000000�0000000�00000022001�13554550454�0016734�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * InspIRCd -- Internet Relay Chat Daemon * * Copyright (C) 2011 Adam <Adam@anope.org> * Copyright (C) 2009 Daniel De Graaf <danieldg@inspircd.org> * Copyright (C) 2007, 2009 Dennis Friis <peavey@inspircd.org> * Copyright (C) 2005-2009 Craig Edwards <craigedwards@brainbox.cc> * Copyright (C) 2007-2008 Robin Burchell <robin+git@viroteck.net> * Copyright (C) 2008 Pippijn van Steenhoven <pip88nl@gmail.com> * * This file is part of InspIRCd. InspIRCd is free software: you can * redistribute it and/or modify it under the terms of the GNU General Public * License as published by the Free Software Foundation, version 2. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <cstring> #include <string> #include <vector> #include <deque> #include <map> #include <set> #include "inspircd.h" #include "convto.h" /******************************************************* * This file contains classes and templates that deal * with the comparison and hashing of 'irc strings'. * An 'irc string' is a string which compares in a * case insensitive manner, and as per RFC 1459 will * treat [ identical to {, ] identical to }, and \ * as identical to |. * * There are functors that accept std::string and * compare/hash them as type irc::string by using * mapping arrays internally. *******************************************************/ /** Seperate from the other casemap tables so that code *can* still exclusively rely on RFC casemapping * if it must. * * This is provided as a pointer so that modules can change it to their custom mapping tables, * e.g. for national character support. */ CoreExport extern unsigned const char *national_case_insensitive_map; /** A mapping of uppercase to lowercase, including scandinavian * 'oddities' as specified by RFC1459, e.g. { -> [, and | -> \ */ CoreExport extern unsigned const char rfc_case_insensitive_map[256]; /** Case insensitive map, ASCII rules. * That is; * [ != {, but A == a. */ CoreExport extern unsigned const char ascii_case_insensitive_map[256]; /** The irc namespace contains a number of helper classes. */ namespace irc { /** Check if two IRC object (e.g. nick or channel) names are equal. * This function uses national_case_insensitive_map to determine equality, which, by default does comparison * according to RFC 1459, treating certain otherwise non-identical characters as identical. * @param s1 First string to compare * @param s2 Second string to compare * @return True if the two names are equal, false otherwise */ CoreExport bool equals(const std::string& s1, const std::string& s2); /** Check whether \p needle exists within \p haystack. * @param haystack The string to search within. * @param needle The string to search for. * @return Either the index at which \p needle was found or std::string::npos. */ CoreExport size_t find(const std::string& haystack, const std::string& needle); /** This class returns true if two strings match. * Case sensitivity is ignored, and the RFC 'character set' * is adhered to */ struct StrHashComp { /** The operator () does the actual comparison in hash_map */ bool operator()(const std::string& s1, const std::string& s2) const { return equals(s1, s2); } }; struct insensitive { size_t CoreExport operator()(const std::string &s) const; }; struct insensitive_swo { bool CoreExport operator()(const std::string& a, const std::string& b) const; }; /** irc::sepstream allows for splitting token seperated lists. * Each successive call to sepstream::GetToken() returns * the next token, until none remain, at which point the method returns * false. */ class CoreExport sepstream { protected: /** Original string. */ std::string tokens; /** Separator value */ char sep; /** Current string position */ size_t pos; /** If set then GetToken() can return an empty string */ bool allow_empty; public: /** Create a sepstream and fill it with the provided data */ sepstream(const std::string &source, char separator, bool allowempty = false); /** Fetch the next token from the stream * @param token The next token from the stream is placed here * @return True if tokens still remain, false if there are none left */ bool GetToken(std::string& token); /** Fetch the next numeric token from the stream * @param token The next token from the stream is placed here * @return True if tokens still remain, false if there are none left */ template<typename Numeric> bool GetNumericToken(Numeric& token) { std::string str; if (!GetToken(str)) return false; token = ConvToNum<Numeric>(str); return true; } /** Fetch the entire remaining stream, without tokenizing * @return The remaining part of the stream */ const std::string GetRemaining(); /** Returns true if the end of the stream has been reached * @return True if the end of the stream has been reached, otherwise false */ bool StreamEnd(); /** Returns true if the specified value exists in the stream * @param value The value to search for * @return True if the value was found, False otherwise */ bool Contains(const std::string& value); }; /** A derived form of sepstream, which seperates on commas */ class CoreExport commasepstream : public sepstream { public: /** Initialize with comma separator */ commasepstream(const std::string &source, bool allowempty = false) : sepstream(source, ',', allowempty) { } }; /** A derived form of sepstream, which seperates on spaces */ class CoreExport spacesepstream : public sepstream { public: /** Initialize with space separator */ spacesepstream(const std::string &source, bool allowempty = false) : sepstream(source, ' ', allowempty) { } }; /** irc::tokenstream reads a string formatted as per RFC1459 and RFC2812. * It will split the string into 'tokens' each containing one parameter * from the string. * For instance, if it is instantiated with the string: * "PRIVMSG #test :foo bar baz qux" * then each successive call to tokenstream::GetToken() will return * "PRIVMSG", "#test", "foo bar baz qux", "". * Note that if the whole string starts with a colon this is not taken * to mean the string is all one parameter, and the first item in the * list will be ":item". This is to allow for parsing 'source' fields * from data. */ class CoreExport tokenstream { private: /** The message we are parsing tokens from. */ std::string message; /** The current position within the message. */ size_t position; public: /** Create a tokenstream and fill it with the provided data. */ tokenstream(const std::string& msg, size_t start = 0, size_t end = std::string::npos); /** Retrieves the underlying message. */ std::string& GetMessage() { return message; } /** Retrieve the next \<middle> token in the token stream. * @param token The next token available, or an empty string if none remain. * @return True if tokens are left to be read, false if the last token was just retrieved. */ bool GetMiddle(std::string& token); /** Retrieve the next \<trailing> token in the token stream. * @param token The next token available, or an empty string if none remain. * @return True if tokens are left to be read, false if the last token was just retrieved. */ bool GetTrailing(std::string& token); }; /** The portparser class seperates out a port range into integers. * A port range may be specified in the input string in the form * "6660,6661,6662-6669,7020". The end of the stream is indicated by * a return value of 0 from portparser::GetToken(). If you attempt * to specify an illegal range (e.g. one where start >= end, or * start or end < 0) then GetToken() will return the first element * of the pair of numbers. */ class CoreExport portparser { private: /** Used to split on commas */ commasepstream sep; /** Current position in a range of ports */ long in_range; /** Starting port in a range of ports */ long range_begin; /** Ending port in a range of ports */ long range_end; /** Allow overlapped port ranges */ bool overlapped; /** Used to determine overlapping of ports * without O(n) algorithm being used */ std::set<long> overlap_set; /** Returns true if val overlaps an existing range */ bool Overlaps(long val); public: /** Create a portparser and fill it with the provided data * @param source The source text to parse from * @param allow_overlapped Allow overlapped ranges */ portparser(const std::string &source, bool allow_overlapped = true); /** Fetch the next token from the stream * @return The next port number is returned, or 0 if none remain */ long GetToken(); }; } �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/include/inspircd.h�������������������������������������������������������������������0000664�0000000�0000000�00000047225�13554550454�0016764�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * InspIRCd -- Internet Relay Chat Daemon * * Copyright (C) 2009 Daniel De Graaf <danieldg@inspircd.org> * Copyright (C) 2007-2008 Robin Burchell <robin+git@viroteck.net> * Copyright (C) 2008 Pippijn van Steenhoven <pip88nl@gmail.com> * Copyright (C) 2003-2008 Craig Edwards <craigedwards@brainbox.cc> * Copyright (C) 2006-2007 Oliver Lupton <oliverlupton@gmail.com> * Copyright (C) 2007 Dennis Friis <peavey@inspircd.org> * Copyright (C) 2003 randomdan <???@???> * * This file is part of InspIRCd. InspIRCd is free software: you can * redistribute it and/or modify it under the terms of the GNU General Public * License as published by the Free Software Foundation, version 2. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once // If the system has a pre-C11 stdint header this must be defined in // order to use the numeric limit macros. #define __STDC_LIMIT_MACROS #include <cfloat> #include <climits> #include <cmath> #include <csignal> #include <cstdarg> #include <cstdio> #include <cstring> #include <ctime> #include <stdint.h> #include <algorithm> #include <bitset> #include <deque> #include <list> #include <map> #include <set> #include <sstream> #include <string> #include <vector> #include "intrusive_list.h" #include "flat_map.h" #include "compat.h" #include "aligned_storage.h" #include "typedefs.h" #include "convto.h" #include "stdalgo.h" CoreExport extern InspIRCd* ServerInstance; /** Base class for manager classes that are still accessed using -> but are no longer pointers */ template <typename T> struct fakederef { T* operator->() { return static_cast<T*>(this); } }; #include "config.h" #include "dynref.h" #include "consolecolors.h" #include "cull_list.h" #include "serialize.h" #include "extensible.h" #include "fileutils.h" #include "ctables.h" #include "numerics.h" #include "numeric.h" #include "uid.h" #include "server.h" #include "users.h" #include "channels.h" #include "timer.h" #include "hashcomp.h" #include "logger.h" #include "usermanager.h" #include "socket.h" #include "command_parse.h" #include "mode.h" #include "socketengine.h" #include "snomasks.h" #include "filelogger.h" #include "message.h" #include "modules.h" #include "clientprotocol.h" #include "threadengine.h" #include "configreader.h" #include "inspstring.h" #include "protocol.h" #include "bancache.h" #include "isupportmanager.h" /** This class contains various STATS counters * It is used by the InspIRCd class, which internally * has an instance of it. */ class serverstats { public: /** Number of accepted connections */ unsigned long Accept; /** Number of failed accepts */ unsigned long Refused; /** Number of unknown commands seen */ unsigned long Unknown; /** Number of nickname collisions handled */ unsigned long Collisions; /** Number of DNS queries sent out */ unsigned long Dns; /** Number of good DNS replies received * NOTE: This may not tally to the number sent out, * due to timeouts and other latency issues. */ unsigned long DnsGood; /** Number of bad (negative) DNS replies received * NOTE: This may not tally to the number sent out, * due to timeouts and other latency issues. */ unsigned long DnsBad; /** Number of inbound connections seen */ unsigned long Connects; /** Total bytes of data transmitted */ unsigned long Sent; /** Total bytes of data received */ unsigned long Recv; #ifdef _WIN32 /** Cpu usage at last sample */ FILETIME LastCPU; /** Time QP sample was read */ LARGE_INTEGER LastSampled; /** QP frequency */ LARGE_INTEGER QPFrequency; #else /** Cpu usage at last sample */ timeval LastCPU; /** Time last sample was read */ timespec LastSampled; #endif /** The constructor initializes all the counts to zero */ serverstats() : Accept(0), Refused(0), Unknown(0), Collisions(0), Dns(0), DnsGood(0), DnsBad(0), Connects(0), Sent(0), Recv(0) { } }; /** The main class of the irc server. * This class contains instances of all the other classes in this software. * Amongst other things, it contains a ModeParser, a DNS object, a CommandParser * object, and a list of active Module objects, and facilities for Module * objects to interact with the core system it implements. */ class CoreExport InspIRCd { private: /** Set up the signal handlers */ void SetSignals(); /** Daemonize the ircd and close standard input/output streams * @return True if the program daemonized succesfully */ bool DaemonSeed(); /** The current time, updated in the mainloop */ struct timespec TIME; /** A 64k buffer used to read socket data into * NOTE: update ValidateNetBufferSize if you change this */ char ReadBuffer[65535]; ClientProtocol::RFCEvents rfcevents; /** Check we aren't running as root, and exit if we are * with exit code EXIT_STATUS_ROOT. */ void CheckRoot(); public: UIDGenerator UIDGen; /** Global cull list, will be processed on next iteration */ CullList GlobalCulls; /** Actions that must happen outside of the current call stack */ ActionList AtomicActions; /** Globally accessible fake user record. This is used to force mode changes etc across s2s, etc.. bit ugly, but.. better than how this was done in 1.1 * Reason for it: * kludge alert! * SendMode expects a User* to send the numeric replies * back to, so we create it a fake user that isnt in the user * hash and set its descriptor to FD_MAGIC_NUMBER so the data * falls into the abyss :p */ FakeUser* FakeClient; /** Find a user in the UUID hash * @param uid The UUID to find * @return A pointer to the user, or NULL if the user does not exist */ User* FindUUID(const std::string &uid); /** Time this ircd was booted */ time_t startup_time; /** Config file pathname specified on the commandline or via ./configure */ std::string ConfigFileName; ExtensionManager Extensions; /** Mode handler, handles mode setting and removal */ ModeParser Modes; /** Command parser, handles client to server commands */ CommandParser Parser; /** Thread engine, Handles threading where required */ ThreadEngine Threads; /** The thread/class used to read config files in REHASH and on startup */ ConfigReaderThread* ConfigThread; /** LogManager handles logging. */ LogManager Logs; /** ModuleManager contains everything related to loading/unloading * modules. */ ModuleManager Modules; /** BanCacheManager is used to speed up checking of restrictions on connection * to the IRCd. */ BanCacheManager BanCache; /** Stats class, holds miscellaneous stats counters */ serverstats stats; /** Server Config class, holds configuration file data */ ServerConfig* Config; /** Snomask manager - handles routing of snomask messages * to opers. */ SnomaskManager SNO; /** Timer manager class, triggers Timer timer events */ TimerManager Timers; /** X-line manager. Handles G/K/Q/E-line setting, removal and matching */ XLineManager* XLines; /** User manager. Various methods and data associated with users. */ UserManager Users; /** Channel list, a hash_map containing all channels XXX move to channel manager class */ chan_hash chanlist; /** List of the open ports */ std::vector<ListenSocket*> ports; /** Set to the current signal received */ static sig_atomic_t s_signal; /** Protocol interface, overridden by server protocol modules */ ProtocolInterface* PI; /** Default implementation of the ProtocolInterface, does nothing */ ProtocolInterface DefaultProtocolInterface; /** Manages the generation and transmission of ISUPPORT. */ ISupportManager ISupport; /** Get the current time * Because this only calls time() once every time around the mainloop, * it is much faster than calling time() directly. * @return The current time as an epoch value (time_t) */ inline time_t Time() { return TIME.tv_sec; } /** The fractional time at the start of this mainloop iteration (nanoseconds) */ inline long Time_ns() { return TIME.tv_nsec; } /** Update the current time. Don't call this unless you have reason to do so. */ void UpdateTime(); /** Generate a random string with the given length * @param length The length in bytes * @param printable if false, the string will use characters 0-255; otherwise, * it will be limited to 0x30-0x7E ('0'-'~', nonspace printable characters) */ std::string GenRandomStr(unsigned int length, bool printable = true); /** Generate a random integer. * This is generally more secure than rand() */ unsigned long GenRandomInt(unsigned long max); /** Fill a buffer with random bits */ TR1NS::function<void(char*, size_t)> GenRandom; /** Fills the output buffer with the specified number of random characters. * This is the default function for InspIRCd::GenRandom. * @param output The output buffer to store random characters in. * @param max The maximum number of random characters to put in the buffer. */ static void DefaultGenRandom(char* output, size_t max); /** Bind to a specific port from a config tag. * @param tag the tag that contains bind information. * @param sa The endpoint to listen on. * @param old_ports Previously listening ports that may be on the same endpoint. */ bool BindPort(ConfigTag* tag, const irc::sockets::sockaddrs& sa, std::vector<ListenSocket*>& old_ports); /** Bind all ports specified in the configuration file. * @return The number of ports bound without error */ int BindPorts(FailedPortList &failed_ports); /** Find a user in the nick hash. * If the user cant be found in the nick hash check the uuid hash * @param nick The nickname to find * @return A pointer to the user, or NULL if the user does not exist */ User* FindNick(const std::string &nick); /** Find a user in the nick hash ONLY */ User* FindNickOnly(const std::string &nick); /** Find a channel in the channels hash * @param chan The channel to find * @return A pointer to the channel, or NULL if the channel does not exist */ Channel* FindChan(const std::string &chan); /** Get a hash map containing all channels, keyed by their name * @return A hash map mapping channel names to Channel pointers */ chan_hash& GetChans() { return chanlist; } /** Determines whether an channel name is valid. */ TR1NS::function<bool(const std::string&)> IsChannel; /** Determines whether a channel name is valid according to the RFC 1459 rules. * This is the default function for InspIRCd::IsChannel. * @param channel The channel name to validate. * @return True if the channel name is valid according to RFC 1459 rules; otherwise, false. */ static bool DefaultIsChannel(const std::string& channel); /** Determines whether a hostname is valid according to RFC 5891 rules. * @param host The hostname to validate. * @return True if the hostname is valid; otherwise, false. */ static bool IsHost(const std::string& host); /** Return true if str looks like a server ID * @param sid string to check against */ static bool IsSID(const std::string& sid); /** Handles incoming signals after being set * @param signal the signal received */ void SignalHandler(int signal); /** Sets the signal received * @param signal the signal received */ static void SetSignal(int signal); /** Causes the server to exit after unloading modules and * closing all open file descriptors. * * @param status The exit code to give to the operating system * (See the ExitStatus enum for valid values) */ void Exit(int status); /** Formats the input string with the specified arguments. * @param formatString The string to format * @param ... A variable number of format arguments. * @return The formatted string */ static std::string Format(const char* formatString, ...) CUSTOM_PRINTF(1, 2); static std::string Format(va_list& vaList, const char* formatString) CUSTOM_PRINTF(2, 0); /** Determines whether a nickname is valid. */ TR1NS::function<bool(const std::string&)> IsNick; /** Determines whether a nickname is valid according to the RFC 1459 rules. * This is the default function for InspIRCd::IsNick. * @param nick The nickname to validate. * @return True if the nickname is valid according to RFC 1459 rules; otherwise, false. */ static bool DefaultIsNick(const std::string& nick); /** Determines whether an ident is valid. */ TR1NS::function<bool(const std::string&)> IsIdent; /** Determines whether a ident is valid according to the RFC 1459 rules. * This is the default function for InspIRCd::IsIdent. * @param ident The ident to validate. * @return True if the ident is valid according to RFC 1459 rules; otherwise, false. */ static bool DefaultIsIdent(const std::string& ident); /** Match two strings using pattern matching, optionally, with a map * to check case against (may be NULL). If map is null, match will be case insensitive. * @param str The literal string to match against * @param mask The glob pattern to match against. * @param map The character map to use when matching. */ static bool Match(const std::string& str, const std::string& mask, unsigned const char* map = NULL); static bool Match(const char* str, const char* mask, unsigned const char* map = NULL); /** Match two strings using pattern matching, optionally, with a map * to check case against (may be NULL). If map is null, match will be case insensitive. * Supports CIDR patterns as well as globs. * @param str The literal string to match against * @param mask The glob or CIDR pattern to match against. * @param map The character map to use when matching. */ static bool MatchCIDR(const std::string& str, const std::string& mask, unsigned const char* map = NULL); static bool MatchCIDR(const char* str, const char* mask, unsigned const char* map = NULL); /** Matches a hostname and IP against a space delimited list of hostmasks. * @param masks The space delimited masks to match against. * @param hostname The hostname to try and match. * @param ipaddr The IP address to try and match. */ static bool MatchMask(const std::string& masks, const std::string& hostname, const std::string& ipaddr); /** Return true if the given parameter is a valid nick!user\@host mask * @param mask A nick!user\@host masak to match against * @return True i the mask is valid */ static bool IsValidMask(const std::string& mask); /** Strips all color and control codes except 001 from the given string * @param sentence The string to strip from */ static void StripColor(std::string &sentence); /** Parses color codes from string values to actual color codes * @param input The data to process */ static void ProcessColors(file_cache& input); /** Rehash the local server * @param uuid The uuid of the user who started the rehash, can be empty */ void Rehash(const std::string& uuid = ""); /** Calculate a duration in seconds from a string in the form 1y2w3d4h6m5s * @param str A string containing a time in the form 1y2w3d4h6m5s * (one year, two weeks, three days, four hours, six minutes and five seconds) * @return The total number of seconds */ static unsigned long Duration(const std::string& str); /** Calculate a duration in seconds from a string in the form 1y2w3d4h6m5s * @param str A string containing a time in the form 1y2w3d4h6m5s * (one year, two weeks, three days, four hours, six minutes and five seconds) * @param duration The location to place the parsed duration valur * @return Whether the duration was a valid format or not */ static bool Duration(const std::string& str, unsigned long& duration); /** Determines whether a string contains a valid duration. * @param str A string containing a time in the form 1y2w3d4h6m5s * @return True if the string is a valid duration; otherwise, false. */ static bool IsValidDuration(const std::string& str); /** Return a duration in seconds as a human-readable string. * @param duration The duration in seconds to convert to a human-readable string. * @return A string representing the given duration. */ static std::string DurationString(time_t duration); /** Attempt to compare a password to a string from the config file. * This will be passed to handling modules which will compare the data * against possible hashed equivalents in the input string. * @param ex The object (user, server, whatever) causing the comparison. * @param data The data from the config file * @param input The data input by the oper * @param hashtype The hash from the config file * @return True if the strings match, false if they do not */ bool PassCompare(Extensible* ex, const std::string& data, const std::string& input, const std::string& hashtype); /** Returns the full version string of this ircd * @return The version string */ std::string GetVersionString(bool getFullVersion = false); /** 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, bool exitonfail = true); /** This constructor initialises all the subsystems and reads the config file. * @param argc The argument count passed to main() * @param argv The argument list passed to main() * @throw <anything> If anything is thrown from here and makes it to * you, you should probably just give up and go home. Yes, really. * It's that bad. Higher level classes should catch any non-fatal exceptions. */ InspIRCd(int argc, char** argv); /** Prepare the ircd for restart or shutdown. * This function unloads all modules which can be unloaded, * closes all open sockets, and closes the logfile. */ void Cleanup(); /** Return a time_t as a human-readable string. * @param format The format to retrieve the date/time in. See `man 3 strftime` * for more information. If NULL, "%a %b %d %T %Y" is assumed. * @param curtime The timestamp to convert to a human-readable string. * @param utc True to convert the time to string as-is, false to convert it to local time first. * @return A string representing the given date/time. */ static std::string TimeString(time_t curtime, const char* format = NULL, bool utc = false); /** Compare two strings in a timing-safe way. If the lengths of the strings differ, the function * returns false immediately (leaking information about the length), otherwise it compares each * character and only returns after all characters have been compared. * @param one First string * @param two Second string * @return True if the strings match, false if they don't */ static bool TimingSafeCompare(const std::string& one, const std::string& two); /** Begin execution of the server. * NOTE: this function NEVER returns. Internally, * it will repeatedly loop. */ void Run(); char* GetReadBuffer() { return this->ReadBuffer; } ClientProtocol::RFCEvents& GetRFCEvents() { return rfcevents; } }; ENTRYPOINT; inline void stdalgo::culldeleter::operator()(classbase* item) { if (item) ServerInstance->GlobalCulls.AddItem(item); } inline void Channel::Write(ClientProtocol::EventProvider& protoevprov, ClientProtocol::Message& msg, char status, const CUList& except_list) { ClientProtocol::Event event(protoevprov, msg); Write(event, status, except_list); } inline void LocalUser::Send(ClientProtocol::EventProvider& protoevprov, ClientProtocol::Message& msg) { ClientProtocol::Event event(protoevprov, msg); Send(event); } #include "numericbuilder.h" #include "clientprotocolmsg.h" #include "clientprotocolevent.h" ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/include/inspsocket.h�����������������������������������������������������������������0000664�0000000�0000000�00000030426�13554550454�0017326�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * InspIRCd -- Internet Relay Chat Daemon * * Copyright (C) 2009 Daniel De Graaf <danieldg@inspircd.org> * Copyright (C) 2007-2008 Robin Burchell <robin+git@viroteck.net> * Copyright (C) 2007 Dennis Friis <peavey@inspircd.org> * Copyright (C) 2006-2007 Craig Edwards <craigedwards@brainbox.cc> * Copyright (C) 2006 Oliver Lupton <oliverlupton@gmail.com> * * This file is part of InspIRCd. InspIRCd is free software: you can * redistribute it and/or modify it under the terms of the GNU General Public * License as published by the Free Software Foundation, version 2. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include "timer.h" class IOHook; /** * States which a socket may be in */ enum BufferedSocketState { /** Socket disconnected */ I_DISCONNECTED, /** Socket connecting */ I_CONNECTING, /** Socket fully connected */ I_CONNECTED, /** Socket has an error */ I_ERROR }; /** * Error types which a socket may exhibit */ enum BufferedSocketError { /** No error */ I_ERR_NONE, /** Socket was closed by peer */ I_ERR_DISCONNECT, /** Socket connect timed out */ I_ERR_TIMEOUT, /** Socket could not be created */ I_ERR_SOCKET, /** Socket could not connect (refused) */ I_ERR_CONNECT, /** Socket could not bind to local port/ip */ I_ERR_BIND, /** Socket could not write data */ I_ERR_WRITE, /** No more file descriptors left to create socket! */ I_ERR_NOMOREFDS, /** Some other error */ I_ERR_OTHER }; /* Required forward declarations */ class BufferedSocket; /** Used to time out socket connections */ class CoreExport SocketTimeout : public Timer { private: /** BufferedSocket the class is attached to */ BufferedSocket* sock; /** File descriptor of class this is attached to */ int sfd; public: /** Create a socket timeout class * @param fd File descriptor of BufferedSocket * @param thesock BufferedSocket to attach to * @param secs_from_now Seconds from now to time out */ SocketTimeout(int fd, BufferedSocket* thesock, unsigned int secs_from_now) : Timer(secs_from_now) , sock(thesock) , sfd(fd) { } /** Handle tick event */ bool Tick(time_t now) CXX11_OVERRIDE; }; /** * StreamSocket is a class that wraps a TCP socket and handles send * and receive queues, including passing them to IO hooks */ class CoreExport StreamSocket : public EventHandler { public: /** Socket send queue */ class SendQueue { public: /** One element of the queue, a continuous buffer */ typedef std::string Element; /** Sequence container of buffers in the queue */ typedef std::deque<Element> Container; /** Container iterator */ typedef Container::const_iterator const_iterator; SendQueue() : nbytes(0) { } /** Return whether the queue is empty * @return True if the queue is empty, false otherwise */ bool empty() const { return (nbytes == 0); } /** Get the number of individual buffers in the queue * @return Number of individual buffers in the queue */ Container::size_type size() const { return data.size(); } /** Get the number of queued bytes * @return Size in bytes of the data in the queue */ size_t bytes() const { return nbytes; } /** Get the first buffer of the queue * @return A reference to the first buffer in the queue */ const Element& front() const { return data.front(); } /** Get an iterator to the first buffer in the queue. * The returned iterator cannot be used to make modifications to the queue, * for that purpose the member functions push_*(), pop_front(), erase_front() and clear() can be used. * @return Iterator referring to the first buffer in the queue, or end() if there are no elements. */ const_iterator begin() const { return data.begin(); } /** Get an iterator to the (theoretical) buffer one past the end of the queue. * @return Iterator referring to one element past the end of the container */ const_iterator end() const { return data.end(); } /** Remove the first buffer in the queue */ void pop_front() { nbytes -= data.front().length(); data.pop_front(); } /** Remove bytes from the beginning of the first buffer * @param n Number of bytes to remove */ void erase_front(Element::size_type n) { nbytes -= n; data.front().erase(0, n); } /** Insert a new buffer at the beginning of the queue * @param newdata Data to add */ void push_front(const Element& newdata) { data.push_front(newdata); nbytes += newdata.length(); } /** Insert a new buffer at the end of the queue * @param newdata Data to add */ void push_back(const Element& newdata) { data.push_back(newdata); nbytes += newdata.length(); } /** Clear the queue */ void clear() { data.clear(); nbytes = 0; } void moveall(SendQueue& other) { nbytes += other.bytes(); data.insert(data.end(), other.data.begin(), other.data.end()); other.clear(); } private: /** Private send queue. Note that individual strings may be shared. */ Container data; /** Length, in bytes, of the sendq */ size_t nbytes; }; /** The type of socket this IOHook represents. */ enum Type { SS_UNKNOWN, SS_USER }; private: /** Whether this socket should close once its sendq is empty */ bool closeonempty; /** Whether the socket is currently closing or not, used to avoid repeatedly closing a closed socket */ bool closing; /** The IOHook that handles raw I/O for this socket, or NULL */ IOHook* iohook; /** Send queue of the socket */ SendQueue sendq; /** Error - if nonempty, the socket is dead, and this is the reason. */ std::string error; /** Check if the socket has an error set, if yes, call OnError * @param err Error to pass to OnError() */ void CheckError(BufferedSocketError err); /** Read data from the socket into the recvq, if successful call OnDataReady() */ void DoRead(); /** Send as much data contained in a SendQueue object as possible. * All data which successfully sent will be removed from the SendQueue. * @param sq SendQueue to flush */ void FlushSendQ(SendQueue& sq); /** Read incoming data into a receive queue. * @param rq Receive queue to put incoming data into * @return < 0 on error or close, 0 if no new data is ready (but the socket is still connected), > 0 if data was read from the socket and put into the recvq */ int ReadToRecvQ(std::string& rq); /** Read data from a hook chain recursively, starting at 'hook'. * If 'hook' is NULL, the recvq is filled with data from SocketEngine::Recv(), otherwise it is filled with data from the * next hook in the chain. * @param hook Next IOHook in the chain, can be NULL * @param rq Receive queue to put incoming data into * @return < 0 on error or close, 0 if no new data is ready (but the socket is still connected), > 0 if data was read from the socket and put into the recvq */ int HookChainRead(IOHook* hook, std::string& rq); protected: /** The data which has been received from the socket. */ std::string recvq; /** Swaps the internals of this StreamSocket with another one. * @param other A StreamSocket to swap internals with. */ void SwapInternals(StreamSocket& other); public: const Type type; StreamSocket(Type sstype = SS_UNKNOWN) : closeonempty(false) , closing(false) , iohook(NULL) , type(sstype) { } IOHook* GetIOHook() const; void AddIOHook(IOHook* hook); void DelIOHook(); /** Flush the send queue */ void DoWrite(); /** Called by the socket engine on a read event */ void OnEventHandlerRead() CXX11_OVERRIDE; /** Called by the socket engine on a write event */ void OnEventHandlerWrite() CXX11_OVERRIDE; /** Called by the socket engine on error * @param errcode Error */ void OnEventHandlerError(int errcode) CXX11_OVERRIDE; /** Sets the error message for this socket. Once set, the socket is dead. */ void SetError(const std::string& err) { if (error.empty()) error = err; } /** Gets the error message for this socket. */ const std::string& getError() const { return error; } /** Called when new data is present in recvq */ virtual void OnDataReady() = 0; /** Called when the socket gets an error from socket engine or IO hook */ virtual void OnError(BufferedSocketError e) = 0; /** Called when the endpoint addresses are changed. * @param local The new local endpoint. * @param remote The new remote endpoint. * @return true if the connection is still open, false if it has been closed */ virtual bool OnSetEndPoint(const irc::sockets::sockaddrs& local, const irc::sockets::sockaddrs& remote); /** Send the given data out the socket, either now or when writes unblock */ void WriteData(const std::string& data); /** Convenience function: read a line from the socket * @param line The line read * @param delim The line delimiter * @return true if a line was read */ bool GetNextLine(std::string& line, char delim = '\n'); /** Useful for implementing sendq exceeded */ size_t getSendQSize() const; SendQueue& GetSendQ() { return sendq; } /** * Close the socket, remove from socket engine, etc */ virtual void Close(); /** If writeblock is true then only close the socket if all data has been sent. Otherwise, close immediately. */ void Close(bool writeblock); /** This ensures that close is called prior to destructor */ CullResult cull() CXX11_OVERRIDE; /** Get the IOHook of a module attached to this socket * @param mod Module whose IOHook to return * @return IOHook belonging to the module or NULL if the module haven't attached an IOHook to this socket */ IOHook* GetModHook(Module* mod) const; }; /** * BufferedSocket is an extendable socket class which modules * can use for TCP socket support. It is fully integrated * into InspIRCds socket loop and attaches its sockets to * the core's instance of the SocketEngine class, meaning * that all use is fully asynchronous. * * To use BufferedSocket, you must inherit a class from it. */ class CoreExport BufferedSocket : public StreamSocket { public: /** Timeout object or NULL */ SocketTimeout* Timeout; /** * The state for this socket, either * listening, connecting, connected * or error. */ BufferedSocketState state; BufferedSocket(); /** * This constructor is used to associate * an existing connecting with an BufferedSocket * class. The given file descriptor must be * valid, and when initialized, the BufferedSocket * will be placed in CONNECTED state. */ BufferedSocket(int newfd); /** Begin connection to the given address * This will create a socket, register with socket engine, and start the asynchronous * connection process. If an error is detected at this point (such as out of file descriptors), * OnError will be called; otherwise, the state will become CONNECTING. * @param dest Remote endpoint to connect to. * @param bind Local endpoint to connect from. * @param maxtime Time to wait for connection */ void DoConnect(const irc::sockets::sockaddrs& dest, const irc::sockets::sockaddrs& bind, unsigned int maxtime); /** This method is called when an outbound connection on your socket is * completed. */ virtual void OnConnected(); /** When there is data waiting to be read on a socket, the OnDataReady() * method is called. */ void OnDataReady() CXX11_OVERRIDE = 0; /** * When an outbound connection fails, and the attempt times out, you * will receive this event. The method will trigger once maxtime * seconds are reached (as given in the constructor) just before the * socket's descriptor is closed. A failed DNS lookup may cause this * event if the DNS server is not responding, as well as a failed * connect() call, because DNS lookups are nonblocking as implemented by * this class. */ virtual void OnTimeout(); virtual ~BufferedSocket(); protected: void OnEventHandlerWrite() CXX11_OVERRIDE; BufferedSocketError BeginConnect(const irc::sockets::sockaddrs& dest, const irc::sockets::sockaddrs& bind, unsigned int timeout); }; inline IOHook* StreamSocket::GetIOHook() const { return iohook; } inline void StreamSocket::DelIOHook() { iohook = NULL; } ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/include/inspstring.h�����������������������������������������������������������������0000664�0000000�0000000�00000003640�13554550454�0017342�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * InspIRCd -- Internet Relay Chat Daemon * * Copyright (C) 2007 Dennis Friis <peavey@inspircd.org> * Copyright (C) 2007 Craig Edwards <craigedwards@brainbox.cc> * * This file is part of InspIRCd. InspIRCd is free software: you can * redistribute it and/or modify it under the terms of the GNU General Public * License as published by the Free Software Foundation, version 2. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once // This (config) is needed as inspstring doesn't pull in the central header #include "config.h" #include <cstring> /** Sets ret to the formated string. last is the last parameter before ..., and format is the format in printf-style */ #define VAFORMAT(ret, last, format) \ do { \ va_list _vaList; \ va_start(_vaList, last); \ ret.assign(InspIRCd::Format(_vaList, format)); \ va_end(_vaList); \ } while (false); /** Compose a hex string from raw data. * @param raw The raw data to compose hex from (can be NULL if rawsize is 0) * @param rawsize The size of the raw data buffer * @return The hex string */ CoreExport std::string BinToHex(const void* raw, size_t rawsize); /** Base64 encode */ CoreExport std::string BinToBase64(const std::string& data, const char* table = NULL, char pad = 0); /** Base64 decode */ CoreExport std::string Base64ToBin(const std::string& data, const char* table = NULL); /** Compose a hex string from the data in a std::string. * @param data The data to compose hex from * @return The hex string. */ inline std::string BinToHex(const std::string& data) { return BinToHex(data.data(), data.size()); } ������������������������������������������������������������������������������������������������inspircd-3.4.0/include/intrusive_list.h�������������������������������������������������������������0000664�0000000�0000000�00000004023�13554550454�0020221�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * InspIRCd -- Internet Relay Chat Daemon * * Copyright (C) 2013-2014 Attila Molnar <attilamolnar@hush.com> * * This file is part of InspIRCd. InspIRCd is free software: you can * redistribute it and/or modify it under the terms of the GNU General Public * License as published by the Free Software Foundation, version 2. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <iterator> namespace insp { struct intrusive_list_def_tag { }; template <typename T, typename Tag = intrusive_list_def_tag> class intrusive_list; template <typename T, typename Tag = intrusive_list_def_tag> class intrusive_list_tail; template <typename T, typename Tag = intrusive_list_def_tag> class intrusive_list_node { T* ptr_next; T* ptr_prev; void unlink() { if (ptr_next) ptr_next->intrusive_list_node<T, Tag>::ptr_prev = this->ptr_prev; if (ptr_prev) ptr_prev->intrusive_list_node<T, Tag>::ptr_next = this->ptr_next; ptr_next = ptr_prev = NULL; } public: intrusive_list_node() : ptr_next(NULL) , ptr_prev(NULL) { } friend class intrusive_list<T, Tag>; friend class intrusive_list_tail<T, Tag>; }; } // namespace insp // Intrusive list where the list only has a pointer to the head element #define INSPIRCD_INTRUSIVE_LIST_NAME intrusive_list #include "intrusive_list_impl.h" #undef INSPIRCD_INTRUSIVE_LIST_NAME // Intrusive list where the list maintains a pointer to both the head and the tail elements. // Additional methods: back(), push_back(), pop_back() #define INSPIRCD_INTRUSIVE_LIST_NAME intrusive_list_tail #define INSPIRCD_INTRUSIVE_LIST_HAS_TAIL #include "intrusive_list_impl.h" #undef INSPIRCD_INTRUSIVE_LIST_NAME #undef INSPIRCD_INTRUSIVE_LIST_HAS_TAIL �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/include/intrusive_list_impl.h��������������������������������������������������������0000664�0000000�0000000�00000006050�13554550454�0021244�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * InspIRCd -- Internet Relay Chat Daemon * * Copyright (C) 2013-2014 Attila Molnar <attilamolnar@hush.com> * * This file is part of InspIRCd. InspIRCd is free software: you can * redistribute it and/or modify it under the terms of the GNU General Public * License as published by the Free Software Foundation, version 2. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ namespace insp { template <typename T, typename Tag> class INSPIRCD_INTRUSIVE_LIST_NAME { public: class iterator : public std::iterator<std::bidirectional_iterator_tag, T*> { T* curr; public: iterator(T* i = NULL) : curr(i) { } iterator& operator++() { curr = curr->intrusive_list_node<T, Tag>::ptr_next; return *this; } iterator operator++(int) { iterator ret(*this); operator++(); return ret; } iterator& operator--() { curr = curr->intrusive_list_node<T, Tag>::ptr_prev; return *this; } iterator operator--(int) { iterator ret(*this); operator--(); return ret; } bool operator==(const iterator& other) const { return (curr == other.curr); } bool operator!=(const iterator& other) const { return (curr != other.curr); } T* operator*() const { return curr; } }; typedef iterator const_iterator; INSPIRCD_INTRUSIVE_LIST_NAME() : listhead(NULL) #ifdef INSPIRCD_INTRUSIVE_LIST_HAS_TAIL , listtail(NULL) #endif , listsize(0) { } bool empty() const { return (size() == 0); } size_t size() const { return listsize; } iterator begin() const { return iterator(listhead); } iterator end() const { return iterator(); } void pop_front() { erase(listhead); } T* front() const { return listhead; } void push_front(T* x) { if (listsize++) { x->intrusive_list_node<T, Tag>::ptr_next = listhead; listhead->intrusive_list_node<T, Tag>::ptr_prev = x; } #ifdef INSPIRCD_INTRUSIVE_LIST_HAS_TAIL else listtail = x; #endif listhead = x; } #ifdef INSPIRCD_INTRUSIVE_LIST_HAS_TAIL T* back() const { return listtail; } void push_back(T* x) { if (listsize++) { x->intrusive_list_node<T, Tag>::ptr_prev = listtail; listtail->intrusive_list_node<T, Tag>::ptr_next = x; } else listhead = x; listtail = x; } void pop_back() { erase(listtail); } #endif void erase(const iterator& it) { erase(*it); } void erase(T* x) { if (listhead == x) listhead = x->intrusive_list_node<T, Tag>::ptr_next; #ifdef INSPIRCD_INTRUSIVE_LIST_HAS_TAIL if (listtail == x) listtail = x->intrusive_list_node<T, Tag>::ptr_prev; #endif x->intrusive_list_node<T, Tag>::unlink(); listsize--; } private: T* listhead; #ifdef INSPIRCD_INTRUSIVE_LIST_HAS_TAIL T* listtail; #endif size_t listsize; }; } // namespace insp ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/include/iohook.h���������������������������������������������������������������������0000664�0000000�0000000�00000012574�13554550454�0016440�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * InspIRCd -- Internet Relay Chat Daemon * * Copyright (C) 2013 Attila Molnar <attilamolnar@hush.com> * * This file is part of InspIRCd. InspIRCd is free software: you can * redistribute it and/or modify it under the terms of the GNU General Public * License as published by the Free Software Foundation, version 2. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once class StreamSocket; class IOHookProvider : public refcountbase, public ServiceProvider { const bool middlehook; public: enum Type { IOH_UNKNOWN, IOH_SSL }; const Type type; /** Constructor * @param mod Module that owns the IOHookProvider * @param Name Name of the provider * @param hooktype One of IOHookProvider::Type * @param middle True if the IOHook instances created by this hook are subclasses of IOHookMiddle, false otherwise */ IOHookProvider(Module* mod, const std::string& Name, Type hooktype = IOH_UNKNOWN, bool middle = false) : ServiceProvider(mod, Name, SERVICE_IOHOOK), middlehook(middle), type(hooktype) { } /** Check if the IOHook provided can appear in the non-last position of a hook chain. * That is the case if and only if the IOHook instances created are subclasses of IOHookMiddle. * @return True if the IOHooks provided are subclasses of IOHookMiddle */ bool IsMiddle() const { return middlehook; } /** Called when the provider should hook an incoming connection and act as being on the server-side of the connection. * This occurs when a bind block has a hook configured and the listener accepts a connection. * @param sock Socket to hook * @param client Client IP address and port * @param server Server IP address and port */ virtual void OnAccept(StreamSocket* sock, irc::sockets::sockaddrs* client, irc::sockets::sockaddrs* server) = 0; /** Called when the provider should hook an outgoing connection and act as being on the client side of the connection. * @param sock Socket to hook */ virtual void OnConnect(StreamSocket* sock) = 0; }; class IOHook : public classbase { public: /** The IOHookProvider for this hook, contains information about the hook, * such as the module providing it and the hook type. */ reference<IOHookProvider> prov; /** Constructor * @param provider IOHookProvider that creates this object */ IOHook(IOHookProvider* provider) : prov(provider) { } /** * Called when the hooked socket has data to write, or when the socket engine returns it as writable * @param sock Hooked socket * @param sendq Send queue to send data from * @return 1 if the sendq has been completely emptied, 0 if there is * still data to send, and -1 if there was an error */ virtual int OnStreamSocketWrite(StreamSocket* sock, StreamSocket::SendQueue& sendq) = 0; /** Called immediately before the hooked socket is closed. When this event is called, shutdown() * has not yet been called on the socket. * @param sock Hooked socket */ virtual void OnStreamSocketClose(StreamSocket* sock) = 0; /** * Called when the hooked socket has data to read * @param sock Hooked socket * @param recvq The receive queue that new data should be appended to * @return 1 if new data has been read, 0 if no new data is ready (but the * socket is still connected), -1 if there was an error or close */ virtual int OnStreamSocketRead(StreamSocket* sock, std::string& recvq) = 0; }; class IOHookMiddle : public IOHook { /** Data already processed by the IOHook waiting to go down the chain */ StreamSocket::SendQueue sendq; /** Data waiting to go up the chain */ std::string precvq; /** Next IOHook in the chain */ IOHook* nexthook; protected: /** Get all queued up data which has not yet been passed up the hook chain * @return RecvQ containing the data */ std::string& GetRecvQ() { return precvq; } /** Get all queued up data which is ready to go down the hook chain * @return SendQueue containing all data waiting to go down the hook chain */ StreamSocket::SendQueue& GetSendQ() { return sendq; } public: /** Constructor * @param provider IOHookProvider that creates this object */ IOHookMiddle(IOHookProvider* provider) : IOHook(provider) , nexthook(NULL) { } /** Get all queued up data which is ready to go down the hook chain * @return SendQueue containing all data waiting to go down the hook chain */ const StreamSocket::SendQueue& GetSendQ() const { return sendq; } /** Get the next IOHook in the chain * @return Next hook in the chain or NULL if this is the last hook */ IOHook* GetNextHook() const { return nexthook; } /** Set the next hook in the chain * @param hook Hook to set as the next hook in the chain */ void SetNextHook(IOHook* hook) { nexthook = hook; } /** Check if a hook is capable of being the non-last hook in a hook chain and if so, cast it to an IOHookMiddle object. * @param hook IOHook to check * @return IOHookMiddle referring to the same hook or NULL */ static IOHookMiddle* ToMiddleHook(IOHook* hook) { if (hook->prov->IsMiddle()) return static_cast<IOHookMiddle*>(hook); return NULL; } friend class StreamSocket; }; ������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/include/isupportmanager.h������������������������������������������������������������0000664�0000000�0000000�00000003420�13554550454�0020356�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * InspIRCd -- Internet Relay Chat Daemon * * Copyright (C) 2013 Peter Powell <petpow@saberuk.com> * * This file is part of InspIRCd. InspIRCd is free software: you can * redistribute it and/or modify it under the terms of the GNU General Public * License as published by the Free Software Foundation, version 2. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once /** This class manages the generation and transmission of ISUPPORT. */ class CoreExport ISupportManager { private: /** The generated lines which are sent to clients. */ std::vector<Numeric::Numeric> cachedlines; /** Escapes an ISUPPORT token value and appends it to the buffer. * @param buffer The buffer to append to. * @param value An ISUPPORT token value. */ void AppendValue(std::string& buffer, const std::string& value); public: /** (Re)build the ISUPPORT vector. * Called by the core on boot after all modules have been loaded, and every time when a module is loaded * or unloaded. Calls the On005Numeric hook, letting modules manipulate the ISUPPORT tokens. */ void Build(); /** Returns the cached std::vector of ISUPPORT lines. * @return A list of Numeric::Numeric objects prepared for sending to users */ const std::vector<Numeric::Numeric>& GetLines() const { return cachedlines; } /** Send the 005 numerics (ISUPPORT) to a user. * @param user The user to send the ISUPPORT numerics to */ void SendTo(LocalUser* user); }; ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/include/listmode.h�������������������������������������������������������������������0000664�0000000�0000000�00000016711�13554550454�0016765�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * InspIRCd -- Internet Relay Chat Daemon * * Copyright (C) 2009 Daniel De Graaf <danieldg@inspircd.org> * * This file is part of InspIRCd. InspIRCd is free software: you can * redistribute it and/or modify it under the terms of the GNU General Public * License as published by the Free Software Foundation, version 2. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once /** The base class for list modes, should be inherited. */ class CoreExport ListModeBase : public ModeHandler { public: /** An item in a listmode's list */ struct ListItem { std::string setter; std::string mask; time_t time; ListItem(const std::string& Mask, const std::string& Setter, time_t Time) : setter(Setter), mask(Mask), time(Time) { } }; /** Items stored in the channel's list */ typedef std::vector<ListItem> ModeList; private: class ChanData { public: ModeList list; int maxitems; ChanData() : maxitems(-1) { } }; /** The number of items a listmode's list may contain */ struct ListLimit { std::string mask; unsigned int limit; ListLimit(const std::string& Mask, unsigned int Limit) : mask(Mask), limit(Limit) { } bool operator==(const ListLimit& other) const { return (this->mask == other.mask && this->limit == other.limit); } }; /** Max items per channel by name */ typedef std::vector<ListLimit> limitlist; /** The default maximum list size. */ static const unsigned int DEFAULT_LIST_SIZE = 100; /** Finds the limit of modes that can be placed on the given channel name according to the config * @param channame The channel name to find the limit for * @return The maximum number of modes of this type that we allow to be set on the given channel name */ unsigned int FindLimit(const std::string& channame); /** Returns the limit on the given channel for this mode. * If the limit is cached then the cached value is returned, * otherwise the limit is determined using FindLimit() and cached * for later queries before it is returned * @param channame The channel name to find the limit for * @param cd The ChanData associated with channel channame * @return The maximum number of modes of this type that we allow to be set on the given channel */ unsigned int GetLimitInternal(const std::string& channame, ChanData* cd); protected: /** Numeric to use when outputting the list */ unsigned int listnumeric; /** Numeric to indicate end of list */ unsigned int endoflistnumeric; /** String to send for end of list */ std::string endofliststring; /** Automatically tidy up entries */ bool tidy; /** Limits on a per-channel basis read from the \<listmode> * config tag. */ limitlist chanlimits; /** Storage key */ SimpleExtItem<ChanData> extItem; public: /** Constructor. * @param Creator The creator of this class * @param Name Mode name * @param modechar Mode character * @param eolstr End of list string * @param lnum List numeric * @param eolnum End of list numeric * @param autotidy Automatically tidy list entries on add */ ListModeBase(Module* Creator, const std::string& Name, char modechar, const std::string& eolstr, unsigned int lnum, unsigned int eolnum, bool autotidy); /** Determines whether some channels have longer lists than others. */ bool HasVariableLength() const { return chanlimits.size() > 1; } /** Get limit of this mode on a channel * @param channel The channel to inspect * @return Maximum number of modes of this type that can be placed on the given channel */ unsigned int GetLimit(Channel* channel); /** Gets the lower list limit for this listmode. */ unsigned int GetLowerLimit(); /** Retrieves the list of all modes set on the given channel * @param channel Channel to get the list from * @return A list with all modes of this type set on the given channel, can be NULL */ ModeList* GetList(Channel* channel); /** Display the list for this mode * See mode.h * @param user The user to send the list to * @param channel The channel the user is requesting the list for */ void DisplayList(User* user, Channel* channel) CXX11_OVERRIDE; /** Tell a user that a list contains no elements. * Sends 'eolnum' numeric with text 'eolstr', unless overridden (see constructor) * @param user The user issuing the command * @param channel The channel that has the empty list * See mode.h */ void DisplayEmptyList(User* user, Channel* channel) CXX11_OVERRIDE; /** Remove all instances of the mode from a channel. * Populates the given modestack with modes that remove every instance of * this mode from the channel. * See mode.h for more details. * @param channel The channel to remove all instances of the mode from * @param changelist Mode change list to populate with the removal of this mode */ void RemoveMode(Channel* channel, Modes::ChangeList& changelist) CXX11_OVERRIDE; /** Perform a rehash of this mode's configuration data */ void DoRehash(); /** Handle the list mode. * See mode.h */ ModeAction OnModeChange(User* source, User*, Channel* channel, std::string &parameter, bool adding) CXX11_OVERRIDE; /** Validate parameters. * Overridden by implementing module. * @param user Source user adding the parameter * @param channel Channel the parameter is being added to * @param parameter The actual parameter being added * @return true if the parameter is valid */ virtual bool ValidateParam(User* user, Channel* channel, std::string& parameter); /** In the event that the mode should be given a parameter, and no parameter was provided, this method is called. * This allows you to give special information to the user, or handle this any way you like. * @param user The user issuing the mode change * @param dest For user mode changes, the target of the mode. For channel mode changes, NULL. * @param channel For channel mode changes, the target of the mode. For user mode changes, NULL. * See mode.h */ virtual void OnParameterMissing(User* user, User* dest, Channel* channel) CXX11_OVERRIDE; /** Tell the user the list is too long. * Overridden by implementing module. * @param source Source user adding the parameter * @param channel Channel the parameter is being added to * @param parameter The actual parameter being added */ virtual void TellListTooLong(User* source, Channel* channel, std::string& parameter); /** Tell the user an item is already on the list. * Overridden by implementing module. * @param source Source user adding the parameter * @param channel Channel the parameter is being added to * @param parameter The actual parameter being added */ virtual void TellAlreadyOnList(User* source, Channel* channel, std::string& parameter); /** Tell the user that the parameter is not in the list. * Overridden by implementing module. * @param source Source user removing the parameter * @param channel Channel the parameter is being removed from * @param parameter The actual parameter being removed */ virtual void TellNotSet(User* source, Channel* channel, std::string& parameter); }; inline ListModeBase::ModeList* ListModeBase::GetList(Channel* channel) { ChanData* cd = extItem.get(channel); if (!cd) return NULL; return &cd->list; } �������������������������������������������������������inspircd-3.4.0/include/logger.h���������������������������������������������������������������������0000664�0000000�0000000�00000021101�13554550454�0016411�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * InspIRCd -- Internet Relay Chat Daemon * * Copyright (C) 2008 Thomas Stagner <aquanight@inspircd.org> * Copyright (C) 2008 Robin Burchell <robin+git@viroteck.net> * * This file is part of InspIRCd. InspIRCd is free software: you can * redistribute it and/or modify it under the terms of the GNU General Public * License as published by the Free Software Foundation, version 2. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once /** Levels at which messages can be logged. */ enum LogLevel { LOG_RAWIO = 5, LOG_DEBUG = 10, LOG_VERBOSE = 20, LOG_DEFAULT = 30, LOG_SPARSE = 40, LOG_NONE = 50 }; /** Simple wrapper providing periodic flushing to a disk-backed file. */ class CoreExport FileWriter { protected: /** The log file (fd is inside this somewhere, * we get it out with fileno()) */ FILE* log; /** The number of write operations after which we should flush. */ unsigned int flush; /** Number of write operations that have occured */ unsigned int writeops; public: /** The constructor takes an already opened logfile. */ FileWriter(FILE* logfile, unsigned int flushcount); /** Write one or more preformatted log lines. * If the data cannot be written immediately, * this class will insert itself into the * SocketEngine, and register a write event, * and when the write event occurs it will * attempt again to write the data. */ void WriteLogLine(const std::string &line); /** Close the log file and cancel any events. */ virtual ~FileWriter(); }; /* * New world logging! * The brief summary: * Logging used to be a simple affair, a FILE * handled by a nonblocking logging class inheriting from EventHandler, that was inserted * into the socket engine, and wrote lines. If nofork was on, it was printf()'d. * * We decided to horribly overcomplicate matters, and create vastly customisable logging. LogManager and LogStream form the visible basis * of the new interface. Basically, a LogStream can be inherited to do different things with logging output. We inherit from it once in core * to create a FileLogStream, that writes to a file, for example. Different LogStreams can hook different types of log messages, and different * levels of output too, for extreme customisation. Multiple LogStreams can hook the same message/levels of output, meaning that e.g. output * can go to a channel as well as a file. * * HOW THIS WORKS * LogManager handles all instances of LogStreams, classes derived from LogStream are instantiated and passed to it. */ /** LogStream base class. Modules (and other stuff) inherit from this to decide what logging they are interested in, and what to do with it. */ class CoreExport LogStream : public classbase { protected: LogLevel loglvl; public: static const char LogHeader[]; LogStream(LogLevel loglevel) : loglvl(loglevel) { } /* A LogStream's destructor should do whatever it needs to close any resources it was using (or indicate that it is no longer using a resource * in the event that the resource is shared, see for example FileLogStream). */ virtual ~LogStream() { } /** Changes the loglevel for this LogStream on-the-fly. * This is needed for -nofork. But other LogStreams could use it to change loglevels. */ void ChangeLevel(LogLevel lvl) { this->loglvl = lvl; } /** Called when there is stuff to log for this particular logstream. The derived class may take no action with it, or do what it * wants with the output, basically. loglevel and type are primarily for informational purposes (the level and type of the event triggered) * and msg is, of course, the actual message to log. */ virtual void OnLog(LogLevel loglevel, const std::string &type, const std::string &msg) = 0; }; typedef std::map<FileWriter*, int> FileLogMap; class CoreExport LogManager : public fakederef<LogManager> { private: /** Lock variable, set to true when a log is in progress, which prevents further loggging from happening and creating a loop. */ bool Logging; /** Map of active log types and what LogStreams will receive them. */ std::map<std::string, std::vector<LogStream *> > LogStreams; /** Refcount map of all LogStreams managed by LogManager. * If a logstream is not listed here, it won't be automatically closed by LogManager, even if it's loaded in one of the other lists. */ std::map<LogStream *, int> AllLogStreams; /** LogStreams with type * (which means everything), and a list a logtypes they are excluded from (eg for "* -USERINPUT -USEROUTPUT"). */ std::map<LogStream *, std::vector<std::string> > GlobalLogStreams; /** Refcounted map of all FileWriters in use by FileLogStreams, for file stream sharing. */ FileLogMap FileLogs; public: LogManager(); ~LogManager(); /** Adds a FileWriter instance to LogManager, or increments the reference count of an existing instance. * Used for file-stream sharing for FileLogStreams. */ void AddLoggerRef(FileWriter* fw) { FileLogMap::iterator i = FileLogs.find(fw); if (i == FileLogs.end()) { FileLogs.insert(std::make_pair(fw, 1)); } else { ++i->second; } } /** Indicates that a FileWriter reference has been removed. Reference count is decreased, and if zeroed, the FileWriter is closed. */ void DelLoggerRef(FileWriter* fw) { FileLogMap::iterator i = FileLogs.find(fw); if (i == FileLogs.end()) return; /* Maybe should log this? */ if (--i->second < 1) { delete i->first; FileLogs.erase(i); } } /** Opens all logfiles defined in the configuration file using \<log method="file">. */ void OpenFileLogs(); /** Removes all LogStreams, meaning they have to be readded for logging to continue. * Only LogStreams that were listed in AllLogStreams are actually closed. */ void CloseLogs(); /** Adds a single LogStream to multiple logtypes. * This automatically handles things like "* -USERINPUT -USEROUTPUT" to mean all but USERINPUT and USEROUTPUT types. * It is not a good idea to mix values of autoclose for the same LogStream. * @param type The type string (from configuration, or whatever) to parse. * @param l The LogStream to add. * @param autoclose True to have the LogStream automatically closed when all references to it are removed from LogManager. False to leave it open. */ void AddLogTypes(const std::string &type, LogStream *l, bool autoclose); /** Registers a new logstream into the logging core, so it can be called for future events * It is not a good idea to mix values of autoclose for the same LogStream. * @param type The type to add this LogStream to. * @param l The LogStream to add. * @param autoclose True to have the LogStream automatically closed when all references to it are removed from LogManager. False to leave it open. * @return True if the LogStream was added successfully, False otherwise. */ bool AddLogType(const std::string &type, LogStream *l, bool autoclose); /** Removes a logstream from the core. After removal, it will not receive further events. * If the LogStream was ever added with autoclose, it will be closed after this call (this means the pointer won't be valid anymore). */ void DelLogStream(LogStream* l); /** Removes a LogStream from a single type. If the LogStream has been registered for "*" it will still receive the type unless you remove it from "*" specifically. * If the LogStream was added with autoclose set to true, then when the last occurrence of the stream is removed it will automatically be closed (freed). */ bool DelLogType(const std::string &type, LogStream *l); /** Logs an event, sending it to all LogStreams registered for the type. * @param type Log message type (ex: "USERINPUT", "MODULE", ...) * @param loglevel Log message level (LOG_DEBUG, LOG_VERBOSE, LOG_DEFAULT, LOG_SPARSE, LOG_NONE) * @param msg The message to be logged (literal). */ void Log(const std::string &type, LogLevel loglevel, const std::string &msg); /** Logs an event, sending it to all LogStreams registered for the type. * @param type Log message type (ex: "USERINPUT", "MODULE", ...) * @param loglevel Log message level (LOG_DEBUG, LOG_VERBOSE, LOG_DEFAULT, LOG_SPARSE, LOG_NONE) * @param fmt The format of the message to be logged. See your C manual on printf() for details. */ void Log(const std::string &type, LogLevel loglevel, const char *fmt, ...) CUSTOM_PRINTF(4, 5); }; ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/include/membership.h�����������������������������������������������������������������0000664�0000000�0000000�00000010037�13554550454�0017273�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * InspIRCd -- Internet Relay Chat Daemon * * Copyright (C) 2012-2014 Attila Molnar <attilamolnar@hush.com> * Copyright (C) 2009 Daniel De Graaf <danieldg@inspircd.org> * * This file is part of InspIRCd. InspIRCd is free software: you can * redistribute it and/or modify it under the terms of the GNU General Public * License as published by the Free Software Foundation, version 2. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include "convto.h" /** * Represents a member of a channel. * A Membership object is created when a user joins a channel, and destroyed when a user leaves * (via kick, part or quit) a channel. * All prefix modes a member has is tracked by this object. Moreover, Memberships are Extensibles * meaning modules can add arbitrary data to them using extensions (see m_delaymsg for an example). */ class CoreExport Membership : public Extensible, public insp::intrusive_list_node<Membership> { public: /** Type of the Membership id */ typedef uint64_t Id; /** User on the channel */ User* const user; /** Channel the user is on */ Channel* const chan; /** List of prefix mode letters this member has, * sorted by prefix rank, highest first */ std::string modes; /** Id of this Membership, set by the protocol module, other components should never read or * write this field. */ Id id; /** Converts a string to a Membership::Id * @param str The string to convert * @return Raw value of type Membership::Id */ static Id IdFromString(const std::string& str) { return ConvToNum<Id>(str); } /** Constructor, sets the user and chan fields to the parameters, does NOT update any bookkeeping * information in the User or the Channel. * Call Channel::JoinUser() or ForceJoin() to make a user join a channel instead of constructing * Membership objects directly. */ Membership(User* u, Channel* c) : user(u), chan(c) {} /** Check if this member has a given prefix mode set * @param pm Prefix mode to check * @return True if the member has the prefix mode set, false otherwise */ bool HasMode(const PrefixMode* pm) const { return (modes.find(pm->GetModeChar()) != std::string::npos); } /** Returns the rank of this member. * The rank of a member is defined as the rank given by the 'strongest' prefix mode a * member has. See the PrefixMode class description for more info. * @return The rank of the member */ unsigned int getRank(); /** Add a prefix character to a user. * Only the core should call this method, usually from * within the mode parser or when the first user joins * the channel (to grant the default privs to them) * @param mh The mode handler of the prefix mode to associate * @param adding True if adding the prefix, false when removing * @return True if a change was made */ bool SetPrefix(PrefixMode* mh, bool adding); /** Get the highest prefix this user has on the channel * @return A character containing the highest prefix. * If the user has no prefix, 0 is returned. If the user has multiple prefixes, * the highest is returned. If you do not recognise the prefix character you * can get, you can deal with it in a 'proportional' manner compared to known * prefixes, using GetPrefixValue(). */ char GetPrefixChar() const; /** Return all prefix chars this member has. * @return A list of all prefix characters. The prefixes will always * be in rank order, greatest first, as certain IRC clients require * this when multiple prefixes are used names lists. */ std::string GetAllPrefixChars() const; /** Sends a server notice to this user in the context of this channel. * @param text The contents of the message to send. */ void WriteNotice(const std::string& text) const; }; �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/include/message.h��������������������������������������������������������������������0000664�0000000�0000000�00000010177�13554550454�0016571�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * InspIRCd -- Internet Relay Chat Daemon * * Copyright (C) 2017 Peter Powell <petpow@saberuk.com> * * This file is part of InspIRCd. InspIRCd is free software: you can * redistribute it and/or modify it under the terms of the GNU General Public * License as published by the Free Software Foundation, version 2. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once /** Whether message was a PRIVMSG or a NOTICE. */ enum MessageType { /** The message is a PRIVMSG. */ MSG_PRIVMSG, /** The message is a NOTICE. */ MSG_NOTICE }; class CoreExport MessageDetails { public: /** Whether to echo the message at all. */ bool echo; /* Whether to send the original message back to clients with echo-message support. */ bool echo_original; /** The users who are exempted from receiving this message. */ CUList exemptions; /* The original message as sent by the user. */ const std::string original_text; /** IRCv3 message tags sent to the server by the user. */ const ClientProtocol::TagMap tags_in; /** IRCv3 message tags sent out to users who get this message. */ ClientProtocol::TagMap tags_out; /** The message which will be sent to clients. */ std::string text; /** The type of message. */ const MessageType type; /** Determines whether the specified message is a CTCP. If the specified message * is a CTCP then the CTCP name and CTCP body are extracted and stored in the * name and body references. * @param name The location to store the parsed CTCP name. * @param body The location to store the parsed CTCP body. */ virtual bool IsCTCP(std::string& name, std::string& body) const = 0; /** Determines whether the specified message is a CTCP. If the specified message * is a CTCP then the CTCP name is extracted and stored in the name reference. * @param name The location to store the parsed CTCP name. */ virtual bool IsCTCP(std::string& name) const = 0; /** Determines whether the specified message is a CTCP. */ virtual bool IsCTCP() const = 0; protected: MessageDetails(MessageType mt, const std::string& msg, const ClientProtocol::TagMap& tags) : echo(true) , echo_original(false) , original_text(msg) , tags_in(tags) , text(msg) , type(mt) { } }; /** Represents the target of a message (NOTICE, PRIVMSG, etc). */ class CoreExport MessageTarget { public: /** An enumeration of possible message target types. */ enum TargetType { /** The target of the message is a user. */ TYPE_USER, /** The target of the message is a channel. */ TYPE_CHANNEL, /** The target of the message is a server. */ TYPE_SERVER }; private: /** The target of the message. */ void* dest; public: /** If type is TYPE_CHANNEL and the user specified a status rank. */ char status; /** The type of the target of the message. If this is TYPE_CHANNEL then dest * is a Channel*, TYPE_USER then dest is a User*, and TYPE_SERVER then dest is * a std::string* containing a server glob. */ MessageTarget::TargetType type; /** Initialises a new channel message target. * @param channel The channel which is the target of the message. * @param statuschar The lowest status rank that the message is being sent to. */ MessageTarget(Channel* channel, char statuschar) : dest(channel) , status(statuschar) , type(TYPE_CHANNEL) { } /** Initialises a new user message target. * @param user The user which is the target of the message. */ MessageTarget(User* user) : dest(user) , status(0) , type(TYPE_USER) { } /** Initialises a new server message target. * @param server The server glob which is the target of the message. */ MessageTarget(std::string* server) : dest(server) , status(0) , type(TYPE_SERVER) { } /** Retrieves the target of this message. */ template<typename T> T* Get() const { return static_cast<T*>(dest); } }; �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/include/mode.h�����������������������������������������������������������������������0000664�0000000�0000000�00000101204�13554550454�0016061�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * InspIRCd -- Internet Relay Chat Daemon * * Copyright (C) 2009 Daniel De Graaf <danieldg@inspircd.org> * Copyright (C) 2004-2006, 2008 Craig Edwards <craigedwards@brainbox.cc> * Copyright (C) 2007 Robin Burchell <robin+git@viroteck.net> * Copyright (C) 2007 Dennis Friis <peavey@inspircd.org> * * This file is part of InspIRCd. InspIRCd is free software: you can * redistribute it and/or modify it under the terms of the GNU General Public * License as published by the Free Software Foundation, version 2. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include "ctables.h" #include "modechange.h" /** * Holds the values for different type of modes * that can exist, USER or CHANNEL type. */ enum ModeType { /** User mode */ MODETYPE_USER = 0, /** Channel mode */ MODETYPE_CHANNEL = 1 }; /** * Holds mode actions - modes can be allowed or denied. */ enum ModeAction { MODEACTION_DENY = 0, /* Drop the mode change, AND a parameter if its a parameterized mode */ MODEACTION_ALLOW = 1 /* Allow the mode */ }; /** * These fixed values can be used to proportionally compare module-defined prefixes to known values. * For example, if your module queries a Channel, and is told that user 'joebloggs' has the prefix * '$', and you dont know what $ means, then you can compare it to these three values to determine * its worth against them. For example if '$' had a value of 15000, you would know it is of higher * status than voice, but lower status than halfop. * No two modes should have equal prefix values. */ enum PrefixModeValue { /* +v */ VOICE_VALUE = 10000, /* +h */ HALFOP_VALUE = 20000, /* +o */ OP_VALUE = 30000 }; enum ParamSpec { /** No parameters */ PARAM_NONE, /** Parameter required on mode setting only */ PARAM_SETONLY, /** Parameter always required */ PARAM_ALWAYS }; class PrefixMode; class ListModeBase; class ParamModeBase; /** Each mode is implemented by ONE ModeHandler class. * You must derive ModeHandler and add the child class to * the list of modes handled by the ircd, using * ModeParser::AddMode. When the mode you implement is * set by a user, the virtual function OnModeChange is * called. If you specify a value greater than 0 for * parameters_on or parameters_off, then when the mode is * set or unset respectively, std::string &parameter will * contain the parameter given by the user, else it will * contain an empty string. You may alter this parameter * string, and if you alter it to an empty string, and your * mode is expected to have a parameter, then this is * equivalent to returning MODEACTION_DENY. */ class CoreExport ModeHandler : public ServiceProvider { public: typedef size_t Id; enum Class { MC_PREFIX, MC_LIST, MC_PARAM, MC_OTHER }; private: /** The opaque id of this mode assigned by the mode parser */ Id modeid; protected: /** What kind of parameters does the mode take? */ ParamSpec parameters_taken; /** * The mode letter you're implementing. */ char mode; /** * True if the mode requires oper status * to set. */ bool oper; /** * Mode is a 'list' mode. The behaviour * of your mode is now set entirely within * the class as of the 1.1 api, rather than * inside the mode parser as in the 1.0 api, * so the only use of this value (along with * IsListMode()) is for the core to determine * wether your module can produce 'lists' or not * (e.g. banlists, etc) */ bool list; /** * The mode type, either MODETYPE_USER or * MODETYPE_CHANNEL. */ ModeType m_type; /** The object type of this mode handler */ const Class type_id; /** The prefix rank required to set this mode on channels. */ unsigned int ranktoset; /** The prefix rank required to unset this mode on channels. */ unsigned int ranktounset; /** If non-empty then the syntax of the parameter for this mode. */ std::string syntax; public: /** * The constructor for ModeHandler initalizes the mode handler. * The constructor of any class you derive from ModeHandler should * probably call this constructor with the parameters set correctly. * @param me The module which created this mode * @param name A one-word name for the mode * @param modeletter The mode letter you wish to handle * @param params Parameters taken by the mode * @param type Type of the mode (MODETYPE_USER or MODETYPE_CHANNEL) * @param mclass The object type of this mode handler, one of ModeHandler::Class */ ModeHandler(Module* me, const std::string& name, char modeletter, ParamSpec params, ModeType type, Class mclass = MC_OTHER); CullResult cull() CXX11_OVERRIDE; virtual ~ModeHandler(); /** Register this object in the ModeParser */ void RegisterService() CXX11_OVERRIDE; /** * Returns true if the mode is a list mode */ bool IsListMode() const { return list; } /** * Check whether this mode is a prefix mode * @return non-NULL if this mode is a prefix mode, NULL otherwise */ PrefixMode* IsPrefixMode(); /** * Check whether this mode is a prefix mode * @return non-NULL if this mode is a prefix mode, NULL otherwise */ const PrefixMode* IsPrefixMode() const; /** * Check whether this mode handler inherits from ListModeBase * @return non-NULL if this mode handler inherits from ListModeBase, NULL otherwise */ ListModeBase* IsListModeBase(); /** * Check whether this mode handler inherits from ListModeBase * @return non-NULL if this mode handler inherits from ListModeBase, NULL otherwise */ const ListModeBase* IsListModeBase() const; /** * Check whether this mode handler inherits from ParamModeBase * @return non-NULL if this mode handler inherits from ParamModeBase, NULL otherwise */ ParamModeBase* IsParameterMode(); /** * Check whether this mode handler inherits from ParamModeBase * @return non-NULL if this mode handler inherits from ParamModeBase, NULL otherwise */ const ParamModeBase* IsParameterMode() const; /** * Returns the mode's type */ inline ModeType GetModeType() const { return m_type; } /** * Returns true if the mode can only be set/unset by an oper */ inline bool NeedsOper() const { return oper; } /** * Check if the mode needs a parameter for adding or removing * @param adding True to check if the mode needs a parameter when setting, false to check if the mode needs a parameter when unsetting * @return True if the mode needs a parameter for the specified action, false if it doesn't */ bool NeedsParam(bool adding) const; /** * Returns the mode character this handler handles. * @return The mode character */ char GetModeChar() const { return mode; } /** Return the id of this mode which is used in User::modes and * Channel::modes as the index to determine whether a mode is set. */ Id GetId() const { return modeid; } /** For user modes, return the current parameter, if any */ virtual std::string GetUserParameter(const User* user) const; /** * Called when a channel mode change access check for your mode occurs. * @param source Contains the user setting the mode. * @param channel contains the destination channel the modes are being set on. * @param parameter The parameter for your mode. This is modifiable. * @param adding This value is true when the mode is being set, or false when it is being unset. * @return allow, deny, or passthru to check against the required level */ virtual ModResult AccessCheck(User* source, Channel* channel, std::string &parameter, bool adding); /** * Called when a mode change for your mode occurs. * @param source Contains the user setting the mode. * @param dest For usermodes, contains the destination user the mode is being set on. For channelmodes, this is an undefined value. * @param channel For channel modes, contains the destination channel the modes are being set on. For usermodes, this is an undefined value. * @param parameter The parameter for your mode, if you indicated that your mode requires a parameter when being set or unset. Note that * if you alter this value, the new value becomes the one displayed and send out to the network, also, if you set this to an empty string * but you specified your mode REQUIRES a parameter, this is equivalent to returning MODEACTION_DENY and will prevent the mode from being * displayed. * @param adding This value is true when the mode is being set, or false when it is being unset. * @return MODEACTION_ALLOW to allow the mode, or MODEACTION_DENY to prevent the mode, also see the description of 'parameter'. */ virtual ModeAction OnModeChange(User* source, User* dest, Channel* channel, std::string &parameter, bool adding); /* Can change the mode parameter as its a ref */ /** * If your mode is a listmode, then this method will be called for displaying an item list, e.g. on MODE \#channel +modechar * without any parameter or other modes in the command. * @param user The user issuing the command * @param channel The channel they're requesting an item list of (e.g. a banlist, or an exception list etc) */ virtual void DisplayList(User* user, Channel* channel); /** In the event that the mode should be given a parameter, and no parameter was provided, this method is called. * This allows you to give special information to the user, or handle this any way you like. * @param user The user issuing the mode change * @param dest For user mode changes, the target of the mode. For channel mode changes, NULL. * @param channel For channel mode changes, the target of the mode. For user mode changes, NULL. */ virtual void OnParameterMissing(User* user, User* dest, Channel* channel); /** * If your mode is a listmode, this method will be called to display an empty list (just the end of list numeric) * @param user The user issuing the command * @param channel The channel tehy're requesting an item list of (e.g. a banlist, or an exception list etc) */ virtual void DisplayEmptyList(User* user, Channel* channel); /** * If your mode needs special action during a server sync to determine which side wins when comparing timestamps, * override this function and use it to return true or false. The default implementation just returns true if * theirs < ours. This will only be called for non-listmodes with parameters, when adding the mode and where * theirs == ours (therefore the default implementation will always return false). * @param their_param Their parameter if the mode has a parameter * @param our_param Our parameter if the mode has a parameter * @param channel The channel we are checking against * @return True if the other side wins the merge, false if we win the merge for this mode. */ virtual bool ResolveModeConflict(std::string &their_param, const std::string &our_param, Channel* channel); /** * When a MODETYPE_USER mode handler is being removed, the core will call this method for every user on the server. * The usermode will be removed using the appropiate server mode using InspIRCd::SendMode(). * @param user The user which the server wants to remove your mode from */ void RemoveMode(User* user); /** * When a MODETYPE_CHANNEL mode handler is being removed, the server will call this method for every channel on the server. * The mode handler has to populate the given modestacker with mode changes that remove the mode from the channel. * The default implementation of this method can remove all kinds of channel modes except listmodes. * In the case of listmodes, the entire list of items must be added to the modestacker (which is handled by ListModeBase, * so if you inherit from it or your mode can be removed by the default implementation then you do not have to implement * this function). * @param channel The channel which the server wants to remove your mode from * @param changelist Mode change list to populate with the removal of this mode */ virtual void RemoveMode(Channel* channel, Modes::ChangeList& changelist); /** Retrieves the level required to modify this mode. * @param adding Whether the mode is being added or removed. */ inline unsigned int GetLevelRequired(bool adding) const { return adding ? ranktoset : ranktounset; } /** Retrieves the syntax of the parameter for this mode. */ const std::string& GetSyntax() const { return syntax; } friend class ModeParser; }; /** * Prefix modes are channel modes that grant a specific rank to members having prefix mode set. * They require a parameter when setting and unsetting; the parameter is always a member of the channel. * A prefix mode may be set on any number of members on a channel, but for a given member a given prefix * mode is either set or not set, in other words members cannot have the same prefix mode set more than once. * * A rank of a member is defined as the rank given by the 'strongest' prefix mode that member has. * Other parts of the IRCd use this rank to determine whether a channel action is allowable for a user or not. * The rank of a prefix mode is constant, i.e. the same rank value is given to all users having that prefix mode set. * * Note that it is possible that the same action requires a different rank on a different channel; * for example changing the topic on a channel having +t set requires a rank that is >= than the rank of a halfop, * but there is no such restriction when +t isn't set. */ class CoreExport PrefixMode : public ModeHandler { protected: /** The prefix character granted by this mode. '@' for op, '+' for voice, etc. * If 0, this mode does not have a visible prefix character. */ char prefix; /** The prefix rank of this mode, used to compare prefix * modes */ unsigned int prefixrank; /** Whether a client with this prefix can remove it from themself. */ bool selfremove; public: /** * Constructor * @param Creator The module creating this mode * @param Name The user-friendly one word name of the prefix mode, e.g.: "op", "voice" * @param ModeLetter The mode letter of this mode * @param Rank Rank given by this prefix mode, see explanation above * @param PrefixChar Prefix character, or 0 if the mode has no prefix character */ PrefixMode(Module* Creator, const std::string& Name, char ModeLetter, unsigned int Rank = 0, char PrefixChar = 0); /** * Called when a channel mode change access check for your mode occurs. * @param source Contains the user setting the mode. * @param channel contains the destination channel the modes are being set on. * @param parameter The parameter for your mode. This is modifiable. * @param adding This value is true when the mode is being set, or false when it is being unset. * @return allow, deny, or passthru to check against the required level */ ModResult AccessCheck(User* source, Channel* channel, std::string &parameter, bool adding) CXX11_OVERRIDE; /** * Handles setting and unsetting the prefix mode. * Finds the given member of the given channel, if it's not found an error message is sent to 'source' * and MODEACTION_DENY is returned. Otherwise the mode change is attempted. * @param source Source of the mode change, an error message is sent to this user if the target is not found * @param dest Unused * @param channel The channel the mode change is happening on * @param param The nickname or uuid of the target user * @param adding True when the mode is being set, false when it is being unset * @return MODEACTION_ALLOW if the change happened, MODEACTION_DENY if no change happened * The latter occurs either when the member cannot be found or when the member already has this prefix set * (when setting) or doesn't have this prefix set (when unsetting). */ ModeAction OnModeChange(User* source, User* dest, Channel* channel, std::string& param, bool adding) CXX11_OVERRIDE; /** * Updates the configuration of this prefix. * @param rank The prefix rank of this mode. * @param setrank The prefix rank required to set this mode on channels. * @param unsetrank The prefix rank required to set this unmode on channels. * @param selfrm Whether a client with this prefix can remove it from themself. */ void Update(unsigned int rank, unsigned int setrank, unsigned int unsetrank, bool selfrm); /** * Removes this prefix mode from all users on the given channel * @param channel The channel which the server wants to remove your mode from * @param changelist Mode change list to populate with the removal of this mode */ void RemoveMode(Channel* channel, Modes::ChangeList& changelist) CXX11_OVERRIDE; /** * Determines whether a user with this prefix mode can remove it. */ bool CanSelfRemove() const { return selfremove; } /** * Mode prefix or 0. If this is defined, you should * also implement GetPrefixRank() to return an integer * value for this mode prefix. */ char GetPrefix() const { return prefix; } /** * Get the 'value' of this modes prefix. * determines which to display when there are multiple. * The mode with the highest value is ranked first. See the * PrefixModeValue enum and Channel::GetPrefixValue() for * more information. */ unsigned int GetPrefixRank() const { return prefixrank; } }; /** A prebuilt mode handler which handles a simple user mode, e.g. no parameters, usable by any user, with no extra * behaviour to the mode beyond the basic setting and unsetting of the mode, not allowing the mode to be set if it * is already set and not allowing it to be unset if it is already unset. * An example of a simple user mode is user mode +w. */ class CoreExport SimpleUserModeHandler : public ModeHandler { public: SimpleUserModeHandler(Module* Creator, const std::string& Name, char modeletter) : ModeHandler(Creator, Name, modeletter, PARAM_NONE, MODETYPE_USER) {} ModeAction OnModeChange(User* source, User* dest, Channel* channel, std::string& parameter, bool adding) CXX11_OVERRIDE; }; /** A prebuilt mode handler which handles a simple channel mode, e.g. no parameters, usable by any user, with no extra * behaviour to the mode beyond the basic setting and unsetting of the mode, not allowing the mode to be set if it * is already set and not allowing it to be unset if it is already unset. * An example of a simple channel mode is channel mode +s. */ class CoreExport SimpleChannelModeHandler : public ModeHandler { public: SimpleChannelModeHandler(Module* Creator, const std::string& Name, char modeletter) : ModeHandler(Creator, Name, modeletter, PARAM_NONE, MODETYPE_CHANNEL) {} ModeAction OnModeChange(User* source, User* dest, Channel* channel, std::string& parameter, bool adding) CXX11_OVERRIDE; }; /** * The ModeWatcher class can be used to alter the behaviour of a mode implemented * by the core or by another module. To use ModeWatcher, derive a class from it, * and attach it to the mode using Server::AddModeWatcher and Server::DelModeWatcher. * A ModeWatcher will be called both before and after the mode change. */ class CoreExport ModeWatcher : public classbase { private: /** * The mode name this class is watching */ const std::string mode; /** * The mode type being watched (user or channel) */ ModeType m_type; public: ModuleRef creator; /** * The constructor initializes the mode and the mode type */ ModeWatcher(Module* creator, const std::string& modename, ModeType type); /** * The default destructor does nothing. */ virtual ~ModeWatcher(); /** * Get the mode name being watched * @return The mode name being watched */ const std::string& GetModeName() const { return mode; } /** * Get the mode type being watched * @return The mode type being watched (user or channel) */ ModeType GetModeType() const { return m_type; } /** * Before the mode character is processed by its handler, this method will be called. * @param source The sender of the mode * @param dest The target user for the mode, if you are watching a user mode * @param channel The target channel for the mode, if you are watching a channel mode * @param parameter The parameter of the mode, if the mode is supposed to have a parameter. * If you alter the parameter you are given, the mode handler will see your atered version * when it handles the mode. * @param adding True if the mode is being added and false if it is being removed * @return True to allow the mode change to go ahead, false to abort it. If you abort the * change, the mode handler (and ModeWatcher::AfterMode()) will never see the mode change. */ virtual bool BeforeMode(User* source, User* dest, Channel* channel, std::string& parameter, bool adding); /** * After the mode character has been processed by the ModeHandler, this method will be called. * @param source The sender of the mode * @param dest The target user for the mode, if you are watching a user mode * @param channel The target channel for the mode, if you are watching a channel mode * @param parameter The parameter of the mode, if the mode is supposed to have a parameter. * You cannot alter the parameter here, as the mode handler has already processed it. * @param adding True if the mode is being added and false if it is being removed */ virtual void AfterMode(User* source, User* dest, Channel* channel, const std::string& parameter, bool adding); }; /** The mode parser handles routing of modes and handling of mode strings. * It marshalls, controls and maintains both ModeWatcher and ModeHandler classes, * parses client to server MODE strings for user and channel modes, and performs * processing for the 004 mode list numeric, amongst other things. */ class CoreExport ModeParser : public fakederef<ModeParser> { public: /** The maximum number of modes which can be created. */ static const ModeHandler::Id MODEID_MAX = 64; /** The maximum length of a mode parameter. */ static const size_t MODE_PARAM_MAX = 250; /** Type of the container that maps mode names to ModeHandlers */ typedef TR1NS::unordered_map<std::string, ModeHandler*, irc::insensitive, irc::StrHashComp> ModeHandlerMap; private: /** Type of the container that maps mode names to ModeWatchers */ typedef insp::flat_multimap<std::string, ModeWatcher*> ModeWatcherMap; /** Last item in the ModeType enum */ static const unsigned int MODETYPE_LAST = 2; /** Mode handlers for each mode, to access a handler subtract * 65 from the ascii value of the mode letter. * The upper bit of the value indicates if its a usermode * or a channel mode, so we have 256 of them not 64. */ ModeHandler* modehandlers[MODETYPE_LAST][128]; /** An array of mode handlers indexed by the mode id */ ModeHandler* modehandlersbyid[MODETYPE_LAST][MODEID_MAX]; /** A map of mode handlers keyed by their name */ ModeHandlerMap modehandlersbyname[MODETYPE_LAST]; /** Lists of mode handlers by type */ struct { /** List of mode handlers that inherit from ListModeBase */ std::vector<ListModeBase*> list; /** List of mode handlers that inherit from PrefixMode */ std::vector<PrefixMode*> prefix; } mhlist; /** Mode watcher classes */ ModeWatcherMap modewatchermap; /** Last processed mode change */ Modes::ChangeList LastChangeList; /** * Attempts to apply a mode change to a user or channel */ ModeAction TryMode(User* user, User* targu, Channel* targc, Modes::Change& mcitem, bool SkipACL); /** Allocates an unused id for the given mode type, throws a ModuleException if out of ids. * @param mt The type of the mode to allocate the id for * @return The id */ ModeHandler::Id AllocateModeId(ModeType mt); public: typedef std::vector<ListModeBase*> ListModeList; typedef std::vector<PrefixMode*> PrefixModeList; typedef unsigned int ModeProcessFlag; enum ModeProcessFlags { /** If only this flag is specified, the mode change will be global * and parameter modes will have their parameters explicitly set * (not merged). This is the default. */ MODE_NONE = 0, /** If this flag is set then the parameters of non-listmodes will be * merged according to their conflict resolution rules. * Does not affect user modes, channel modes without a parameter and * listmodes. */ MODE_MERGE = 1, /** If this flag is set then the linking module will ignore the mode change * and not send it to other servers. The mode change will be processed * locally and sent to local user(s) as usual. */ MODE_LOCALONLY = 2, /** If this flag is set then the mode change will be subject to access checks. * For more information see the documentation of the PrefixMode class, * ModeHandler::ranktoset and ModeHandler::AccessCheck(). * Modules may explicitly allow a mode change regardless of this flag by returning * MOD_RES_ALLOW from the OnPreMode hook. Only affects channel mode changes. */ MODE_CHECKACCESS = 4 }; ModeParser(); ~ModeParser(); static bool IsModeChar(char chr); /** Tidy a banmask. This makes a banmask 'acceptable' if fields are left out. * E.g. * * nick -> nick!*@* * * nick!ident -> nick!ident@* * * host.name -> *!*\@host.name * * ident@host.name -> *!ident\@host.name * * This method can be used on both IPV4 and IPV6 user masks. */ static void CleanMask(std::string &mask); /** Gets the last mode change to be processed. */ const Modes::ChangeList& GetLastChangeList() const { return LastChangeList; } /** Add a mode to the mode parser. * Throws a ModuleException if the mode cannot be added. */ void AddMode(ModeHandler* mh); /** Delete a mode from the mode parser. * When a mode is deleted, the mode handler will be called * for every user (if it is a user mode) or for every channel * (if it is a channel mode) to unset the mode on all objects. * This prevents modes staying in the system which no longer exist. * @param mh The mode handler to remove * @return True if the mode was successfully removed. */ bool DelMode(ModeHandler* mh); /** Add a mode watcher. * A mode watcher is triggered before and after a mode handler is * triggered. See the documentation of class ModeWatcher for more * information. * @param mw The ModeWatcher you want to add */ void AddModeWatcher(ModeWatcher* mw); /** Delete a mode watcher. * A mode watcher is triggered before and after a mode handler is * triggered. See the documentation of class ModeWatcher for more * information. * @param mw The ModeWatcher you want to delete * @return True if the ModeWatcher was deleted correctly */ bool DelModeWatcher(ModeWatcher* mw); /** Process a list of mode changes entirely. If the mode changes do not fit into one MODE line * then multiple MODE lines are generated. * @param user The source of the mode change, can be a server user. * @param targetchannel Channel to apply the mode change on. NULL if changing modes on a channel. * @param targetuser User to apply the mode change on. NULL if changing modes on a user. * @param changelist Modes to change in form of a Modes::ChangeList. * @param flags Optional flags controlling how the mode change is processed, * defaults to MODE_NONE. */ void Process(User* user, Channel* targetchannel, User* targetuser, Modes::ChangeList& changelist, ModeProcessFlag flags = MODE_NONE); /** Process a single MODE line's worth of mode changes, taking max modes and line length limits * into consideration. Return value indicates how many modes were processed. * @param user The source of the mode change, can be a server user. * @param targetchannel Channel to apply the mode change on. NULL if changing modes on a channel. * @param targetuser User to apply the mode change on. NULL if changing modes on a user. * @param changelist Modes to change in form of a Modes::ChangeList. May not process * the entire list due to MODE line length and max modes limitations. * @param flags Optional flags controlling how the mode change is processed, * defaults to MODE_NONE. * @param beginindex Index of the first element in changelist to process. Mode changes before * the element with this index are ignored. * @return Number of mode changes processed from changelist. */ unsigned int ProcessSingle(User* user, Channel* targetchannel, User* targetuser, Modes::ChangeList& changelist, ModeProcessFlag flags = MODE_NONE, unsigned int beginindex = 0); /** Turn a list of parameters compatible with the format of the MODE command into * Modes::ChangeList form. All modes are processed, regardless of max modes. Unknown modes * are skipped. * @param user The source of the mode change, can be a server user. Error numerics are sent to * this user. * @param type MODETYPE_USER if this is a user mode change or MODETYPE_CHANNEL if this * is a channel mode change. * @param parameters List of strings describing the mode change to convert to a ChangeList. * Must be using the same format as the parameters of a MODE command. * @param changelist ChangeList object to populate. * @param beginindex Index of the first element that is part of the MODE list in the parameters * container. Defaults to 1. * @param endindex Index of the first element that is not part of the MODE list. By default, * the entire container is considered part of the MODE list. */ void ModeParamsToChangeList(User* user, ModeType type, const std::vector<std::string>& parameters, Modes::ChangeList& changelist, unsigned int beginindex = 1, unsigned int endindex = UINT_MAX); /** Find the mode handler for a given mode name and type. * @param modename The mode name to search for. * @param mt Type of mode to search for, user or channel. * @return A pointer to a ModeHandler class, or NULL of there isn't a handler for the given mode name. */ ModeHandler* FindMode(const std::string& modename, ModeType mt); /** Find the mode handler for a given mode and type. * @param modeletter mode letter to search for * @param mt type of mode to search for, user or channel * @returns a pointer to a ModeHandler class, or NULL of there isnt a handler for the given mode */ ModeHandler* FindMode(unsigned const char modeletter, ModeType mt); /** Find the mode handler for the given prefix mode * @param modeletter The mode letter to search for * @return A pointer to the PrefixMode or NULL if the mode wasn't found or it isn't a prefix mode */ PrefixMode* FindPrefixMode(unsigned char modeletter); /** Find a mode handler by its prefix. * If there is no mode handler with the given prefix, NULL will be returned. * @param pfxletter The prefix to find, e.g. '@' * @return The mode handler which handles this prefix, or NULL if there is none. */ PrefixMode* FindPrefix(unsigned const char pfxletter); /** Generates a list of modes, comma seperated by type: * 1; Listmodes EXCEPT those with a prefix * 2; Modes that take a param when adding or removing * 3; Modes that only take a param when adding * 4; Modes that dont take a param */ std::string GiveModeList(ModeType mt); /** This returns the PREFIX=(ohv)@%+ section of the 005 numeric, or * just the "@%+" part if the parameter false */ std::string BuildPrefixes(bool lettersAndModes = true); /** Get a list of all mode handlers that inherit from ListModeBase * @return A list containing ListModeBase modes */ const ListModeList& GetListModes() const { return mhlist.list; } /** Get a list of all prefix modes * @return A list containing all prefix modes */ const PrefixModeList& GetPrefixModes() const { return mhlist.prefix; } /** Get a mode name -> ModeHandler* map containing all modes of the given type * @param mt Type of modes to return, MODETYPE_USER or MODETYPE_CHANNEL * @return A map of mode handlers of the given type */ const ModeHandlerMap& GetModes(ModeType mt) const { return modehandlersbyname[mt]; } /** Show the list of a list mode to a user. Modules can deny the listing. * @param user User to show the list to. * @param chan Channel to show the list of. * @param mh List mode to show the list of. */ void ShowListModeList(User* user, Channel* chan, ModeHandler* mh); }; inline PrefixMode* ModeHandler::IsPrefixMode() { return (this->type_id == MC_PREFIX ? static_cast<PrefixMode*>(this) : NULL); } inline const PrefixMode* ModeHandler::IsPrefixMode() const { return (this->type_id == MC_PREFIX ? static_cast<const PrefixMode*>(this) : NULL); } inline ListModeBase* ModeHandler::IsListModeBase() { return (this->type_id == MC_LIST ? reinterpret_cast<ListModeBase*>(this) : NULL); } inline const ListModeBase* ModeHandler::IsListModeBase() const { return (this->type_id == MC_LIST ? reinterpret_cast<const ListModeBase*>(this) : NULL); } inline ParamModeBase* ModeHandler::IsParameterMode() { return (this->type_id == MC_PARAM ? reinterpret_cast<ParamModeBase*>(this) : NULL); } inline const ParamModeBase* ModeHandler::IsParameterMode() const { return (this->type_id == MC_PARAM ? reinterpret_cast<const ParamModeBase*>(this) : NULL); } ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/include/modechange.h�����������������������������������������������������������������0000664�0000000�0000000�00000006441�13554550454�0017236�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * InspIRCd -- Internet Relay Chat Daemon * * Copyright (C) 2014 Attila Molnar <attilamolnar@hush.com> * * This file is part of InspIRCd. InspIRCd is free software: you can * redistribute it and/or modify it under the terms of the GNU General Public * License as published by the Free Software Foundation, version 2. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once namespace Modes { struct Change; class ChangeList; } /** A single mode to be changed */ struct Modes::Change { bool adding; ModeHandler* mh; std::string param; /** * @param handler Mode handler * @param add True if this mode is being set, false if removed * @param parameter Mode parameter */ Change(ModeHandler* handler, bool add, const std::string& parameter) : adding(add) , mh(handler) , param(parameter) { } }; /** A list of mode changes that can be applied on a Channel or User */ class Modes::ChangeList { public: typedef std::vector<Change> List; /** Add a new mode to be changed to this ChangeList * @param change Mode change to add */ void push(const Modes::Change& change) { items.push_back(change); } /** Insert multiple mode changes to the ChangeList * @param first Iterator to the first change to insert * @param last Iterator to the first change to not insert */ void push(List::const_iterator first, List::const_iterator last) { items.insert(items.end(), first, last); } /** Add a new mode to be changed to this ChangeList * @param mh Mode handler * @param adding True if this mode is being set, false if removed * @param param Mode parameter */ void push(ModeHandler* mh, bool adding, const std::string& param = std::string()) { items.push_back(Change(mh, adding, param)); } /** Add a new mode to this ChangeList which will be set on the target * @param mh Mode handler * @param param Mode parameter */ void push_add(ModeHandler* mh, const std::string& param = std::string()) { push(mh, true, param); } /** Add a new mode to this ChangeList which will be unset from the target * @param mh Mode handler * @param param Mode parameter */ void push_remove(ModeHandler* mh, const std::string& param = std::string()) { push(mh, false, param); } /** Remove all mode changes from this stack */ void clear() { items.clear(); } /** Checks whether the ChangeList is empty, equivalent to (size() != 0). * @return True if the ChangeList is empty, false otherwise. */ bool empty() const { return items.empty(); } /** Get number of mode changes in this ChangeList * @return Number of mode changes in this ChangeList */ List::size_type size() const { return items.size(); } /** Get the list of mode changes in this ChangeList * @return List of modes added to this ChangeList */ const List& getlist() const { return items; } /** Get the list of mode changes in this ChangeList * @return List of modes added to this ChangeList */ List& getlist() { return items; } private: List items; }; �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/include/modules.h��������������������������������������������������������������������0000664�0000000�0000000�00000150113�13554550454�0016610�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * InspIRCd -- Internet Relay Chat Daemon * * Copyright (C) 2009-2010 Daniel De Graaf <danieldg@inspircd.org> * Copyright (C) 2006-2007, 2009 Dennis Friis <peavey@inspircd.org> * Copyright (C) 2003-2008 Craig Edwards <craigedwards@brainbox.cc> * Copyright (C) 2008 Thomas Stagner <aquanight@inspircd.org> * Copyright (C) 2007 Robin Burchell <robin+git@viroteck.net> * Copyright (C) 2006-2007 Oliver Lupton <oliverlupton@gmail.com> * Copyright (C) 2003 randomdan <???@???> * * This file is part of InspIRCd. InspIRCd is free software: you can * redistribute it and/or modify it under the terms of the GNU General Public * License as published by the Free Software Foundation, version 2. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include "dynamic.h" #include "base.h" #include "ctables.h" #include "inspsocket.h" #include <string> #include <deque> #include <sstream> #include "timer.h" #include "mode.h" /** Used to specify the behaviour of a module. */ enum ModuleFlags { /** The module has no special attributes. */ VF_NONE = 0, /** The module is a coremod and can be assumed to be loaded on all servers. */ VF_CORE = 1, /* The module is included with InspIRCd. */ VF_VENDOR = 2, /** The module MUST be loaded on all servers on a network to link. */ VF_COMMON = 4, /** The module SHOULD be loaded on all servers on a network for consistency. */ VF_OPTCOMMON = 8 }; #define MOD_RES_ALLOW (ModResult(1)) #define MOD_RES_PASSTHRU (ModResult(0)) #define MOD_RES_DENY (ModResult(-1)) /** Used to represent an allow/deny module result. * Not constructed as an enum because it reverses the value logic of some functions; * the compiler will inline accesses to have the same efficiency as integer operations. */ struct ModResult { int res; ModResult() : res(0) {} explicit ModResult(int r) : res(r) {} inline bool operator==(const ModResult& r) const { return res == r.res; } inline bool operator!=(const ModResult& r) const { return res != r.res; } inline bool operator!() const { return !res; } inline bool check(bool def) const { return (res == 1 || (res == 0 && def)); } /** * Merges two results, preferring ALLOW to DENY */ inline ModResult operator+(const ModResult& r) const { if (res == r.res || r.res == 0) return *this; if (res == 0) return r; // they are different, and neither is passthru return MOD_RES_ALLOW; } }; /** InspIRCd major version. * 1.2 -> 102; 2.1 -> 201; 2.12 -> 212 */ #define INSPIRCD_VERSION_MAJ 300 /** InspIRCd API version. * If you change any API elements, increment this value. This counter should be * reset whenever the major version is changed. Modules can use these two values * and numerical comparisons in preprocessor macros if they wish to support * multiple versions of InspIRCd in one file. */ #define INSPIRCD_VERSION_API 7 /** * This #define allows us to call a method in all * loaded modules in a readable simple way, e.g.: * 'FOREACH_MOD(OnConnect,(user));' */ #define FOREACH_MOD(y,x) do { \ const Module::List& _handlers = ServerInstance->Modules->EventHandlers[I_ ## y]; \ for (Module::List::const_reverse_iterator _i = _handlers.rbegin(), _next; _i != _handlers.rend(); _i = _next) \ { \ _next = _i+1; \ try \ { \ if (!(*_i)->dying) \ (*_i)->y x ; \ } \ catch (CoreException& modexcept) \ { \ ServerInstance->Logs->Log("MODULE", LOG_DEFAULT, "Exception caught: " + modexcept.GetReason()); \ } \ } \ } while (0); /** * Custom module result handling loop. This is a paired macro, and should only * be used with while_each_hook. * * See src/channels.cpp for an example of use. */ #define DO_EACH_HOOK(n,v,args) \ do { \ const Module::List& _handlers = ServerInstance->Modules->EventHandlers[I_ ## n]; \ for (Module::List::const_reverse_iterator _i = _handlers.rbegin(), _next; _i != _handlers.rend(); _i = _next) \ { \ _next = _i+1; \ try \ { \ if (!(*_i)->dying) \ v = (*_i)->n args; #define WHILE_EACH_HOOK(n) \ } \ catch (CoreException& except_ ## n) \ { \ ServerInstance->Logs->Log("MODULE", LOG_DEFAULT, "Exception caught: " + (except_ ## n).GetReason()); \ } \ } \ } while(0) /** * Module result iterator * Runs the given hook until some module returns a useful result. * * Example: ModResult result; * FIRST_MOD_RESULT(OnUserPreNick, result, (user, newnick)) */ #define FIRST_MOD_RESULT(n,v,args) do { \ v = MOD_RES_PASSTHRU; \ DO_EACH_HOOK(n,v,args) \ { \ if (v != MOD_RES_PASSTHRU) \ break; \ } \ WHILE_EACH_HOOK(n); \ } while (0) /** Holds a module's Version information. * The members (set by the constructor only) indicate details as to the version number * of a module. A class of type Version is returned by the GetVersion method of the Module class. */ class CoreExport Version { public: /** Module description */ const std::string description; /** Flags */ const int Flags; /** Server linking description string */ const std::string link_data; /** Simple module version */ Version(const std::string &desc, int flags = VF_NONE); /** Complex version information, including linking compatability data */ Version(const std::string &desc, int flags, const std::string& linkdata); }; class CoreExport DataProvider : public ServiceProvider { public: DataProvider(Module* Creator, const std::string& Name) : ServiceProvider(Creator, Name, SERVICE_DATA) {} }; /** Priority types which can be used by Module::Prioritize() */ enum Priority { PRIORITY_FIRST, PRIORITY_LAST, PRIORITY_BEFORE, PRIORITY_AFTER }; /** Implementation-specific flags which may be set in Module::Implements() */ enum Implementation { I_OnUserConnect, I_OnUserPreQuit, I_OnUserQuit, I_OnUserDisconnect, I_OnUserJoin, I_OnUserPart, I_OnSendSnotice, I_OnUserPreJoin, I_OnUserPreKick, I_OnUserKick, I_OnOper, I_OnUserPreInvite, I_OnUserInvite, I_OnUserPreMessage, I_OnUserPreNick, I_OnUserPostMessage, I_OnUserMessageBlocked, I_OnMode, I_OnShutdown, I_OnDecodeMetaData, I_OnAcceptConnection, I_OnUserInit, I_OnUserPostInit, I_OnChangeHost, I_OnChangeRealName, I_OnAddLine, I_OnDelLine, I_OnExpireLine, I_OnUserPostNick, I_OnPreMode, I_On005Numeric, I_OnKill, I_OnLoadModule, I_OnUnloadModule, I_OnBackgroundTimer, I_OnPreCommand, I_OnCheckReady, I_OnCheckInvite, I_OnRawMode, I_OnCheckKey, I_OnCheckLimit, I_OnCheckBan, I_OnCheckChannelBan, I_OnExtBanCheck, I_OnPreChangeHost, I_OnPreTopicChange, I_OnConnectionFail, I_OnPostTopicChange, I_OnPostConnect, I_OnPostDeoper, I_OnPreChangeRealName, I_OnUserRegister, I_OnChannelPreDelete, I_OnChannelDelete, I_OnPostOper, I_OnPostCommand, I_OnPostJoin, I_OnBuildNeighborList, I_OnGarbageCollect, I_OnSetConnectClass, I_OnUserMessage, I_OnPassCompare, I_OnNumeric, I_OnPreRehash, I_OnModuleRehash, I_OnChangeIdent, I_OnSetUserIP, I_OnServiceAdd, I_OnServiceDel, I_OnUserWrite, I_END }; /** Base class for all InspIRCd modules * This class is the base class for InspIRCd modules. All modules must inherit from this class, * its methods will be called when irc server events occur. class inherited from module must be * instantiated by the ModuleFactory class (see relevent section) for the module to be initialised. */ class CoreExport Module : public classbase, public usecountbase { /** Detach an event from this module * @param i Event type to detach */ void DetachEvent(Implementation i); public: /** A list of modules. */ typedef std::vector<Module*> List; /** File that this module was loaded from */ std::string ModuleSourceFile; /** Reference to the dlopen() value */ DLLManager* ModuleDLLManager; /** If true, this module will be unloaded soon, further unload attempts will fail * Value is used by the ModuleManager internally, you should not modify it */ bool dying; /** Default constructor. * Creates a module class. Don't do any type of hook registration or checks * for other modules here; do that in init(). */ Module(); /** Module setup * \exception ModuleException Throwing this class, or any class derived from ModuleException, causes loading of the module to abort. */ virtual void init() {} /** Clean up prior to destruction * If you override, you must call this AFTER your module's cleanup */ CullResult cull() CXX11_OVERRIDE; /** Default destructor. * destroys a module class */ virtual ~Module(); virtual void Prioritize() { } /** This method is called when you should reload module specific configuration: * on boot, on a /REHASH and on module load. * @param status The current status, can be inspected for more information; * also used for reporting configuration errors and warnings. */ virtual void ReadConfig(ConfigStatus& status); /** Returns the version number of a Module. * The method should return a Version object with its version information assigned via * Version::Version */ virtual Version GetVersion() = 0; /** Called when a user connects. * The details of the connecting user are available to you in the parameter User *user * @param user The user who is connecting */ virtual void OnUserConnect(LocalUser* user); /** Called when before a user quits. * The details of the exiting user are available to you in the parameter User *user * This event is only called when the user is fully registered when they quit. To catch * raw disconnections, use the OnUserDisconnect method. * @param user The user who is quitting * @param message The user's quit message (as seen by non-opers) * @param oper_message The user's quit message (as seen by opers) */ virtual ModResult OnUserPreQuit(LocalUser* user, std::string& message, std::string& oper_message); /** Called when a user quits. * The details of the exiting user are available to you in the parameter User *user * This event is only called when the user is fully registered when they quit. To catch * raw disconnections, use the OnUserDisconnect method. * @param user The user who is quitting * @param message The user's quit message (as seen by non-opers) * @param oper_message The user's quit message (as seen by opers) */ virtual void OnUserQuit(User* user, const std::string &message, const std::string &oper_message); /** Called whenever a user's socket is closed. * The details of the exiting user are available to you in the parameter User *user * This event is called for all users, registered or not, as a cleanup method for modules * which might assign resources to user, such as dns lookups, objects and sockets. * @param user The user who is disconnecting */ virtual void OnUserDisconnect(LocalUser* user); /** Called whenever a channel is about to be deleted * @param chan The channel being deleted * @return An integer specifying whether or not the channel may be deleted. 0 for yes, 1 for no. */ virtual ModResult OnChannelPreDelete(Channel *chan); /** Called whenever a channel is deleted, either by QUIT, KICK or PART. * @param chan The channel being deleted */ virtual void OnChannelDelete(Channel* chan); /** Called when a user joins a channel. * The details of the joining user are available to you in the parameter User *user, * and the details of the channel they have joined is available in the variable Channel *channel * @param memb The channel membership being created * @param sync This is set to true if the JOIN is the result of a network sync and the remote user is being introduced * to a channel due to the network sync. * @param created This is true if the join created the channel * @param except_list A list of users not to send to. */ virtual void OnUserJoin(Membership* memb, bool sync, bool created, CUList& except_list); /** Called after a user joins a channel * Identical to OnUserJoin, but called immediately afterwards, when any linking module has * seen the join. * @param memb The channel membership created */ virtual void OnPostJoin(Membership* memb); /** Called when a user parts a channel. * The details of the leaving user are available to you in the parameter User *user, * and the details of the channel they have left is available in the variable Channel *channel * @param memb The channel membership being destroyed * @param partmessage The part message, or an empty string (may be modified) * @param except_list A list of users to not send to. */ virtual void OnUserPart(Membership* memb, std::string &partmessage, CUList& except_list); /** Called on rehash. * This method is called prior to a /REHASH or when a SIGHUP is received from the operating * system. This is called in all cases -- including when this server will not execute the * rehash because it is directed at a remote server. * * @param user The user performing the rehash, if any. If this is server initiated, the value of * this variable will be NULL. * @param parameter The (optional) parameter given to REHASH from the user. Empty when server * initiated. */ virtual void OnPreRehash(User* user, const std::string &parameter); /** Called on rehash. * This method is called when a user initiates a module-specific rehash. This can be used to do * expensive operations (such as reloading SSL certificates) that are not executed on a normal * rehash for efficiency. A rehash of this type does not reload the core configuration. * * @param user The user performing the rehash. * @param parameter The parameter given to REHASH */ virtual void OnModuleRehash(User* user, const std::string &parameter); /** Called whenever a snotice is about to be sent to a snomask. * snomask and type may both be modified; the message may not. * @param snomask The snomask the message is going to (e.g. 'A') * @param type The textual description the snomask will go to (e.g. 'OPER') * @param message The text message to be sent via snotice * @return 1 to block the snotice from being sent entirely, 0 else. */ virtual ModResult OnSendSnotice(char &snomask, std::string &type, const std::string &message); /** Called whenever a user is about to join a channel, before any processing is done. * Returning a value of 1 from this function stops the process immediately, causing no * output to be sent to the user by the core. If you do this you must produce your own numerics, * notices etc. This is useful for modules which may want to mimic +b, +k, +l etc. Returning -1 from * this function forces the join to be allowed, bypassing restrictions such as banlists, invite, keys etc. * * IMPORTANT NOTE! * * If the user joins a NEW channel which does not exist yet, OnUserPreJoin will be called BEFORE the channel * record is created. This will cause Channel* chan to be NULL. There is very little you can do in form of * processing on the actual channel record at this point, however the channel NAME will still be passed in * char* cname, so that you could for example implement a channel blacklist or whitelist, etc. * @param user The user joining the channel * @param chan If the channel is a new channel, this will be NULL, otherwise it will be a pointer to the channel being joined * @param cname The channel name being joined. For new channels this is valid where chan is not. * @param privs A string containing the users privilages when joining the channel. For new channels this will contain "o". * You may alter this string to alter the user's modes on the channel. * @param keygiven The key given to join the channel, or an empty string if none was provided * @return 1 To prevent the join, 0 to allow it. */ virtual ModResult OnUserPreJoin(LocalUser* user, Channel* chan, const std::string& cname, std::string& privs, const std::string& keygiven); /** Called whenever a user is about to be kicked. * Returning a value of 1 from this function stops the process immediately, causing no * output to be sent to the user by the core. If you do this you must produce your own numerics, * notices etc. * @param source The user issuing the kick * @param memb The channel membership of the user who is being kicked. * @param reason The kick reason * @return 1 to prevent the kick, 0 to continue normally, -1 to explicitly allow the kick regardless of normal operation */ virtual ModResult OnUserPreKick(User* source, Membership* memb, const std::string &reason); /** Called whenever a user is kicked. * If this method is called, the kick is already underway and cannot be prevented, so * to prevent a kick, please use Module::OnUserPreKick instead of this method. * @param source The user issuing the kick * @param memb The channel membership of the user who was kicked. * @param reason The kick reason * @param except_list A list of users to not send to. */ virtual void OnUserKick(User* source, Membership* memb, const std::string &reason, CUList& except_list); /** Called whenever a user opers locally. * The User will contain the oper mode 'o' as this function is called after any modifications * are made to the user's structure by the core. * @param user The user who is opering up * @param opertype The opers type name */ virtual void OnOper(User* user, const std::string &opertype); /** Called after a user opers locally. * This is identical to Module::OnOper(), except it is called after OnOper so that other modules * can be gauranteed to already have processed the oper-up, for example m_spanningtree has sent * out the OPERTYPE, etc. * @param user The user who is opering up * @param opername The name of the oper that the user is opering up to. Only valid locally. Empty string otherwise. * @param opertype The opers type name */ virtual void OnPostOper(User* user, const std::string &opername, const std::string &opertype); /** Called after a user deopers locally. * @param user The user who has deopered. */ virtual void OnPostDeoper(User* user); /** Called whenever a user is about to invite another user into a channel, before any processing is done. * Returning 1 from this function stops the process immediately, causing no * output to be sent to the user by the core. If you do this you must produce your own numerics, * notices etc. This is useful for modules which may want to filter invites to channels. * @param source The user who is issuing the INVITE * @param dest The user being invited * @param channel The channel the user is being invited to * @param timeout The time the invite will expire (0 == never) * @return 1 to deny the invite, 0 to check whether or not the user has permission to invite, -1 to explicitly allow the invite */ virtual ModResult OnUserPreInvite(User* source,User* dest,Channel* channel, time_t timeout); /** Called after a user has been successfully invited to a channel. * You cannot prevent the invite from occuring using this function, to do that, * use OnUserPreInvite instead. * @param source The user who is issuing the INVITE * @param dest The user being invited * @param channel The channel the user is being invited to * @param timeout The time the invite will expire (0 == never) * @param notifyrank Rank required to get an invite announcement (if enabled) * @param notifyexcepts List of users to not send the default NOTICE invite announcement to */ virtual void OnUserInvite(User* source, User* dest, Channel* channel, time_t timeout, unsigned int notifyrank, CUList& notifyexcepts); /** Called before a user sends a message to a channel, a user, or a server glob mask. * @param user The user sending the message. * @param target The target of the message. This can either be a channel, a user, or a server * glob mask. * @param details Details about the message such as the message text and type. See the * MessageDetails class for more information. * @return MOD_RES_ALLOW to explicitly allow the message, MOD_RES_DENY to explicitly deny the * message, or MOD_RES_PASSTHRU to let another module handle the event. */ virtual ModResult OnUserPreMessage(User* user, const MessageTarget& target, MessageDetails& details); /** Called when sending a message to all "neighbors" of a given user - * that is, all users that share a common channel. This is used in * commands such as NICK, QUIT, etc. * @param source The source of the message * @param include_c Channels to scan for users to include * @param exceptions Map of user->bool that overrides the inclusion decision * * Set exceptions[user] = true to include, exceptions[user] = false to exclude */ virtual void OnBuildNeighborList(User* source, IncludeChanList& include_c, std::map<User*, bool>& exceptions); /** Called before local nickname changes. This can be used to implement Q-lines etc. * If your method returns nonzero, the nickchange is silently forbidden, and it is down to your * module to generate some meaninful output. * @param user The username changing their nick * @param newnick Their new nickname * @return 1 to deny the change, 0 to allow */ virtual ModResult OnUserPreNick(LocalUser* user, const std::string& newnick); /** Called immediately after a user sends a message to a channel, a user, or a server glob mask. * @param user The user sending the message. * @param target The target of the message. This can either be a channel, a user, or a server * glob mask. * @param details Details about the message such as the message text and type. See the * MessageDetails class for more information. */ virtual void OnUserPostMessage(User* user, const MessageTarget& target, const MessageDetails& details); /** Called immediately before a user sends a message to a channel, a user, or a server glob mask. * @param user The user sending the message. * @param target The target of the message. This can either be a channel, a user, or a server * glob mask. * @param details Details about the message such as the message text and type. See the * MessageDetails class for more information. */ virtual void OnUserMessage(User* user, const MessageTarget& target, const MessageDetails& details); /** Called when a message sent by a user to a channel, a user, or a server glob mask is blocked. * @param user The user sending the message. * @param target The target of the message. This can either be a channel, a user, or a server * glob mask. * @param details Details about the message such as the message text and type. See the * MessageDetails class for more information. */ virtual void OnUserMessageBlocked(User* user, const MessageTarget& target, const MessageDetails& details); /** Called after every MODE command sent from a user * Either the usertarget or the chantarget variable contains the target of the modes, * the actual target will have a non-NULL pointer. * All changed modes are available in the changelist object. * @param user The user sending the MODEs * @param usertarget The target user of the modes, NULL if the target is a channel * @param chantarget The target channel of the modes, NULL if the target is a user * @param changelist The changed modes. * @param processflags Flags passed to ModeParser::Process(), see ModeParser::ModeProcessFlags * for the possible flags. */ virtual void OnMode(User* user, User* usertarget, Channel* chantarget, const Modes::ChangeList& changelist, ModeParser::ModeProcessFlag processflags); /** Allows module data, sent via ProtoSendMetaData, to be decoded again by a receiving module. * Please see src/modules/m_swhois.cpp for a working example of how to use this method call. * @param target The Channel* or User* that data should be added to * @param extname The extension name which is being sent * @param extdata The extension data, encoded at the other end by an identical module */ virtual void OnDecodeMetaData(Extensible* target, const std::string &extname, const std::string &extdata); /** Called whenever a user's hostname is changed. * This event triggers after the host has been set. * @param user The user whos host is being changed * @param newhost The new hostname being set */ virtual void OnChangeHost(User* user, const std::string &newhost); /** Called whenever a user's real name is changed. * This event triggers after the name has been set. * @param user The user who's real name is being changed * @param real The new real name being set on the user */ virtual void OnChangeRealName(User* user, const std::string& real); /** Called whenever a user's IDENT is changed. * This event triggers after the name has been set. * @param user The user who's IDENT is being changed * @param ident The new IDENT being set on the user */ virtual void OnChangeIdent(User* user, const std::string &ident); /** Called whenever an xline is added by a local user. * This method is triggered after the line is added. * @param source The sender of the line or NULL for local server * @param line The xline being added */ virtual void OnAddLine(User* source, XLine* line); /** Called whenever an xline is deleted MANUALLY. See OnExpireLine for expiry. * This method is triggered after the line is deleted. * @param source The user removing the line or NULL for local server * @param line the line being deleted */ virtual void OnDelLine(User* source, XLine* line); /** Called whenever an xline expires. * This method is triggered after the line is deleted. * @param line The line being deleted. */ virtual void OnExpireLine(XLine *line); /** Called before the module is unloaded to clean up extensibles. * This method is called once for every channel, membership, and user. * so that you can clear up any data relating to the specified extensible. * @param type The type of extensible being cleaned up. If this is EXT_CHANNEL * then item is a Channel*, EXT_MEMBERSHIP then item is a Membership*, * and EXT_USER then item is a User*. * @param item A pointer to the extensible which is being cleaned up. */ virtual void OnCleanup(ExtensionItem::ExtensibleType type, Extensible* item); /** Called after any nickchange, local or remote. This can be used to track users after nickchanges * have been applied. Please note that although you can see remote nickchanges through this function, you should * NOT make any changes to the User if the user is a remote user as this may cause a desnyc. * check user->server before taking any action (including returning nonzero from the method). * Because this method is called after the nickchange is taken place, no return values are possible * to indicate forbidding of the nick change. Use OnUserPreNick for this. * @param user The user changing their nick * @param oldnick The old nickname of the user before the nickchange */ virtual void OnUserPostNick(User* user, const std::string &oldnick); /** Called before a mode change via the MODE command, to allow a single access check for * a full mode change (use OnRawMode to check individual modes) * * Returning MOD_RES_ALLOW will skip prefix level checks, but can be overridden by * OnRawMode for each individual mode * * @param source the user making the mode change * @param dest the user destination of the umode change (NULL if a channel mode) * @param channel the channel destination of the mode change * @param modes Modes being changed, can be edited */ virtual ModResult OnPreMode(User* source, User* dest, Channel* channel, Modes::ChangeList& modes); /** Called when a 005 numeric is about to be output. * The module should modify the 005 numeric if needed to indicate its features. * @param tokens The 005 map to be modified if neccessary. */ virtual void On005Numeric(std::map<std::string, std::string>& tokens); /** Called when a client is disconnected by KILL. * If a client is killed by a server, e.g. a nickname collision or protocol error, * source is NULL. * Return 1 from this function to prevent the kill, and 0 from this function to allow * it as normal. If you prevent the kill no output will be sent to the client, it is * down to your module to generate this information. * NOTE: It is NOT advisable to stop kills which originate from servers or remote users. * If you do so youre risking race conditions, desyncs and worse! * @param source The user sending the KILL * @param dest The user being killed * @param reason The kill reason * @return 1 to prevent the kill, 0 to allow */ virtual ModResult OnKill(User* source, User* dest, const std::string &reason); /** Called whenever a module is loaded. * mod will contain a pointer to the module, and string will contain its name, * for example m_widgets.so. This function is primary for dependency checking, * your module may decide to enable some extra features if it sees that you have * for example loaded "m_killwidgets.so" with "m_makewidgets.so". It is highly * recommended that modules do *NOT* bail if they cannot satisfy dependencies, * but instead operate under reduced functionality, unless the dependency is * absolutely neccessary (e.g. a module that extends the features of another * module). * @param mod A pointer to the new module */ virtual void OnLoadModule(Module* mod); /** Called whenever a module is unloaded. * mod will contain a pointer to the module, and string will contain its name, * for example m_widgets.so. This function is primary for dependency checking, * your module may decide to enable some extra features if it sees that you have * for example loaded "m_killwidgets.so" with "m_makewidgets.so". It is highly * recommended that modules do *NOT* bail if they cannot satisfy dependencies, * but instead operate under reduced functionality, unless the dependency is * absolutely neccessary (e.g. a module that extends the features of another * module). * @param mod Pointer to the module being unloaded (still valid) */ virtual void OnUnloadModule(Module* mod); /** Called once every five seconds for background processing. * This timer can be used to control timed features. Its period is not accurate * enough to be used as a clock, but it is gauranteed to be called at least once in * any five second period, directly from the main loop of the server. * @param curtime The current timer derived from time(2) */ virtual void OnBackgroundTimer(time_t curtime); /** Called whenever any command is about to be executed. * This event occurs for all registered commands, wether they are registered in the core, * or another module, and for invalid commands. Invalid commands may only be sent to this * function when the value of validated is false. By returning 1 from this method you may prevent the * command being executed. If you do this, no output is created by the core, and it is * down to your module to produce any output neccessary. * Note that unless you return 1, you should not destroy any structures (e.g. by using * InspIRCd::QuitUser) otherwise when the command's handler function executes after your * method returns, it will be passed an invalid pointer to the user object and crash!) * @param command The command being executed * @param parameters An array of array of characters containing the parameters for the command * @param user the user issuing the command * @param validated True if the command has passed all checks, e.g. it is recognised, has enough parameters, the user has permission to execute it, etc. * You should only change the parameter list and command string if validated == false (e.g. before the command lookup occurs). * @return 1 to block the command, 0 to allow */ virtual ModResult OnPreCommand(std::string& command, CommandBase::Params& parameters, LocalUser* user, bool validated); /** Called after any command has been executed. * This event occurs for all registered commands, wether they are registered in the core, * or another module, but it will not occur for invalid commands (e.g. ones which do not * exist within the command table). The result code returned by the command handler is * provided. * @param command The command being executed * @param parameters An array of array of characters containing the parameters for the command * @param user the user issuing the command * @param result The return code given by the command handler, one of CMD_SUCCESS or CMD_FAILURE * @param loop Whether the command is being called from LoopCall or directly. */ virtual void OnPostCommand(Command* command, const CommandBase::Params& parameters, LocalUser* user, CmdResult result, bool loop); /** Called after a user object is initialised and added to the user list. * When this is called the user has not had their I/O hooks checked or had their initial * connect class assigned and may not yet have a serialiser. You probably want to use * the OnUserPostInit or OnUserSetIP hooks instead of this one. * @param user The connecting user. */ virtual void OnUserInit(LocalUser* user); /** Called after a user object has had their I/O hooks checked, their initial connection * class assigned, and had a serialiser set. * @param user The connecting user. */ virtual void OnUserPostInit(LocalUser* user); /** Called to check if a user who is connecting can now be allowed to register * If any modules return false for this function, the user is held in the waiting * state until all modules return true. For example a module which implements ident * lookups will continue to return false for a user until their ident lookup is completed. * Note that the registration timeout for a user overrides these checks, if the registration * timeout is reached, the user is disconnected even if modules report that the user is * not ready to connect. * @param user The user to check * @return true to indicate readiness, false if otherwise */ virtual ModResult OnCheckReady(LocalUser* user); /** Called whenever a user is about to register their connection (e.g. before the user * is sent the MOTD etc). Modules can use this method if they are performing a function * which must be done before the actual connection is completed (e.g. ident lookups, * dnsbl lookups, etc). * Note that you should NOT delete the user record here by causing a disconnection! * Use OnUserConnect for that instead. * @param user The user registering * @return 1 to indicate user quit, 0 to continue */ virtual ModResult OnUserRegister(LocalUser* user); /** Called whenever a user joins a channel, to determine if invite checks should go ahead or not. * This method will always be called for each join, wether or not the channel is actually +i, and * determines the outcome of an if statement around the whole section of invite checking code. * return 1 to explicitly allow the join to go ahead or 0 to ignore the event. * @param user The user joining the channel * @param chan The channel being joined * @return 1 to explicitly allow the join, 0 to proceed as normal */ virtual ModResult OnCheckInvite(User* user, Channel* chan); /** Called whenever a mode character is processed. * Return 1 from this function to block the mode character from being processed entirely. * @param user The user who is sending the mode * @param chan The channel the mode is being sent to (or NULL if a usermode) * @param mh The mode handler for the mode being changed * @param param The parameter for the mode or an empty string * @param adding true of the mode is being added, false if it is being removed * @return ACR_DENY to deny the mode, ACR_DEFAULT to do standard mode checking, and ACR_ALLOW * to skip all permission checking. Please note that for remote mode changes, your return value * will be ignored! */ virtual ModResult OnRawMode(User* user, Channel* chan, ModeHandler* mh, const std::string& param, bool adding); /** Called whenever a user joins a channel, to determine if key checks should go ahead or not. * This method will always be called for each join, wether or not the channel is actually +k, and * determines the outcome of an if statement around the whole section of key checking code. * if the user specified no key, the keygiven string will be a valid but empty value. * return 1 to explicitly allow the join to go ahead or 0 to ignore the event. * @param user The user joining the channel * @param chan The channel being joined * @param keygiven The key given on joining the channel. * @return 1 to explicitly allow the join, 0 to proceed as normal */ virtual ModResult OnCheckKey(User* user, Channel* chan, const std::string &keygiven); /** Called whenever a user joins a channel, to determine if channel limit checks should go ahead or not. * This method will always be called for each join, wether or not the channel is actually +l, and * determines the outcome of an if statement around the whole section of channel limit checking code. * return 1 to explicitly allow the join to go ahead or 0 to ignore the event. * @param user The user joining the channel * @param chan The channel being joined * @return 1 to explicitly allow the join, 0 to proceed as normal */ virtual ModResult OnCheckLimit(User* user, Channel* chan); /** * Checks for a user's ban from the channel * @param user The user to check * @param chan The channel to check in * @return MOD_RES_DENY to mark as banned, MOD_RES_ALLOW to skip the * ban check, or MOD_RES_PASSTHRU to check bans normally */ virtual ModResult OnCheckChannelBan(User* user, Channel* chan); /** * Checks for a user's match of a single ban * @param user The user to check for match * @param chan The channel on which the match is being checked * @param mask The mask being checked * @return MOD_RES_DENY to mark as banned, MOD_RES_ALLOW to skip the * ban check, or MOD_RES_PASSTHRU to check bans normally */ virtual ModResult OnCheckBan(User* user, Channel* chan, const std::string& mask); /** Checks for a match on a given extban type * @return MOD_RES_DENY to mark as banned, MOD_RES_ALLOW to skip the * ban check, or MOD_RES_PASSTHRU to check bans normally */ virtual ModResult OnExtBanCheck(User* user, Channel* chan, char type); /** Called whenever a change of a local users displayed host is attempted. * Return 1 to deny the host change, or 0 to allow it. * @param user The user whos host will be changed * @param newhost The new hostname * @return 1 to deny the host change, 0 to allow */ virtual ModResult OnPreChangeHost(LocalUser* user, const std::string &newhost); /** Called whenever a change of a local users real name is attempted. * return MOD_RES_DENY to deny the name change, or MOD_RES_ALLOW to allow it. * @param user The user whos real name will be changed * @param newhost The new real name. * @return MOD_RES_DENY to deny the real name change, MOD_RES_ALLOW to allow */ virtual ModResult OnPreChangeRealName(LocalUser* user, const std::string &newhost); /** Called before a topic is changed. * Return 1 to deny the topic change, 0 to check details on the change, -1 to let it through with no checks * As with other 'pre' events, you should only ever block a local event. * @param user The user changing the topic * @param chan The channels who's topic is being changed * @param topic The actual topic text * @return 1 to block the topic change, 0 to allow */ virtual ModResult OnPreTopicChange(User* user, Channel* chan, const std::string &topic); /** Called whenever a topic has been changed. * To block topic changes you must use OnPreTopicChange instead. * @param user The user changing the topic * @param chan The channels who's topic is being changed * @param topic The actual topic text */ virtual void OnPostTopicChange(User* user, Channel* chan, const std::string &topic); /** Called whenever a password check is to be made. Replaces the old OldOperCompare API. * The password field (from the config file) is in 'password' and is to be compared against * 'input'. This method allows for encryption of passwords (oper, connect:allow, die/restart, etc). * You should return a nonzero value to override the normal comparison, or zero to pass it on. * @param ex The object that's causing the authentication (User* for \<oper> \<connect:allow> etc, Server* for \<link>). * @param password The password from the configuration file (the password="" value). * @param input The password entered by the user or whoever. * @param hashtype The hash value from the config * @return 0 to do nothing (pass on to next module/default), 1 == password is OK, -1 == password is not OK */ virtual ModResult OnPassCompare(Extensible* ex, const std::string &password, const std::string &input, const std::string& hashtype); /** Called after a user has fully connected and all modules have executed OnUserConnect * This event is informational only. You should not change any user information in this * event. To do so, use the OnUserConnect method to change the state of local users. * This is called for both local and remote users. * @param user The user who is connecting */ virtual void OnPostConnect(User* user); /** Called when a port accepts a connection * Return MOD_RES_ACCEPT if you have used the file descriptor. * @param fd The file descriptor returned from accept() * @param sock The socket connection for the new user * @param client The client IP address and port * @param server The server IP address and port */ virtual ModResult OnAcceptConnection(int fd, ListenSocket* sock, irc::sockets::sockaddrs* client, irc::sockets::sockaddrs* server); /** Called at intervals for modules to garbage-collect any hashes etc. * Certain data types such as hash_map 'leak' buckets, which must be * tidied up and freed by copying into a new item every so often. This * method is called when it is time to do that. */ virtual void OnGarbageCollect(); /** Called when a user's connect class is being matched * @return MOD_RES_ALLOW to force the class to match, MOD_RES_DENY to forbid it, or * MOD_RES_PASSTHRU to allow normal matching (by host/port). */ virtual ModResult OnSetConnectClass(LocalUser* user, ConnectClass* myclass); virtual ModResult OnNumeric(User* user, const Numeric::Numeric& numeric); /** Called whenever a local user's IP is set for the first time, or when a local user's IP changes due to * a module like m_cgiirc changing it. * @param user The user whose IP is being set */ virtual void OnSetUserIP(LocalUser* user); /** Called whenever a ServiceProvider is registered. * @param service ServiceProvider being registered. */ virtual void OnServiceAdd(ServiceProvider& service); /** Called whenever a ServiceProvider is unregistered. * @param service ServiceProvider being unregistered. */ virtual void OnServiceDel(ServiceProvider& service); /** Called whenever a message is about to be written to a user. * @param user The user who is having a message sent to them. * @param msg The message which is being written to the user. * @return MOD_RES_ALLOW to explicitly allow the message to be sent, MOD_RES_DENY to explicitly * deny the message from being sent, or MOD_RES_PASSTHRU to let another module handle the event. */ virtual ModResult OnUserWrite(LocalUser* user, ClientProtocol::Message& msg); /** Called when a user connection has been unexpectedly disconnected. * @param user The user who has been unexpectedly disconnected. * @param error The type of error which caused this connection failure. * @return MOD_RES_ALLOW to explicitly retain the user as a zombie, MOD_RES_DENY to explicitly * disconnect the user, or MOD_RES_PASSTHRU to let another module handle the event. */ virtual ModResult OnConnectionFail(LocalUser* user, BufferedSocketError error); /** Called before a server shuts down. * @param reason The reason the server is shutting down. * @param restart Whether the server is restarting. */ virtual void OnShutdown(const std::string& reason); }; /** ModuleManager takes care of all things module-related * in the core. */ class CoreExport ModuleManager : public fakederef<ModuleManager> { public: typedef std::vector<ServiceProvider*> ServiceList; private: /** Holds a string describing the last module error to occur */ std::string LastModuleError; /** List of loaded modules and shared object/dll handles * keyed by module name */ std::map<std::string, Module*> Modules; enum { PRIO_STATE_FIRST, PRIO_STATE_AGAIN, PRIO_STATE_LAST } prioritizationState; /** Loads all core modules (core_*) */ void LoadCoreModules(std::map<std::string, ServiceList>& servicemap); /** Calls the Prioritize() method in all loaded modules * @return True if all went well, false if a dependency loop was detected */ bool PrioritizeHooks(); /** Unregister all user modes or all channel modes owned by a module * @param mod Module whose modes to unregister * @param modetype MODETYPE_USER to unregister user modes, MODETYPE_CHANNEL to unregister channel modes */ void UnregisterModes(Module* mod, ModeType modetype); public: typedef std::map<std::string, Module*> ModuleMap; /** Event handler hooks. * This needs to be public to be used by FOREACH_MOD and friends. */ Module::List EventHandlers[I_END]; /** List of data services keyed by name */ std::multimap<std::string, ServiceProvider*, irc::insensitive_swo> DataProviders; /** A list of ServiceProviders waiting to be registered. * Non-NULL when constructing a Module, NULL otherwise. * When non-NULL ServiceProviders add themselves to this list on creation and the core * automatically registers them (that is, call AddService()) after the Module is constructed, * and before Module::init() is called. * If a service is created after the construction of the Module (for example in init()) it * has to be registered manually. */ ServiceList* NewServices; /** Expands the name of a module by prepending "m_" and appending ".so". * No-op if the name already has the ".so" extension. * @param modname Module name to expand * @return Module name starting with "m_" and ending with ".so" */ static std::string ExpandModName(const std::string& modname); /** Simple, bog-standard, boring constructor. */ ModuleManager(); /** Destructor */ ~ModuleManager(); /** Change the priority of one event in a module. * Each module event has a list of modules which are attached to that event type. * If you wish to be called before or after other specific modules, you may use this * method (usually within void Module::Prioritize()) to set your events priority. * You may use this call in other methods too, however, this is not supported behaviour * for a module. * @param mod The module to change the priority of * @param i The event to change the priority of * @param s The state you wish to use for this event. Use one of * PRIO_FIRST to set the event to be first called, PRIO_LAST to * set it to be the last called, or PRIO_BEFORE and PRIORITY_AFTER * to set it to be before or after one or more other modules. * @param which If PRIO_BEFORE or PRIORITY_AFTER is set in parameter 's', * then this contains a the module that your module must be placed before * or after. */ bool SetPriority(Module* mod, Implementation i, Priority s, Module* which = NULL); /** Change the priority of all events in a module. * @param mod The module to set the priority of * @param s The priority of all events in the module. * Note that with this method, it is not possible to effectively use * PRIO_BEFORE or PRIORITY_AFTER, you should use the more fine tuned * SetPriority method for this, where you may specify other modules to * be prioritized against. */ void SetPriority(Module* mod, Priority s); /** Attach an event to a module. * You may later detatch the event with ModuleManager::Detach(). * If your module is unloaded, all events are automatically detatched. * @param i Event type to attach * @param mod Module to attach event to * @return True if the event was attached */ bool Attach(Implementation i, Module* mod); /** Detatch an event from a module. * This is not required when your module unloads, as the core will * automatically detatch your module from all events it is attached to. * @param i Event type to detach * @param mod Module to detach event from * @return True if the event was detached */ bool Detach(Implementation i, Module* mod); /** Attach an array of events to a module * @param i Event types (array) to attach * @param mod Module to attach events to * @param sz The size of the implementation array */ void Attach(Implementation* i, Module* mod, size_t sz); /** Detach all events from a module (used on unload) * @param mod Module to detach from */ void DetachAll(Module* mod); /** Attach all events to a module (used on module load) * @param mod Module to attach to all events */ void AttachAll(Module* mod); /** Returns text describing the last module error * @return The last error message to occur */ std::string& LastError(); /** Load a given module file * @param filename The file to load * @param defer Defer module init (loading many modules) * @return True if the module was found and loaded */ bool Load(const std::string& filename, bool defer = false); /** Unload a given module file. Note that the module will not be * completely gone until the cull list has finished processing. * * @return true on success; if false, LastError will give a reason */ bool Unload(Module* module); /** Called by the InspIRCd constructor to load all modules from the config file. */ void LoadAll(); void UnloadAll(); void DoSafeUnload(Module*); /** Check if a module can be unloaded and if yes, prepare it for unload * @param mod Module to be unloaded * @return True if the module is unloadable, false otherwise. * If true the module must be unloaded in the current main loop iteration. */ bool CanUnload(Module* mod); /** Find a module by name, and return a Module* to it. * This is preferred over iterating the module lists yourself. * @param name The module name to look up * @return A pointer to the module, or NULL if the module cannot be found */ Module* Find(const std::string &name); /** Register a service provided by a module */ void AddService(ServiceProvider&); /** Unregister a service provided by a module */ void DelService(ServiceProvider&); /** Register all services in a given ServiceList * @param list The list containing the services to register */ void AddServices(const ServiceList& list); inline void AddServices(ServiceProvider** list, int count) { for(int i=0; i < count; i++) AddService(*list[i]); } /** Find a service by name. * If multiple modules provide a given service, the first one loaded will be chosen. */ ServiceProvider* FindService(ServiceType Type, const std::string& name); template<typename T> inline T* FindDataService(const std::string& name) { return static_cast<T*>(FindService(SERVICE_DATA, name)); } /** Get a map of all loaded modules keyed by their name * @return A ModuleMap containing all loaded modules */ const ModuleMap& GetModules() const { return Modules; } /** Make a service referenceable by dynamic_references * @param name Name that will be used by dynamic_references to find the object * @param service Service to make referenceable by dynamic_references */ void AddReferent(const std::string& name, ServiceProvider* service); /** Make a service no longer referenceable by dynamic_references * @param service Service to make no longer referenceable by dynamic_references */ void DelReferent(ServiceProvider* service); }; /** Do not mess with these functions unless you know the C preprocessor * well enough to explain why they are needed. The order is important. */ #define MODULE_INIT_STR MODULE_INIT_STR_FN_2(MODULE_INIT_SYM) #define MODULE_INIT_STR_FN_2(x) MODULE_INIT_STR_FN_1(x) #define MODULE_INIT_STR_FN_1(x) #x #define MODULE_INIT_SYM MODULE_INIT_SYM_FN_2(INSPIRCD_VERSION_MAJ, INSPIRCD_VERSION_API) #define MODULE_INIT_SYM_FN_2(x,y) MODULE_INIT_SYM_FN_1(x,y) #define MODULE_INIT_SYM_FN_1(x,y) inspircd_module_ ## x ## _ ## y /** This definition is used as shorthand for the various classes * and functions needed to make a module loadable by the OS. * It defines the class factory and external init_module function. */ #define MODULE_INIT(y) \ extern "C" DllExport Module * MODULE_INIT_SYM() \ { \ return new y; \ } \ extern "C" DllExport const char inspircd_src_version[] = INSPIRCD_VERSION; �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/include/modules/���������������������������������������������������������������������0000775�0000000�0000000�00000000000�13554550454�0016436�5����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/include/modules/account.h������������������������������������������������������������0000664�0000000�0000000�00000002572�13554550454�0020251�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * InspIRCd -- Internet Relay Chat Daemon * * Copyright (C) 2008 Craig Edwards <craigedwards@brainbox.cc> * * This file is part of InspIRCd. InspIRCd is free software: you can * redistribute it and/or modify it under the terms of the GNU General Public * License as published by the Free Software Foundation, version 2. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <map> #include <string> #include "event.h" typedef StringExtItem AccountExtItem; inline AccountExtItem* GetAccountExtItem() { return static_cast<AccountExtItem*>(ServerInstance->Extensions.GetItem("accountname")); } class AccountEventListener : public Events::ModuleEventListener { public: AccountEventListener(Module* mod) : ModuleEventListener(mod, "event/account") { } /** Called when a user logs in or logs out * @param user User logging in or out * @param newaccount New account name of the user or empty string if the user * logged out */ virtual void OnAccountChange(User* user, const std::string& newaccount) = 0; }; ��������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/include/modules/away.h���������������������������������������������������������������0000664�0000000�0000000�00000004557�13554550454�0017563�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * InspIRCd -- Internet Relay Chat Daemon * * Copyright (C) 2016-2017 Peter Powell <petpow@saberuk.com> * * This file is part of InspIRCd. InspIRCd is free software: you can * redistribute it and/or modify it under the terms of the GNU General Public * License as published by the Free Software Foundation, version 2. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include "event.h" namespace Away { class EventListener; class EventProvider; } class Away::EventListener : public Events::ModuleEventListener { protected: EventListener(Module* mod) : ModuleEventListener(mod, "event/away") { } public: /** Called when a user wishes to mark themselves as away. * @param user The user who is going away. * @param message The away message that the user set. * @return Either MOD_RES_ALLOW to allow the user to mark themself as away, MOD_RES_DENY to * disallow the user to mark themself as away, or MOD_RES_PASSTHRU to let another module * handle the event. */ virtual ModResult OnUserPreAway(LocalUser* user, std::string& message) { return MOD_RES_PASSTHRU; } /** Called when a user wishes to mark themselves as back. * @param user The user who is going away. * @param message The away message that the user set. * @return Either MOD_RES_ALLOW to allow the user to mark themself as back, MOD_RES_DENY to * disallow the user to mark themself as back, or MOD_RES_PASSTHRU to let another module * handle the event. */ virtual ModResult OnUserPreBack(LocalUser* user) { return MOD_RES_PASSTHRU; } /** Called when a user has marked themself as away. * @param user The user who has gone away. */ virtual void OnUserAway(User* user) = 0; /** Called when a user has returned from being away. * @param user The user who has returned from being away. */ virtual void OnUserBack(User* user) = 0; }; class Away::EventProvider : public Events::ModuleEventProvider { public: EventProvider(Module* mod) : ModuleEventProvider(mod, "event/away") { } }; �������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/include/modules/callerid.h�����������������������������������������������������������0000664�0000000�0000000�00000002636�13554550454�0020375�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * InspIRCd -- Internet Relay Chat Daemon * * Copyright (C) 2018 Peter Powell <petpow@saberuk.com> * * This file is part of InspIRCd. InspIRCd is free software: you can * redistribute it and/or modify it under the terms of the GNU General Public * License as published by the Free Software Foundation, version 2. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once namespace CallerID { class APIBase; class API; } class CallerID::APIBase : public DataProvider { public: APIBase(Module* parent) : DataProvider(parent, "m_callerid_api") { } /** Determines whether \p source is on the accept list of \p target. * @param source The user to search for in the accept list. * @param target The user who's accept list to search in. * @return True if \p source is on \p target's accept list; otherwise, false. */ virtual bool IsOnAcceptList(User* source, User* target) = 0; }; class CallerID::API : public dynamic_reference<CallerID::APIBase> { public: API(Module* parent) : dynamic_reference<CallerID::APIBase>(parent, "m_callerid_api") { } }; ��������������������������������������������������������������������������������������������������inspircd-3.4.0/include/modules/cap.h����������������������������������������������������������������0000664�0000000�0000000�00000024052�13554550454�0017355�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * InspIRCd -- Internet Relay Chat Daemon * * Copyright (C) 2015 Attila Molnar <attilamolnar@hush.com> * * This file is part of InspIRCd. InspIRCd is free software: you can * redistribute it and/or modify it under the terms of the GNU General Public * License as published by the Free Software Foundation, version 2. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include "event.h" namespace Cap { static const unsigned int MAX_CAPS = (sizeof(intptr_t) * 8) - 1; static const intptr_t CAP_302_BIT = (intptr_t)1 << MAX_CAPS; static const unsigned int MAX_VALUE_LENGTH = 100; typedef intptr_t Ext; class ExtItem : public LocalIntExt { public: ExtItem(Module* mod); void FromInternal(Extensible* container, const std::string& value) CXX11_OVERRIDE; std::string ToHuman(const Extensible* container, void* item) const CXX11_OVERRIDE; std::string ToInternal(const Extensible* container, void* item) const CXX11_OVERRIDE; }; class Capability; enum Protocol { /** Supports capability negotiation protocol v3.1, or none */ CAP_LEGACY, /** Supports capability negotiation v3.2 */ CAP_302 }; class EventListener : public Events::ModuleEventListener { public: EventListener(Module* mod) : ModuleEventListener(mod, "event/cap") { } /** Called whenever a new client capability becomes available or unavailable * @param cap Capability being added or removed * @param add If true, the capability is being added, otherwise its being removed */ virtual void OnCapAddDel(Capability* cap, bool add) = 0; /** Called whenever the value of a cap changes. * @param cap Capability whose value changed */ virtual void OnCapValueChange(Capability* cap) { } }; class Manager : public DataProvider { public: Manager(Module* mod) : DataProvider(mod, "capmanager") { } /** Register a client capability. * Modules should call Capability::SetActive(true) instead of this method. * @param cap Capability to register */ virtual void AddCap(Capability* cap) = 0; /** Unregister a client capability. * Modules should call Capability::SetActive(false) instead of this method. * @param cap Capability to unregister */ virtual void DelCap(Capability* cap) = 0; /** Find a capability by name * @param name Capability to find * @return Capability object pointer if found, NULL otherwise */ virtual Capability* Find(const std::string& name) const = 0; /** Notify manager when a value of a cap changed * @param cap Cap whose value changed */ virtual void NotifyValueChange(Capability* cap) = 0; }; /** Represents a client capability. * * Capabilities offer extensions to the client to server protocol. They must be negotiated with clients before they have any effect on the protocol. * Each cap must have a unique name that is used during capability negotiation. * * After construction the cap is ready to be used by clients without any further setup, like other InspIRCd services. * The get() method accepts a user as parameter and can be used to check whether that user has negotiated usage of the cap. This is only known for local users. * * The cap module must be loaded for the capability to work. The IsRegistered() method can be used to query whether the cap is actually online or not. * The capability can be deactivated and reactivated with the SetActive() method. Deactivated caps behave as if they don't exist. * * It is possible to implement special behavior by inheriting from this class and overriding some of its methods. */ class Capability : public ServiceProvider, private dynamic_reference_base::CaptureHook { typedef size_t Bit; /** Bit allocated to this cap, undefined if the cap is unregistered */ Bit bit; /** Extension containing all caps set by a user. NULL if the cap is unregistered. */ ExtItem* extitem; /** True if the cap is active. Only active caps are registered in the manager. */ bool active; /** Reference to the cap manager object */ dynamic_reference<Manager> manager; void OnCapture() CXX11_OVERRIDE { if (active) SetActive(true); } void Unregister() { bit = 0; extitem = NULL; } Ext AddToMask(Ext mask) const { return (mask | GetMask()); } Ext DelFromMask(Ext mask) const { return (mask & (~GetMask())); } Bit GetMask() const { return bit; } friend class ManagerImpl; protected: /** Notify the manager that the value of the capability changed. * Must be called if the value of the cap changes for any reason. */ void NotifyValueChange() { if (IsRegistered()) manager->NotifyValueChange(this); } public: /** Constructor, initializes the capability. * Caps are active by default. * @param mod Module providing the cap * @param Name Raw name of the cap as used in the protocol (CAP LS, etc.) */ Capability(Module* mod, const std::string& Name) : ServiceProvider(mod, Name, SERVICE_CUSTOM) , active(true) , manager(mod, "capmanager") { Unregister(); } ~Capability() { SetActive(false); } void RegisterService() CXX11_OVERRIDE { manager.SetCaptureHook(this); SetActive(true); } /** Check whether a user has the capability turned on. * This method is safe to call if the cap is unregistered and will return false. * @param user User to check * @return True if the user is using this capability, false otherwise */ bool get(User* user) const { if (!IsRegistered()) return false; Ext caps = extitem->get(user); return ((caps & GetMask()) != 0); } /** Turn the capability on/off for a user. If the cap is not registered this method has no effect. * @param user User to turn the cap on/off for * @param val True to turn the cap on, false to turn it off */ void set(User* user, bool val) { if (!IsRegistered()) return; Ext curr = extitem->get(user); extitem->set(user, (val ? AddToMask(curr) : DelFromMask(curr))); } /** Activate or deactivate the capability. * If activating, the cap is marked as active and if the manager is available the cap is registered in the manager. * If deactivating, the cap is marked as inactive and if it is registered, it will be unregistered. * Users who had the cap turned on will have it turned off automatically. * @param activate True to activate the cap, false to deactivate it */ void SetActive(bool activate) { active = activate; if (manager) { if (activate) manager->AddCap(this); else manager->DelCap(this); } } /** Get the name of the capability that's used in the protocol * @return Name of the capability as used in the protocol */ const std::string& GetName() const { return name; } /** Check whether the capability is active. The cap must be active and registered to be used by users. * @return True if the cap is active, false if it has been deactivated */ bool IsActive() const { return active; } /** Check whether the capability is registered * The cap must be active and the manager must be available for a cap to be registered. * @return True if the cap is registered in the manager, false otherwise */ bool IsRegistered() const { return (extitem != NULL); } /** Get the CAP negotiation protocol version of a user. * The cap must be registered for this to return anything other than CAP_LEGACY. * @param user User whose negotiation protocol version to query * @return One of the Capability::Protocol enum indicating the highest supported capability negotiation protocol version */ Protocol GetProtocol(LocalUser* user) const { return ((IsRegistered() && (extitem->get(user) & CAP_302_BIT)) ? CAP_302 : CAP_LEGACY); } /** Called when a user requests to turn this capability on or off. * @param user User requesting to change the state of the cap * @param add True if requesting to turn the cap on, false if requesting to turn it off * @return True to allow the request, false to reject it */ virtual bool OnRequest(LocalUser* user, bool add) { return true; } /** Called when a user requests a list of all capabilities and this capability is about to be included in the list. * The default behavior always includes the cap in the list. * @param user User querying a list capabilities * @return True to add this cap to the list sent to the user, false to not list it */ virtual bool OnList(LocalUser* user) { return true; } /** Query the value of this capability for a user * @param user User who will get the value of the capability * @return Value to show to the user. If NULL, the capability has no value (default). */ virtual const std::string* GetValue(LocalUser* user) const { return NULL; } }; /** Reference to a cap. The cap may be provided by another module. */ class Reference { dynamic_reference_nocheck<Capability> ref; public: /** Constructor, initializes the capability reference * @param mod Module creating this object * @param Name Raw name of the cap as used in the protocol (CAP LS, etc.) */ Reference(Module* mod, const std::string& Name) : ref(mod, "cap/" + Name) { } /** Check whether a user has the referenced capability turned on. * @param user User to check * @return True if the user is using the referenced capability, false otherwise */ bool get(LocalUser* user) { if (ref) return ref->get(user); return false; } }; class MessageBase : public ClientProtocol::Message { public: MessageBase(const std::string& subcmd) : ClientProtocol::Message("CAP", ServerInstance->Config->ServerName) { PushParamPlaceholder(); PushParam(subcmd); } void SetUser(LocalUser* user) { if (user->registered & REG_NICK) ReplaceParamRef(0, user->nick); else ReplaceParam(0, "*"); } }; } ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/include/modules/ctctags.h������������������������������������������������������������0000664�0000000�0000000�00000011277�13554550454�0020247�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * InspIRCd -- Internet Relay Chat Daemon * * Copyright (C) 2019 Peter Powell <petpow@saberuk.com> * * This file is part of InspIRCd. InspIRCd is free software: you can * redistribute it and/or modify it under the terms of the GNU General Public * License as published by the Free Software Foundation, version 2. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include "event.h" namespace CTCTags { class EventListener; class TagMessage; class TagMessageDetails; } class CTCTags::TagMessage : public ClientProtocol::Message { public: TagMessage(User* source, const Channel* targetchan, const ClientProtocol::TagMap& Tags) : ClientProtocol::Message("TAGMSG", source) { PushParamRef(targetchan->name); AddTags(Tags); } TagMessage(User* source, const User* targetuser, const ClientProtocol::TagMap& Tags) : ClientProtocol::Message("TAGMSG", source) { if (targetuser->registered & REG_NICK) PushParamRef(targetuser->nick); else PushParam("*"); AddTags(Tags); } TagMessage(User* source, const char* targetstr, const ClientProtocol::TagMap& Tags) : ClientProtocol::Message("TAGMSG", source) { PushParam(targetstr); AddTags(Tags); } }; class CTCTags::TagMessageDetails { public: /** Whether to echo the tags at all. */ bool echo; /* Whether to send the original tags back to clients with echo-message support. */ bool echo_original; /** The users who are exempted from receiving this message. */ CUList exemptions; /** IRCv3 message tags sent to the server by the user. */ const ClientProtocol::TagMap tags_in; /** IRCv3 message tags sent out to users who get this message. */ ClientProtocol::TagMap tags_out; TagMessageDetails(const ClientProtocol::TagMap& tags) : echo(true) , echo_original(false) , tags_in(tags) { } }; class CTCTags::EventListener : public Events::ModuleEventListener { protected: EventListener(Module* mod, unsigned int eventprio = DefaultPriority) : ModuleEventListener(mod, "event/tagmsg", eventprio) { } public: /** Called before a user sends a tag message to a channel, a user, or a server glob mask. * @param user The user sending the message. * @param target The target of the message. This can either be a channel, a user, or a server * glob mask. * @param details Details about the message such as the message tags or whether to echo. See the * TagMessageDetails class for more information. * @return MOD_RES_ALLOW to explicitly allow the message, MOD_RES_DENY to explicitly deny the * message, or MOD_RES_PASSTHRU to let another module handle the event. */ virtual ModResult OnUserPreTagMessage(User* user, const MessageTarget& target, TagMessageDetails& details) { return MOD_RES_PASSTHRU; } /** Called immediately after a user sends a tag message to a channel, a user, or a server glob mask. * @param user The user sending the message. * @param target The target of the message. This can either be a channel, a user, or a server * glob mask. * @param details Details about the message such as the message tags or whether to echo. See the * TagMessageDetails class for more information. */ virtual void OnUserPostTagMessage(User* user, const MessageTarget& target, const TagMessageDetails& details) { } /** Called immediately before a user sends a tag message to a channel, a user, or a server glob mask. * @param user The user sending the message. * @param target The target of the message. This can either be a channel, a user, or a server * glob mask. * @param details Details about the message such as the message tags or whether to echo. See the * TagMessageDetails class for more information. */ virtual void OnUserTagMessage(User* user, const MessageTarget& target, const TagMessageDetails& details) { } /** Called when a tag message sent by a user to a channel, a user, or a server glob mask is blocked. * @param user The user sending the message. * @param target The target of the message. This can either be a channel, a user, or a server * glob mask. * @param details Details about the message such as the message tags or whether to echo. See the * TagMessageDetails class for more information. */ virtual void OnUserTagMessageBlocked(User* user, const MessageTarget& target, const TagMessageDetails& details) { } }; ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/include/modules/dns.h����������������������������������������������������������������0000664�0000000�0000000�00000011330�13554550454�0017371�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * InspIRCd -- Internet Relay Chat Daemon * * Copyright (C) 2013 Adam <Adam@anope.org> * Copyright (C) 2003-2013 Anope Team <team@anope.org> * * This file is part of InspIRCd. InspIRCd is free software: you can * redistribute it and/or modify it under the terms of the GNU General Public * License as published by the Free Software Foundation, version 2. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once namespace DNS { /** Valid query types */ enum QueryType { /* Nothing */ QUERY_NONE, /* A simple A lookup */ QUERY_A = 1, /* A CNAME lookup */ QUERY_CNAME = 5, /* Reverse DNS lookup */ QUERY_PTR = 12, /* TXT */ QUERY_TXT = 16, /* IPv6 AAAA lookup */ QUERY_AAAA = 28 }; /** Flags that can be AND'd into DNSPacket::flags to receive certain values */ enum { QUERYFLAGS_QR = 0x8000, QUERYFLAGS_OPCODE = 0x7800, QUERYFLAGS_AA = 0x400, QUERYFLAGS_TC = 0x200, QUERYFLAGS_RD = 0x100, QUERYFLAGS_RA = 0x80, QUERYFLAGS_Z = 0x70, QUERYFLAGS_RCODE = 0xF }; enum Error { ERROR_NONE, ERROR_UNKNOWN, ERROR_UNLOADED, ERROR_TIMEDOUT, ERROR_MALFORMED, ERROR_NOT_AN_ANSWER, ERROR_NONSTANDARD_QUERY, ERROR_FORMAT_ERROR, ERROR_SERVER_FAILURE, ERROR_DOMAIN_NOT_FOUND, ERROR_NOT_IMPLEMENTED, ERROR_REFUSED, ERROR_NO_RECORDS, ERROR_INVALIDTYPE }; typedef uint16_t RequestId; const int PORT = 53; class Exception : public ModuleException { public: Exception(const std::string& message) : ModuleException(message) { } }; struct Question { std::string name; QueryType type; Question() : type(QUERY_NONE) { } Question(const std::string& n, QueryType t) : name(n), type(t) { } bool operator==(const Question& other) const { return ((name == other.name) && (type == other.type)); } bool operator!=(const Question& other) const { return (!(*this == other)); } struct hash { size_t operator()(const Question& question) const { return irc::insensitive()(question.name); } }; }; struct ResourceRecord : Question { unsigned int ttl; std::string rdata; time_t created; ResourceRecord(const std::string& n, QueryType t) : Question(n, t), ttl(0), created(ServerInstance->Time()) { } ResourceRecord(const Question& question) : Question(question), ttl(0), created(ServerInstance->Time()) { } }; struct Query { Question question; std::vector<ResourceRecord> answers; Error error; bool cached; Query() : error(ERROR_NONE), cached(false) { } Query(const Question& q) : question(q), error(ERROR_NONE), cached(false) { } const ResourceRecord* FindAnswerOfType(QueryType qtype) const { for (std::vector<DNS::ResourceRecord>::const_iterator i = answers.begin(); i != answers.end(); ++i) { const DNS::ResourceRecord& rr = *i; if (rr.type == qtype) return &rr; } return NULL; } }; class ReplySocket; class Request; /** DNS manager */ class Manager : public DataProvider { public: Manager(Module* mod) : DataProvider(mod, "DNS") { } virtual void Process(Request* req) = 0; virtual void RemoveRequest(Request* req) = 0; virtual std::string GetErrorStr(Error) = 0; virtual std::string GetTypeStr(QueryType) = 0; }; /** A DNS query. */ class Request : public Timer { protected: Manager* const manager; public: Question question; /* Use result cache if available */ bool use_cache; /* Request id */ RequestId id; /* Creator of this request */ Module* const creator; Request(Manager* mgr, Module* mod, const std::string& addr, QueryType qt, bool usecache = true) : Timer(ServerInstance->Config->ConfValue("dns")->getDuration("timeout", 5, 1)) , manager(mgr) , question(addr, qt) , use_cache(usecache) , id(0) , creator(mod) { } virtual ~Request() { manager->RemoveRequest(this); } /** Called when this request succeeds * @param r The query sent back from the nameserver */ virtual void OnLookupComplete(const Query* req) = 0; /** Called when this request fails or times out. * @param r The query sent back from the nameserver, check the error code. */ virtual void OnError(const Query* req) { } /** Used to time out the query, calls OnError and asks the TimerManager * to delete this request */ bool Tick(time_t now) CXX11_OVERRIDE { Query rr(this->question); rr.error = ERROR_TIMEDOUT; this->OnError(&rr); delete this; return false; } }; } // namespace DNS ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/include/modules/exemption.h����������������������������������������������������������0000664�0000000�0000000�00000005133�13554550454�0020621�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * InspIRCd -- Internet Relay Chat Daemon * * Copyright (C) 2016-2017 Peter Powell <petpow@saberuk.com> * * This file is part of InspIRCd. InspIRCd is free software: you can * redistribute it and/or modify it under the terms of the GNU General Public * License as published by the Free Software Foundation, version 2. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include "event.h" namespace CheckExemption { class EventListener; class EventProvider; /** Helper function for calling the CheckExemption::EventListener::OnCheckExemption event. * @param prov The CheckExemption::EventProvider which is calling the event. * @param user The user to check exemption for. * @param chan The channel to check exemption on. * @param restriction The restriction to check for. * @return Either MOD_RES_ALLOW if the exemption was confirmed, MOD_RES_DENY if the exemption was * denied or MOD_RES_PASSTHRU if no module handled the event. */ inline ModResult Call(const CheckExemption::EventProvider& prov, User* user, Channel* chan, const std::string& restriction); } class CheckExemption::EventListener : public Events::ModuleEventListener { protected: EventListener(Module* mod, unsigned int eventprio = DefaultPriority) : ModuleEventListener(mod, "event/exemption", eventprio) { } public: /** Called when checking if a user is exempt from something. * @param user The user to check exemption for. * @param chan The channel to check exemption on. * @param restriction The restriction to check for. * @return Either MOD_RES_ALLOW to confirm an exemption, MOD_RES_DENY to deny an exemption, * or MOD_RES_PASSTHRU to let another module handle the event. */ virtual ModResult OnCheckExemption(User* user, Channel* chan, const std::string& restriction) = 0; }; class CheckExemption::EventProvider : public Events::ModuleEventProvider { public: EventProvider(Module* mod) : ModuleEventProvider(mod, "event/exemption") { } }; inline ModResult CheckExemption::Call(const CheckExemption::EventProvider& prov, User* user, Channel* chan, const std::string& restriction) { ModResult result; FIRST_MOD_RESULT_CUSTOM(prov, CheckExemption::EventListener, OnCheckExemption, result, (user, chan, restriction)); return result; } �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/include/modules/geolocation.h��������������������������������������������������������0000664�0000000�0000000�00000004211�13554550454�0021110�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * InspIRCd -- Internet Relay Chat Daemon * * Copyright (C) 2019 Peter Powell <petpow@saberuk.com> * * This file is part of InspIRCd. InspIRCd is free software: you can * redistribute it and/or modify it under the terms of the GNU General Public * License as published by the Free Software Foundation, version 2. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once namespace Geolocation { class APIBase; class API; class Location; } class Geolocation::APIBase : public DataProvider { public: APIBase(Module* parent) : DataProvider(parent, "geolocationapi") { } /** Looks up the location of the specified user. * @param user The user to look up the location of. * @return Either an instance of the Location class or NULL if no location could be found. */ virtual Location* GetLocation(User* user) = 0; /** Looks up the location of the specified IP address. * @param sa The IP address to look up the location of. * @return Either an instance of the Location class or NULL if no location could be found. */ virtual Location* GetLocation(irc::sockets::sockaddrs& sa) = 0; }; class Geolocation::API : public dynamic_reference<Geolocation::APIBase> { public: API(Module* parent) : dynamic_reference<Geolocation::APIBase>(parent, "geolocationapi") { } }; class Geolocation::Location : public usecountbase { private: /** The two character country code for this location. */ std::string code; /** The country name for this location. */ std::string name; public: Location(const std::string& Code, const std::string& Name) : code(Code) , name(Name) { } /** Retrieves the two character country code for this location. */ std::string GetCode() const { return code; } /** Retrieves the country name for this location. */ std::string GetName() const { return name; } }; ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/include/modules/hash.h���������������������������������������������������������������0000664�0000000�0000000�00000003674�13554550454�0017544�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * InspIRCd -- Internet Relay Chat Daemon * * Copyright (C) 2010 Daniel De Graaf <danieldg@inspircd.org> * * This file is part of InspIRCd. InspIRCd is free software: you can * redistribute it and/or modify it under the terms of the GNU General Public * License as published by the Free Software Foundation, version 2. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include "modules.h" class HashProvider : public DataProvider { public: const unsigned int out_size; const unsigned int block_size; HashProvider(Module* mod, const std::string& Name, unsigned int osiz = 0, unsigned int bsiz = 0) : DataProvider(mod, "hash/" + Name), out_size(osiz), block_size(bsiz) { } virtual std::string GenerateRaw(const std::string& data) = 0; virtual std::string ToPrintable(const std::string& raw) { return BinToHex(raw); } virtual bool Compare(const std::string& input, const std::string& hash) { return InspIRCd::TimingSafeCompare(Generate(input), hash); } std::string Generate(const std::string& data) { return ToPrintable(GenerateRaw(data)); } /** HMAC algorithm, RFC 2104 */ std::string hmac(const std::string& key, const std::string& msg) { std::string hmac1, hmac2; std::string kbuf = key.length() > block_size ? GenerateRaw(key) : key; kbuf.resize(block_size); for (size_t n = 0; n < block_size; n++) { hmac1.push_back(static_cast<char>(kbuf[n] ^ 0x5C)); hmac2.push_back(static_cast<char>(kbuf[n] ^ 0x36)); } hmac2.append(msg); hmac1.append(GenerateRaw(hmac2)); return GenerateRaw(hmac1); } bool IsKDF() const { return (!block_size); } }; ��������������������������������������������������������������������inspircd-3.4.0/include/modules/httpd.h��������������������������������������������������������������0000664�0000000�0000000�00000017573�13554550454�0017747�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * InspIRCd -- Internet Relay Chat Daemon * * Copyright (C) 2009 Daniel De Graaf <danieldg@inspircd.org> * Copyright (C) 2008 Pippijn van Steenhoven <pip88nl@gmail.com> * Copyright (C) 2007 John Brooks <john.brooks@dereferenced.net> * Copyright (C) 2007 Dennis Friis <peavey@inspircd.org> * Copyright (C) 2006 Craig Edwards <craigedwards@brainbox.cc> * * This file is part of InspIRCd. InspIRCd is free software: you can * redistribute it and/or modify it under the terms of the GNU General Public * License as published by the Free Software Foundation, version 2. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include "base.h" #include "event.h" #include <string> #include <sstream> #include <map> class HTTPQueryParameters : public insp::flat_multimap<std::string, std::string> { public: bool get(const std::string& key, std::string& value) const { const_iterator it = find(key); if (it == end()) return false; value = it->second; return true; } std::string getString(const std::string& key, const std::string& def = "") const { std::string value; if (!get(key, value)) return def; return value; } template <typename T> T getNum(const std::string& key, T def = 0) const { std::string value; if (!get(key, value)) return def; return ConvToNum<T>(value); } unsigned long getDuration(const std::string& key, unsigned long def = 0) const { unsigned long value; if (!InspIRCd::Duration(getString(key, "0"), value)) return def; return value; } bool getBool(const std::string& key, bool def = false) const { return getNum<bool>(key, def); } }; struct HTTPRequestURI { std::string path; HTTPQueryParameters query_params; std::string fragment; }; /** A modifyable list of HTTP header fields */ class HTTPHeaders { protected: std::map<std::string,std::string> headers; public: /** Set the value of a header * Sets the value of the named header. If the header is already present, it will be replaced */ void SetHeader(const std::string &name, const std::string &data) { headers[name] = data; } /** Set the value of a header, only if it doesn't exist already * Sets the value of the named header. If the header is already present, it will NOT be updated */ void CreateHeader(const std::string &name, const std::string &data) { if (!IsSet(name)) SetHeader(name, data); } /** Remove the named header */ void RemoveHeader(const std::string &name) { headers.erase(name); } /** Remove all headers */ void Clear() { headers.clear(); } /** Get the value of a header * @return The value of the header, or an empty string */ std::string GetHeader(const std::string &name) { std::map<std::string,std::string>::iterator it = headers.find(name); if (it == headers.end()) return std::string(); return it->second; } /** Check if the given header is specified * @return true if the header is specified */ bool IsSet(const std::string &name) { std::map<std::string,std::string>::iterator it = headers.find(name); return (it != headers.end()); } /** Get all headers, formatted by the HTTP protocol * @return Returns all headers, formatted according to the HTTP protocol. There is no request terminator at the end */ std::string GetFormattedHeaders() { std::string re; for (std::map<std::string,std::string>::iterator i = headers.begin(); i != headers.end(); i++) re += i->first + ": " + i->second + "\r\n"; return re; } }; class HttpServerSocket; /** This class represents a HTTP request. */ class HTTPRequest { protected: std::string type; std::string ipaddr; std::string postdata; HTTPRequestURI parseduri; public: HTTPHeaders *headers; int errorcode; /** A socket pointer, which you must return in your HTTPDocument class * if you reply to this request. */ HttpServerSocket* sock; /** Initialize HTTPRequest. * This constructor is called by m_httpd.so to initialize the class. * @param request_type The request type, e.g. GET, POST, HEAD * @param hdr The headers sent with the request * @param opaque An opaque pointer used internally by m_httpd, which you must pass back to the module in your reply. * @param ip The IP address making the web request. * @param pdata The post data (content after headers) received with the request, up to Content-Length in size */ HTTPRequest(const std::string& request_type, const HTTPRequestURI& Parseduri, HTTPHeaders* hdr, HttpServerSocket* socket, const std::string &ip, const std::string &pdata) : type(request_type) , ipaddr(ip) , postdata(pdata) , parseduri(Parseduri) , headers(hdr) , sock(socket) { } /** Get the post data (request content). * All post data will be returned, including carriage returns and linefeeds. * @return The postdata */ std::string& GetPostData() { return postdata; } /** Get the request type. * Any request type can be intercepted, even ones which are invalid in the HTTP/1.1 spec. * @return The request type, e.g. GET, POST, HEAD */ std::string& GetType() { return type; } HTTPRequestURI& GetParsedURI() { return parseduri; } std::string& GetPath() { return GetParsedURI().path; } /** Get IP address of requester. * The requesting system's ip address will be returned. * @return The IP address as a string */ std::string& GetIP() { return ipaddr; } }; /** If you want to reply to HTTP requests, you must return a HTTPDocumentResponse to * the httpd module via the HTTPdAPI. * When you initialize this class you initialize it with all components required to * form a valid HTTP response: the document data and a response code. * You can add additional HTTP headers, if you want. */ class HTTPDocumentResponse { public: /** Module that generated this reply */ Module* const module; std::stringstream* document; unsigned int responsecode; /** Any extra headers to include with the defaults */ HTTPHeaders headers; HTTPRequest& src; /** Initialize a HTTPDocumentResponse ready for sending to the httpd module. * @param mod A pointer to the module who responded to the request * @param req The request you obtained from the HTTPRequest at an earlier time * @param doc A stringstream containing the document body * @param response A valid HTTP/1.0 or HTTP/1.1 response code. The response text will be determined for you * based upon the response code. */ HTTPDocumentResponse(Module* mod, HTTPRequest& req, std::stringstream* doc, unsigned int response) : module(mod), document(doc), responsecode(response), src(req) { } }; class HTTPdAPIBase : public DataProvider { public: HTTPdAPIBase(Module* parent) : DataProvider(parent, "m_httpd_api") { } /** Answer an incoming HTTP request with the provided document * @param response The response created by your module that will be sent to the client */ virtual void SendResponse(HTTPDocumentResponse& response) = 0; }; /** The API provided by the httpd module that allows other modules to respond to incoming * HTTP requests */ class HTTPdAPI : public dynamic_reference<HTTPdAPIBase> { public: HTTPdAPI(Module* parent) : dynamic_reference<HTTPdAPIBase>(parent, "m_httpd_api") { } }; class HTTPACLEventListener : public Events::ModuleEventListener { public: HTTPACLEventListener(Module* mod) : ModuleEventListener(mod, "event/http-acl") { } virtual ModResult OnHTTPACLCheck(HTTPRequest& req) = 0; }; class HTTPRequestEventListener : public Events::ModuleEventListener { public: HTTPRequestEventListener(Module* mod) : ModuleEventListener(mod, "event/http-request") { } virtual ModResult OnHTTPRequest(HTTPRequest& req) = 0; }; �������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/include/modules/invite.h�������������������������������������������������������������0000664�0000000�0000000�00000010170�13554550454�0020104�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * InspIRCd -- Internet Relay Chat Daemon * * Copyright (C) 2012, 2015 Attila Molnar <attilamolnar@hush.com> * * This file is part of InspIRCd. InspIRCd is free software: you can * redistribute it and/or modify it under the terms of the GNU General Public * License as published by the Free Software Foundation, version 2. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once namespace Invite { class APIBase; class API; class Invite; typedef insp::intrusive_list<Invite, LocalUser> List; } class Invite::APIBase : public DataProvider { public: APIBase(Module* parent); /** Create or extend an Invite. * When a user is invited to join a channel either a new Invite object is created or * or the expiration timestamp is updated if there is already a pending Invite for * the given (user, channel) pair and the new expiration time is further than the current. * @param user Target user * @param chan Target channel * @param timeout Timestamp when the invite should expire, 0 for no expiration */ virtual void Create(LocalUser* user, Channel* chan, time_t timeout) = 0; /** Retrieves the Invite object for the given (user, channel) pair * @param user Target user * @param chan Target channel * @return Invite object for the given (channel, user) pair if it exists, NULL otherwise */ virtual Invite* Find(LocalUser* user, Channel* chan) = 0; /** Returns the list of channels a user has been invited to but has not yet joined. * @param user User whose invite list to retrieve * @return List of channels the user is invited to or NULL if the list is empty */ virtual const List* GetList(LocalUser* user) = 0; /** Check if a user is invited to a channel * @param user User to check * @param chan Channel to check * @return True if the user is invited to the channel, false otherwise */ bool IsInvited(LocalUser* user, Channel* chan) { return (Find(user, chan) != NULL); } /** Removes an Invite if it exists * @param user User whose invite to remove * @param chan Channel to remove the invite to * @return True if the user was invited to the channel and the invite was removed, false if the user wasn't invited */ virtual bool Remove(LocalUser* user, Channel* chan) = 0; }; class Invite::API : public dynamic_reference<APIBase> { public: API(Module* parent) : dynamic_reference<APIBase>(parent, "core_channel_invite") { } }; /** * The Invite class contains all data about a pending invite. * Invite objects are referenced from the user and the channel they belong to. */ class Invite::Invite : public insp::intrusive_list_node<Invite, LocalUser>, public insp::intrusive_list_node<Invite, Channel> { public: /** User the invite is for */ LocalUser* const user; /** Channel where the user is invited to */ Channel* const chan; /** Check whether the invite will expire or not * @return True if the invite is timed, false if it doesn't expire */ bool IsTimed() const { return (expiretimer != NULL); } /** Serialize this object * @param human Whether to serialize for human consumption or not. * @param show_chans True to include channel in the output, false to include the nick/uuid * @param out Output will be appended to this string */ void Serialize(bool human, bool show_chans, std::string& out); friend class APIImpl; private: /** Timer handling expiration. If NULL this invite doesn't expire. */ Timer* expiretimer; /** Constructor, only available to the module providing the invite API (core_channel). * To create Invites use InviteAPI::Create(). * @param user User being invited * @param chan Channel the user is invited to */ Invite(LocalUser* user, Channel* chan); /** Destructor, only available to the module providing the invite API (core_channel). * To remove Invites use InviteAPI::Remove(). */ ~Invite(); }; ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/include/modules/ircv3.h��������������������������������������������������������������0000664�0000000�0000000�00000006242�13554550454�0017641�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * InspIRCd -- Internet Relay Chat Daemon * * Copyright (C) 2015 Attila Molnar <attilamolnar@hush.com> * * This file is part of InspIRCd. InspIRCd is free software: you can * redistribute it and/or modify it under the terms of the GNU General Public * License as published by the Free Software Foundation, version 2. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include "modules/cap.h" namespace IRCv3 { class WriteNeighborsWithCap; template <typename T> class CapTag; } class IRCv3::WriteNeighborsWithCap : public User::ForEachNeighborHandler { const Cap::Capability& cap; ClientProtocol::Event& protoev; void Execute(LocalUser* user) CXX11_OVERRIDE { if (cap.get(user)) user->Send(protoev); } public: WriteNeighborsWithCap(User* user, ClientProtocol::Event& ev, const Cap::Capability& capability, bool include_self = false) : cap(capability) , protoev(ev) { user->ForEachNeighbor(*this, include_self); } }; /** Base class for simple message tags. * Message tags provided by classes derived from this class will be sent to clients that have negotiated * a client capability, also managed by this class. * * Derived classes specify the name of the capability and the message tag and provide a public GetValue() * method with the following signature: const std::string* GetValue(ClientProtocol::Message& msg). * The returned value determines whether to attach the tag to the message. If it is NULL, the tag won't * be attached. If it is non-NULL the tag will be attached with the value in the string. If the string is * empty the tag is attached without a value. * * Providers inheriting from this class don't accept incoming tags by default. * * For more control, inherit from ClientProtocol::MessageTagProvider directly. * * Template parameter T is the derived class. */ template <typename T> class IRCv3::CapTag : public ClientProtocol::MessageTagProvider { protected: Cap::Capability cap; const std::string tagname; bool ShouldSendTag(LocalUser* user, const ClientProtocol::MessageTagData& tagdata) CXX11_OVERRIDE { return cap.get(user); } void OnPopulateTags(ClientProtocol::Message& msg) CXX11_OVERRIDE { T& tag = static_cast<T&>(*this); const std::string* const val = tag.GetValue(msg); if (val) msg.AddTag(tagname, this, *val); } public: /** Constructor. * @param mod Module that owns the tag. * @param capname Name of the client capability. * A client capability with this name will be created. It will be available to all clients and it won't * have a value. * See Cap::Capability for more info on client capabilities. * @param Tagname Name of the message tag, to use in the protocol. */ CapTag(Module* mod, const std::string& capname, const std::string& Tagname) : ClientProtocol::MessageTagProvider(mod) , cap(mod, capname) , tagname(Tagname) { } }; ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/include/modules/ircv3_batch.h��������������������������������������������������������0000664�0000000�0000000�00000013775�13554550454�0021013�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * InspIRCd -- Internet Relay Chat Daemon * * Copyright (C) 2016 Attila Molnar <attilamolnar@hush.com> * * This file is part of InspIRCd. InspIRCd is free software: you can * redistribute it and/or modify it under the terms of the GNU General Public * License as published by the Free Software Foundation, version 2. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once // For CapReference #include "modules/cap.h" namespace IRCv3 { namespace Batch { typedef uint64_t RefTag; class Manager; class ManagerImpl; class Batch; struct BatchInfo; class API; class CapReference; static const unsigned int MAX_BATCHES = (sizeof(intptr_t) * 8) - 1; } } /** Batch Manager. * Implements batch starting and stopping. When it becomes unavailable (due to e.g. module unload) * all running batches are stopped. */ class IRCv3::Batch::Manager : public DataProvider, public ClientProtocol::MessageTagProvider { public: /** Constructor. * @param mod Module that owns the Manager. */ Manager(Module* mod) : DataProvider(mod, "batchapi") , ClientProtocol::MessageTagProvider(mod) { } /** Start a batch. * Check Batch::IsRunning() to learn if the batch has been started. * @param batch Batch to start. */ virtual void Start(Batch& batch) = 0; /** End a batch. * @param batch Batch to end. */ virtual void End(Batch& batch) = 0; }; /** Represents a batch. * Batches are used to group together physically separate client protocol messages that logically belong * together for one reason or another. The type of a batch, if provided, indicates what kind of grouping * it does. * * Batch objects have two states: running and stopped. If a batch is running, messages can be added to it. * If a message has been added to a batch and that message is sent to a client that negotiated the batch * capability then the client will receive a message tag attached to the message indicating the batch that * the message is a part of. If a message M is part of a batch B and M is sent to a client that hasn't yet * received any message from batch B it will get a batch start message for B before M. When a batch B is * stopped, every client that received at least one message which was in batch B will receive an end of * batch message for B. * A message may only be part of a single batch at any given time. */ class IRCv3::Batch::Batch { Manager* manager; const std::string type; RefTag reftag; std::string reftagstr; unsigned int bit; BatchInfo* batchinfo; ClientProtocol::Message* batchstartmsg; ClientProtocol::Message* batchendmsg; void Setup(unsigned int b) { bit = b; reftag = (1 << bit); reftagstr = ConvToStr(reftag); } unsigned int GetId() const { return bit; } intptr_t GetBit() const { return reftag; } public: /** Constructor. * The batch is initially stopped. To start it, pass it to Manager::Start(). * @param Type Batch type string, used to indicate what kind of grouping the batch does. May be empty. */ Batch(const std::string& Type) : manager(NULL) , type(Type) , batchinfo(NULL) , batchstartmsg(NULL) { } /** Destructor. * If the batch is running, it is ended. */ ~Batch() { if (manager) manager->End(*this); } /** Add a message to the batch. * If the batch isn't running then this method does nothing. * @param msg Message to add to the batch. If it is already part of any batch, this method is a no-op. */ void AddToBatch(ClientProtocol::Message& msg) { if (manager) msg.AddTag("batch", manager, reftagstr, this); } /** Get batch reference tag which is an opaque id for the batch and is used in the client protocol. * Only running batches have a reference tag assigned. * @return Reference tag as a string, only valid if the batch is running. */ const std::string& GetRefTagStr() const { return reftagstr; } /** Get batch type. * @return Batch type string. */ const std::string& GetType() const { return type; } /** Check whether the batch is running. * Batches can be started with Manager::Start() and stopped with Manager::End(). * @return True if the batch is running, false otherwise. */ bool IsRunning() const { return (manager != NULL); } /** Get the batch start client protocol message. * The returned message object can be manipulated to add extra parameters or labels to the message. The first * parameter of the message is the batch reference tag generated by the module providing batch support. * If the batch type string was specified, it will be the second parameter of the message. * May only be called if IsRunning() == true. * @return Mutable batch start client protocol message. */ ClientProtocol::Message& GetBatchStartMessage() { return *batchstartmsg; } /** Get the batch end client protocol message. * The returned message object can be manipulated to add extra parameters or labels to the message. The first * parameter of the message is the batch reference tag generated by the module providing batch support. * If the batch type string was specified, it will be the second parameter of the message. * May only be called if IsRunning() == true. * @return Mutable batch end client protocol message. */ ClientProtocol::Message& GetBatchEndMessage() { return *batchendmsg; } friend class ManagerImpl; }; /** Batch API. Use this to access the Manager. */ class IRCv3::Batch::API : public dynamic_reference_nocheck<Manager> { public: API(Module* mod) : dynamic_reference_nocheck<Manager>(mod, "batchapi") { } }; /** Reference to the batch cap. * Can be used to check whether a user has the batch client cap enabled. */ class IRCv3::Batch::CapReference : public Cap::Reference { public: CapReference(Module* mod) : Cap::Reference(mod, "batch") { } }; ���inspircd-3.4.0/include/modules/ircv3_replies.h������������������������������������������������������0000664�0000000�0000000�00000007075�13554550454�0021371�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * InspIRCd -- Internet Relay Chat Daemon * * Copyright (C) 2019 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/>. */ // IMPORTANT: The contents of this file are experimental and are not presently // covered by the InspIRCd API stability guarantee. #pragma once #include "modules/cap.h" namespace IRCv3 { namespace Replies { class Reply; class Fail; class Note; class Warn; } } /** Base class for standard replies. */ class IRCv3::Replies::Reply { private: /** The name of the command for this reply. */ std::string cmd; /** The event provider for this reply. */ ClientProtocol::EventProvider evprov; protected: /** Initializes a new instance of the Reply class. * @param Creator The module which created this instance. * @param Cmd The name of the command to reply with. */ Reply(Module* Creator, const std::string& Cmd) : cmd(Cmd) , evprov(Creator, Cmd) { } public: /** * Sends a standard reply to the specified user. * @param user The user to send the reply to. * @param command The command that the reply relates to. * @param code A machine readable code for this reply. * @param description A human readable description of this reply. */ void Send(LocalUser* user, Command* command, const std::string& code, const std::string& description) { ClientProtocol::Message msg(cmd.c_str(), ServerInstance->Config->ServerName); msg.PushParamRef(command->name); msg.PushParam(code); msg.PushParam(description); ClientProtocol::Event ev(evprov, msg); user->Send(ev); } /** * Sends a standard reply to the specified user if they have the specified cap * or a notice if they do not.s * @param user The user to send the reply to. * @param command The command that the reply relates to. * @param code A machine readable code for this reply. * @param description A human readable description of this reply. */ void SendIfCap(LocalUser* user, const Cap::Capability& cap, Command* command, const std::string& code, const std::string& description) { if (cap.get(user)) Send(user, command, code, description); else user->WriteNotice(InspIRCd::Format("*** %s: %s", command->name.c_str(), description.c_str())); } }; /** Sends a FAIL standard reply. */ class IRCv3::Replies::Fail : public IRCv3::Replies::Reply { public: /** Initializes a new instance of the Fail class. * @param Creator The module which created this instance. */ Fail(Module* Creator) : Reply(Creator, "FAIL") { } }; /** Sends a NOTE standard reply. */ class IRCv3::Replies::Note : public IRCv3::Replies::Reply { public: /** Initializes a new instance of the Note class. * @param Creator The module which created this instance. */ Note(Module* Creator) : Reply(Creator, "NOTE") { } }; /** Sends a WARN standard reply. */ class IRCv3::Replies::Warn : public IRCv3::Replies::Reply { public: /** Initializes a new instance of the Warn class. * @param Creator The module which created this instance. */ Warn(Module* Creator) : Reply(Creator, "WARN") { } }; �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/include/modules/ircv3_servertime.h���������������������������������������������������0000664�0000000�0000000�00000005331�13554550454�0022104�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * InspIRCd -- Internet Relay Chat Daemon * * Copyright (C) 2016 Attila Molnar <attilamolnar@hush.com> * * This file is part of InspIRCd. InspIRCd is free software: you can * redistribute it and/or modify it under the terms of the GNU General Public * License as published by the Free Software Foundation, version 2. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once namespace IRCv3 { namespace ServerTime { class Manager; class API; /** Format a unix timestamp into the format used by server-time. * @param secs UNIX timestamp to format. * @params millisecs Number of milliseconds to format. * @return Time in server-time format, as a string. */ inline std::string FormatTime(time_t secs, long millisecs = 0) { std::string timestr = InspIRCd::TimeString(secs, "%Y-%m-%dT%H:%M:%S.Z", true); timestr.insert(20, InspIRCd::Format("%03ld", millisecs)); return timestr; } } } /** Implements manipulating the server time on messages. * A timestamp can be attached to outgoing client protocol messages to indicate the time when the message * was generated by us. If a message has server time attached then recipient clients who have negotiated * the appropriate protocol extension will receive it. */ class IRCv3::ServerTime::Manager : public DataProvider { protected: ClientProtocol::MessageTagProvider* tagprov; public: /** Constructor. * @param mod Module that owns the Manager. */ Manager(Module* mod) : DataProvider(mod, "servertimeapi") { } /** Set the server time on a message. * @param msg Message to set the time on. No-op if the message already has server time set. * @param t Unix timestamp to set. */ void Set(ClientProtocol::Message& msg, time_t t) { Set(msg, FormatTime(t)); } /** Set the server time on a message. * @param msg Message to set the time on. No-op if the message already has server time set. * @param timestr Timestamp to set. Must be in server time format. * The FormatTime() function can be used to convert unix timestamps into the required format. */ void Set(ClientProtocol::Message& msg, const std::string& timestr) { msg.AddTag("time", tagprov, timestr); } }; /** Server time API. Use this to access the Manager. */ class IRCv3::ServerTime::API : public dynamic_reference_nocheck<Manager> { public: API(Module* mod) : dynamic_reference_nocheck<Manager>(mod, "servertimeapi") { } }; �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/include/modules/ldap.h���������������������������������������������������������������0000664�0000000�0000000�00000011367�13554550454�0017537�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * InspIRCd -- Internet Relay Chat Daemon * * Copyright (C) 2015 Adam <Adam@anope.org> * Copyright (C) 2003-2015 Anope Team <team@anope.org> * * This file is part of InspIRCd. InspIRCd is free software: you can * redistribute it and/or modify it under the terms of the GNU General Public * License as published by the Free Software Foundation, version 2. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once typedef int LDAPQuery; class LDAPException : public ModuleException { public: LDAPException(const std::string& reason) : ModuleException(reason) { } virtual ~LDAPException() throw() { } }; struct LDAPModification { enum LDAPOperation { LDAP_ADD, LDAP_DEL, LDAP_REPLACE }; LDAPOperation op; std::string name; std::vector<std::string> values; }; typedef std::vector<LDAPModification> LDAPMods; struct LDAPAttributes : public std::map<std::string, std::vector<std::string> > { size_t size(const std::string& attr) const { const std::vector<std::string>& array = this->getArray(attr); return array.size(); } const std::vector<std::string> keys() const { std::vector<std::string> k; for (const_iterator it = this->begin(), it_end = this->end(); it != it_end; ++it) k.push_back(it->first); return k; } const std::string& get(const std::string& attr) const { const std::vector<std::string>& array = this->getArray(attr); if (array.empty()) throw LDAPException("Empty attribute " + attr + " in LDAPResult::get"); return array[0]; } const std::vector<std::string>& getArray(const std::string& attr) const { const_iterator it = this->find(attr); if (it == this->end()) throw LDAPException("Unknown attribute " + attr + " in LDAPResult::getArray"); return it->second; } }; enum QueryType { QUERY_UNKNOWN, QUERY_BIND, QUERY_SEARCH, QUERY_ADD, QUERY_DELETE, QUERY_MODIFY, QUERY_COMPARE }; struct LDAPResult { std::vector<LDAPAttributes> messages; std::string error; QueryType type; LDAPQuery id; LDAPResult() : type(QUERY_UNKNOWN), id(-1) { } size_t size() const { return this->messages.size(); } bool empty() const { return this->messages.empty(); } const LDAPAttributes& get(size_t sz) const { if (sz >= this->messages.size()) throw LDAPException("Index out of range"); return this->messages[sz]; } const std::string& getError() const { return this->error; } }; class LDAPInterface { public: ModuleRef creator; LDAPInterface(Module* m) : creator(m) { } virtual ~LDAPInterface() { } virtual void OnResult(const LDAPResult& r) = 0; virtual void OnError(const LDAPResult& err) = 0; }; class LDAPProvider : public DataProvider { public: LDAPProvider(Module* Creator, const std::string& Name) : DataProvider(Creator, Name) { } /** Attempt to bind to the LDAP server as a manager * @param i The LDAPInterface the result is sent to */ virtual void BindAsManager(LDAPInterface* i) = 0; /** Bind to LDAP * @param i The LDAPInterface the result is sent to * @param who The binddn * @param pass The password */ virtual void Bind(LDAPInterface* i, const std::string& who, const std::string& pass) = 0; /** Search ldap for the specified filter * @param i The LDAPInterface the result is sent to * @param base The base DN to search * @param filter The filter to apply */ virtual void Search(LDAPInterface* i, const std::string& base, const std::string& filter) = 0; /** Add an entry to LDAP * @param i The LDAPInterface the result is sent to * @param dn The dn of the entry to add * @param attributes The attributes */ virtual void Add(LDAPInterface* i, const std::string& dn, LDAPMods& attributes) = 0; /** Delete an entry from LDAP * @param i The LDAPInterface the result is sent to * @param dn The dn of the entry to delete */ virtual void Del(LDAPInterface* i, const std::string& dn) = 0; /** Modify an existing entry in LDAP * @param i The LDAPInterface the result is sent to * @param base The base DN to modify * @param attributes The attributes to modify */ virtual void Modify(LDAPInterface* i, const std::string& base, LDAPMods& attributes) = 0; /** Compare an attribute in LDAP with our value * @param i The LDAPInterface the result is sent to * @param dn DN to use for comparing * @param attr Attr of DN to compare with * @param val value to compare attr of dn */ virtual void Compare(LDAPInterface* i, const std::string& dn, const std::string& attr, const std::string& val) = 0; }; �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/include/modules/names.h��������������������������������������������������������������0000664�0000000�0000000�00000003017�13554550454�0017713�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * InspIRCd -- Internet Relay Chat Daemon * * Copyright (C) 2019 Peter Powell <petpow@saberuk.com> * * This file is part of InspIRCd. InspIRCd is free software: you can * redistribute it and/or modify it under the terms of the GNU General Public * License as published by the Free Software Foundation, version 2. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include "event.h" namespace Names { class EventListener; } class Names::EventListener : public Events::ModuleEventListener { public: EventListener(Module* mod) : ModuleEventListener(mod, "event/names") { } /* Called for every item in a NAMES list. * @param issuer The user who initiated the NAMES request. * @param memb The channel membership of the user who is being considered for inclusion. * @param prefixes The prefix character(s) to show in front of the user's nickname. * @param nick The nickname of the user to show. * @return Return MOD_RES_PASSTHRU to allow the member to be displayed, MOD_RES_DENY to cause them to be * excluded from this NAMES list */ virtual ModResult OnNamesListItem(LocalUser* issuer, Membership* memb, std::string& prefixes, std::string& nick) = 0; }; �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/include/modules/regex.h��������������������������������������������������������������0000664�0000000�0000000�00000003422�13554550454�0017722�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * InspIRCd -- Internet Relay Chat Daemon * * Copyright (C) 2009 Daniel De Graaf <danieldg@inspircd.org> * Copyright (C) 2008 Thomas Stagner <aquanight@inspircd.org> * * This file is part of InspIRCd. InspIRCd is free software: you can * redistribute it and/or modify it under the terms of the GNU General Public * License as published by the Free Software Foundation, version 2. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include "inspircd.h" class Regex : public classbase { protected: /** The uncompiled regex string. */ std::string regex_string; // Constructor may as well be protected, as this class is abstract. Regex(const std::string& rx) : regex_string(rx) { } public: virtual ~Regex() { } virtual bool Matches(const std::string& text) = 0; const std::string& GetRegexString() const { return regex_string; } }; class RegexFactory : public DataProvider { public: RegexFactory(Module* Creator, const std::string& Name) : DataProvider(Creator, Name) { } virtual Regex* Create(const std::string& expr) = 0; }; class RegexException : public ModuleException { public: RegexException(const std::string& regex, const std::string& error) : ModuleException("Error in regex '" + regex + "': " + error) { } RegexException(const std::string& regex, const std::string& error, int offset) : ModuleException("Error in regex '" + regex + "' at offset " + ConvToStr(offset) + ": " + error) { } }; ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/include/modules/reload.h�������������������������������������������������������������0000664�0000000�0000000�00000004750�13554550454�0020063�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * InspIRCd -- Internet Relay Chat Daemon * * Copyright (C) 2015 Attila Molnar <attilamolnar@hush.com> * * This file is part of InspIRCd. InspIRCd is free software: you can * redistribute it and/or modify it under the terms of the GNU General Public * License as published by the Free Software Foundation, version 2. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include "event.h" namespace ReloadModule { class EventListener; class DataKeeper; /** Container for data saved by modules before another module is reloaded. */ class CustomData { struct Data { EventListener* handler; void* data; Data(EventListener* Handler, void* moddata) : handler(Handler), data(moddata) { } }; typedef std::vector<Data> List; List list; public: /** Add data to the saved state of a module. * The provided handler's OnReloadModuleRestore() method will be called when the reload is done with the pointer * provided. * @param handler Handler for restoring the data * @param data Pointer to the data, will be passed back to the provided handler's OnReloadModuleRestore() after the * reload finishes */ void add(EventListener* handler, void* data) { list.push_back(Data(handler, data)); } friend class DataKeeper; }; class EventListener : public Events::ModuleEventListener { public: EventListener(Module* mod) : ModuleEventListener(mod, "event/reloadmodule") { } /** Called whenever a module is about to be reloaded. Use this event to save data related to the module that you want * to be restored after the reload. * @param mod Module to be reloaded * @param cd CustomData instance that can store your data once. */ virtual void OnReloadModuleSave(Module* mod, CustomData& cd) = 0; /** Restore data after a reload. Only called if data was added in OnReloadModuleSave(). * @param mod Reloaded module, if NULL the reload failed and the module no longer exists * @param data Pointer that was passed to CustomData::add() in OnReloadModuleSave() at the time when the module's state * was saved */ virtual void OnReloadModuleRestore(Module* mod, void* data) = 0; }; } ������������������������inspircd-3.4.0/include/modules/sasl.h���������������������������������������������������������������0000664�0000000�0000000�00000001733�13554550454�0017555�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * InspIRCd -- Internet Relay Chat Daemon * * Copyright (C) 2010 Daniel De Graaf <danieldg@inspircd.org> * * This file is part of InspIRCd. InspIRCd is free software: you can * redistribute it and/or modify it under the terms of the GNU General Public * License as published by the Free Software Foundation, version 2. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include "event.h" class SASLEventListener : public Events::ModuleEventListener { public: SASLEventListener(Module* mod) : ModuleEventListener(mod, "event/sasl") { } virtual void OnSASLAuth(const CommandBase::Params& params) = 0; }; �������������������������������������inspircd-3.4.0/include/modules/server.h�������������������������������������������������������������0000664�0000000�0000000�00000011430�13554550454�0020114�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * InspIRCd -- Internet Relay Chat Daemon * * Copyright (C) 2009 Daniel De Graaf <danieldg@inspircd.org> * * This file is part of InspIRCd. InspIRCd is free software: you can * redistribute it and/or modify it under the terms of the GNU General Public * License as published by the Free Software Foundation, version 2. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #ifdef __GNUC__ # pragma GCC diagnostic push # pragma GCC diagnostic ignored "-Wdeprecated-declarations" #endif #include "event.h" namespace ServerProtocol { class BroadcastEventListener; class LinkEventListener; class MessageEventListener; class SyncEventListener; } class ServerProtocol::BroadcastEventListener : public Events::ModuleEventListener { public: BroadcastEventListener(Module* mod) : ModuleEventListener(mod, "event/server-broadcast") { } /** Fired when a channel message is being broadcast across the network. * @param channel The channel which is having a message sent to it. * @param server The server which might have a message broadcast to it. * @return Either MOD_RES_ALLOW to always send the message to the server, MOD_RES_DENY to never * send the message to the server or MOD_RES_PASSTHRU if no module handled the event. */ virtual ModResult OnBroadcastMessage(Channel* channel, const Server* server) { return MOD_RES_PASSTHRU; } }; class ServerProtocol::LinkEventListener : public Events::ModuleEventListener { public: LinkEventListener(Module* mod) : ModuleEventListener(mod, "event/server-link") { } /** Fired when a server has linked to the network. * @param server Server that recently linked. */ virtual void OnServerLink(const Server* server) { } /** Fired when a server has finished bursting. * @param server Server that recently finished bursting. */ virtual void OnServerBurst(const Server* server) { } /** Fired when a server splits * @param server Server that split * @param error Whether the server split because of an error. */ virtual void OnServerSplit(const Server* server, bool error) { OnServerSplit(server); } /** Fired when a server splits * @param server Server that split */ DEPRECATED_METHOD(virtual void OnServerSplit(const Server* server)) { } }; class ServerProtocol::MessageEventListener : public Events::ModuleEventListener { public: MessageEventListener(Module* mod) : ModuleEventListener(mod, "event/server-message") { } /** Fired when a server message is being sent by a user. * @param source The user who sent the message. * @param name The name of the command which was sent. * @param tags The tags which will be sent with the message. */ virtual void OnBuildMessage(User* source, const char* name, ClientProtocol::TagMap& tags) { } /** Fired when a server message is being sent by a server. * @param source The server who sent the message. * @param name The name of the command which was sent. * @param tags The tags which will be sent with the message. */ virtual void OnBuildMessage(Server* source, const char* name, ClientProtocol::TagMap& tags) { } }; class ServerProtocol::SyncEventListener : public Events::ModuleEventListener { public: SyncEventListener(Module* mod) : ModuleEventListener(mod, "event/server-sync") { } /** Allows modules to synchronize user metadata during a netburst. This will * be called for every user visible on your side of the burst. * @param user The user being synchronized. * @param server The target of the burst. */ virtual void OnSyncUser(User* user, ProtocolServer& server) { } /** Allows modules to synchronize channel metadata during a netburst. This will * be called for every channel visible on your side of the burst. * @param chan The channel being synchronized. * @param server The target of the burst. */ virtual void OnSyncChannel(Channel* chan, ProtocolServer& server) { } /** Allows modules to synchronize network metadata during a netburst. * @param server The target of the burst. */ virtual void OnSyncNetwork(ProtocolServer& server) { } }; /** Compatibility struct for <3.3.0 modules. */ class ServerEventListener : public ServerProtocol::BroadcastEventListener , public ServerProtocol::LinkEventListener , public ServerProtocol::SyncEventListener { public: ServerEventListener(Module* mod) : ServerProtocol::BroadcastEventListener(mod) , ServerProtocol::LinkEventListener(mod) , ServerProtocol::SyncEventListener(mod) { } }; #ifdef __GNUC__ # pragma GCC diagnostic pop #endif ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/include/modules/shun.h���������������������������������������������������������������0000664�0000000�0000000�00000003502�13554550454�0017564�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * InspIRCd -- Internet Relay Chat Daemon * * Copyright (C) 2017 Dylan Frank <b00mx0r@aureus.pw> * * This file is part of InspIRCd. InspIRCd is free software: you can * redistribute it and/or modify it under the terms of the GNU General Public * License as published by the Free Software Foundation, version 2. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include "xline.h" /** Shun class */ class Shun : public XLine { public: /** Create a Shun. * @param s_time The set time * @param d The duration of the xline * @param src The sender of the xline * @param re The reason of the xline * @param shunmask Mask to match */ Shun(time_t s_time, unsigned long d, const std::string& src, const std::string& re, const std::string& shunmask) : XLine(s_time, d, src, re, "SHUN") , matchtext(shunmask) { } bool Matches(User* u) CXX11_OVERRIDE { LocalUser* lu = IS_LOCAL(u); if (lu && lu->exempt) return false; if (InspIRCd::Match(u->GetFullHost(), matchtext) || InspIRCd::Match(u->GetFullRealHost(), matchtext) || InspIRCd::Match(u->nick+"!"+u->ident+"@"+u->GetIPString(), matchtext)) return true; if (InspIRCd::MatchCIDR(u->GetIPString(), matchtext, ascii_case_insensitive_map)) return true; return false; } bool Matches(const std::string& str) CXX11_OVERRIDE { return (matchtext == str); } const std::string& Displayable() CXX11_OVERRIDE { return matchtext; } private: /** Matching mask **/ std::string matchtext; }; ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/include/modules/sql.h����������������������������������������������������������������0000664�0000000�0000000�00000015466�13554550454�0017422�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * InspIRCd -- Internet Relay Chat Daemon * * Copyright (C) 2017 Peter Powell <petpow@saberuk.com> * Copyright (C) 2010 Daniel De Graaf <danieldg@inspircd.org> * * This file is part of InspIRCd. InspIRCd is free software: you can * redistribute it and/or modify it under the terms of the GNU General Public * License as published by the Free Software Foundation, version 2. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once namespace SQL { class Error; class Field; class Provider; class Query; class Result; /** A list of parameter replacement values. */ typedef std::vector<std::string> ParamList; /** A map of parameter replacement values. */ typedef std::map<std::string, std::string> ParamMap; /** A list of SQL fields from a specific row. */ typedef std::vector<Field> Row; /** An enumeration of possible error codes. */ enum ErrorCode { /** No error has occurred. */ SUCCESS, /** The database identifier is invalid. */ BAD_DBID, /** The database connection has failed. */ BAD_CONN, /** Executing the query failed. */ QSEND_FAIL, /** Reading the response failed. */ QREPLY_FAIL }; /** Populates a parameter map with information about a user. * @param user The user to collect information from. * @param userinfo The map to populate. */ void PopulateUserInfo(User* user, ParamMap& userinfo); } /** Represents a single SQL field. */ class SQL::Field { private: /** Whether this SQL field is NULL. */ bool null; /** The underlying SQL value. */ std::string value; public: /** Creates a new NULL SQL field. */ Field() : null(true) { } /** Creates a new non-NULL SQL field. * @param v The value of the field. */ Field(const std::string& v) : null(false) , value(v) { } /** Determines whether this SQL entry is NULL. */ inline bool IsNull() const { return null; } /** Retrieves the underlying value. */ inline operator const std::string&() const { return value; } }; /** Represents the result of an SQL query. */ class SQL::Result : public classbase { public: /** * Return the number of rows in the result. * * Note that if you have perfomed an INSERT or UPDATE query or other * query which will not return rows, this will return the number of * affected rows. In this case you SHOULD NEVER access any of the result * set rows, as there aren't any! * @returns Number of rows in the result set. */ virtual int Rows() = 0; /** Retrieves the next available row from the database. * @param result A list to store the fields from this row in. * @return True if a row could be retrieved; otherwise, false. */ virtual bool GetRow(Row& result) = 0; /** Retrieves a list of SQL columns in the result. * @param result A reference to the vector to store column names in. */ virtual void GetCols(std::vector<std::string>& result) = 0; /** * Check if there's a column with the specified name in the result * * @param the column name * @param on success, this is the column index * @returns true, or false if the column is not found */ virtual bool HasColumn(const std::string& column, size_t& index) = 0; }; /** SQL::Error holds the error state of a request. * The error string varies from database software to database software * and should be used to display informational error messages to users. */ class SQL::Error { private: /** The custom error message if one has been specified. */ const std::string message; public: /** The code which represents this error. */ const ErrorCode code; /** Initialize an SQL::Error from an error code. * @param c A code which represents this error. */ Error(ErrorCode c) : code(c) { } /** Initialize an SQL::Error from an error code and a custom error message. * @param c A code which represents this error. * @param m A custom error message. */ Error(ErrorCode c, const std::string m) : message(m) , code(c) { } /** Retrieves the error message. */ const char* ToString() const { if (!message.empty()) return message.c_str(); switch (code) { case BAD_DBID: return "Invalid database identifier"; case BAD_CONN: return "Invalid connection"; case QSEND_FAIL: return "Sending query failed"; case QREPLY_FAIL: return "Getting query result failed"; default: return "Unknown error"; } } }; /** * Object representing an SQL query. This should be allocated on the heap and * passed to an SQL::Provider, which will free it when the query is complete or * when the querying module is unloaded. * * You should store whatever information is needed to have the callbacks work in * this object (UID of user, channel name, etc). */ class SQL::Query : public classbase { protected: /** Creates a new SQL query. */ Query(Module* Creator) : creator(Creator) { } public: const ModuleRef creator; /* Destroys this Query instance. */ virtual ~Query() { } /** Called when an SQL error happens. * @param error The error that occurred. */ virtual void OnError(Error& error) = 0; /** Called when a SQL result is received. * @param result The result of the SQL query. */ virtual void OnResult(Result& result) = 0; }; /** * Provider object for SQL servers */ class SQL::Provider : public DataProvider { public: Provider(Module* Creator, const std::string& Name) : DataProvider(Creator, Name) { } /** Submit an asynchronous SQL query. * @param callback The result reporting point * @param query The hardcoded query string. If you have parameters to substitute, see below. */ virtual void Submit(Query* callback, const std::string& query) = 0; /** Submit an asynchronous SQL query. * @param callback The result reporting point * @param format The simple parameterized query string ('?' parameters) * @param p Parameters to fill in for the '?' entries */ virtual void Submit(Query* callback, const std::string& format, const SQL::ParamList& p) = 0; /** Submit an asynchronous SQL query. * @param callback The result reporting point * @param format The parameterized query string ('$name' parameters) * @param p Parameters to fill in for the '$name' entries */ virtual void Submit(Query* callback, const std::string& format, const ParamMap& p) = 0; }; inline void SQL::PopulateUserInfo(User* user, ParamMap& userinfo) { userinfo["nick"] = user->nick; userinfo["host"] = user->GetRealHost(); userinfo["ip"] = user->GetIPString(); userinfo["real"] = user->GetRealName(); userinfo["ident"] = user->ident; userinfo["server"] = user->server->GetName(); userinfo["uuid"] = user->uuid; } ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/include/modules/ssl.h����������������������������������������������������������������0000664�0000000�0000000�00000017745�13554550454�0017426�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * InspIRCd -- Internet Relay Chat Daemon * * Copyright (C) 2009 Daniel De Graaf <danieldg@inspircd.org> * Copyright (C) 2006 Craig Edwards <craigedwards@brainbox.cc> * * This file is part of InspIRCd. InspIRCd is free software: you can * redistribute it and/or modify it under the terms of the GNU General Public * License as published by the Free Software Foundation, version 2. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <string> #include "iohook.h" /** ssl_cert is a class which abstracts SSL certificate * and key information. * * Because gnutls and openssl represent key information in * wildly different ways, this class allows it to be accessed * in a unified manner. These classes are attached to ssl- * connected local users using SSLCertExt */ class ssl_cert : public refcountbase { public: std::string dn; std::string issuer; std::string error; std::string fingerprint; bool trusted, invalid, unknownsigner, revoked; ssl_cert() : trusted(false), invalid(true), unknownsigner(true), revoked(false) {} /** Get certificate distinguished name * @return Certificate DN */ const std::string& GetDN() { return dn; } /** Get Certificate issuer * @return Certificate issuer */ const std::string& GetIssuer() { return issuer; } /** Get error string if an error has occured * @return The error associated with this users certificate, * or an empty string if there is no error. */ const std::string& GetError() { return error; } /** Get key fingerprint. * @return The key fingerprint as a hex string. */ const std::string& GetFingerprint() { return fingerprint; } /** Get trust status * @return True if this is a trusted certificate * (the certificate chain validates) */ bool IsTrusted() { return trusted; } /** Get validity status * @return True if the certificate itself is * correctly formed. */ bool IsInvalid() { return invalid; } /** Get signer status * @return True if the certificate appears to be * self-signed. */ bool IsUnknownSigner() { return unknownsigner; } /** Get revokation status. * @return True if the certificate is revoked. * Note that this only works properly for GnuTLS * right now. */ bool IsRevoked() { return revoked; } /** Get certificate usability * @return True if the certificate is not expired nor revoked */ bool IsUsable() { return !invalid && !revoked && error.empty(); } /** Get CA trust status * @return True if the certificate is issued by a CA * and valid. */ bool IsCAVerified() { return IsUsable() && trusted && !unknownsigner; } std::string GetMetaLine() { std::stringstream value; bool hasError = !error.empty(); value << (IsInvalid() ? "v" : "V") << (IsTrusted() ? "T" : "t") << (IsRevoked() ? "R" : "r") << (IsUnknownSigner() ? "s" : "S") << (hasError ? "E" : "e") << " "; if (hasError) value << GetError(); else value << GetFingerprint() << " " << GetDN() << " " << GetIssuer(); return value.str(); } }; class SSLIOHook : public IOHook { protected: /** Peer SSL certificate, set by the SSL module */ reference<ssl_cert> certificate; /** Reduce elements in a send queue by appending later elements to the first element until there are no more * elements to append or a desired length is reached * @param sendq SendQ to work on * @param targetsize Target size of the front element */ static void FlattenSendQueue(StreamSocket::SendQueue& sendq, size_t targetsize) { if ((sendq.size() <= 1) || (sendq.front().length() >= targetsize)) return; // Avoid multiple repeated SSL encryption invocations // This adds a single copy of the queue, but avoids // much more overhead in terms of system calls invoked // by an IOHook. std::string tmp; tmp.reserve(std::min(targetsize, sendq.bytes())+1); do { tmp.append(sendq.front()); sendq.pop_front(); } while (!sendq.empty() && tmp.length() < targetsize); sendq.push_front(tmp); } public: static SSLIOHook* IsSSL(StreamSocket* sock) { IOHook* const iohook = sock->GetIOHook(); if ((iohook) && ((iohook->prov->type == IOHookProvider::IOH_SSL))) return static_cast<SSLIOHook*>(iohook); return NULL; } SSLIOHook(IOHookProvider* hookprov) : IOHook(hookprov) { } /** * Get the certificate sent by this peer * @return The SSL certificate sent by the peer, NULL if no cert was sent */ virtual ssl_cert* GetCertificate() const { return certificate; } /** * Get the fingerprint of the peer's certificate * @return The fingerprint of the SSL client certificate sent by the peer, * empty if no cert was sent */ virtual std::string GetFingerprint() const { ssl_cert* cert = GetCertificate(); if (cert && cert->IsUsable()) return cert->GetFingerprint(); return ""; } /** * Get the ciphersuite negotiated with the peer * @param out String where the ciphersuite string will be appended to */ virtual void GetCiphersuite(std::string& out) const = 0; /** Retrieves the name of the SSL connection which is sent via SNI. * @param out String that the server name will be appended to. * returns True if the server name was retrieved; otherwise, false. */ virtual bool GetServerName(std::string& out) const = 0; }; /** Helper functions for obtaining SSL client certificates and key fingerprints * from StreamSockets */ class SSLClientCert { public: /** * Get the client certificate from a socket * @param sock The socket to get the certificate from, the socket does not have to use SSL * @return The SSL client certificate information, NULL if the peer is not using SSL */ static ssl_cert* GetCertificate(StreamSocket* sock) { SSLIOHook* ssliohook = SSLIOHook::IsSSL(sock); if (!ssliohook) return NULL; return ssliohook->GetCertificate(); } /** * Get the fingerprint of a client certificate from a socket * @param sock The socket to get the certificate fingerprint from, the * socket does not have to use SSL * @return The key fingerprint from the SSL certificate sent by the peer, * empty if no cert was sent or the peer is not using SSL */ static std::string GetFingerprint(StreamSocket* sock) { ssl_cert* cert = SSLClientCert::GetCertificate(sock); if (cert) return cert->GetFingerprint(); return ""; } }; class UserCertificateAPIBase : public DataProvider { public: UserCertificateAPIBase(Module* parent) : DataProvider(parent, "m_sslinfo_api") { } /** Get the SSL certificate of a user * @param user The user whose certificate to get, user may be remote * @return The SSL certificate of the user or NULL if the user is not using SSL */ virtual ssl_cert* GetCertificate(User* user) = 0; /** Set the SSL certificate of a user. * @param user The user whose certificate to set. * @param cert The SSL certificate to set for the user. */ virtual void SetCertificate(User* user, ssl_cert* cert) = 0; /** Get the key fingerprint from a user's certificate * @param user The user whose key fingerprint to get, user may be remote * @return The key fingerprint from the user's SSL certificate or an empty string * if the user is not using SSL or did not provide a client certificate */ std::string GetFingerprint(User* user) { ssl_cert* cert = GetCertificate(user); if (cert) return cert->GetFingerprint(); return ""; } }; /** API implemented by m_sslinfo that allows modules to retrive the SSL certificate * information of local and remote users. It can also be used to find out whether a * user is using SSL or not. */ class UserCertificateAPI : public dynamic_reference<UserCertificateAPIBase> { public: UserCertificateAPI(Module* parent) : dynamic_reference<UserCertificateAPIBase>(parent, "m_sslinfo_api") { } }; ���������������������������inspircd-3.4.0/include/modules/stats.h��������������������������������������������������������������0000664�0000000�0000000�00000010426�13554550454�0017750�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * InspIRCd -- Internet Relay Chat Daemon * * Copyright (C) 2016 Attila Molnar <attilamolnar@hush.com> * * This file is part of InspIRCd. InspIRCd is free software: you can * redistribute it and/or modify it under the terms of the GNU General Public * License as published by the Free Software Foundation, version 2. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include "event.h" namespace Stats { class Context; class EventListener; class Row; } class Stats::EventListener : public Events::ModuleEventListener { public: EventListener(Module* mod) : ModuleEventListener(mod, "event/stats") { } /** Called when the STATS command is executed. * @param stats Context of the /STATS request, contains requesting user, list of answer rows etc. * @return MOD_RES_DENY if the stats request has been fulfilled. Otherwise, MOD_RES_PASSTHRU. */ virtual ModResult OnStats(Stats::Context& stats) = 0; }; class Stats::Row : public Numeric::Numeric { public: Row(unsigned int num) : Numeric(num) { } }; class Stats::Context { /** Source user of the STATS request */ User* const source; /** List of reply rows */ std::vector<Row> rows; /** Symbol indicating the type of this STATS request (usually a letter) */ const char symbol; public: /** Constructor * @param src Source user of the STATS request, can be a local or remote user * @param sym Symbol (letter) indicating the type of the request */ Context(User* src, char sym) : source(src) , symbol(sym) { } /** Get the source user of the STATS request * @return Source user of the STATS request */ User* GetSource() const { return source; } /** Get the list of reply rows * @return List of rows generated as reply for the request */ const std::vector<Row>& GetRows() const { return rows; } /** Get the symbol (letter) indicating what type of STATS was requested * @return Symbol specified by the requesting user */ char GetSymbol() const { return symbol; } /** Add a row to the reply list * @param row Reply to add */ void AddRow(const Row& row) { rows.push_back(row); } template <typename T1> void AddRow(unsigned int numeric, T1 p1) { Row n(numeric); n.push(p1); AddRow(n); } template <typename T1, typename T2> void AddRow(unsigned int numeric, T1 p1, T2 p2) { Row n(numeric); n.push(p1); n.push(p2); AddRow(n); } template <typename T1, typename T2, typename T3> void AddRow(unsigned int numeric, T1 p1, T2 p2, T3 p3) { Row n(numeric); n.push(p1); n.push(p2); n.push(p3); AddRow(n); } template <typename T1, typename T2, typename T3, typename T4> void AddRow(unsigned int numeric, T1 p1, T2 p2, T3 p3, T4 p4) { Row n(numeric); n.push(p1); n.push(p2); n.push(p3); n.push(p4); AddRow(n); } template <typename T1, typename T2, typename T3, typename T4, typename T5> void AddRow(unsigned int numeric, T1 p1, T2 p2, T3 p3, T4 p4, T5 p5) { Row n(numeric); n.push(p1); n.push(p2); n.push(p3); n.push(p4); n.push(p5); AddRow(n); } template <typename T1, typename T2, typename T3, typename T4, typename T5, typename T6> void AddRow(unsigned int numeric, T1 p1, T2 p2, T3 p3, T4 p4, T5 p5, T6 p6) { Row n(numeric); n.push(p1); n.push(p2); n.push(p3); n.push(p4); n.push(p5); n.push(p6); AddRow(n); } template <typename T1, typename T2, typename T3, typename T4, typename T5, typename T6, typename T7> void AddRow(unsigned int numeric, T1 p1, T2 p2, T3 p3, T4 p4, T5 p5, T6 p6, T7 p7) { Row n(numeric); n.push(p1); n.push(p2); n.push(p3); n.push(p4); n.push(p5); n.push(p6); n.push(p7); AddRow(n); } template <typename T1, typename T2, typename T3, typename T4, typename T5, typename T6, typename T7, typename T8> void AddRow(unsigned int numeric, T1 p1, T2 p2, T3 p3, T4 p4, T5 p5, T6 p6, T7 p7, T8 p8) { Row n(numeric); n.push(p1); n.push(p2); n.push(p3); n.push(p4); n.push(p5); n.push(p6); n.push(p7); n.push(p8); AddRow(n); } }; ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/include/modules/webirc.h�������������������������������������������������������������0000664�0000000�0000000�00000002155�13554550454�0020065�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * InspIRCd -- Internet Relay Chat Daemon * * Copyright (C) 2016-2017 Peter Powell <petpow@saberuk.com> * * This file is part of InspIRCd. InspIRCd is free software: you can * redistribute it and/or modify it under the terms of the GNU General Public * License as published by the Free Software Foundation, version 2. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include "event.h" namespace WebIRC { class EventListener; typedef insp::flat_map<std::string, std::string, irc::insensitive_swo> FlagMap; } class WebIRC::EventListener : public Events::ModuleEventListener { protected: EventListener(Module* mod) : ModuleEventListener(mod, "event/webirc") { } public: virtual void OnWebIRCAuth(LocalUser* user, const FlagMap* flags) = 0; }; �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/include/modules/who.h����������������������������������������������������������������0000664�0000000�0000000�00000005450�13554550454�0017410�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * InspIRCd -- Internet Relay Chat Daemon * * Copyright (C) 2015 Attila Molnar <attilamolnar@hush.com> * * This file is part of InspIRCd. InspIRCd is free software: you can * redistribute it and/or modify it under the terms of the GNU General Public * License as published by the Free Software Foundation, version 2. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include "event.h" namespace Who { class EventListener; class Request; } class Who::EventListener : public Events::ModuleEventListener { public: EventListener(Module* mod) : ModuleEventListener(mod, "event/who") { } /** Called when a result from WHO is about to be queued. * @param request Details about the WHO request which caused this response. * @param source The user who initiated this WHO request. * @param user The user that this line of the WHO request is about. * @param memb The channel membership of the user or NULL if not targeted at a channel. * @param numeric The numeric which will be sent in response to the request. * @return MOD_RES_ALLOW to explicitly allow the response, MOD_RES_DENY to explicitly deny the * response, or MOD_RES_PASSTHRU to let another module handle the event. */ virtual ModResult OnWhoLine(const Request& request, LocalUser* source, User* user, Membership* memb, Numeric::Numeric& numeric) = 0; }; class Who::Request { public: /** The flags for matching users to include. */ std::bitset<UCHAR_MAX> flags; /** Whether we are matching using a wildcard or a flag. */ bool fuzzy_match; /** The text to match against. */ std::string matchtext; /** The WHO/WHOX responses we will send to the source. */ std::vector<Numeric::Numeric> results; /** Whether the source requested a WHOX response. */ bool whox; /** The fields to include in the WHOX response. */ std::bitset<UCHAR_MAX> whox_fields; /** A user specified label for the WHOX response. */ std::string whox_querytype; /** Get the index in the response parameters for the different data fields * * The fields 'r' (realname) and 'd' (hops) will always be missing in a non-WHOX * query, because WHOX splits them to 2 fields, where old WHO has them as one. * * @param flag The field name to look for * @param out The index will be stored in this value * @return True if the field is available, false otherwise */ virtual bool GetFieldIndex(char flag, size_t& out) const = 0; protected: Request() : fuzzy_match(false) , whox(false) { } }; ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/include/modules/whois.h��������������������������������������������������������������0000664�0000000�0000000�00000007131�13554550454�0017742�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * InspIRCd -- Internet Relay Chat Daemon * * Copyright (C) 2015 Attila Molnar <attilamolnar@hush.com> * * This file is part of InspIRCd. InspIRCd is free software: you can * redistribute it and/or modify it under the terms of the GNU General Public * License as published by the Free Software Foundation, version 2. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include "event.h" namespace Whois { class EventListener; class LineEventListener; class Context; } class Whois::EventListener : public Events::ModuleEventListener { public: EventListener(Module* mod) : ModuleEventListener(mod, "event/whois") { } /** Called whenever a /WHOIS is performed by a local user. * @param whois Whois context, can be used to send numerics */ virtual void OnWhois(Context& whois) = 0; }; class Whois::LineEventListener : public Events::ModuleEventListener { public: LineEventListener(Module* mod) : ModuleEventListener(mod, "event/whoisline") { } /** Called whenever a line of WHOIS output is sent to a user. * You may change the numeric and the text of the output by changing * the values numeric and text, but you cannot change the user the * numeric is sent to. * @param whois Whois context, can be used to send numerics * @param numeric Numeric being sent * @return MOD_RES_DENY to drop the line completely so that the user does not * receive it, or MOD_RES_PASSTHRU to allow the line to be sent. */ virtual ModResult OnWhoisLine(Context& whois, Numeric::Numeric& numeric) = 0; }; class Whois::Context { protected: /** User doing the WHOIS */ LocalUser* const source; /** User being WHOISed */ User* const target; public: Context(LocalUser* src, User* targ) : source(src) , target(targ) { } /** Returns true if the user is /WHOISing himself * @return True if whois source is the same user as the whois target, false if they are different users */ bool IsSelfWhois() const { return (source == target); } /** Returns the LocalUser who has done the /WHOIS * @return LocalUser doing the /WHOIS */ LocalUser* GetSource() const { return source; } /** Returns the target of the /WHOIS * @return User who was /WHOIS'd */ User* GetTarget() const { return target; } /** Send a line of WHOIS data to the source of the WHOIS */ template <typename T1> void SendLine(unsigned int numeric, T1 p1) { Numeric::Numeric n(numeric); n.push(target->nick); n.push(p1); SendLine(n); } template <typename T1, typename T2> void SendLine(unsigned int numeric, T1 p1, T2 p2) { Numeric::Numeric n(numeric); n.push(target->nick); n.push(p1); n.push(p2); SendLine(n); } template <typename T1, typename T2, typename T3> void SendLine(unsigned int numeric, T1 p1, T2 p2, T3 p3) { Numeric::Numeric n(numeric); n.push(target->nick); n.push(p1); n.push(p2); n.push(p3); SendLine(n); } template <typename T1, typename T2, typename T3, typename T4> void SendLine(unsigned int numeric, T1 p1, T2 p2, T3 p3, T4 p4) { Numeric::Numeric n(numeric); n.push(target->nick); n.push(p1); n.push(p2); n.push(p3); n.push(p4); SendLine(n); } /** Send a line of WHOIS data to the source of the WHOIS * @param numeric Numeric to send */ virtual void SendLine(Numeric::Numeric& numeric) = 0; }; ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/include/numeric.h��������������������������������������������������������������������0000664�0000000�0000000�00000004427�13554550454�0016610�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * InspIRCd -- Internet Relay Chat Daemon * * Copyright (C) 2016 Attila Molnar <attilamolnar@hush.com> * * This file is part of InspIRCd. InspIRCd is free software: you can * redistribute it and/or modify it under the terms of the GNU General Public * License as published by the Free Software Foundation, version 2. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include "numerics.h" namespace Numeric { class Numeric; } class Numeric::Numeric { /** Numeric number */ unsigned int numeric; /** Parameters of the numeric */ CommandBase::Params params; /** Source server of the numeric, if NULL (the default) then it is the local server */ Server* sourceserver; public: /** Constructor * @param num Numeric number (RPL_*, ERR_*) */ Numeric(unsigned int num) : numeric(num) , sourceserver(NULL) { } /** Add a parameter to the numeric. The parameter will be converted to a string first with ConvToStr(). * @param x Parameter to add */ template <typename T> Numeric& push(const T& x) { params.push_back(ConvToStr(x)); return *this; } /** Set the source server of the numeric. The source server defaults to the local server. * @param server Server to set as source */ void SetServer(Server* server) { sourceserver = server; } /** Get the source server of the numeric * @return Source server or NULL if the source is the local server */ Server* GetServer() const { return sourceserver; } /** Get the number of the numeric as an unsigned integer * @return Numeric number as an unsigned integer */ unsigned int GetNumeric() const { return numeric; } /** Get the parameters of the numeric * @return Parameters of the numeric as a const vector of strings */ const CommandBase::Params& GetParams() const { return params; } /** Get the parameters of the numeric * @return Parameters of the numeric as a vector of strings */ CommandBase::Params& GetParams() { return params; } }; �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/include/numericbuilder.h�������������������������������������������������������������0000664�0000000�0000000�00000014517�13554550454�0020160�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * InspIRCd -- Internet Relay Chat Daemon * * Copyright (C) 2015-2016 Attila Molnar <attilamolnar@hush.com> * * This file is part of InspIRCd. InspIRCd is free software: you can * redistribute it and/or modify it under the terms of the GNU General Public * License as published by the Free Software Foundation, version 2. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once namespace Numeric { class WriteNumericSink; class WriteRemoteNumericSink; template <char Sep, bool SendEmpty, typename Sink> class GenericBuilder; template <char Sep = ',', bool SendEmpty = false> class Builder; template <unsigned int NumStaticParams, bool SendEmpty, typename Sink> class GenericParamBuilder; template <unsigned int NumStaticParams, bool SendEmpty = false> class ParamBuilder; } class Numeric::WriteNumericSink { LocalUser* const user; public: WriteNumericSink(LocalUser* u) : user(u) { } void operator()(Numeric& numeric) const { user->WriteNumeric(numeric); } }; class Numeric::WriteRemoteNumericSink { User* const user; public: WriteRemoteNumericSink(User* u) : user(u) { } void operator()(Numeric& numeric) const { user->WriteRemoteNumeric(numeric); } }; template <char Sep, bool SendEmpty, typename Sink> class Numeric::GenericBuilder { Sink sink; Numeric numeric; const std::string::size_type max; bool HasRoom(const std::string::size_type additional) const { return (numeric.GetParams().back().size() + additional <= max); } public: GenericBuilder(Sink s, unsigned int num, bool addparam = true, size_t additionalsize = 0) : sink(s) , numeric(num) , max(ServerInstance->Config->Limits.MaxLine - ServerInstance->Config->ServerName.size() - additionalsize - 10) { if (addparam) numeric.push(std::string()); } Numeric& GetNumeric() { return numeric; } void Add(const std::string& entry) { if (!HasRoom(entry.size())) Flush(); numeric.GetParams().back().append(entry).push_back(Sep); } void Add(const std::string& entry1, const std::string& entry2) { if (!HasRoom(entry1.size() + entry2.size())) Flush(); numeric.GetParams().back().append(entry1).append(entry2).push_back(Sep); } void Flush() { std::string& data = numeric.GetParams().back(); if (IsEmpty()) { if (!SendEmpty) return; } else { data.erase(data.size()-1); } sink(numeric); data.clear(); } bool IsEmpty() const { return (numeric.GetParams().back().empty()); } }; template <char Sep, bool SendEmpty> class Numeric::Builder : public GenericBuilder<Sep, SendEmpty, WriteNumericSink> { public: Builder(LocalUser* user, unsigned int num, bool addparam = true, size_t additionalsize = 0) : ::Numeric::GenericBuilder<Sep, SendEmpty, WriteNumericSink>(WriteNumericSink(user), num, addparam, additionalsize + user->nick.size()) { } }; template <unsigned int NumStaticParams, bool SendEmpty, typename Sink> class Numeric::GenericParamBuilder { Sink sink; Numeric numeric; std::string::size_type currlen; std::string::size_type max; bool HasRoom(const std::string::size_type additional) const { return (currlen + additional <= max); } public: GenericParamBuilder(Sink s, unsigned int num, size_t additionalsize) : sink(s) , numeric(num) , currlen(0) , max(ServerInstance->Config->Limits.MaxLine - ServerInstance->Config->ServerName.size() - additionalsize - 10) { } void AddStatic(const std::string& entry) { max -= (entry.length() + 1); numeric.GetParams().push_back(entry); } void Add(const std::string& entry) { if (!HasRoom(entry.size())) Flush(); currlen += entry.size() + 1; numeric.GetParams().push_back(entry); } void Flush() { if ((!SendEmpty) && (IsEmpty())) return; sink(numeric); currlen = 0; numeric.GetParams().erase(numeric.GetParams().begin() + NumStaticParams, numeric.GetParams().end()); } bool IsEmpty() const { return (numeric.GetParams().size() <= NumStaticParams); } }; template <unsigned int NumStaticParams, bool SendEmpty> class Numeric::ParamBuilder : public GenericParamBuilder<NumStaticParams, SendEmpty, WriteNumericSink> { public: ParamBuilder(LocalUser* user, unsigned int num) : ::Numeric::GenericParamBuilder<NumStaticParams, SendEmpty, WriteNumericSink>(WriteNumericSink(user), num, user->nick.size()) { } }; namespace Numerics { class InvalidModeParameter; class NoSuchChannel; class NoSuchNick; } /* Builder for the ERR_INVALIDMODEPARAM numeric. */ class Numerics::InvalidModeParameter : public Numeric::Numeric { private: void push_message(ModeHandler* mode, const std::string& message) { if (!message.empty()) { // The caller has specified their own message. push(message); return; } const std::string& syntax = mode->GetSyntax(); if (!syntax.empty()) { // If the mode has a syntax hint we include it in the message. push(InspIRCd::Format("Invalid %s mode parameter. Syntax: %s.", mode->name.c_str(), syntax.c_str())); } else { // Otherwise, send it without. push(InspIRCd::Format("Invalid %s mode parameter.", mode->name.c_str())); } } public: InvalidModeParameter(Channel* chan, ModeHandler* mode, const std::string& parameter, const std::string& message = "") : Numeric(ERR_INVALIDMODEPARAM) { push(chan->name); push(mode->GetModeChar()); push(parameter); push_message(mode, message); } InvalidModeParameter(User* user, ModeHandler* mode, const std::string& parameter, const std::string& message = "") : Numeric(ERR_INVALIDMODEPARAM) { push(user->registered & REG_NICK ? user->nick : "*"); push(mode->GetModeChar()); push(parameter); push_message(mode, message); } }; /** Builder for the ERR_NOSUCHCHANNEL numeric. */ class Numerics::NoSuchChannel : public Numeric::Numeric { public: NoSuchChannel(const std::string& chan) : Numeric(ERR_NOSUCHCHANNEL) { push(chan); push("No such channel"); } }; /** Builder for the ERR_NOSUCHNICK numeric. */ class Numerics::NoSuchNick : public Numeric::Numeric { public: NoSuchNick(const std::string& nick) : Numeric(ERR_NOSUCHNICK) { push(nick); push("No such nick"); } }; ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/include/numerics.h�������������������������������������������������������������������0000664�0000000�0000000�00000014607�13554550454�0016774�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * InspIRCd -- Internet Relay Chat Daemon * * Copyright (C) 2008 Robin Burchell <robin+git@viroteck.net> * Copyright (C) 2008 Craig Edwards <craigedwards@brainbox.cc> * * This file is part of InspIRCd. InspIRCd is free software: you can * redistribute it and/or modify it under the terms of the GNU General Public * License as published by the Free Software Foundation, version 2. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once /* * Module authors, please note! * While you are free to use any numerics on this list, like the rest of the core, you * *should not* be editing it! * * If you *do* have a suggestion for a numeric you genuinely believe would be useful, * please speak to us. :) * * Thanks to Darom, jackmcbarn and Brain for suggesting and discussing this. * * Please note that the list may not be exhaustive, it'll be done when I have * nothing better to do with my time. -- w00t (jul 13, 2008) */ enum { RPL_ISUPPORT = 5, // not RFC, extremely common though (defined as RPL_BOUNCE in 2812, widely ignored) RPL_SNOMASKIS = 8, // unrealircd RPL_MAP = 15, // ircu RPL_ENDMAP = 17, // ircu RPL_MAPUSERS = 18, // insp-specific RPL_UMODEIS = 221, RPL_LUSERCLIENT = 251, RPL_LUSEROP = 252, RPL_LUSERUNKNOWN = 253, RPL_LUSERCHANNELS = 254, RPL_LUSERME = 255, RPL_ADMINME = 256, RPL_ADMINLOC1 = 257, RPL_ADMINLOC2 = 258, RPL_ADMINEMAIL = 259, RPL_LOCALUSERS = 265, RPL_GLOBALUSERS = 266, RPL_AWAY = 301, RPL_USERHOST = 302, RPL_ISON = 303, RPL_WHOISSERVER = 312, RPL_ENDOFWHOIS = 318, RPL_LISTSTART = 321, RPL_LIST = 322, RPL_LISTEND = 323, RPL_CHANNELMODEIS = 324, RPL_CHANNELCREATED = 329, // ??? RPL_NOTOPICSET = 331, RPL_TOPIC = 332, RPL_TOPICTIME = 333, // not RFC, extremely common though RPL_USERIP = 340, RPL_INVITING = 341, RPL_INVITELIST = 346, // insp-specific (stolen from ircu) RPL_ENDOFINVITELIST = 347, // insp-specific (stolen from ircu) RPL_VERSION = 351, RPL_NAMREPLY = 353, RPL_LINKS = 364, RPL_ENDOFLINKS = 365, RPL_ENDOFNAMES = 366, RPL_INFO = 371, RPL_ENDOFINFO = 374, RPL_MOTD = 372, RPL_MOTDSTART = 375, RPL_ENDOFMOTD = 376, RPL_YOUAREOPER = 381, RPL_REHASHING = 382, RPL_TIME = 391, RPL_YOURDISPLAYEDHOST = 396, // from charybdis/etc, common convention /* * Error range of numerics. */ ERR_NOSUCHNICK = 401, ERR_NOSUCHSERVER = 402, ERR_NOSUCHCHANNEL = 403, // used to indicate an invalid channel name also, so don't rely on RFC text (don't do that anyway!) ERR_CANNOTSENDTOCHAN = 404, ERR_TOOMANYCHANNELS = 405, ERR_WASNOSUCHNICK = 406, ERR_NOTEXTTOSEND = 412, ERR_UNKNOWNCOMMAND = 421, ERR_NOMOTD = 422, ERR_NONICKNAMEGIVEN = 431, ERR_ERRONEUSNICKNAME = 432, ERR_NICKNAMEINUSE = 433, ERR_USERNOTINCHANNEL = 441, ERR_NOTONCHANNEL = 442, ERR_USERONCHANNEL = 443, ERR_CANTCHANGENICK = 447, // unrealircd, probably ERR_NOTREGISTERED = 451, ERR_NEEDMOREPARAMS = 461, ERR_ALREADYREGISTERED = 462, ERR_YOUREBANNEDCREEP = 465, ERR_UNKNOWNMODE = 472, /* * A quick side-rant about the next group of numerics.. * There are clients out there that like to assume that just because they don't receive a numeric * they know, that they have joined the channel. * * If IRC was at all properly standardised, this may even be a semi-acceptable assumption to make, * but that's not the case as we all know, so IT IS NOT ACCEPTABLE. Especially for Insp users, where * differing modules MAY potentially choose to block joins and send NOTICEs or other text to the user * instead! * * tl;dr version: * DON'T MAKE YOUR CLIENT ASSUME YOU JOINED UNLESS YOU RECEIVE A JOIN WITH YOUR DAMN NICK ON IT. * Thanks. * * -- A message from the IRC group for coder sanity, and w00t */ ERR_BADCHANNELKEY = 475, ERR_BADCHANMASK = 476, ERR_INVITEONLYCHAN = 473, ERR_CHANNELISFULL = 471, ERR_BANNEDFROMCHAN = 474, ERR_BANLISTFULL = 478, ERR_NOPRIVILEGES = 481, // rfc, beware though, we use this for other things opers may not do also ERR_CHANOPRIVSNEEDED = 482, // rfc, beware though, we use this for other things like trying to kick a uline ERR_RESTRICTED = 484, ERR_NOOPERHOST = 491, ERR_UNKNOWNSNOMASK = 501, // insp-specific ERR_USERSDONTMATCH = 502, ERR_CANTSENDTOUSER = 531, // ??? RPL_SYNTAX = 650, // insp-specific ERR_INVALIDMODEPARAM = 696, // insp-specific ERR_LISTMODEALREADYSET = 697, // insp-specific ERR_LISTMODENOTSET = 698, // insp-specific RPL_OTHERUMODEIS = 803, // insp-specific RPL_OTHERSNOMASKIS = 804, // insp-specific ERR_CANTUNLOADMODULE = 972, // insp-specific RPL_UNLOADEDMODULE = 973, // insp-specific ERR_CANTLOADMODULE = 974, // insp-specific RPL_LOADEDMODULE = 975 // insp-specific }; �������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/include/parammode.h������������������������������������������������������������������0000664�0000000�0000000�00000004645�13554550454�0017115�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * InspIRCd -- Internet Relay Chat Daemon * * Copyright (C) 2014 Attila Molnar <attilamolnar@hush.com> * * This file is part of InspIRCd. InspIRCd is free software: you can * redistribute it and/or modify it under the terms of the GNU General Public * License as published by the Free Software Foundation, version 2. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once class CoreExport ParamModeBase : public ModeHandler { private: virtual void OnUnsetInternal(User* source, Channel* chan) = 0; public: ParamModeBase(Module* Creator, const std::string& Name, char modeletter, ParamSpec ps) : ModeHandler(Creator, Name, modeletter, ps, MODETYPE_CHANNEL, MC_PARAM) { } ModeAction OnModeChange(User* source, User* dest, Channel* channel, std::string& param, bool adding) CXX11_OVERRIDE; // Does nothing by default virtual bool IsParameterSecret() { return false; } virtual void OnUnset(User* source, Channel* chan) { } virtual ModeAction OnSet(User* source, Channel* chan, std::string& param) = 0; virtual void GetParameter(Channel* chan, std::string& out) = 0; }; /** Defines a parameter mode * T = Child class * ExtItemT = Type of the extension item used to store the parameter * * When unsetting the mode, the extension is automatically unset. */ template <typename T, typename ExtItemT> class ParamMode : public ParamModeBase { public: ExtItemT ext; /** * @param Creator Module handling this mode * @param Name The internal name of this mode * @param modeletter The mode letter of this mode * @param ps The parameter type of this mode, one of ParamSpec */ ParamMode(Module* Creator, const std::string& Name, char modeletter, ParamSpec ps = PARAM_SETONLY) : ParamModeBase(Creator, Name, modeletter, ps) , ext("parammode_" + Name, ExtensionItem::EXT_CHANNEL, Creator) { } void OnUnsetInternal(User* source, Channel* chan) CXX11_OVERRIDE { this->OnUnset(source, chan); ext.unset(chan); } void GetParameter(Channel* chan, std::string& out) CXX11_OVERRIDE { T* mh = static_cast<T*>(this); mh->SerializeParam(chan, ext.get(chan), out); } }; �������������������������������������������������������������������������������������������inspircd-3.4.0/include/protocol.h�������������������������������������������������������������������0000664�0000000�0000000�00000012605�13554550454�0017004�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * InspIRCd -- Internet Relay Chat Daemon * * Copyright (C) 2008 Robin Burchell <robin+git@viroteck.net> * Copyright (C) 2008 Craig Edwards <craigedwards@brainbox.cc> * * This file is part of InspIRCd. InspIRCd is free software: you can * redistribute it and/or modify it under the terms of the GNU General Public * License as published by the Free Software Foundation, version 2. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include "hashcomp.h" class User; class ProtocolServer { public: /** Send metadata related to this server to the target server * @param key The 'key' of the data * @param data The string representation of the data */ virtual void SendMetaData(const std::string& key, const std::string& data) = 0; }; class CoreExport ProtocolInterface { public: typedef ProtocolServer Server; class ServerInfo { public: std::string servername; std::string parentname; std::string description; unsigned int usercount; unsigned int opercount; unsigned int latencyms; }; typedef std::vector<ServerInfo> ServerList; virtual ~ProtocolInterface() { } /** Send an ENCAP message to all servers matching a wildcard string. * See the protocol documentation for the purpose of ENCAP. * @param targetmask The target server mask (can contain wildcards) * @param cmd The ENCAP subcommand * @param params List of string parameters which are dependant on the subcommand * @param source The source of the message (prefix), must be a local user or NULL which means use local server * @return Always true if the target mask contains wildcards; otherwise true if the server name was found, * and the message was sent, false if it was not found. * ENCAP (should) be used instead of creating new protocol messages for easier third party application support. */ virtual bool SendEncapsulatedData(const std::string& targetmask, const std::string& cmd, const CommandBase::Params& params, User* source = NULL) { return false; } /** Send an ENCAP message to all servers. * See the protocol documentation for the purpose of ENCAP. * @param cmd The ENCAP subcommand * @param params List of string parameters which are dependant on the subcommand * @param source The source of the message (prefix), must be a local user or a user behind 'omit' * or NULL which is equivalent to the local server * @param omit If non-NULL the message won't be sent in the direction of this server, useful for forwarding messages */ virtual void BroadcastEncap(const std::string& cmd, const CommandBase::Params& params, User* source = NULL, User* omit = NULL) { } /** Send metadata for a channel to other linked servers. * @param chan The channel to send metadata for * @param key The 'key' of the data, e.g. "swhois" for swhois desc on a user * @param data The string representation of the data */ virtual void SendMetaData(Channel* chan, const std::string& key, const std::string& data) { } /** Send metadata for a user to other linked servers. * @param user The user to send metadata for * @param key The 'key' of the data, e.g. "swhois" for swhois desc on a user * @param data The string representation of the data */ virtual void SendMetaData(User* user, const std::string& key, const std::string& data) { } /** Send metadata related to the server to other linked servers. * @param key The 'key' of the data * @param data The string representation of the data */ virtual void SendMetaData(const std::string& key, const std::string& data) { } /** Send a notice to users with a given snomask. * @param snomask The snomask required for the message to be sent. * @param text The message to send. */ virtual void SendSNONotice(char snomask, const std::string& text) { } /** Send a message to a channel. * @param target The channel to message. * @param status The status character (e.g. %) required to receive. * @param text The message to send. * @param type The message type (MSG_PRIVMSG or MSG_NOTICE) */ virtual void SendMessage(Channel* target, char status, const std::string& text, MessageType type = MSG_PRIVMSG) { } /** Send a message to a user. * @param target The user to message. * @param text The message to send. * @param type The message type (MSG_PRIVMSG or MSG_NOTICE) */ virtual void SendMessage(User* target, const std::string& text, MessageType type = MSG_PRIVMSG) { } /** Send a notice to a channel. * @param target The channel to message. * @param status The status character (e.g. %) required to receive. * @param text The message to send. */ void SendChannelNotice(Channel* target, char status, const std::string &text) { SendMessage(target, status, text, MSG_NOTICE); } /** Send a notice to a user. * @param target The user to message. * @param text The message to send. */ void SendUserNotice(User* target, const std::string &text) { SendMessage(target, text, MSG_NOTICE); } /** Fill a list of servers and information about them. * @param sl The list of servers to fill. * XXX: document me properly, this is shit. */ virtual void GetServerList(ServerList& sl) { } }; ���������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/include/serialize.h������������������������������������������������������������������0000664�0000000�0000000�00000007305�13554550454�0017133�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * InspIRCd -- Internet Relay Chat Daemon * * Copyright (C) 2019 Peter Powell <petpow@saberuk.com> * * This file is part of InspIRCd. InspIRCd is free software: you can * redistribute it and/or modify it under the terms of the GNU General Public * License as published by the Free Software Foundation, version 2. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once /** Base class for serializable elements. */ class CoreExport Serializable { protected: Serializable() { } public: /** Encapsulates a chunk of serialised data. */ class CoreExport Data { public: /** Maps keys to serialised data. */ typedef insp::flat_map<std::string, Data> ChildMap; /** Maps keys to simple values. */ typedef insp::flat_map<std::string, std::string> EntryMap; private: /** A mapping of keys to serialised data. */ ChildMap children; /** A mapping of keys to values. */ EntryMap entries; public: /** Retrieves the child elements. */ const ChildMap& GetChildren() const { return children; } ChildMap& GetChildren() { return children; } /** Retrieves the key/value map. */ const EntryMap& GetEntries() const { return entries; } EntryMap& GetEntries() { return entries; } /** Loads the serialised data with the specified key. * @param key The key by which this serialised data is identified. * @param out The location to store the serialised data for this key. */ Data& Load(const std::string& key, Data& out); /** Loads the value with the specified key. * @param key The key by which this data is identified. * @param out The location to store the value for this keu */ Data& Load(const std::string& key, std::string& out); /** Loads the value with the specified key. The value will be converted to the specified type. * @param key The key by which this data is identified. * @param out The location to store the value for this key. */ template <typename T> Data& Load(const std::string& key, T& out) { // Attempt to load as a string. std::string str; Load(key, str); std::stringstream ss(str); ss >> out; return *this; } /** Stores the serialised data against the specified key. * @param key The key by which this serialised data should be stored against. * @param out The serialised data to store. */ Data& Store(const std::string& key, const Data& value); /** Stores the value against the specified key. * @param key The key by which this value should be stored against. * @param out The value to store. */ Data& Store(const std::string& key, const std::string& value); /** Stores the value against the specified key. The value will be converted to a string using ConvToStr. * @param key The key by which this value should be stored against. * @param out The value to store. */ template <typename T> Data& Store(const std::string& key, const T& value) { return Store(key, ConvToStr(value)); } }; /** Deserializes the specified Data instance into this object. * @param data The Data object to deserialize from. * @return True if the deserialisation succeeded; otherwise, false. */ virtual bool Deserialize(Data& data) = 0; /** Serializes the this object into the specified Data obect. * @param data The Data object to serialize to. * @return True if the serialisation succeeded; otherwise, false. */ virtual bool Serialize(Data& data) = 0; }; ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/include/server.h���������������������������������������������������������������������0000664�0000000�0000000�00000005074�13554550454�0016453�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * InspIRCd -- Internet Relay Chat Daemon * * Copyright (C) 2014 Attila Molnar <attilamolnar@hush.com> * * This file is part of InspIRCd. InspIRCd is free software: you can * redistribute it and/or modify it under the terms of the GNU General Public * License as published by the Free Software Foundation, version 2. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once class CoreExport Server : public classbase { protected: /** The unique identifier for this server. */ const std::string id; /** The name of this server */ const std::string name; /** The description of this server. * This can be updated by the protocol module (for remote servers) or by a rehash (for the local server). */ std::string description; /** True if this server is ulined */ bool uline; /** True if this server is a silent uline, i.e. silent="true" in the uline block */ bool silentuline; /** Allow ConfigReaderThread to update the description on a rehash */ friend class ConfigReaderThread; public: Server(const std::string& srvid, const std::string& srvname, const std::string& srvdesc) : id(srvid) , name(srvname) , description(srvdesc) , uline(false) , silentuline(false) { } DEPRECATED_METHOD(Server(const std::string& srvname, const std::string& srvdesc)) : name(srvname) , description(srvdesc) , uline(false) , silentuline(false) { } /** Retrieves the unique identifier for this server (e.g. 36C). */ const std::string& GetId() const { return id; } /** * Returns the name of this server * @return The name of this server, for example "irc.inspircd.org". */ const std::string& GetName() const { return name; } /** Returns the description of this server * @return The description of this server */ const std::string& GetDesc() const { return description; } /** * Checks whether this server is ulined * @return True if this server is ulined, false otherwise. */ bool IsULine() const { return uline; } /** * Checks whether this server is a silent uline * Silent uline servers introduce, quit and oper up users without a snotice being generated. * @return True if this server is a silent uline, false otherwise. */ bool IsSilentULine() const { return silentuline; } }; ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/include/snomasks.h�������������������������������������������������������������������0000664�0000000�0000000�00000011623�13554550454�0017000�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * InspIRCd -- Internet Relay Chat Daemon * * Copyright (C) 2010 Daniel De Graaf <danieldg@inspircd.org> * Copyright (C) 2008 Robin Burchell <robin+git@viroteck.net> * Copyright (C) 2007 Dennis Friis <peavey@inspircd.org> * Copyright (C) 2006 Craig Edwards <craigedwards@brainbox.cc> * * This file is part of InspIRCd. InspIRCd is free software: you can * redistribute it and/or modify it under the terms of the GNU General Public * License as published by the Free Software Foundation, version 2. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once class SnomaskManager; class Snomask { /** Description of this snomask, e.g.: OPER, ANNOUNCEMENT, XLINE */ std::string Description; /** Information about the last sent message, * used for sending "last message repeated X times" messages */ std::string LastMessage; char LastLetter; unsigned int Count; /** Log and send a message to all opers who have the given snomask set * @param letter The target users of this message * @param desc The description of this snomask, will be prepended to the message * @param msg The message to send */ static void Send(char letter, const std::string& desc, const std::string& msg); public: /** Create a new Snomask */ Snomask(); /** Sends a message to all opers with this snomask. * @param message The message to send * @param letter The snomask character to send the message to. */ void SendMessage(const std::string& message, char letter); /** Sends out the (last message repeated N times) message */ void Flush(); /** Returns the description of this snomask * @param letter The letter of this snomask. If uppercase, the description of the remote * variant of this snomask will be returned (i.e.: "REMOTE" will be prepended to the description). * @return The description of this snomask */ std::string GetDescription(char letter) const; friend class SnomaskManager; }; /** Snomask manager handles routing of SNOMASK (usermode +s) messages to opers. * Modules and the core can enable and disable snomask characters. If they do, * then sending snomasks using these characters becomes possible. */ class CoreExport SnomaskManager : public fakederef<SnomaskManager> { Snomask masks[26]; public: /** Create a new SnomaskManager */ SnomaskManager(); /** Enable a snomask. * @param letter The snomask letter to enable. Once enabled, * server notices may be routed to users with this letter in * their list, and users may add this letter to their list. * @param description The descriptive text sent along with any * server notices, at the start of the notice, e.g. "GLOBOPS". */ void EnableSnomask(char letter, const std::string &description); /** Write to all users with a given snomask (local server only) * @param letter The snomask letter to write to * @param text The text to send to the users */ void WriteToSnoMask(char letter, const std::string &text); /** Write to all users with a given snomask (local server only) * @param letter The snomask letter to write to * @param text A format string containing text to send * @param ... Format arguments */ void WriteToSnoMask(char letter, const char* text, ...) CUSTOM_PRINTF(3, 4); /** Write to all users with a given snomask (sent globally) * @param letter The snomask letter to write to * @param text The text to send to the users */ void WriteGlobalSno(char letter, const std::string &text); /** Write to all users with a given snomask (sent globally) * @param letter The snomask letter to write to * @param text A format string containing text to send * @param ... Format arguments */ void WriteGlobalSno(char letter, const char* text, ...) CUSTOM_PRINTF(3, 4); /** Called once per 5 seconds from the mainloop, this flushes any cached * snotices. The way the caching works is as follows: * Calls to WriteToSnoMask write to a cache, if the call is the same as it was * for the previous call, then a count is incremented. If it is different, * the previous message it just sent normally via NOTICE (with count if > 1) * and the new message is cached. This acts as a sender in case the number of notices * is not particularly significant, in order to keep notices going out. */ void FlushSnotices(); /** Check whether a given character is an enabled (initialized) snomask. * Valid snomask chars are lower- or uppercase letters and have a description. * Snomasks are initialized with EnableSnomask(). * @param ch The character to check * @return True if the given char is allowed to be set via +s. */ bool IsSnomaskUsable(char ch) const; }; �������������������������������������������������������������������������������������������������������������inspircd-3.4.0/include/socket.h���������������������������������������������������������������������0000664�0000000�0000000�00000014040�13554550454�0016426�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * InspIRCd -- Internet Relay Chat Daemon * * Copyright (C) 2009 Daniel De Graaf <danieldg@inspircd.org> * Copyright (C) 2005-2007 Craig Edwards <craigedwards@brainbox.cc> * Copyright (C) 2007 Dennis Friis <peavey@inspircd.org> * Copyright (C) 2007 Robin Burchell <robin+git@viroteck.net> * Copyright (C) 2006 Oliver Lupton <oliverlupton@gmail.com> * Copyright (C) 2006 William Pitcock <nenolod@dereferenced.org> * * This file is part of InspIRCd. InspIRCd is free software: you can * redistribute it and/or modify it under the terms of the GNU General Public * License as published by the Free Software Foundation, version 2. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #ifndef _WIN32 #include <arpa/inet.h> #include <sys/time.h> #include <sys/resource.h> #include <sys/types.h> #include <sys/socket.h> #include <sys/stat.h> #include <sys/un.h> #include <netinet/in.h> #include <unistd.h> #include <fcntl.h> #include <netdb.h> #else #include "inspircd_win32wrapper.h" #endif #include <cerrno> /* Contains irc-specific definitions */ namespace irc { /** This namespace contains various protocol-independent helper classes. * It also contains some types which are often used by the core and modules * in place of inet_* functions and types. */ namespace sockets { union CoreExport sockaddrs { struct sockaddr sa; struct sockaddr_in in4; struct sockaddr_in6 in6; struct sockaddr_un un; /** Return the family of the socket (e.g. AF_INET). */ int family() const; /** Return the size of the structure for syscall passing */ socklen_t sa_size() const; /** Return port number or -1 if invalid */ int port() const; /** Return IP only */ std::string addr() const; /** Return human-readable IP/port pair */ std::string str() const; bool operator==(const sockaddrs& other) const; inline bool operator!=(const sockaddrs& other) const { return !(*this == other); } }; struct CoreExport cidr_mask { /** Type, AF_INET or AF_INET6 */ unsigned char type; /** Length of the mask in bits (0-128) */ unsigned char length; /** Raw bits. Unused bits must be zero */ unsigned char bits[16]; cidr_mask() {} /** Construct a CIDR mask from the string. Will normalize (127.0.0.1/8 => 127.0.0.0/8). */ cidr_mask(const std::string& mask); /** Construct a CIDR mask of a given length from the given address */ cidr_mask(const irc::sockets::sockaddrs& addr, unsigned char len); /** Equality of bits, type, and length */ bool operator==(const cidr_mask& other) const; /** Ordering defined for maps */ bool operator<(const cidr_mask& other) const; /** Match within this CIDR? */ bool match(const irc::sockets::sockaddrs& addr) const; /** Human-readable string */ std::string str() const; }; /** Match CIDR, including an optional username/nickname part. * * This function will compare a human-readable address (plus * optional username and nickname) against a human-readable * CIDR mask, for example joe!bloggs\@1.2.3.4 against * *!bloggs\@1.2.0.0/16. This method supports both IPV4 and * IPV6 addresses. * @param address The human readable address, e.g. fred\@1.2.3.4 * @param cidr_mask The human readable mask, e.g. *\@1.2.0.0/16 * @param match_with_username Does the mask include a nickname segment? * @return True if the mask matches the address */ CoreExport bool MatchCIDR(const std::string &address, const std::string &cidr_mask, bool match_with_username); /** Convert an address-port pair into a binary sockaddr * @param addr The IP address, IPv4 or IPv6 * @param port The port, 0 for unspecified * @param sa The structure to place the result in. Will be zeroed prior to conversion * @return true if the conversion was successful, false if not. */ CoreExport bool aptosa(const std::string& addr, int port, irc::sockets::sockaddrs& sa); /** Convert a UNIX socket path to a binary sockaddr. * @param path The path to the UNIX socket. * @param sa The structure to place the result in. Will be zeroed prior to conversion. * @return True if the conversion was successful; otherwise, false. */ CoreExport bool untosa(const std::string& path, irc::sockets::sockaddrs& sa); /** Determines whether the specified file is a UNIX socket. * @param file The path to the file to check. * @return True if the file is a UNIX socket; otherwise, false. */ CoreExport bool isunix(const std::string& file); } } /** A list of failed port bindings, used for informational purposes on startup */ typedef std::vector<std::pair<irc::sockets::sockaddrs, int> > FailedPortList; #include "socketengine.h" /** This class handles incoming connections on client ports. * It will create a new User for every valid connection * and assign it a file descriptor. */ class CoreExport ListenSocket : public EventHandler { public: reference<ConfigTag> bind_tag; const irc::sockets::sockaddrs bind_sa; class IOHookProvRef : public dynamic_reference_nocheck<IOHookProvider> { public: IOHookProvRef() : dynamic_reference_nocheck<IOHookProvider>(NULL, std::string()) { } }; typedef TR1NS::array<IOHookProvRef, 2> IOHookProvList; /** IOHook providers for handling connections on this socket, * may be empty. */ IOHookProvList iohookprovs; /** Create a new listening socket */ ListenSocket(ConfigTag* tag, const irc::sockets::sockaddrs& bind_to); /** Close the socket */ ~ListenSocket(); /** Handles new connections, called by the socket engine */ void OnEventHandlerRead() CXX11_OVERRIDE; /** Inspects the bind block belonging to this socket to set the name of the IO hook * provider which this socket will use for incoming connections. */ void ResetIOHookProvider(); }; ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/include/socketengine.h���������������������������������������������������������������0000664�0000000�0000000�00000051746�13554550454�0017632�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * InspIRCd -- Internet Relay Chat Daemon * * Copyright (C) 2009 Daniel De Graaf <danieldg@inspircd.org> * Copyright (C) 2007-2008 Robin Burchell <robin+git@viroteck.net> * Copyright (C) 2005-2007 Craig Edwards <craigedwards@brainbox.cc> * Copyright (C) 2007 Dennis Friis <peavey@inspircd.org> * * This file is part of InspIRCd. InspIRCd is free software: you can * redistribute it and/or modify it under the terms of the GNU General Public * License as published by the Free Software Foundation, version 2. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vector> #include <string> #include <map> #include "config.h" #include "socket.h" #include "base.h" #ifndef _WIN32 #include <sys/uio.h> #endif #ifndef IOV_MAX #define IOV_MAX 1024 #endif /** * Event mask for SocketEngine events */ enum EventMask { /** Do not test this socket for readability */ FD_WANT_NO_READ = 0x1, /** Give a read event at all times when reads will not block. */ FD_WANT_POLL_READ = 0x2, /** Give a read event when there is new data to read. * * An event MUST be sent if there is new data to be read, and the most * recent read/recv() on this FD returned EAGAIN. An event MAY be sent * at any time there is data to be read on the socket. */ FD_WANT_FAST_READ = 0x4, /** Give an optional read event when reads begin to unblock * * This state is useful if you want to leave data in the OS receive * queue but not get continuous event notifications about it, because * it may not require a system call to transition from FD_WANT_FAST_READ */ FD_WANT_EDGE_READ = 0x8, /** Mask for all read events */ FD_WANT_READ_MASK = 0x0F, /** Do not test this socket for writeability */ FD_WANT_NO_WRITE = 0x10, /** Give a write event at all times when writes will not block. * * You probably shouldn't use this state; if it's likely that the write * will not block, try it first, then use FD_WANT_FAST_WRITE if it * fails. If it's likely to block (or you are using polling-style reads) * then use FD_WANT_SINGLE_WRITE. */ FD_WANT_POLL_WRITE = 0x20, /** Give a write event when writes don't block any more * * An event MUST be sent if writes will not block, and the most recent * write/send() on this FD returned EAGAIN, or connect() returned * EINPROGRESS. An event MAY be sent at any time that writes will not * block. * * Before calling OnEventHandler*(), a socket engine MAY change the state of * the FD back to FD_WANT_EDGE_WRITE if it is simpler (for example, if a * one-shot notification was registered). If further writes are needed, * it is the responsibility of the event handler to change the state to * one that will generate the required notifications */ FD_WANT_FAST_WRITE = 0x40, /** Give an optional write event on edge-triggered write unblock. * * This state is useful to avoid system calls when moving to/from * FD_WANT_FAST_WRITE when writing data to a mostly-unblocked socket. */ FD_WANT_EDGE_WRITE = 0x80, /** Request a one-shot poll-style write notification. The socket will * return to the FD_WANT_NO_WRITE state before OnEventHandler*() is called. */ FD_WANT_SINGLE_WRITE = 0x100, /** Mask for all write events */ FD_WANT_WRITE_MASK = 0x1F0, /** Add a trial read. During the next DispatchEvents invocation, this * will call OnEventHandlerRead() unless reads are known to be * blocking. */ FD_ADD_TRIAL_READ = 0x1000, /** Assert that reads are known to block. This cancels FD_ADD_TRIAL_READ. * Reset by SE before running OnEventHandlerRead(). */ FD_READ_WILL_BLOCK = 0x2000, /** Add a trial write. During the next DispatchEvents invocation, this * will call OnEventHandlerWrite() unless writes are known to be * blocking. * * This could be used to group several writes together into a single * send() syscall, or to ensure that writes are blocking when attempting * to use FD_WANT_FAST_WRITE. */ FD_ADD_TRIAL_WRITE = 0x4000, /** Assert that writes are known to block. This cancels FD_ADD_TRIAL_WRITE. * Reset by SE before running OnEventHandlerWrite(). */ FD_WRITE_WILL_BLOCK = 0x8000, /** Mask for trial read/trial write */ FD_TRIAL_NOTE_MASK = 0x5000 }; /** This class is a basic I/O handler class. * Any object which wishes to receive basic I/O events * from the socketengine must derive from this class and * implement the OnEventHandler*() methods. The derived class * must then be added to SocketEngine using the method * SocketEngine::AddFd(), after which point the derived * class will receive events to its OnEventHandler*() methods. * The event mask passed to SocketEngine::AddFd() determines * what events the EventHandler gets notified about and with * what semantics. SocketEngine::ChangeEventMask() can be * called to update the event mask later. The only * requirement beyond this for an event handler is that it * must have a file descriptor. What this file descriptor * is actually attached to is completely up to you. */ class CoreExport EventHandler : public classbase { private: /** Private state maintained by socket engine */ int event_mask; void SetEventMask(int mask) { event_mask = mask; } protected: /** File descriptor. * All events which can be handled must have a file descriptor. This * allows you to add events for sockets, fifo's, pipes, and various * other forms of IPC. Do not change this while the object is * registered with the SocketEngine */ int fd; /** Swaps the internals of this EventHandler with another one. * @param other A EventHandler to swap internals with. */ void SwapInternals(EventHandler& other); public: /** Get the current file descriptor * @return The file descriptor of this handler */ inline int GetFd() const { return fd; } inline int GetEventMask() const { return event_mask; } /** Set a new file desciptor * @param FD The new file descriptor. Do not call this method without * first deleting the object from the SocketEngine if you have * added it to a SocketEngine instance. */ void SetFd(int FD); /** Constructor */ EventHandler(); /** Destructor */ virtual ~EventHandler() {} /** Called by the socket engine in case of a read event */ virtual void OnEventHandlerRead() = 0; /** Called by the socket engine in case of a write event. * The default implementation does nothing. */ virtual void OnEventHandlerWrite(); /** Called by the socket engine in case of an error event. * The default implementation does nothing. * @param errornum Error code */ virtual void OnEventHandlerError(int errornum); friend class SocketEngine; }; /** Provides basic file-descriptor-based I/O support. * The actual socketengine class presents the * same interface on all operating systems, but * its private members and internal behaviour * should be treated as blackboxed, and vary * from system to system and upon the config * settings chosen by the server admin. */ class CoreExport SocketEngine { public: /** Socket engine statistics: count of various events, bandwidth usage */ class Statistics { mutable size_t indata; mutable size_t outdata; mutable time_t lastempty; /** Reset the byte counters and lastempty if there wasn't a reset in this second. */ void CheckFlush() const; public: /** Constructor, initializes member vars except indata and outdata because those are set to 0 * in CheckFlush() the first time Update() or GetBandwidth() is called. */ Statistics() : lastempty(0), TotalEvents(0), ReadEvents(0), WriteEvents(0), ErrorEvents(0) { } /** Update counters for network data received. * This should be called after every read-type syscall. * @param len_in Number of bytes received, or -1 for error, as typically * returned by a read-style syscall. */ void UpdateReadCounters(int len_in); /** Update counters for network data sent. * This should be called after every write-type syscall. * @param len_out Number of bytes sent, or -1 for error, as typically * returned by a read-style syscall. */ void UpdateWriteCounters(int len_out); /** Get data transfer statistics. * @param kbitpersec_in Filled with incoming traffic in this second in kbit/s. * @param kbitpersec_out Filled with outgoing traffic in this second in kbit/s. * @param kbitpersec_total Filled with total traffic in this second in kbit/s. */ void CoreExport GetBandwidth(float& kbitpersec_in, float& kbitpersec_out, float& kbitpersec_total) const; unsigned long TotalEvents; unsigned long ReadEvents; unsigned long WriteEvents; unsigned long ErrorEvents; }; private: /** Reference table, contains all current handlers **/ static std::vector<EventHandler*> ref; /** Current number of descriptors in the engine. */ static size_t CurrentSetSize; /** The maximum number of descriptors in the engine. */ static size_t MaxSetSize; /** List of handlers that want a trial read/write */ static std::set<int> trials; /** Socket engine statistics: count of various events, bandwidth usage */ static Statistics stats; /** Look up the fd limit using rlimit. */ static void LookupMaxFds(); /** Terminates the program when the socket engine fails to initialize. */ static void InitError(); static void OnSetEvent(EventHandler* eh, int old_mask, int new_mask); /** Add an event handler to the base socket engine. AddFd(EventHandler*, int) should call this. */ static bool AddFdRef(EventHandler* eh); static void DelFdRef(EventHandler* eh); template <typename T> static void ResizeDouble(std::vector<T>& vect) { if (SocketEngine::CurrentSetSize > vect.size()) vect.resize(SocketEngine::CurrentSetSize * 2); } public: #ifndef _WIN32 typedef iovec IOVector; #else typedef WindowsIOVec IOVector; #endif /** Constructor. * The constructor transparently initializes * the socket engine which the ircd is using. * Please note that if there is a catastrophic * failure (for example, you try and enable * epoll on a 2.4 linux kernel) then this * function may bail back to the shell. * @return void, but it is acceptable for this function to bail back to * the shell or operating system on fatal error. */ static void Init(); /** Destructor. * The destructor transparently tidies up * any resources used by the socket engine. */ static void Deinit(); /** Add an EventHandler object to the engine. Use AddFd to add a file * descriptor to the engine and have the socket engine monitor it. You * must provide an object derived from EventHandler which implements * the required OnEventHandler*() methods. * @param eh An event handling object to add * @param event_mask The initial event mask for the object */ static bool AddFd(EventHandler* eh, int event_mask); /** If you call this function and pass it an * event handler, that event handler will * receive the next available write event, * even if the socket is a readable socket only. * Developers should avoid constantly keeping * an eventhandler in the writeable state, * as this will consume large amounts of * CPU time. * @param eh The event handler to change * @param event_mask The changes to make to the wait state */ static void ChangeEventMask(EventHandler* eh, int event_mask); /** Returns the number of file descriptors reported by the system this program may use * when it was started. * @return If non-zero the number of file descriptors that the system reported that we * may use. */ static size_t GetMaxFds() { return MaxSetSize; } /** Returns the number of file descriptors being queried * @return The set size */ static size_t GetUsedFds() { return CurrentSetSize; } /** Delete an event handler from the engine. * This function call deletes an EventHandler * from the engine, returning true if it succeeded * and false if it failed. This does not free the * EventHandler pointer using delete, if this is * required you must do this yourself. * @param eh The event handler object to remove */ static void DelFd(EventHandler* eh); /** Returns true if a file descriptor exists in * the socket engine's list. * @param fd The event handler to look for * @return True if this fd has an event handler */ static bool HasFd(int fd); /** Returns the EventHandler attached to a specific fd. * If the fd isnt in the socketengine, returns NULL. * @param fd The event handler to look for * @return A pointer to the event handler, or NULL */ static EventHandler* GetRef(int fd); /** Waits for events and dispatches them to handlers. Please note that * this doesn't wait long, only a couple of milliseconds. It returns the * number of events which occurred during this call. This method will * dispatch events to their handlers by calling their * EventHandler::OnEventHandler*() methods. * @return The number of events which have occured. */ static int DispatchEvents(); /** Dispatch trial reads and writes. This causes the actual socket I/O * to happen when writes have been pre-buffered. */ static void DispatchTrialWrites(); /** Returns true if the file descriptors in the given event handler are * within sensible ranges which can be handled by the socket engine. */ static bool BoundsCheckFd(EventHandler* eh); /** Abstraction for BSD sockets accept(2). * This function should emulate its namesake system call exactly. * @param fd This version of the call takes an EventHandler instead of a bare file descriptor. * @param addr The client IP address and port * @param addrlen The size of the sockaddr parameter. * @return This method should return exactly the same values as the system call it emulates. */ static int Accept(EventHandler* fd, sockaddr *addr, socklen_t *addrlen); /** Close the underlying fd of an event handler, remove it from the socket engine and set the fd to -1. * @param eh The EventHandler to close. * @return 0 on success, a negative value on error */ static int Close(EventHandler* eh); /** Abstraction for BSD sockets close(2). * This function should emulate its namesake system call exactly. * This function should emulate its namesake system call exactly. * @return This method should return exactly the same values as the system call it emulates. */ static int Close(int fd); /** Abstraction for BSD sockets send(2). * This function should emulate its namesake system call exactly. * @param fd This version of the call takes an EventHandler instead of a bare file descriptor. * @param buf The buffer in which the data that is sent is stored. * @param len The size of the buffer. * @param flags A flag value that controls the sending of the data. * @return This method should return exactly the same values as the system call it emulates. */ static int Send(EventHandler* fd, const void *buf, size_t len, int flags); /** Abstraction for vector write function writev(). * This function should emulate its namesake system call exactly. * @param fd EventHandler to send data with * @param iov Array of IOVectors containing the buffers to send and their lengths in the platform's * native format. * @param count Number of elements in iov. * @return This method should return exactly the same values as the system call it emulates. */ static int WriteV(EventHandler* fd, const IOVector* iov, int count); #ifdef _WIN32 /** Abstraction for vector write function writev() that accepts a POSIX format iovec. * This function should emulate its namesake system call exactly. * @param fd EventHandler to send data with * @param iov Array of iovecs containing the buffers to send and their lengths in POSIX format. * @param count Number of elements in iov. * @return This method should return exactly the same values as the system call it emulates. */ static int WriteV(EventHandler* fd, const iovec* iov, int count); #endif /** Abstraction for BSD sockets recv(2). * This function should emulate its namesake system call exactly. * @param fd This version of the call takes an EventHandler instead of a bare file descriptor. * @param buf The buffer in which the data that is read is stored. * @param len The size of the buffer. * @param flags A flag value that controls the reception of the data. * @return This method should return exactly the same values as the system call it emulates. */ static int Recv(EventHandler* fd, void *buf, size_t len, int flags); /** Abstraction for BSD sockets recvfrom(2). * This function should emulate its namesake system call exactly. * @param fd This version of the call takes an EventHandler instead of a bare file descriptor. * @param buf The buffer in which the data that is read is stored. * @param len The size of the buffer. * @param flags A flag value that controls the reception of the data. * @param from The remote IP address and port. * @param fromlen The size of the from parameter. * @return This method should return exactly the same values as the system call it emulates. */ static int RecvFrom(EventHandler* fd, void *buf, size_t len, int flags, sockaddr *from, socklen_t *fromlen); /** Abstraction for BSD sockets sendto(2). * This function should emulate its namesake system call exactly. * @param fd This version of the call takes an EventHandler instead of a bare file descriptor. * @param buf The buffer in which the data that is sent is stored. * @param len The size of the buffer. * @param flags A flag value that controls the sending of the data. * @param address The remote IP address and port. * @return This method should return exactly the same values as the system call it emulates. */ static int SendTo(EventHandler* fd, const void* buf, size_t len, int flags, const irc::sockets::sockaddrs& address); /** Abstraction for BSD sockets connect(2). * This function should emulate its namesake system call exactly. * @param fd This version of the call takes an EventHandler instead of a bare file descriptor. * @param address The server IP address and port. * @return This method should return exactly the same values as the system call it emulates. */ static int Connect(EventHandler* fd, const irc::sockets::sockaddrs& address); /** Make a file descriptor blocking. * @param fd a file descriptor to set to blocking mode * @return 0 on success, -1 on failure, errno is set appropriately. */ static int Blocking(int fd); /** Make a file descriptor nonblocking. * @param fd A file descriptor to set to nonblocking mode * @return 0 on success, -1 on failure, errno is set appropriately. */ static int NonBlocking(int fd); /** Abstraction for BSD sockets shutdown(2). * This function should emulate its namesake system call exactly. * @param fd This version of the call takes an EventHandler instead of a bare file descriptor. * @param how What part of the socket to shut down * @return This method should return exactly the same values as the system call it emulates. */ static int Shutdown(EventHandler* fd, int how); /** Abstraction for BSD sockets shutdown(2). * This function should emulate its namesake system call exactly. * @return This method should return exactly the same values as the system call it emulates. */ static int Shutdown(int fd, int how); /** Abstraction for BSD sockets bind(2). * This function should emulate its namesake system call exactly. * @return This method should return exactly the same values as the system call it emulates. */ static int Bind(int fd, const irc::sockets::sockaddrs& addr); /** Abstraction for BSD sockets listen(2). * This function should emulate its namesake system call exactly. * @return This method should return exactly the same values as the system call it emulates. */ static int Listen(int sockfd, int backlog); /** Set SO_REUSEADDR and SO_LINGER on this file descriptor */ static void SetReuse(int sockfd); /** This function is called immediately after fork(). * Some socket engines (notably kqueue) cannot have their * handles inherited by forked processes. This method * allows for the socket engine to re-create its handle * after the daemon forks as the socket engine is created * long BEFORE the daemon forks. * @return void, but it is acceptable for this function to bail back to * the shell or operating system on fatal error. */ static void RecoverFromFork(); /** Get data transfer and event statistics */ static const Statistics& GetStats() { return stats; } /** Should we ignore the error in errno? * Checks EAGAIN and WSAEWOULDBLOCK */ static bool IgnoreError(); /** Return the last socket related error. strrerror(errno) on *nix */ static std::string LastError(); /** Returns the error for the given error num, strerror(errnum) on *nix */ static std::string GetError(int errnum); }; inline bool SocketEngine::IgnoreError() { if ((errno == EAGAIN) || (errno == EWOULDBLOCK)) return true; #ifdef _WIN32 if (WSAGetLastError() == WSAEWOULDBLOCK) return true; #endif return false; } ��������������������������inspircd-3.4.0/include/stdalgo.h��������������������������������������������������������������������0000664�0000000�0000000�00000022553�13554550454�0016603�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * InspIRCd -- Internet Relay Chat Daemon * * Copyright (C) 2014 Attila Molnar <attilamolnar@hush.com> * * This file is part of InspIRCd. InspIRCd is free software: you can * redistribute it and/or modify it under the terms of the GNU General Public * License as published by the Free Software Foundation, version 2. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once namespace stdalgo { namespace vector { /** * Erase a single element from a vector by overwriting it with a copy of the last element, * which is then removed. This, in contrast to vector::erase(), does not result in all * elements after the erased element being moved. * @param vect Vector to remove the element from * @param it Iterator to the element to remove * @return Nothing, but all iterators, references and pointers to the erased element and the * last element are invalidated */ template <typename T> inline void swaperase(typename std::vector<T>& vect, const typename std::vector<T>::iterator& it) { *it = vect.back(); vect.pop_back(); } /** * Find and if exists, erase a single element from a vector by overwriting it with a * copy of the last element, which is then removed. This, in contrast to vector::erase(), * does not result in all elements after the erased element being moved. * If the given value occurs multiple times, the one with the lowest index is removed. * Individual elements are compared to the given value using operator==(). * @param vect Vector to remove the element from * @param val Value of the element to look for and remove * @return True if the element was found and removed, false if it wasn't found. * If true, all iterators, references and pointers pointing to either the first element that * is equal to val or to the last element are invalidated. */ template <typename T> inline bool swaperase(typename std::vector<T>& vect, const T& val) { const typename std::vector<T>::iterator it = std::find(vect.begin(), vect.end(), val); if (it != vect.end()) { swaperase(vect, it); return true; } return false; } } namespace string { /** Get underlying C string of the string passed as parameter. Useful in template functions. * @param str C string * @return Same as input */ inline const char* tocstr(const char* str) { return str; } /** Get underlying C string of the string passed as parameter. Useful in template functions. * @param str std::string object * @return str.c_str() */ inline const char* tocstr(const std::string& str) { return str.c_str(); } /** Check if two strings are equal case insensitively. * @param str1 First string to compare. * @param str2 Second string to compare. * @return True if the strings are equal case-insensitively, false otherwise. */ template <typename S1, typename S2> inline bool equalsci(const S1& str1, const S2& str2) { return (!strcasecmp(tocstr(str1), tocstr(str2))); } /** Joins the contents of a vector to a string. * @param sequence Zero or more items to join. * @param separator The character to place between the items, defaults to ' ' (space). * @return The joined string. */ template<typename Collection> inline std::string join(const Collection& sequence, char separator = ' ') { std::string joined; if (sequence.empty()) return joined; for (typename Collection::const_iterator iter = sequence.begin(); iter != sequence.end(); ++iter) joined.append(ConvToStr(*iter)).push_back(separator); joined.erase(joined.end() - 1); return joined; } /** Replace first occurrence of a substring ('target') in a string ('str') with another string ('replacement'). * @param str String to perform replacement in * @param target String to replace * @param replacement String to put in place of 'target' * @return True if 'target' was replaced with 'replacement', false if it was not found in 'str'. */ template<typename CharT, typename Traits, typename Alloc> inline bool replace(std::basic_string<CharT, Traits, Alloc>& str, const std::basic_string<CharT, Traits, Alloc>& target, const std::basic_string<CharT, Traits, Alloc>& replacement) { const typename std::basic_string<CharT, Traits, Alloc>::size_type p = str.find(target); if (p == std::basic_string<CharT, Traits, Alloc>::npos) return false; str.replace(p, target.size(), replacement); return true; } /** Replace all occurrences of a string ('target') in a string ('str') with another string ('replacement'). * @param str String to perform replacement in * @param target String to replace * @param replacement String to put in place of 'target' */ template<typename CharT, typename Traits, typename Alloc> inline void replace_all(std::basic_string<CharT, Traits, Alloc>& str, const std::basic_string<CharT, Traits, Alloc>& target, const std::basic_string<CharT, Traits, Alloc>& replacement) { if (target.empty()) return; typename std::basic_string<CharT, Traits, Alloc>::size_type p = 0; while ((p = str.find(target, p)) != std::basic_string<CharT, Traits, Alloc>::npos) { str.replace(p, target.size(), replacement); p += replacement.size(); } } } /** * Deleter that uses operator delete to delete the item */ template <typename T> struct defaultdeleter { void operator()(T* o) { delete o; } }; /** * Deleter that adds the item to the cull list, that is, queues it for * deletion at the end of the current mainloop iteration */ struct culldeleter { void operator()(classbase* item); }; /** * Deletes all elements in a container using operator delete * @param cont The container containing the elements to delete */ template <template<typename, typename> class Cont, typename T, typename Alloc> inline void delete_all(const Cont<T*, Alloc>& cont) { std::for_each(cont.begin(), cont.end(), defaultdeleter<T>()); } /** * Remove an element from a container * @param cont Container to remove the element from * @param val Value of the element to look for and remove * @return True if the element was found and removed, false otherwise */ template <template<typename, typename> class Cont, typename T, typename Alloc> inline bool erase(Cont<T, Alloc>& cont, const T& val) { const typename Cont<T, Alloc>::iterator it = std::find(cont.begin(), cont.end(), val); if (it != cont.end()) { cont.erase(it); return true; } return false; } /** * Check if an element with the given value is in a container. Equivalent to (std::find(cont.begin(), cont.end(), val) != cont.end()). * @param cont Container to find the element in * @param val Value of the element to look for * @return True if the element was found in the container, false otherwise */ template <template<typename, typename> class Cont, typename T, typename Alloc> inline bool isin(const Cont<T, Alloc>& cont, const T& val) { return (std::find(cont.begin(), cont.end(), val) != cont.end()); } namespace string { /** * Escape a string * @param str String to escape * @param out Output, must not be the same string as str */ template <char from, char to, char esc> inline void escape(const std::string& str, std::string& out) { for (std::string::const_iterator i = str.begin(); i != str.end(); ++i) { char c = *i; if (c == esc) out.append(2, esc); else { if (c == from) { out.push_back(esc); c = to; } out.push_back(c); } } } /** * Escape a string using the backslash character as the escape character * @param str String to escape * @param out Output, must not be the same string as str */ template <char from, char to> inline void escape(const std::string& str, std::string& out) { escape<from, to, '\\'>(str, out); } /** * Unescape a string * @param str String to unescape * @param out Output, must not be the same string as str * @return True if the string was unescaped, false if an invalid escape sequence is present in the input in which case out will contain a partially unescaped string */ template<char from, char to, char esc> inline bool unescape(const std::string& str, std::string& out) { for (std::string::const_iterator i = str.begin(); i != str.end(); ++i) { char c = *i; if (c == '\\') { ++i; if (i == str.end()) return false; char nextc = *i; if (nextc == esc) c = esc; else if (nextc != to) return false; // Invalid escape sequence else c = from; } out.push_back(c); } return true; } /** * Unescape a string using the backslash character as the escape character * @param str String to unescape * @param out Output, must not be the same string as str * @return True if the string was unescaped, false if an invalid escape sequence is present in the input in which case out will contain a partially unescaped string */ template <char from, char to> inline bool unescape(const std::string& str, std::string& out) { return unescape<from, to, '\\'>(str, out); } } } �����������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/include/threadengine.h���������������������������������������������������������������0000664�0000000�0000000�00000006774�13554550454�0017612�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * InspIRCd -- Internet Relay Chat Daemon * * Copyright (C) 2009 Daniel De Graaf <danieldg@inspircd.org> * Copyright (C) 2008 Craig Edwards <craigedwards@brainbox.cc> * * This file is part of InspIRCd. InspIRCd is free software: you can * redistribute it and/or modify it under the terms of the GNU General Public * License as published by the Free Software Foundation, version 2. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vector> #include <string> #include <map> #include "config.h" #include "base.h" /** Derive from this class to implement your own threaded sections of * code. Be sure to keep your code thread-safe and not prone to deadlocks * and race conditions if you MUST use threading! */ class CoreExport Thread { private: /** Set to true when the thread is to exit */ bool ExitFlag; /** Opaque thread state managed by the ThreadEngine */ ThreadEngine::ThreadState state; /** ThreadEngine manages Thread::state */ friend class ThreadEngine; protected: /** Get thread's current exit status. * (are we being asked to exit?) */ bool GetExitFlag() { return ExitFlag; } public: /** Set Creator to NULL at this point */ Thread() : ExitFlag(false) { } /** Override this method to put your actual * threaded code here. */ virtual void Run() = 0; /** Signal the thread to exit gracefully. */ virtual void SetExitFlag(); /** Join the thread (calls SetExitFlag and waits for exit) */ void join(); }; class CoreExport QueuedThread : public Thread { ThreadQueueData queue; protected: /** Waits for an enqueue operation to complete * You MUST hold the queue lock when you call this. * It will be unlocked while you wait, and will be relocked * before the function returns */ void WaitForQueue() { queue.Wait(); } public: /** Lock queue. */ void LockQueue() { queue.Lock(); } /** Unlock queue. */ void UnlockQueue() { queue.Unlock(); } /** Unlock queue and wake up worker */ void UnlockQueueWakeup() { queue.Wakeup(); queue.Unlock(); } void SetExitFlag() CXX11_OVERRIDE { queue.Lock(); Thread::SetExitFlag(); queue.Wakeup(); queue.Unlock(); } }; class CoreExport SocketThread : public Thread { ThreadQueueData queue; ThreadSignalData signal; protected: /** Waits for an enqueue operation to complete * You MUST hold the queue lock when you call this. * It will be unlocked while you wait, and will be relocked * before the function returns */ void WaitForQueue() { queue.Wait(); } public: /** Notifies parent by making the SignalFD ready to read * No requirements on locking */ void NotifyParent(); SocketThread(); virtual ~SocketThread(); /** Lock queue. */ void LockQueue() { queue.Lock(); } /** Unlock queue. */ void UnlockQueue() { queue.Unlock(); } /** Unlock queue and send wakeup to worker */ void UnlockQueueWakeup() { queue.Wakeup(); queue.Unlock(); } void SetExitFlag() CXX11_OVERRIDE { queue.Lock(); Thread::SetExitFlag(); queue.Wakeup(); queue.Unlock(); } /** * Called in the context of the parent thread after a notification * has passed through the socket */ virtual void OnNotify() = 0; }; ����inspircd-3.4.0/include/threadengines/���������������������������������������������������������������0000775�0000000�0000000�00000000000�13554550454�0017606�5����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/include/threadengines/threadengine_pthread.h�����������������������������������������0000664�0000000�0000000�00000007275�13554550454�0024136�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * InspIRCd -- Internet Relay Chat Daemon * * Copyright (C) 2009 Daniel De Graaf <danieldg@inspircd.org> * Copyright (C) 2008 Craig Edwards <craigedwards@brainbox.cc> * * This file is part of InspIRCd. InspIRCd is free software: you can * redistribute it and/or modify it under the terms of the GNU General Public * License as published by the Free Software Foundation, version 2. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <pthread.h> #include "typedefs.h" /** The ThreadEngine class has the responsibility of initialising * Thread derived classes. It does this by creating operating system * level threads which are then associated with the class transparently. * This allows Thread classes to be derived without needing to know how * the OS implements threads. You should ensure that any sections of code * that use threads are threadsafe and do not interact with any other * parts of the code which are NOT known threadsafe! If you really MUST * access non-threadsafe code from a Thread, use the Mutex class to wrap * access to the code carefully. */ class CoreExport ThreadEngine { public: /** Per-thread state, present in each Thread object, managed by the ThreadEngine */ struct ThreadState { pthread_t pthread_id; }; /** Create a new thread. This takes an already allocated * Thread* pointer and initializes it to use this threading * engine. On failure, this function may throw a CoreException. * @param thread_to_init Pointer to a newly allocated Thread * derived object. */ void Start(Thread* thread_to_init); /** Stop a thread gracefully. * First, this function asks the thread to terminate by calling Thread::SetExitFlag(). * Next, it waits until the thread terminates (on the operating system level). Finally, * all OS-level resources associated with the thread are released. The Thread instance * passed to the function is NOT freed. * When this function returns, the thread is stopped and you can destroy it or restart it * at a later point. * Stopping a thread that is not running is a bug. * @param thread The thread to stop. */ void Stop(Thread* thread); }; /** The Mutex class represents a mutex, which can be used to keep threads * properly synchronised. Use mutexes sparingly, as they are a good source * of thread deadlocks etc, and should be avoided except where absolutely * neccessary. Note that the internal behaviour of the mutex varies from OS * to OS depending on the thread engine, for example in windows a Mutex * in InspIRCd uses critical sections, as they are faster and simpler to * manage. */ class CoreExport Mutex { protected: pthread_mutex_t putex; public: /** Constructor. */ Mutex() { pthread_mutex_init(&putex, NULL); } /** Enter/enable the mutex lock. */ void Lock() { pthread_mutex_lock(&putex); } /** Leave/disable the mutex lock. */ void Unlock() { pthread_mutex_unlock(&putex); } /** Destructor */ ~Mutex() { pthread_mutex_destroy(&putex); } }; class ThreadQueueData : public Mutex { pthread_cond_t cond; public: ThreadQueueData() { pthread_cond_init(&cond, NULL); } ~ThreadQueueData() { pthread_cond_destroy(&cond); } void Wakeup() { pthread_cond_signal(&cond); } void Wait() { pthread_cond_wait(&cond, &putex); } }; class ThreadSignalSocket; class ThreadSignalData { public: ThreadSignalSocket* sock; }; �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/include/threadengines/threadengine_win32.h�������������������������������������������0000664�0000000�0000000�00000007367�13554550454�0023453�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * InspIRCd -- Internet Relay Chat Daemon * * Copyright (C) 2009 Daniel De Graaf <danieldg@inspircd.org> * Copyright (C) 2008 Craig Edwards <craigedwards@brainbox.cc> * * This file is part of InspIRCd. InspIRCd is free software: you can * redistribute it and/or modify it under the terms of the GNU General Public * License as published by the Free Software Foundation, version 2. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include "config.h" #include "base.h" class Thread; /** The ThreadEngine class has the responsibility of initialising * Thread derived classes. It does this by creating operating system * level threads which are then associated with the class transparently. * This allows Thread classes to be derived without needing to know how * the OS implements threads. You should ensure that any sections of code * that use threads are threadsafe and do not interact with any other * parts of the code which are NOT known threadsafe! If you really MUST * access non-threadsafe code from a Thread, use the Mutex class to wrap * access to the code carefully. */ class CoreExport ThreadEngine { public: /** Per-thread state, present in each Thread object, managed by the ThreadEngine */ struct ThreadState { HANDLE handle; }; static DWORD WINAPI Entry(void* parameter); /** Create a new thread. This takes an already allocated * Thread* pointer and initializes it to use this threading * engine. On failure, this function may throw a CoreException. * @param thread_to_init Pointer to a newly allocated Thread * derived object. */ void Start(Thread* thread_to_init); /** Stop a thread gracefully. * First, this function asks the thread to terminate by calling Thread::SetExitFlag(). * Next, it waits until the thread terminates (on the operating system level). Finally, * all OS-level resources associated with the thread are released. The Thread instance * passed to the function is NOT freed. * When this function returns, the thread is stopped and you can destroy it or restart it * at a later point. * Stopping a thread that is not running is a bug. * @param thread The thread to stop. */ void Stop(Thread* thread); }; /** The Mutex class represents a mutex, which can be used to keep threads * properly synchronised. Use mutexes sparingly, as they are a good source * of thread deadlocks etc, and should be avoided except where absolutely * neccessary. Note that the internal behaviour of the mutex varies from OS * to OS depending on the thread engine, for example in windows a Mutex * in InspIRCd uses critical sections, as they are faster and simpler to * manage. */ class CoreExport Mutex { private: CRITICAL_SECTION wutex; public: Mutex() { InitializeCriticalSection(&wutex); } void Lock() { EnterCriticalSection(&wutex); } void Unlock() { LeaveCriticalSection(&wutex); } ~Mutex() { DeleteCriticalSection(&wutex); } }; class ThreadQueueData : public Mutex { HANDLE event; public: ThreadQueueData() { event = CreateEvent(NULL, false, false, NULL); if (event == NULL) throw CoreException("CreateEvent() failed in ThreadQueueData::ThreadQueueData()!"); } ~ThreadQueueData() { CloseHandle(event); } void Wakeup() { PulseEvent(event); } void Wait() { Unlock(); WaitForSingleObject(event, INFINITE); Lock(); } }; class ThreadSignalData { public: int connFD; ThreadSignalData() { connFD = -1; } }; �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/include/timer.h����������������������������������������������������������������������0000664�0000000�0000000�00000007316�13554550454�0016266�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * InspIRCd -- Internet Relay Chat Daemon * * Copyright (C) 2007-2008 Robin Burchell <robin+git@viroteck.net> * Copyright (C) 2007 Dennis Friis <peavey@inspircd.org> * Copyright (C) 2006-2007 Craig Edwards <craigedwards@brainbox.cc> * * This file is part of InspIRCd. InspIRCd is free software: you can * redistribute it and/or modify it under the terms of the GNU General Public * License as published by the Free Software Foundation, version 2. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once class Module; /** Timer class for one-second resolution timers * Timer provides a facility which allows module * developers to create one-shot timers. The timer * can be made to trigger at any time up to a one-second * resolution. To use Timer, inherit a class from * Timer, then insert your inherited class into the * queue using Server::AddTimer(). The Tick() method of * your object (which you have to override) will be called * at the given time. */ class CoreExport Timer { /** The triggering time */ time_t trigger; /** Number of seconds between triggers */ unsigned int secs; /** True if this is a repeating timer */ bool repeat; public: /** Default constructor, initializes the triggering time * @param secs_from_now The number of seconds from now to trigger the timer * @param repeating Repeat this timer every secs_from_now seconds if set to true */ Timer(unsigned int secs_from_now, bool repeating = false); /** Default destructor, removes the timer from the timer manager */ virtual ~Timer(); /** Retrieve the current triggering time */ time_t GetTrigger() const { return trigger; } /** Sets the trigger timeout to a new value * This does not update the bookkeeping in TimerManager, use SetInterval() * to change the interval between ticks while keeping TimerManager updated */ void SetTrigger(time_t nexttrigger) { trigger = nexttrigger; } /** Sets the interval between two ticks. */ void SetInterval(unsigned int interval); /** Called when the timer ticks. * You should override this method with some useful code to * handle the tick event. * @param TIME The current time. * @return True if the Timer object is still valid, false if it was destructed. */ virtual bool Tick(time_t TIME) = 0; /** Returns true if this timer is set to repeat */ bool GetRepeat() const { return repeat; } /** Returns the interval (number of seconds between ticks) * of this timer object. */ unsigned int GetInterval() const { return secs; } /** Cancels the repeat state of a repeating timer. * If you call this method, then the next time your * timer ticks, it will be removed immediately after. */ void CancelRepeat() { repeat = false; } }; /** This class manages sets of Timers, and triggers them at their defined times. * This will ensure timers are not missed, as well as removing timers that have * expired and allowing the addition of new ones. */ class CoreExport TimerManager { typedef std::multimap<time_t, Timer*> TimerMap; /** A list of all pending timers */ TimerMap Timers; public: /** Tick all pending Timers * @param TIME the current system time */ void TickTimers(time_t TIME); /** Add an Timer * @param T an Timer derived class to add */ void AddTimer(Timer *T); /** Remove a Timer * @param T an Timer derived class to remove */ void DelTimer(Timer* T); }; ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/include/token_list.h�����������������������������������������������������������������0000664�0000000�0000000�00000004050�13554550454�0017311�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * InspIRCd -- Internet Relay Chat Daemon * * Copyright (C) 2017 Peter Powell <petpow@saberuk.com> * * This file is part of InspIRCd. InspIRCd is free software: you can * redistribute it and/or modify it under the terms of the GNU General Public * License as published by the Free Software Foundation, version 2. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include "compat.h" class CoreExport TokenList { private: /** Whether this list includes all tokens by default. */ bool permissive; /** Either the tokens to exclude if in permissive mode or the tokens to include if in strict mode. */ insp::flat_set<std::string, irc::insensitive_swo> tokens; public: /** Adds a space-delimited list of tokens to the token list. * @param tokenlist The list of space-delimited tokens to add. */ void AddList(const std::string& tokenlist); /** Adds a single token to the token list. * @param token The token to add. */ void Add(const std::string& token); /** Removes all tokens from the token list. */ void Clear(); /** Determines whether the specified token exists in the token list. * @param token The token to search for. */ bool Contains(const std::string& token) const; /** Removes the specified token from the token list. * @param token The token to remove. */ void Remove(const std::string& token); /** Retrieves a string which represents the contents of this token list. */ std::string ToString() const; /** Determines whether the specified token list contains the same tokens as this instance. * @param other The tokenlist to compare against. * @return True if the token lists are equal; otherwise, false. */ bool operator==(const TokenList& other) const; }; ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/include/typedefs.h�������������������������������������������������������������������0000664�0000000�0000000�00000007466�13554550454�0016777�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * InspIRCd -- Internet Relay Chat Daemon * * Copyright (C) 2009 Daniel De Graaf <danieldg@inspircd.org> * Copyright (C) 2005, 2008 Craig Edwards <craigedwards@brainbox.cc> * Copyright (C) 2007 Dennis Friis <peavey@inspircd.org> * * This file is part of InspIRCd. InspIRCd is free software: you can * redistribute it and/or modify it under the terms of the GNU General Public * License as published by the Free Software Foundation, version 2. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once class BanCacheManager; class BufferedSocket; class Channel; class Command; class ConfigStatus; class ConfigTag; class Extensible; class FakeUser; class InspIRCd; class Invitation; class IOHookProvider; class LocalUser; class Membership; class Module; class OperInfo; class ProtocolServer; class RemoteUser; class Server; class ServerConfig; class ServerLimits; class Thread; class User; class XLine; class XLineManager; class XLineFactory; struct ConnectClass; struct ModResult; namespace ClientProtocol { class Event; class EventProvider; class Message; class MessageTagProvider; class Serializer; typedef std::vector<Message*> MessageList; typedef std::vector<std::string> ParamList; typedef std::string SerializedMessage; struct MessageTagData { MessageTagProvider* tagprov; std::string value; void* provdata; MessageTagData(MessageTagProvider* prov, const std::string& val, void* data = NULL); }; /** Map of message tag values and providers keyed by their name. * Sorted in descending order to ensure tag names beginning with symbols (such as '+') come later when iterating * the container than tags with a normal name. */ typedef insp::flat_map<std::string, MessageTagData, std::greater<std::string> > TagMap; } #include "hashcomp.h" #include "base.h" typedef TR1NS::unordered_map<std::string, User*, irc::insensitive, irc::StrHashComp> user_hash; typedef TR1NS::unordered_map<std::string, Channel*, irc::insensitive, irc::StrHashComp> chan_hash; /** List of channels to consider when building the neighbor list of a user */ typedef std::vector<Membership*> IncludeChanList; /** A cached text file stored with its contents as lines */ typedef std::vector<std::string> file_cache; /** A mapping of configuration keys to their assigned values. */ typedef insp::flat_map<std::string, std::string, irc::insensitive_swo> ConfigItems; /** The entire configuration */ typedef std::multimap<std::string, reference<ConfigTag>, irc::insensitive_swo> ConfigDataHash; /** Iterator of ConfigDataHash */ typedef ConfigDataHash::const_iterator ConfigIter; /** Iterator pair, used for tag-name ranges */ typedef std::pair<ConfigIter,ConfigIter> ConfigTagList; /** Files read by the configuration */ typedef std::map<std::string, file_cache> ConfigFileCache; /** Generic user list, used for exceptions */ typedef std::set<User*> CUList; /** Contains an ident and host split into two strings */ typedef std::pair<std::string, std::string> IdentHostPair; /** A map of xline factories */ typedef std::map<std::string, XLineFactory*> XLineFactMap; /** A map of XLines indexed by string */ typedef std::map<std::string, XLine*, irc::insensitive_swo> XLineLookup; /** A map of XLineLookup maps indexed by string */ typedef std::map<std::string, XLineLookup > XLineContainer; /** An iterator in an XLineContainer */ typedef XLineContainer::iterator ContainerIter; /** An interator in an XLineLookup */ typedef XLineLookup::iterator LookupIter; namespace Stats { class Context; } ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/include/uid.h������������������������������������������������������������������������0000664�0000000�0000000�00000003474�13554550454�0015730�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * InspIRCd -- Internet Relay Chat Daemon * * Copyright (C) 2007 Robin Burchell <robin+git@viroteck.net> * * This file is part of InspIRCd. InspIRCd is free software: you can * redistribute it and/or modify it under the terms of the GNU General Public * License as published by the Free Software Foundation, version 2. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once class CoreExport UIDGenerator { private: /** Holds the current UID. Used to generate the next one. */ std::string current_uid; /** Increments the current UID by one. */ void IncrementUID(unsigned int pos); public: /** * This is the maximum length of a UUID (unique user identifier). * This length is set in compliance with TS6 protocol, and really should not be changed. Ever. * It allows for a lot of clients as-is. -- w00t. */ static const unsigned int UUID_LENGTH = 9; /** Initializes this UID generator with the given SID * @param sid SID that conforms to InspIRCd::IsSID() */ void init(const std::string& sid); /** Returns the next available UID for this server. */ std::string GetUID(); /** Generates a pseudorandom SID based on a servername and a description * Guaranteed to return the same if invoked with the same parameters * @param servername The server name to use as seed * @param serverdesc The server description to use as seed * @return A valid SID */ static std::string GenerateSID(const std::string& servername, const std::string& serverdesc); }; ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/include/usermanager.h����������������������������������������������������������������0000664�0000000�0000000�00000014551�13554550454�0017456�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * InspIRCd -- Internet Relay Chat Daemon * * Copyright (C) 2008 Robin Burchell <robin+git@viroteck.net> * * This file is part of InspIRCd. InspIRCd is free software: you can * redistribute it and/or modify it under the terms of the GNU General Public * License as published by the Free Software Foundation, version 2. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <list> class CoreExport UserManager : public fakederef<UserManager> { public: struct CloneCounts { unsigned int global; unsigned int local; CloneCounts() : global(0), local(0) { } }; /** Container that maps IP addresses to clone counts */ typedef std::map<irc::sockets::cidr_mask, CloneCounts> CloneMap; /** Sequence container in which each element is a User* */ typedef std::vector<User*> OperList; /** A list holding local users */ typedef insp::intrusive_list<LocalUser> LocalList; private: /** Map of IP addresses for clone counting */ CloneMap clonemap; /** A CloneCounts that contains zero for both local and global */ const CloneCounts zeroclonecounts; /** Local client list, a list containing only local clients */ LocalList local_users; /** Last used already sent id, used when sending messages to neighbors to help determine whether the message has * been sent to a particular user or not. See User::ForEachNeighbor() for more info. */ already_sent_t already_sent_id; public: /** Constructor, initializes variables */ UserManager(); /** Destructor, destroys all users in clientlist */ ~UserManager(); /** Nickname string -> User* map. Contains all users, including unregistered ones. */ user_hash clientlist; /** UUID -> User* map. Contains all users, including unregistered ones. */ user_hash uuidlist; /** Oper list, a vector containing all local and remote opered users */ OperList all_opers; /** Number of unregistered users online right now. * (Unregistered means before USER/NICK/dns) */ unsigned int unregistered_count; /** Perform background user events for all local users such as PING checks, registration timeouts, * penalty management and recvq processing for users who have data in their recvq due to throttling. */ void DoBackgroundUserStuff(); /** Handle a client connection. * Creates a new LocalUser object, inserts it into the appropriate containers, * initializes it as not yet registered, and adds it to the socket engine. * * The new user may immediately be quit after being created, for example if the user limit * is reached or if the user is banned. * @param socket File descriptor of the connection * @param via Listener socket that this user connected to * @param client The IP address and client port of the user * @param server The server IP address and port used by the user */ void AddUser(int socket, ListenSocket* via, irc::sockets::sockaddrs* client, irc::sockets::sockaddrs* server); /** Disconnect a user gracefully. * When this method returns the user provided will be quit, but the User object will continue to be valid and will be deleted at the end of the current main loop iteration. * @param user The user to remove * @param quitreason The quit reason to show to normal users * @param operreason The quit reason to show to opers, can be NULL if same as quitreason */ void QuitUser(User* user, const std::string& quitreason, const std::string* operreason = NULL); /** Add a user to the clone map * @param user The user to add */ void AddClone(User* user); /** Remove all clone counts from the user, you should * use this if you change the user's IP address * after they have registered. * @param user The user to remove */ void RemoveCloneCounts(User *user); /** Rebuild clone counts. Required when \<cidr> settings change. */ void RehashCloneCounts(); /** Return the number of local and global clones of this user * @param user The user to get the clone counts for * @return The clone counts of this user. The returned reference is volatile - you * must assume that it becomes invalid as soon as you call any function other than * your own. */ const CloneCounts& GetCloneCounts(User* user) const; /** Return a map containg IP addresses and their clone counts * @return The clone count map */ const CloneMap& GetCloneMap() const { return clonemap; } /** Return a count of all global users, unknown and known connections * @return The number of users on the network, including local unregistered users */ unsigned int UserCount() const { return this->clientlist.size(); } /** Return a count of fully registered connections on the network * @return The number of registered users on the network */ unsigned int RegisteredUserCount() { return this->clientlist.size() - this->UnregisteredUserCount(); } /** Return a count of opered (umode +o) users on the network * @return The number of opers on the network */ unsigned int OperCount() const { return this->all_opers.size(); } /** Return a count of local unregistered (before NICK/USER) users * @return The number of local unregistered (unknown) connections */ unsigned int UnregisteredUserCount() const { return this->unregistered_count; } /** Return a count of local registered users * @return The number of registered local users */ unsigned int LocalUserCount() const { return (this->local_users.size() - this->UnregisteredUserCount()); } /** Get a hash map containing all users, keyed by their nickname * @return A hash map mapping nicknames to User pointers */ user_hash& GetUsers() { return clientlist; } /** Get a list containing all local users * @return A const list of local users */ const LocalList& GetLocalUsers() const { return local_users; } /** Send a server notice to all local users * @param text The text format string to send * @param ... The format arguments */ void ServerNoticeAll(const char* text, ...) CUSTOM_PRINTF(2, 3); /** Retrieves the next already sent id, guaranteed to be not equal to any user's already_sent field * @return Next already_sent id */ already_sent_t NextAlreadySentId(); }; �������������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/include/users.h����������������������������������������������������������������������0000664�0000000�0000000�00000071126�13554550454�0016307�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * InspIRCd -- Internet Relay Chat Daemon * * Copyright (C) 2009 Daniel De Graaf <danieldg@inspircd.org> * Copyright (C) 2007-2008 Robin Burchell <robin+git@viroteck.net> * Copyright (C) 2008 Thomas Stagner <aquanight@inspircd.org> * Copyright (C) 2003-2007 Craig Edwards <craigedwards@brainbox.cc> * Copyright (C) 2007 Burlex <???@???> * Copyright (C) 2007 Dennis Friis <peavey@inspircd.org> * * This file is part of InspIRCd. InspIRCd is free software: you can * redistribute it and/or modify it under the terms of the GNU General Public * License as published by the Free Software Foundation, version 2. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include "socket.h" #include "inspsocket.h" #include "mode.h" #include "membership.h" /** connect class types */ enum ClassTypes { /** connect:allow */ CC_ALLOW = 0, /** connect:deny */ CC_DENY = 1, /** named connect block (for opers, etc) */ CC_NAMED = 2 }; /** Registration state of a user, e.g. * have they sent USER, NICK, PASS yet? */ enum RegistrationState { #ifndef _WIN32 // Burlex: This is already defined in win32, luckily it is still 0. REG_NONE = 0, /* Has sent nothing */ #endif REG_USER = 1, /* Has sent USER */ REG_NICK = 2, /* Has sent NICK */ REG_NICKUSER = 3, /* Bitwise combination of REG_NICK and REG_USER */ REG_ALL = 7 /* REG_NICKUSER plus next bit along */ }; enum UserType { USERTYPE_LOCAL = 1, USERTYPE_REMOTE = 2, USERTYPE_SERVER = 3 }; /** Holds information relevent to &lt;connect allow&gt; and &lt;connect deny&gt; tags in the config file. */ struct CoreExport ConnectClass : public refcountbase { reference<ConfigTag> config; /** Type of line, either CC_ALLOW or CC_DENY */ char type; /** True if this class uses fake lag to manage flood, false if it kills */ bool fakelag; /** Connect class name */ std::string name; /** Max time to register the connection in seconds */ unsigned int registration_timeout; /** Host mask for this line */ std::string host; /** Number of seconds between pings for this line */ unsigned int pingtime; /** Maximum size of sendq for users in this class (bytes) * Users cannot send commands if they go over this limit */ unsigned long softsendqmax; /** Maximum size of sendq for users in this class (bytes) * Users are killed if they go over this limit */ unsigned long hardsendqmax; /** Maximum size of recvq for users in this class (bytes) */ unsigned long recvqmax; /** Seconds worth of penalty before penalty system activates */ unsigned int penaltythreshold; /** Maximum rate of commands (units: millicommands per second) */ unsigned int commandrate; /** Local max when connecting by this connection class */ unsigned long maxlocal; /** Global max when connecting by this connection class */ unsigned long maxglobal; /** True if max connections for this class is hit and a warning is wanted */ bool maxconnwarn; /** Max channels for this class */ unsigned int maxchans; /** How many users may be in this connect class before they are refused? * (0 = no limit = default) */ unsigned long limit; /** If set to true, no user DNS lookups are to be performed */ bool resolvehostnames; /** * If non-empty the server ports which this user has to be using */ insp::flat_set<int> ports; /** Create a new connect class with no settings. */ ConnectClass(ConfigTag* tag, char type, const std::string& mask); /** Create a new connect class with inherited settings. */ ConnectClass(ConfigTag* tag, char type, const std::string& mask, const ConnectClass& parent); /** Update the settings in this block to match the given block */ void Update(const ConnectClass* newSettings); const std::string& GetName() { return name; } const std::string& GetHost() { return host; } /** Returns the registration timeout */ time_t GetRegTimeout() { return (registration_timeout ? registration_timeout : 90); } /** Returns the ping frequency */ unsigned int GetPingTime() { return (pingtime ? pingtime : 120); } /** Returns the maximum sendq value (soft limit) * Note that this is in addition to internal OS buffers */ unsigned long GetSendqSoftMax() { return (softsendqmax ? softsendqmax : 4096); } /** Returns the maximum sendq value (hard limit) */ unsigned long GetSendqHardMax() { return (hardsendqmax ? hardsendqmax : 0x100000); } /** Returns the maximum recvq value */ unsigned long GetRecvqMax() { return (recvqmax ? recvqmax : 4096); } /** Returns the penalty threshold value */ unsigned int GetPenaltyThreshold() { return penaltythreshold ? penaltythreshold : (fakelag ? 10 : 20); } unsigned int GetCommandRate() { return commandrate ? commandrate : 1000; } /** Return the maximum number of local sessions */ unsigned long GetMaxLocal() { return maxlocal; } /** Returns the maximum number of global sessions */ unsigned long GetMaxGlobal() { return maxglobal; } }; /** Holds all information about a user * This class stores all information about a user connected to the irc server. Everything about a * connection is stored here primarily, from the user's socket ID (file descriptor) through to the * user's nickname and hostname. */ class CoreExport User : public Extensible { private: /** Cached nick!ident@dhost value using the displayed hostname */ std::string cached_fullhost; /** Cached ident@ip value using the real IP address */ std::string cached_hostip; /** Cached ident@realhost value using the real hostname */ std::string cached_makehost; /** Cached nick!ident@realhost value using the real hostname */ std::string cached_fullrealhost; /** Set by GetIPString() to avoid constantly re-grabbing IP via sockets voodoo. */ std::string cachedip; /** If set then the hostname which is displayed to users. */ std::string displayhost; /** The real hostname of this user. */ std::string realhost; /** The real name of this user. */ std::string realname; /** The user's mode list. * Much love to the STL for giving us an easy to use bitset, saving us RAM. * if (modes[modeid]) is set, then the mode is set. * For example, to work out if mode +i is set, we check the field * User::modes[invisiblemode->modeid] == true. */ std::bitset<ModeParser::MODEID_MAX> modes; public: /** To execute a function for each local neighbor of a user, inherit from this class and * pass an instance of it to User::ForEachNeighbor(). */ class ForEachNeighborHandler { public: /** Method to execute for each local neighbor of a user. * Derived classes must implement this. * @param user Current neighbor */ virtual void Execute(LocalUser* user) = 0; }; /** List of Memberships for this user */ typedef insp::intrusive_list<Membership> ChanList; /** Time that the object was instantiated (used for TS calculation etc) */ time_t age; /** Time the connection was created, set in the constructor. This * may be different from the time the user's classbase object was * created. */ time_t signon; /** Client address that the user is connected from. * Do not modify this value directly, use SetClientIP() to change it. * Port is not valid for remote users. */ irc::sockets::sockaddrs client_sa; /** The users nickname. * An invalid nickname indicates an unregistered connection prior to the NICK command. * Use InspIRCd::IsNick() to validate nicknames. */ std::string nick; /** The user's unique identifier. * This is the unique identifier which the user has across the network. */ const std::string uuid; /** The users ident reply. * Two characters are added to the user-defined limit to compensate for the tilde etc. */ std::string ident; /** What snomasks are set on this user. * This functions the same as the above modes. */ std::bitset<64> snomasks; /** Channels this user is on */ ChanList chans; /** The server the user is connected to. */ Server* server; /** The user's away message. * If this string is empty, the user is not marked as away. */ std::string awaymsg; /** Time the user last went away. * This is ONLY RELIABLE if user IsAway()! */ time_t awaytime; /** The oper type they logged in as, if they are an oper. */ reference<OperInfo> oper; /** Used by User to indicate the registration status of the connection * It is a bitfield of the REG_NICK, REG_USER and REG_ALL bits to indicate * the connection state. */ unsigned int registered:3; /** If this is set to true, then all socket operations for the user * are dropped into the bit-bucket. * This value is set by QuitUser, and is not needed seperately from that call. * Please note that setting this value alone will NOT cause the user to quit. */ unsigned int quitting:1; /** What type of user is this? */ const UserType usertype:2; /** Get client IP string from sockaddr, using static internal buffer * @return The IP string */ const std::string& GetIPString(); /** Retrieves this user's hostname. * @param uncloak If true then return the real host; otherwise, the display host. */ const std::string& GetHost(bool uncloak) const; /** Retrieves this user's displayed hostname. */ const std::string& GetDisplayedHost() const; /** Retrieves this user's real hostname. */ const std::string& GetRealHost() const; /** Retrieves this user's real name. */ const std::string& GetRealName() const; /** Get CIDR mask, using default range, for this user */ irc::sockets::cidr_mask GetCIDRMask(); /** Sets the client IP for this user * @return true if the conversion was successful */ virtual bool SetClientIP(const std::string& address); virtual void SetClientIP(const irc::sockets::sockaddrs& sa); /** Constructor * @throw CoreException if the UID allocated to the user already exists */ User(const std::string& uid, Server* srv, UserType objtype); /** Returns the full displayed host of the user * This member function returns the hostname of the user as seen by other users * on the server, in nick!ident\@host form. * @return The full masked host of the user */ virtual const std::string& GetFullHost(); /** Returns the full real host of the user * This member function returns the hostname of the user as seen by other users * on the server, in nick!ident\@host form. If any form of hostname cloaking is in operation, * e.g. through a module, then this method will ignore it and return the true hostname. * @return The full real host of the user */ virtual const std::string& GetFullRealHost(); /** This clears any cached results that are used for GetFullRealHost() etc. * The results of these calls are cached as generating them can be generally expensive. */ void InvalidateCache(); /** Returns whether this user is currently away or not. If true, * further information can be found in User::awaymsg and User::awaytime * @return True if the user is away, false otherwise */ bool IsAway() const { return (!awaymsg.empty()); } /** Returns whether this user is an oper or not. If true, * oper information can be obtained from User::oper * @return True if the user is an oper, false otherwise */ bool IsOper() const { return oper; } /** Returns true if a notice mask is set * @param sm A notice mask character to check * @return True if the notice mask is set */ bool IsNoticeMaskSet(unsigned char sm); /** Get the mode letters of modes set on the user as a string. * @param includeparams True to get the parameters of the modes as well. Defaults to false. * @return Mode letters of modes set on the user and optionally the parameters of those modes, if any. * The returned string always begins with a '+' character. If the user has no modes set, "+" is returned. */ std::string GetModeLetters(bool includeparams = false) const; /** Returns true if a specific mode is set * @param m The user mode * @return True if the mode is set */ bool IsModeSet(unsigned char m) const; bool IsModeSet(const ModeHandler* mh) const; bool IsModeSet(const ModeHandler& mh) const { return IsModeSet(&mh); } bool IsModeSet(UserModeReference& moderef) const; /** Set a specific usermode to on or off * @param mh The user mode * @param value On or off setting of the mode */ void SetMode(ModeHandler* mh, bool value); void SetMode(ModeHandler& mh, bool value) { SetMode(&mh, value); } /** Returns true or false for if a user can execute a privilaged oper command. * This is done by looking up their oper type from User::oper, then referencing * this to their oper classes and checking the commands they can execute. * @param command A command (should be all CAPS) * @return True if this user can execute the command */ virtual bool HasCommandPermission(const std::string& command); /** Returns true if a user has a given permission. * This is used to check whether or not users may perform certain actions which admins may not wish to give to * all operators, yet are not commands. An example might be oper override, mass messaging (/notice $*), etc. * * @param privstr The priv to chec, e.g. "users/override/topic". These are loaded free-form from the config file. * @return True if this user has the permission in question. */ virtual bool HasPrivPermission(const std::string& privstr); /** Returns true or false if a user can set a privileged user or channel mode. * This is done by looking up their oper type from User::oper, then referencing * this to their oper classes, and checking the modes they can set. * @param mh Mode to check * @return True if the user can set or unset this mode. */ virtual bool HasModePermission(const ModeHandler* mh) const; /** Creates a usermask with real host. * Takes a buffer to use and fills the given buffer with the hostmask in the format user\@host * @return the usermask in the format user\@host */ const std::string& MakeHost(); /** Creates a usermask with real ip. * Takes a buffer to use and fills the given buffer with the ipmask in the format user\@ip * @return the usermask in the format user\@ip */ const std::string& MakeHostIP(); /** Oper up the user using the given opertype. * This will also give the +o usermode. */ void Oper(OperInfo* info); /** Oper down. * This will clear the +o usermode and unset the user's oper type */ void UnOper(); /** Sends a server notice to this user. * @param text The contents of the message to send. */ void WriteNotice(const std::string& text); /** Send a NOTICE message from the local server to the user. * @param text Text to send */ virtual void WriteRemoteNotice(const std::string& text); virtual void WriteRemoteNumeric(const Numeric::Numeric& numeric); template <typename T1> void WriteRemoteNumeric(unsigned int numeric, T1 p1) { Numeric::Numeric n(numeric); n.push(p1); WriteRemoteNumeric(n); } template <typename T1, typename T2> void WriteRemoteNumeric(unsigned int numeric, T1 p1, T2 p2) { Numeric::Numeric n(numeric); n.push(p1); n.push(p2); WriteRemoteNumeric(n); } template <typename T1, typename T2, typename T3> void WriteRemoteNumeric(unsigned int numeric, T1 p1, T2 p2, T3 p3) { Numeric::Numeric n(numeric); n.push(p1); n.push(p2); n.push(p3); WriteRemoteNumeric(n); } template <typename T1, typename T2, typename T3, typename T4> void WriteRemoteNumeric(unsigned int numeric, T1 p1, T2 p2, T3 p3, T4 p4) { Numeric::Numeric n(numeric); n.push(p1); n.push(p2); n.push(p3); n.push(p4); WriteRemoteNumeric(n); } template <typename T1, typename T2, typename T3, typename T4, typename T5> void WriteRemoteNumeric(unsigned int numeric, T1 p1, T2 p2, T3 p3, T4 p4, T5 p5) { Numeric::Numeric n(numeric); n.push(p1); n.push(p2); n.push(p3); n.push(p4); n.push(p5); WriteRemoteNumeric(n); } void WriteNumeric(const Numeric::Numeric& numeric); template <typename T1> void WriteNumeric(unsigned int numeric, T1 p1) { Numeric::Numeric n(numeric); n.push(p1); WriteNumeric(n); } template <typename T1, typename T2> void WriteNumeric(unsigned int numeric, T1 p1, T2 p2) { Numeric::Numeric n(numeric); n.push(p1); n.push(p2); WriteNumeric(n); } template <typename T1, typename T2, typename T3> void WriteNumeric(unsigned int numeric, T1 p1, T2 p2, T3 p3) { Numeric::Numeric n(numeric); n.push(p1); n.push(p2); n.push(p3); WriteNumeric(n); } template <typename T1, typename T2, typename T3, typename T4> void WriteNumeric(unsigned int numeric, T1 p1, T2 p2, T3 p3, T4 p4) { Numeric::Numeric n(numeric); n.push(p1); n.push(p2); n.push(p3); n.push(p4); WriteNumeric(n); } template <typename T1, typename T2, typename T3, typename T4, typename T5> void WriteNumeric(unsigned int numeric, T1 p1, T2 p2, T3 p3, T4 p4, T5 p5) { Numeric::Numeric n(numeric); n.push(p1); n.push(p2); n.push(p3); n.push(p4); n.push(p5); WriteNumeric(n); } /** Write to all users that can see this user (including this user in the list if include_self is true), appending CR/LF * @param protoev Protocol event to send, may contain any number of messages. * @param include_self Should the message be sent back to the author? */ void WriteCommonRaw(ClientProtocol::Event& protoev, bool include_self = true); /** Execute a function once for each local neighbor of this user. By default, the neighbors of a user are the users * who have at least one common channel with the user. Modules are allowed to alter the set of neighbors freely. * This function is used for example to send something conditionally to neighbors, or to send different messages * to different users depending on their oper status. * @param handler Function object to call, inherited from ForEachNeighborHandler. * @param include_self True to include this user in the set of neighbors, false otherwise. * Modules may override this. Has no effect if this user is not local. */ void ForEachNeighbor(ForEachNeighborHandler& handler, bool include_self = true); /** Return true if the user shares at least one channel with another user * @param other The other user to compare the channel list against * @return True if the given user shares at least one channel with this user */ bool SharesChannelWith(User *other); /** Change the displayed hostname of this user. * @param host The new displayed hostname of this user. * @return True if the hostname was changed successfully; otherwise, false. */ bool ChangeDisplayedHost(const std::string& host); /** Change the real hostname of this user. * @param host The new real hostname of this user. * @param resetdisplay Whether to reset the display host to this value. */ void ChangeRealHost(const std::string& host, bool resetdisplay); /** Change the ident (username) of a user. * ALWAYS use this function, rather than writing User::ident directly, * as this triggers module events allowing the change to be syncronized to * remote servers. * @param newident The new ident to set * @return True if the change succeeded, false if it didn't */ bool ChangeIdent(const std::string& newident); /** Change a users realname field. * @param real The user's new real name * @return True if the change succeeded, false if otherwise */ bool ChangeRealName(const std::string& real); /** Change a user's nick * @param newnick The new nick. If equal to the users uuid, the nick change always succeeds. * @param newts The time at which this nick change happened. * @return True if the change succeeded */ bool ChangeNick(const std::string& newnick, time_t newts = 0); /** Remove this user from all channels they are on, and delete any that are now empty. * This is used by QUIT, and will not send part messages! */ void PurgeEmptyChannels(); /** Default destructor */ virtual ~User(); CullResult cull() CXX11_OVERRIDE; /** @copydoc Serializable::Deserialize. */ bool Deserialize(Data& data) CXX11_OVERRIDE; /** @copydoc Serializable::Deserialize. */ bool Serialize(Serializable::Data& data) CXX11_OVERRIDE; }; class CoreExport UserIOHandler : public StreamSocket { private: size_t checked_until; public: LocalUser* const user; UserIOHandler(LocalUser* me) : StreamSocket(StreamSocket::SS_USER) , checked_until(0) , user(me) { } void OnDataReady() CXX11_OVERRIDE; bool OnSetEndPoint(const irc::sockets::sockaddrs& local, const irc::sockets::sockaddrs& remote) CXX11_OVERRIDE; void OnError(BufferedSocketError error) CXX11_OVERRIDE; /** Adds to the user's write buffer. * You may add any amount of text up to this users sendq value, if you exceed the * sendq value, the user will be removed, and further buffer adds will be dropped. * @param data The data to add to the write buffer */ void AddWriteBuf(const std::string &data); /** Swaps the internals of this UserIOHandler with another one. * @param other A UserIOHandler to swap internals with. */ void SwapInternals(UserIOHandler& other); }; typedef unsigned int already_sent_t; class CoreExport LocalUser : public User, public insp::intrusive_list_node<LocalUser> { /** Add a serialized message to the send queue of the user. * @param serialized Bytes to add. */ void Write(const ClientProtocol::SerializedMessage& serialized); /** Send a protocol event to the user, consisting of one or more messages. * @param protoev Event to send, may contain any number of messages. * @param msglist Message list used temporarily internally to pass to hooks and store messages * before Write(). */ void Send(ClientProtocol::Event& protoev, ClientProtocol::MessageList& msglist); /** Message list, can be passed to the two parameter Send(). */ static ClientProtocol::MessageList sendmsglist; public: LocalUser(int fd, irc::sockets::sockaddrs* client, irc::sockets::sockaddrs* server); LocalUser(int fd, const std::string& uuid, Serializable::Data& data); CullResult cull() CXX11_OVERRIDE; UserIOHandler eh; /** Serializer to use when communicating with the user */ ClientProtocol::Serializer* serializer; /** Stats counter for bytes inbound */ unsigned int bytes_in; /** Stats counter for bytes outbound */ unsigned int bytes_out; /** Stats counter for commands inbound */ unsigned int cmds_in; /** Stats counter for commands outbound */ unsigned int cmds_out; /** Password specified by the user when they registered (if any). * This is stored even if the \<connect> block doesnt need a password, so that * modules may check it. */ std::string password; /** Contains a pointer to the connect class a user is on from */ reference<ConnectClass> MyClass; /** Get the connect class which this user belongs to. * @return A pointer to this user's connect class. */ ConnectClass* GetClass() const { return MyClass; } /** Call this method to find the matching \<connect> for a user, and to check them against it. */ void CheckClass(bool clone_count = true); /** Server address and port that this user is connected to. */ irc::sockets::sockaddrs server_sa; /** Recursion fix: user is out of SendQ and will be quit as soon as possible. * This can't be handled normally because QuitUser itself calls Write on other * users, which could trigger their SendQ to overrun. */ unsigned int quitting_sendq:1; /** has the user responded to their previous ping? */ unsigned int lastping:1; /** This is true if the user matched an exception (E-line). It is used to save time on ban checks. */ unsigned int exempt:1; /** The time at which this user should be pinged next. */ time_t nextping; /** Time that the connection last sent a message, used to calculate idle time */ time_t idle_lastmsg; /** This value contains how far into the penalty threshold the user is. * This is used either to enable fake lag or for excess flood quits */ unsigned int CommandFloodPenalty; already_sent_t already_sent; /** Check if the user matches a G- or K-line, and disconnect them if they do. * @param doZline True if Z-lines should be checked (if IP has changed since initial connect) * Returns true if the user matched a ban, false else. */ bool CheckLines(bool doZline = false); /** Use this method to fully connect a user. * This will send the message of the day, check G/K/E-lines, etc. */ void FullConnect(); /** Set the connect class to which this user belongs to. * @param explicit_name Set this string to tie the user to a specific class name. Otherwise, the class is fitted by checking \<connect> tags from the configuration file. * @return A reference to this user's current connect class. */ void SetClass(const std::string &explicit_name = ""); bool SetClientIP(const std::string& address) CXX11_OVERRIDE; void SetClientIP(const irc::sockets::sockaddrs& sa) CXX11_OVERRIDE; /** Send a NOTICE message from the local server to the user. * The message will be sent even if the user is connected to a remote server. * @param text Text to send */ void WriteRemoteNotice(const std::string& text) CXX11_OVERRIDE; /** Returns true or false for if a user can execute a privilaged oper command. * This is done by looking up their oper type from User::oper, then referencing * this to their oper classes and checking the commands they can execute. * @param command A command (should be all CAPS) * @return True if this user can execute the command */ bool HasCommandPermission(const std::string& command) CXX11_OVERRIDE; /** Returns true if a user has a given permission. * This is used to check whether or not users may perform certain actions which admins may not wish to give to * all operators, yet are not commands. An example might be oper override, mass messaging (/notice $*), etc. * * @param privstr The priv to chec, e.g. "users/override/topic". These are loaded free-form from the config file. * @return True if this user has the permission in question. */ bool HasPrivPermission(const std::string& privstr) CXX11_OVERRIDE; /** Returns true or false if a user can set a privileged user or channel mode. * This is done by looking up their oper type from User::oper, then referencing * this to their oper classes, and checking the modes they can set. * @param mh Mode to check * @return True if the user can set or unset this mode. */ bool HasModePermission(const ModeHandler* mh) const CXX11_OVERRIDE; /** Change nick to uuid, unset REG_NICK and send a nickname overruled numeric. * This is called when another user (either local or remote) needs the nick of this user and this user * isn't registered. */ void OverruleNick(); /** Send a protocol event to the user, consisting of one or more messages. * @param protoev Event to send, may contain any number of messages. */ void Send(ClientProtocol::Event& protoev); /** Send a single message to the user. * @param protoevprov Protocol event provider. * @param msg Message to send. */ void Send(ClientProtocol::EventProvider& protoevprov, ClientProtocol::Message& msg); /** @copydoc Serializable::Deserialize. */ bool Deserialize(Data& data) CXX11_OVERRIDE; /** @copydoc Serializable::Deserialize. */ bool Serialize(Serializable::Data& data) CXX11_OVERRIDE; }; class RemoteUser : public User { public: RemoteUser(const std::string& uid, Server* srv) : User(uid, srv, USERTYPE_REMOTE) { } }; class CoreExport FakeUser : public User { public: FakeUser(const std::string& uid, Server* srv) : User(uid, srv, USERTYPE_SERVER) { nick = srv->GetName(); } FakeUser(const std::string& uid, const std::string& sname, const std::string& sdesc) : User(uid, new Server(uid, sname, sdesc), USERTYPE_SERVER) { nick = sname; } CullResult cull() CXX11_OVERRIDE; const std::string& GetFullHost() CXX11_OVERRIDE; const std::string& GetFullRealHost() CXX11_OVERRIDE; }; /* Faster than dynamic_cast */ /** Is a local user */ inline LocalUser* IS_LOCAL(User* u) { return (u != NULL && u->usertype == USERTYPE_LOCAL) ? static_cast<LocalUser*>(u) : NULL; } /** Is a remote user */ inline RemoteUser* IS_REMOTE(User* u) { return (u != NULL && u->usertype == USERTYPE_REMOTE) ? static_cast<RemoteUser*>(u) : NULL; } /** Is a server fakeuser */ inline FakeUser* IS_SERVER(User* u) { return (u != NULL && u->usertype == USERTYPE_SERVER) ? static_cast<FakeUser*>(u) : NULL; } inline bool User::IsModeSet(const ModeHandler* mh) const { return ((mh->GetId() != ModeParser::MODEID_MAX) && (modes[mh->GetId()])); } inline bool User::IsModeSet(UserModeReference& moderef) const { if (!moderef) return false; return IsModeSet(*moderef); } inline void User::SetMode(ModeHandler* mh, bool value) { if (mh && mh->GetId() != ModeParser::MODEID_MAX) modes[mh->GetId()] = value; } ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/include/xline.h����������������������������������������������������������������������0000664�0000000�0000000�00000036715�13554550454�0016272�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * InspIRCd -- Internet Relay Chat Daemon * * Copyright (C) 2009 Daniel De Graaf <danieldg@inspircd.org> * Copyright (C) 2004-2007 Craig Edwards <craigedwards@brainbox.cc> * Copyright (C) 2007 Robin Burchell <robin+git@viroteck.net> * Copyright (C) 2007 Dennis Friis <peavey@inspircd.org> * * This file is part of InspIRCd. InspIRCd is free software: you can * redistribute it and/or modify it under the terms of the GNU General Public * License as published by the Free Software Foundation, version 2. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once /** XLine is the base class for ban lines such as G-lines and K-lines. * Modules may derive from this, and their xlines will automatically be * handled as expected by any protocol modules (e.g. m_spanningtree will * propogate them using AddLine). The process of translating a type+pattern * to a known line type is done by means of an XLineFactory object (see * below). */ class CoreExport XLine : public classbase { protected: /** Default 'apply' action. Quits the user. * @param u User to apply the line against * @param line The line typed, used for display purposes in the quit message * @param bancache If true, the user will be added to the bancache if they match. Else not. */ void DefaultApply(User* u, const std::string &line, bool bancache); public: /** Create an XLine. * @param s_time The set time * @param d The duration of the xline * @param src The sender of the xline * @param re The reason of the xline * @param t The line type, should be set by the derived class constructor */ XLine(time_t s_time, unsigned long d, const std::string& src, const std::string& re, const std::string& t) : set_time(s_time) , duration(d) , source(src) , reason(re) , type(t) , from_config(false) { expiry = set_time + duration; } /** Destructor */ virtual ~XLine() { } /** Change creation time of an xline. Updates expiry * to be after the creation time. */ virtual void SetCreateTime(time_t created) { set_time = created; expiry = created + duration; } /** Returns true whether or not the given user is covered by this line. * @param u The user to match against. The mechanics of the match * are defined by the derived class. * @return True if there is a match. */ virtual bool Matches(User *u) = 0; /** Returns true whether or not the given string is covered by this line. * @param str The string to match against. The details of what must be * in this string and the mechanics of the match are defined by the * derived class. * @return True if there is a match */ virtual bool Matches(const std::string &str) = 0; /** Apply a line against a user. The mechanics of what occurs when * the line is applied are specific to the derived class. * @param u The user to apply against */ virtual void Apply(User* u); /** Called when the line is unset either via expiry or * via explicit removal. */ virtual void Unset() { } /** Called when the expiry message is to be displayed for the * line. Usually a line in the form 'expiring X-line blah, set by...' * see the DisplayExpiry methods of GLine, ELine etc. */ virtual void DisplayExpiry(); /** Returns the displayable form of the pattern for this xline, * e.g. '*\@foo' or '*baz*'. This must always return the full pattern * in a form which can be used to construct an entire derived xline, * even if it is stored differently internally (e.g. GLine stores the * ident and host parts separately but will still return ident\@host * for its Displayable() method). */ virtual const std::string& Displayable() = 0; /** Called when the xline has just been added. */ virtual void OnAdd() { } /** The time the line was added. */ time_t set_time; /** The duration of the ban, or 0 if permenant */ unsigned long duration; /** Source of the ban. This can be a servername or an oper nickname */ std::string source; /** Reason for the ban */ std::string reason; /** Expiry time. Does not contain useful data if the duration is 0. */ time_t expiry; /** "Q", "K", etc. Set only by derived classes constructor to the * type of line this is. */ const std::string type; // Whether this XLine was loaded from the server config. bool from_config; virtual bool IsBurstable(); }; /** KLine class */ class CoreExport KLine : public XLine { public: /** Create a K-line. * @param s_time The set time * @param d The duration of the xline * @param src The sender of the xline * @param re The reason of the xline * @param ident Ident to match * @param host Host to match */ KLine(time_t s_time, unsigned long d, const std::string& src, const std::string& re, const std::string& ident, const std::string& host) : XLine(s_time, d, src, re, "K"), identmask(ident), hostmask(host) { matchtext = this->identmask; matchtext.append("@").append(this->hostmask); } /** Destructor */ ~KLine() { } bool Matches(User* u) CXX11_OVERRIDE; bool Matches(const std::string& str) CXX11_OVERRIDE; void Apply(User* u) CXX11_OVERRIDE; const std::string& Displayable() CXX11_OVERRIDE; bool IsBurstable() CXX11_OVERRIDE; /** Ident mask (ident part only) */ std::string identmask; /** Host mask (host part only) */ std::string hostmask; std::string matchtext; }; /** GLine class */ class CoreExport GLine : public XLine { public: /** Create a G-line. * @param s_time The set time * @param d The duration of the xline * @param src The sender of the xline * @param re The reason of the xline * @param ident Ident to match * @param host Host to match */ GLine(time_t s_time, unsigned long d, const std::string& src, const std::string& re, const std::string& ident, const std::string& host) : XLine(s_time, d, src, re, "G"), identmask(ident), hostmask(host) { matchtext = this->identmask; matchtext.append("@").append(this->hostmask); } /** Destructor */ ~GLine() { } bool Matches(User* u) CXX11_OVERRIDE; bool Matches(const std::string& str) CXX11_OVERRIDE; void Apply(User* u) CXX11_OVERRIDE; const std::string& Displayable() CXX11_OVERRIDE; /** Ident mask (ident part only) */ std::string identmask; /** Host mask (host part only) */ std::string hostmask; std::string matchtext; }; /** ELine class */ class CoreExport ELine : public XLine { public: /** Create an E-line. * @param s_time The set time * @param d The duration of the xline * @param src The sender of the xline * @param re The reason of the xline * @param ident Ident to match * @param host Host to match */ ELine(time_t s_time, unsigned long d, const std::string& src, const std::string& re, const std::string& ident, const std::string& host) : XLine(s_time, d, src, re, "E"), identmask(ident), hostmask(host) { matchtext = this->identmask; matchtext.append("@").append(this->hostmask); } ~ELine() { } bool Matches(User* u) CXX11_OVERRIDE; bool Matches(const std::string& str) CXX11_OVERRIDE; void Unset() CXX11_OVERRIDE; void OnAdd() CXX11_OVERRIDE; const std::string& Displayable() CXX11_OVERRIDE; /** Ident mask (ident part only) */ std::string identmask; /** Host mask (host part only) */ std::string hostmask; std::string matchtext; }; /** ZLine class */ class CoreExport ZLine : public XLine { public: /** Create a Z-line. * @param s_time The set time * @param d The duration of the xline * @param src The sender of the xline * @param re The reason of the xline * @param ip IP to match */ ZLine(time_t s_time, unsigned long d, const std::string& src, const std::string& re, const std::string& ip) : XLine(s_time, d, src, re, "Z"), ipaddr(ip) { } /** Destructor */ ~ZLine() { } bool Matches(User* u) CXX11_OVERRIDE; bool Matches(const std::string& str) CXX11_OVERRIDE; void Apply(User* u) CXX11_OVERRIDE; const std::string& Displayable() CXX11_OVERRIDE; /** IP mask (no ident part) */ std::string ipaddr; }; /** QLine class */ class CoreExport QLine : public XLine { public: /** Create a Q-line. * @param s_time The set time * @param d The duration of the xline * @param src The sender of the xline * @param re The reason of the xline * @param nickname Nickname to match */ QLine(time_t s_time, unsigned long d, const std::string& src, const std::string& re, const std::string& nickname) : XLine(s_time, d, src, re, "Q"), nick(nickname) { } /** Destructor */ ~QLine() { } bool Matches(User* u) CXX11_OVERRIDE; bool Matches(const std::string& str) CXX11_OVERRIDE; void Apply(User* u) CXX11_OVERRIDE; const std::string& Displayable() CXX11_OVERRIDE; /** Nickname mask */ std::string nick; }; /** XLineFactory is used to generate an XLine pointer, given just the * pattern, timing information and type of line to create. This is used * for example in the spanningtree module which will call an XLineFactory * to create a new XLine when it is inbound on a server link, so that it * does not have to know the specifics of the internals of an XLine class * and/or how to call its constructor. */ class CoreExport XLineFactory { protected: std::string type; public: /** Create an XLine factory * @param t Type of XLine this factory generates */ XLineFactory(const std::string &t) : type(t) { } /** Return the type of XLine this factory generates * @return The type of XLine this factory generates */ virtual const std::string& GetType() { return type; } /** Generate a specialized XLine*. * @param set_time Time this line was created * @param duration Duration of the line * @param source The sender of the line, nickname or server * @param reason The reason for the line * @param xline_specific_mask The mask string for the line, specific to the XLine type being created. * @return A specialized XLine class of the given type for this factory. */ virtual XLine* Generate(time_t set_time, unsigned long duration, const std::string& source, const std::string& reason, const std::string& xline_specific_mask) = 0; virtual bool AutoApplyToUserList(XLine* x) { return true; } /** Destructor */ virtual ~XLineFactory() { } }; /** XLineManager is a class used to manage G-lines, K-lines, E-lines, Z-lines and Q-lines, * or any other line created by a module. It also manages XLineFactory classes which * can generate a specialized XLine for use by another module. */ class CoreExport XLineManager { protected: /** Used to hold XLines which have not yet been applied. */ std::vector<XLine *> pending_lines; /** Current xline factories */ XLineFactMap line_factory; /** Container of all lines, this is a map of maps which * allows for fast lookup for add/remove of a line, and * the shortest possible timed O(n) for checking a user * against a line. */ XLineContainer lookup_lines; public: /** Constructor */ XLineManager(); /** Destructor */ ~XLineManager(); /** Split an ident and host into two seperate strings. * This allows for faster matching. */ IdentHostPair IdentSplit(const std::string &ident_and_host); /** Checks what users match E-lines and sets their ban exempt flag accordingly. */ void CheckELines(); /** Get all lines of a certain type to an XLineLookup (std::map<std::string, XLine*>). * NOTE: When this function runs any expired items are removed from the list before it * is returned to the caller. * @param type The type to look up * @return A list of all XLines of the given type. */ XLineLookup* GetAll(const std::string &type); /** Remove all lines of a certain type. */ void DelAll(const std::string &type); /** Return all known types of line currently stored by the XLineManager. * @return A vector containing all known line types currently stored in the main list. */ std::vector<std::string> GetAllTypes(); /** Add a new XLine * @param line The line to be added * @param user The user adding the line or NULL for the local server * @return True if the line was added successfully */ bool AddLine(XLine* line, User* user); /** Delete an XLine * @param hostmask The xline-specific string identifying the line, e.g. "*@foo" * @param type The type of xline * @param reason The xline reason, if it is being removed successfully * @param user The user removing the line or NULL if its the local server * @param simulate If this is true, don't actually remove the line, just return * @return True if the line was deleted successfully */ bool DelLine(const char* hostmask, const std::string& type, std::string& reason, User* user, bool simulate = false); /** Registers an xline factory. * An xline factory is a class which when given a particular xline type, * will generate a new XLine specialized to that type. For example if you * pass the XLineFactory that handles G-lines some data it will return a * pointer to a GLine, polymorphically represented as XLine. This is used where * you do not know the full details of the item you wish to create, e.g. in a * server protocol module like m_spanningtree, when you receive xlines from other * servers. * @param xlf XLineFactory pointer to register */ bool RegisterFactory(XLineFactory* xlf); /** Unregisters an xline factory. * You must do this when your module unloads. * @param xlf XLineFactory pointer to unregister */ bool UnregisterFactory(XLineFactory* xlf); /** Get the XLineFactory for a specific type. * Returns NULL if there is no known handler for this xline type. * @param type The type of XLine you require the XLineFactory for */ XLineFactory* GetFactory(const std::string &type); /** Check if a user matches an XLine * @param type The type of line to look up * @param user The user to match against (what is checked is specific to the xline type) * @return The reason for the line if there is a match, or NULL if there is no match */ XLine* MatchesLine(const std::string &type, User* user); /** Check if a pattern matches an XLine * @param type The type of line to look up * @param pattern A pattern string specific to the xline type * @return The matching XLine if there is a match, or NULL if there is no match */ XLine* MatchesLine(const std::string &type, const std::string &pattern); /** Expire a line given two iterators which identify it in the main map. * @param container Iterator to the first level of entries the map * @param item Iterator to the second level of entries in the map * @param silent If true, doesn't send an expiry SNOTICE. */ void ExpireLine(ContainerIter container, LookupIter item, bool silent = false); /** Apply any new lines that are pending to be applied. * This will only apply lines in the pending_lines list, to save on * CPU time. */ void ApplyLines(); /** Handle /STATS for a given type. * NOTE: Any items in the list for this particular line type which have expired * will be expired and removed before the list is displayed. * @param type The type of stats to show * @param numeric The numeric to give to each result line * @param stats Stats context */ void InvokeStats(const std::string& type, unsigned int numeric, Stats::Context& stats); /** Expire X-lines which were added by the server configuration and have been removed. */ void ExpireRemovedConfigLines(const std::string& type, const insp::flat_set<std::string>& configlines); }; ���������������������������������������������������inspircd-3.4.0/locales/�����������������������������������������������������������������������������0000775�0000000�0000000�00000000000�13554550454�0014765�5����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/locales/bynets/����������������������������������������������������������������������0000775�0000000�0000000�00000000000�13554550454�0016271�5����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/locales/bynets/belarussian-w1251-charlink��������������������������������������������0000775�0000000�0000000�00000006031�13554550454�0023075�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������xC0 xC1 xC2 xC3 xC4 xC5 xC6 xC7 xC8 xC9 xCA xCB xCC xCD xCE xCF xD0 xD1 xD2 xD3 xD4 xD5 xD6 xD7 xD8 xD9 xDA xDB xDC xDD xDE xDF xE0 xE1 xE2 xE3 xE4 xE5 xE6 xE7 xE8 xE9 xEA xEB xEC xED xEE xEF xF0 xF1 xF2 xF3 xF4 xF5 xF6 xF7 xF8 xF9 xFA xFB xFC xFD xFE xFF xA8 xB8 xA1 xA2 xB2 xB3 .ި 0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 0x9, 0xa,0xb, 0xc, 0xd, 0xe, 0xf, 0x10, 0x11, 0x12, 0x13, 0x14,0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d,0x1e, 0x1f,' ', '!', '"', '#', '$', '%', '&', 0x27, '(', ')','*', '+', ',', '-', '.', '/','0', '1', '2', '3', '4', '5', '6', '7', '8', '9',':', ';', '<', '=', '>', '?','@', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i','j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's','t', 'u', 'v', 'w', 'x', 'y', 'z', '[', '\\', ']', '^','_','`', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i','j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's','t', 'u', 'v', 'w', 'x', 'y', 'z', '{', '|', '}', '~',0x7f,0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89,0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f,0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99,0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f,0xa0, 'y', 'y', 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, 0xb8, 0xa9,0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf,0xb0, 0xb1, 'i', 'i', 0xb4, 0xb5, 0xb6, 0xb7, 0xb8, 0xb9,0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf, 'a', 0xe1, 'b', 0xe3, 0xe4, 'e', 0xe6, '3', 0xe8, 0xe9, 'k', 0xeb, 'm', 'h', 'o', 0xef, 'p', 'c', 't', 'y', 0xf4, 'x', 0xf6, 0xf7, 0xf8, 0xf9,0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff, 'a', 0xe1, 'b', 0xe3, 0xe4, 'e', 0xe6, '3', 0xe8, 0xe9, 'k', 0xeb, 'm', 'h', 'o', 0xef, 'p', 'c', 't', 'y', 0xf4, 'x', 0xf6, 0xf7, 0xf8, 0xf9,0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff 0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 0x9, 0xa,0xb, 0xc, 0xd, 0xe, 0xf, 0x10, 0x11, 0x12, 0x13, 0x14,0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d,0x1e, 0x1f,' ', '!', '"', '#', '$', '%', '&', 0x27, '(', ')','*', '+', ',', '-', '.', '/','0', '1', '2', '3', '4', '5', '6', '7', '8', '9',':', ';', '<', '=', '>', '?','@', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I','J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S','T', 'U', 'V', 'W', 'X', 'Y', 'Z', '[', '\\', ']', '^',0x5f,'`', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I','J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S','T', 'U', 'V', 'W', 'X', 'Y', 'Z', '{', '|', '}', '~',0x7f,0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89,0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f,0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99,0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f,0xa0, 'Y', 'Y', 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, 0xb8, 0xa9,0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf,0xb0, 0xb1, 'I', 'I', 0xb4, 0xb5, 0xb6, 0xb7, 0xa8, 0xb9,0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf, 'A', 0xc1, 'B', 0xc3, 0xc4, 'E', 0xc6, '3', 0xc8, 0xc9, 'K', 0xcb, 'M', 'H', 'O', 0xcf, 'P', 'C', 'T', 'Y', 0xd4, 'X', 0xd6, 0xd7, 0xd8, 0xd9,0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf, 'A', 0xc1, 'B', 0xc3, 0xc4, 'E', 0xc6, '3', 0xc8, 0xc9, 'K', 0xcb, 'M', 'H', 'O', 0xcf, 'P', 'C', 'T', 'Y', 0xd4, 'X', 0xd6, 0xd7, 0xd8, 0xd9,0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/locales/bynets/chinese���������������������������������������������������������������0000775�0000000�0000000�00000000223�13554550454�0017632�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������ xA4 xA4 xA1 xF3 xA5 xA5 xA1 xF6 xB0 xD6 xA1 xFE xD7 xD7 xA1 xF9 xD8 xF7 xA1 xFE x81 xA0 x40 x7E x81 xA0 x80 xFE xAA xFE x40 x7E xAA xFE x80 xA0 �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/locales/bynets/chinese-ja������������������������������������������������������������0000775�0000000�0000000�00000000043�13554550454�0020222�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������ xA4 xA4 xA1 xF3 xA5 xA5 xA1 xF6 ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/locales/bynets/chinese-simp����������������������������������������������������������0000775�0000000�0000000�00000000063�13554550454�0020602�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������ xB0 xD6 xA1 xFE xD7 xD7 xA1 xF9 xD8 xF7 xA1 xFE �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/locales/bynets/chinese-trad����������������������������������������������������������0000775�0000000�0000000�00000000103�13554550454�0020557�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������ x81 xA0 x40 x7E x81 xA0 x80 xFE xAA xFE x40 x7E xAA xFE x80 xA0 �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/locales/bynets/gbk�������������������������������������������������������������������0000775�0000000�0000000�00000000223�13554550454�0016757�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������ xA4 xA4 xA1 xF3 xA5 xA5 xA1 xF6 xB0 xD6 xA1 xFE xD7 xD7 xA1 xF9 xD8 xF7 xA1 xFE x81 xA0 x40 x7E x81 xA0 x80 xFE xAA xFE x40 x7E xAA xFE x80 xA0 �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/locales/bynets/hebrew����������������������������������������������������������������0000775�0000000�0000000�00000000177�13554550454�0017500�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������xE0 xE1 xE2 xE3 xE4 xE5 xE6 xE7 xE8 xE9 xEA xEB xEC xED xEE xEF xF0 xF1 xF2 xF3 xF4 xF5 xF6 xF7 xF8 xF9 xFA xFB xFC xFD xFE �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/locales/bynets/latin1����������������������������������������������������������������0000775�0000000�0000000�00000001103�13554550454�0017402�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������xE4 xC4 xF6 xD6 xFC xDC xDF xE4 xC4 xF6 xD6 xFC xDC xE9 xEB xF6 xEF xFC xE8 xE6 xC6 xE5 xC5 xF8 xD8 xC0 xC2 xE0 xE2 xC7 xE7 xC8 xC9 xCA xCB xE8 xE9 xEA xEB xCE xCF xEE xEF xD4 xF4 xD9 xDB xDC xF9 xFB xFC xFF xE1 xC1 xE9 xC9 xED xCD xF3 xD3 xFA xDA xFC xDC xF1 xD1 xC0 xC8 xC9 xCC xCD xD2 xD3 xD9 xDA xE0 xE8 xE9 xEC xED xF2 xF3 xF9 xFA xC0 xC8 xC9 xCC xCD xD2 xD3 xD9 xDA xE0 xE8 xE9 xEC xED xF2 xF3 xF9 xFA xE0 xC0 xE8 xC8 xE9 xC9 xED xCD xF2 xD2 xF3 xD3 xFA xDA xEF xCF xFC xDC xE5 xC5 xE4 xC4 xF6 xD6 xC6 xE6 xD6 xF6 xC1 xE1 xCD xED xD0 xF0 xDA xFA xD3 xF3 xDD xFD xDE xFE �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/locales/bynets/latin2����������������������������������������������������������������0000775�0000000�0000000�00000000257�13554550454�0017414�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������xE1 xE9 xED xF3 xF6 xF5 xFA xFC xFB xC1 xC9 xCD xD3 xD6 xD5 xDA xDC xDB xAA xBA xC2 xC3 xCE xDE xE2 xE3 xEE xFE xB1 xE6 xEA xB3 xF1 xF3 xB6 xBF xBC xA1 xC6 x77 x65 x64 x28 �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/locales/bynets/russian-utf8-ranges���������������������������������������������������0000775�0000000�0000000�00000000066�13554550454�0022046�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������ xD0 x81 x01 xD1 x91 x01 xD0 x90 x30 xD1 x80 x10 ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/locales/bynets/russian-w1251-charlink������������������������������������������������0000775�0000000�0000000�00000006061�13554550454�0022254�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������xC0 xC1 xC2 xC3 xC4 xC5 xC6 xC7 xC8 xC9 xCA xCB xCC xCD xCE xCF xD0 xD1 xD2 xD3 xD4 xD5 xD6 xD7 xD8 xD9 xDA xDB xDC xDD xDE xDF xE0 xE1 xE2 xE3 xE4 xE5 xE6 xE7 xE8 xE9 xEA xEB xEC xED xEE xEF xF0 xF1 xF2 xF3 xF4 xF5 xF6 xF7 xF8 xF9 xFA xFB xFC xFD xFE xFF xA8 xB8 .ި 0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 0x9, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, ' ', '!', '"', '#', '$', '%', '&', 0x27, '(', ')', '*', '+', ',', '-', '.', '/', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', ':', ';', '<', '=', '>', '?', '@', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '[', '\\', ']', '^', '_', '`', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '{', '|', '}', '~', 0x7f, 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, 0xb8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf, 'a', 0xe1, 'b', 0xe3, 0xe4, 'e', 0xe6, '3', 0xe8, 0xe9, 'k', 0xeb, 'm', 'h', 'o', 0xef, 'p', 'c', 't', 'y', 0xf4, 'x', 0xf6, 0xf7, 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff, 'a', 0xe1, 'b', 0xe3, 0xe4, 'e', 0xe6, '3', 0xe8, 0xe9, 'k', 0xeb, 'm', 'h', 'o', 0xef, 'p', 'c', 't', 'y', 0xf4, 'x', 0xf6, 0xf7, 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff 0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 0x9, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, ' ', '!', '"', '#', '$', '%', '&', 0x27, '(', ')', '*', '+', ',', '-', '.', '/', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', ':', ';', '<', '=', '>', '?', '@', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', '[', '\\', ']', '^',0x5f, '`', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', '{', '|', '}', '~',0x7f,0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89,0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f,0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99,0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f,0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, 0xa8, 0xa9,0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf,0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, 0xa8, 0xb9,0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf, 'A', 0xc1, 'B', 0xc3, 0xc4, 'E', 0xc6, '3', 0xc8, 0xc9, 'K', 0xcb, 'M', 'H', 'O', 0xcf, 'P', 'C', 'T', 'Y', 0xd4, 'X', 0xd6, 0xd7, 0xd8, 0xd9,0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf, 'A', 0xc1, 'B', 0xc3, 0xc4, 'E', 0xc6, '3', 0xc8, 0xc9, 'K', 0xcb, 'M', 'H', 'O', 0xcf, 'P', 'C', 'T', 'Y', 0xd4, 'X', 0xd6, 0xd7, 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/locales/bynets/ukrainian-w1251-charlink����������������������������������������������0000775�0000000�0000000�00000007057�13554550454�0022557�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������0xc0, 0xc1, 0xc2, 0xc3, 0xa5, 0xc4, 0xc5, 0xaa, 0xc6, 0xc7, 0xc8, 0xb2, 0xaf, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xdc, 0xde, 0xdf, 0xe0, 0xe1, 0xe2, 0xe3, 0xb4, 0xe4, 0xe5, 0xba, 0xe6, 0xe7, 0xe8, 0xb3, 0xbf, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9, 0xfc, 0xfe, 0xff 0xc0, 0xc1, 0xc2, 0xc3, 0xa5, 0xc4, 0xc5, 0xaa, 0xc6, 0xc7, 0xc8, 0xb2, 0xaf, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xdc, 0xde, 0xdf 0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 0x9, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, 0x40, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, 0xa0, 0x79, 0x79, 0xa3, 0xa4, 0xe3, 0xa6, 0xa7, 0xb8, 0xa9, 0xba, 0xab, 0xac, 0xad, 0xae, 0x69, 0xb0, 0xb1, 0x69, 0x69, 0xe3, 0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0x69, 0x61, 0xe1, 0x62, 0xe3, 0xe4, 0x65, 0xe6, 0x33, 0xe8, 0xe9, 0x6b, 0xeb, 0x6d, 0x68, 0x6f, 0xef, 0x70, 0x63, 0x74, 0x79, 0xf4, 0x78, 0xf6, 0xf7, 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff, 0x61, 0xe1, 0x62, 0xe3, 0xe4, 0x65, 0xe6, 0x33, 0xe8, 0xe9, 0x6b, 0xeb, 0x6d, 0x68, 0x6f, 0xef, 0x70, 0x63, 0x74, 0x79, 0xf4, 0x78, 0xf6, 0xf7, 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff 0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 0x9, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, 0x60, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, 0xa0, 0x59, 0x59, 0xa3, 0xa4, 0xc3, 0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0x49, 0xb0, 0xb1, 0x49, 0x49, 0xc3, 0xb5, 0xb6, 0xb7, 0xa8, 0xb9, 0xaa, 0xbb, 0xbc, 0xbd, 0xbe, 0x49, 0x41, 0xc1, 0x42, 0xc3, 0xc4, 0x45, 0xc6, 0x33, 0xc8, 0xc9, 0x4b, 0xcb, 0x4d, 0x48, 0x4f, 0xcf, 0x50, 0x43, 0x54, 0x59, 0xd4, 0x58, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf, 0x41, 0xc1, 0x42, 0xc3, 0xc4, 0x45, 0xc6, 0x33, 0xc8, 0xc9, 0x4b, 0xcb, 0x4d, 0x48, 0x4f, 0xcf, 0x50, 0x43, 0x54, 0x59, 0xd4, 0x58, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/locales/bynets/windows-1250����������������������������������������������������������0000775�0000000�0000000�00000000647�13554550454�0020305�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������xE1 xE9 xED xF3 xF6 xF5 xFA xFC xFB xC1 xC9 xCD xD3 xD6 xD5 xDA xDC xDB xAA xBA xC2 xC3 xCE xDE xE2 xE3 xEE xFE xB9 xE6 xEA xB3 xF1 xF3 x9C xBF x9F xA5 xC6 xCA xA3 xD1 xD3 x8C xAF x8F x8A x8D x8E x9A x9D x9E xC1 xC8 xC9 xCC xF8 xF9 xFA xFD x22 x29 x3B x0A x09 x7D x0A x09 x69 x66 x20 x28 xF8 xF9 xFA xFD x8A x8D x8E x9A x9D x9E xBC xBE xC0 xC1 xC4 xC5 xC8 xC9 xCD xCF xE0 xE1 xE4 xE5 xE8 xE9 xED xEF xF2 xF3 xF4 xFA xFD �����������������������������������������������������������������������������������������inspircd-3.4.0/locales/ca_ES.iso88591���������������������������������������������������������������0000775�0000000�0000000�00000005045�13554550454�0017101�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������. . 0x00 0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09 0x0A 0x0B 0x0C 0x0D 0x0E 0x0F 0x10 0x11 0x12 0x13 0x14 0x15 0x16 0x17 0x18 0x19 0x1A 0x1B 0x1C 0x1D 0x1E 0x1F 0x20 0x21 0x22 0x23 0x24 0x25 0x26 0x27 0x28 0x29 0x2A 0x2B 0x2C 0x2D 0x2E 0x2F 0x30 0x31 0x32 0x33 0x34 0x35 0x36 0x37 0x38 0x39 0x3A 0x3B 0x3C 0x3D 0x3E 0x3F 0x40 0x61 0x62 0x63 0x64 0x65 0x66 0x67 0x68 0x69 0x6A 0x6B 0x6C 0x6D 0x6E 0x6F 0x70 0x71 0x72 0x73 0x74 0x75 0x76 0x77 0x78 0x79 0x7A 0x5B 0x5C 0x5D 0x5E 0x5F 0x60 0x61 0x62 0x63 0x64 0x65 0x66 0x67 0x68 0x69 0x6A 0x6B 0x6C 0x6D 0x6E 0x6F 0x70 0x71 0x72 0x73 0x74 0x75 0x76 0x77 0x78 0x79 0x7A 0x7B 0x7C 0x7D 0x7E 0x7F 0x80 0x81 0x82 0x83 0x84 0x85 0x86 0x87 0x88 0x89 0x8A 0x8B 0x8C 0x8D 0x8E 0x8F 0x90 0x91 0x92 0x93 0x94 0x95 0x96 0x97 0x98 0x99 0x9A 0x9B 0x9C 0x9D 0x9E 0x9F 0xA0 0xA1 0xA2 0xA3 0xA4 0xA5 0xA6 0xA7 0xA8 0xA9 0xAA 0xAB 0xAC 0xAD 0xAE 0xAF 0xB0 0xB1 0xB2 0xB3 0xB4 0xB5 0xB6 0xB7 0xB8 0xB9 0xBA 0xBB 0xBC 0xBD 0xBE 0xBF 0xE0 0xE1 0xE2 0xE3 0xE4 0xE5 0xE6 0xE7 0xE8 0xE9 0xEA 0xEB 0xEC 0xED 0xEE 0xEF 0xF0 0xF1 0xF2 0xF3 0xF4 0xF5 0xF6 0xD7 0xF8 0xF9 0xFA 0xFB 0xFC 0xFD 0xFE 0xDF 0xE0 0xE1 0xE2 0xE3 0xE4 0xE5 0xE6 0xE7 0xE8 0xE9 0xEA 0xEB 0xEC 0xED 0xEE 0xEF 0xF0 0xF1 0xF2 0xF3 0xF4 0xF5 0xF6 0xF7 0xF8 0xF9 0xFA 0xFB 0xFC 0xFD 0xFE 0xFF 0x00 0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09 0x0A 0x0B 0x0C 0x0D 0x0E 0x0F 0x10 0x11 0x12 0x13 0x14 0x15 0x16 0x17 0x18 0x19 0x1A 0x1B 0x1C 0x1D 0x1E 0x1F 0x20 0x21 0x22 0x23 0x24 0x25 0x26 0x27 0x28 0x29 0x2A 0x2B 0x2C 0x2D 0x2E 0x2F 0x30 0x31 0x32 0x33 0x34 0x35 0x36 0x37 0x38 0x39 0x3A 0x3B 0x3C 0x3D 0x3E 0x3F 0x40 0x41 0x42 0x43 0x44 0x45 0x46 0x47 0x48 0x49 0x4A 0x4B 0x4C 0x4D 0x4E 0x4F 0x50 0x51 0x52 0x53 0x54 0x55 0x56 0x57 0x58 0x59 0x5A 0x5B 0x5C 0x5D 0x5E 0x5F 0x60 0x41 0x42 0x43 0x44 0x45 0x46 0x47 0x48 0x49 0x4A 0x4B 0x4C 0x4D 0x4E 0x4F 0x50 0x51 0x52 0x53 0x54 0x55 0x56 0x57 0x58 0x59 0x5A 0x7B 0x7C 0x7D 0x7E 0x7F 0x80 0x81 0x82 0x83 0x84 0x85 0x86 0x87 0x88 0x89 0x8A 0x8B 0x8C 0x8D 0x8E 0x8F 0x90 0x91 0x92 0x93 0x94 0x95 0x96 0x97 0x98 0x99 0x9A 0x9B 0x9C 0x9D 0x9E 0x9F 0xA0 0xA1 0xA2 0xA3 0xA4 0xA5 0xA6 0xA7 0xA8 0xA9 0xAA 0xAB 0xAC 0xAD 0xAE 0xAF 0xB0 0xB1 0xB2 0xB3 0xB4 0xB5 0xB6 0xB7 0xB8 0xB9 0xBA 0xBB 0xBC 0xBD 0xBE 0xBF 0xC0 0xC1 0xC2 0xC3 0xC4 0xC5 0xC6 0xC7 0xC8 0xC9 0xCA 0xCB 0xCC 0xCD 0xCE 0xCF 0xD0 0xD1 0xD2 0xD3 0xD4 0xD5 0xD6 0xD7 0xD8 0xD9 0xDA 0xDB 0xDC 0xDD 0xDE 0xDF 0xC0 0xC1 0xC2 0xC3 0xC4 0xC5 0xC6 0xC7 0xC8 0xC9 0xCA 0xCB 0xCC 0xCD 0xCE 0xCF 0xD0 0xD1 0xD2 0xD3 0xD4 0xD5 0xD6 0xF7 0xD8 0xD9 0xDA 0xDB 0xDC 0xDD 0xDE 0xFF �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/locales/ca_ES.iso88591_braces��������������������������������������������������������0000775�0000000�0000000�00000005045�13554550454�0020420�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������. . 0x00 0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09 0x0A 0x0B 0x0C 0x0D 0x0E 0x0F 0x10 0x11 0x12 0x13 0x14 0x15 0x16 0x17 0x18 0x19 0x1A 0x1B 0x1C 0x1D 0x1E 0x1F 0x20 0x21 0x22 0x23 0x24 0x25 0x26 0x27 0x28 0x29 0x2A 0x2B 0x2C 0x2D 0x2E 0x2F 0x30 0x31 0x32 0x33 0x34 0x35 0x36 0x37 0x38 0x39 0x3A 0x3B 0x3C 0x3D 0x3E 0x3F 0x40 0x61 0x62 0x63 0x64 0x65 0x66 0x67 0x68 0x69 0x6A 0x6B 0x6C 0x6D 0x6E 0x6F 0x70 0x71 0x72 0x73 0x74 0x75 0x76 0x77 0x78 0x79 0x7A 0x7B 0x7C 0x7D 0x5E 0x5F 0x60 0x61 0x62 0x63 0x64 0x65 0x66 0x67 0x68 0x69 0x6A 0x6B 0x6C 0x6D 0x6E 0x6F 0x70 0x71 0x72 0x73 0x74 0x75 0x76 0x77 0x78 0x79 0x7A 0x7B 0x7C 0x7D 0x7E 0x7F 0x80 0x81 0x82 0x83 0x84 0x85 0x86 0x87 0x88 0x89 0x8A 0x8B 0x8C 0x8D 0x8E 0x8F 0x90 0x91 0x92 0x93 0x94 0x95 0x96 0x97 0x98 0x99 0x9A 0x9B 0x9C 0x9D 0x9E 0x9F 0xA0 0xA1 0xA2 0xA3 0xA4 0xA5 0xA6 0xA7 0xA8 0xA9 0xAA 0xAB 0xAC 0xAD 0xAE 0xAF 0xB0 0xB1 0xB2 0xB3 0xB4 0xB5 0xB6 0xB7 0xB8 0xB9 0xBA 0xBB 0xBC 0xBD 0xBE 0xBF 0xE0 0xE1 0xE2 0xE3 0xE4 0xE5 0xE6 0xE7 0xE8 0xE9 0xEA 0xEB 0xEC 0xED 0xEE 0xEF 0xF0 0xF1 0xF2 0xF3 0xF4 0xF5 0xF6 0xD7 0xF8 0xF9 0xFA 0xFB 0xFC 0xFD 0xFE 0xDF 0xE0 0xE1 0xE2 0xE3 0xE4 0xE5 0xE6 0xE7 0xE8 0xE9 0xEA 0xEB 0xEC 0xED 0xEE 0xEF 0xF0 0xF1 0xF2 0xF3 0xF4 0xF5 0xF6 0xF7 0xF8 0xF9 0xFA 0xFB 0xFC 0xFD 0xFE 0xFF 0x00 0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09 0x0A 0x0B 0x0C 0x0D 0x0E 0x0F 0x10 0x11 0x12 0x13 0x14 0x15 0x16 0x17 0x18 0x19 0x1A 0x1B 0x1C 0x1D 0x1E 0x1F 0x20 0x21 0x22 0x23 0x24 0x25 0x26 0x27 0x28 0x29 0x2A 0x2B 0x2C 0x2D 0x2E 0x2F 0x30 0x31 0x32 0x33 0x34 0x35 0x36 0x37 0x38 0x39 0x3A 0x3B 0x3C 0x3D 0x3E 0x3F 0x40 0x41 0x42 0x43 0x44 0x45 0x46 0x47 0x48 0x49 0x4A 0x4B 0x4C 0x4D 0x4E 0x4F 0x50 0x51 0x52 0x53 0x54 0x55 0x56 0x57 0x58 0x59 0x5A 0x5B 0x5C 0x5D 0x5E 0x5F 0x60 0x41 0x42 0x43 0x44 0x45 0x46 0x47 0x48 0x49 0x4A 0x4B 0x4C 0x4D 0x4E 0x4F 0x50 0x51 0x52 0x53 0x54 0x55 0x56 0x57 0x58 0x59 0x5A 0x5B 0x5C 0x5D 0x7E 0x7F 0x80 0x81 0x82 0x83 0x84 0x85 0x86 0x87 0x88 0x89 0x8A 0x8B 0x8C 0x8D 0x8E 0x8F 0x90 0x91 0x92 0x93 0x94 0x95 0x96 0x97 0x98 0x99 0x9A 0x9B 0x9C 0x9D 0x9E 0x9F 0xA0 0xA1 0xA2 0xA3 0xA4 0xA5 0xA6 0xA7 0xA8 0xA9 0xAA 0xAB 0xAC 0xAD 0xAE 0xAF 0xB0 0xB1 0xB2 0xB3 0xB4 0xB5 0xB6 0xB7 0xB8 0xB9 0xBA 0xBB 0xBC 0xBD 0xBE 0xBF 0xC0 0xC1 0xC2 0xC3 0xC4 0xC5 0xC6 0xC7 0xC8 0xC9 0xCA 0xCB 0xCC 0xCD 0xCE 0xCF 0xD0 0xD1 0xD2 0xD3 0xD4 0xD5 0xD6 0xD7 0xD8 0xD9 0xDA 0xDB 0xDC 0xDD 0xDE 0xDF 0xC0 0xC1 0xC2 0xC3 0xC4 0xC5 0xC6 0xC7 0xC8 0xC9 0xCA 0xCB 0xCC 0xCD 0xCE 0xCF 0xD0 0xD1 0xD2 0xD3 0xD4 0xD5 0xD6 0xF7 0xD8 0xD9 0xDA 0xDB 0xDC 0xDD 0xDE 0xFF �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/locales/cjk-utf8���������������������������������������������������������������������0000775�0000000�0000000�00000000153�13554550454�0016345�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������ 0xE0 0xA0 0x80 0xED 0x9F 0xBF 0xEF 0xA4 0x80 0xEF 0xBF 0xBF 0xF0 0x90 0x80 0x80 0xF3 0xAF 0xBF 0xBF ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/locales/cp1250�����������������������������������������������������������������������0000775�0000000�0000000�00000005202�13554550454�0015624�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������. . 0x00 0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09 0x0A 0x0B 0x0C 0x0D 0x0E 0x0F 0x10 0x11 0x12 0x13 0x14 0x15 0x16 0x17 0x18 0x19 0x1A 0x1B 0x1C 0x1D 0x1E 0x1F 0x20 0x21 0x22 0x23 0x24 0x25 0x26 0x27 0x28 0x29 0x2A 0x2B 0x2C 0x2D 0x2E 0x2F 0x30 0x31 0x32 0x33 0x34 0x35 0x36 0x37 0x38 0x39 0x3A 0x3B 0x3C 0x3D 0x3E 0x3F 0x40 0x61 0x62 0x63 0x64 0x65 0x66 0x67 0x68 0x69 0x6A 0x6B 0x6C 0x6D 0x6E 0x6F 0x70 0x71 0x72 0x73 0x74 0x75 0x76 0x77 0x78 0x79 0x7A 0x5B 0x5C 0x5D 0x5E 0x5F 0x60 0x61 0x62 0x63 0x64 0x65 0x66 0x67 0x68 0x69 0x6A 0x6B 0x6C 0x6D 0x6E 0x6F 0x70 0x71 0x72 0x73 0x74 0x75 0x76 0x77 0x78 0x79 0x7A 0x7B 0x7C 0x7D 0x7E 0x7F 0x80 0x81 0x82 0x83 0x84 0x85 0x86 0x87 0x88 0x89 0x9A 0x8B 0x9C 0x9D 0x9E 0x9F 0x90 0x91 0x92 0x93 0x94 0x95 0x96 0x97 0x98 0x99 0x9A 0x9B 0x9C 0x9D 0x9E 0x9F 0xA0 0xA1 0xA2 0xB3 0xA4 0xB9 0xA6 0xA7 0xA8 0xA9 0xBA 0xAB 0xAC 0xAD 0xAE 0xBF 0xB0 0xB1 0xB2 0xB3 0xB4 0xB5 0xB6 0xB7 0xB8 0xB9 0xBA 0xBB 0xBE 0xBD 0xBE 0xBF 0xE0 0xE1 0xE2 0xE3 0xE4 0xE5 0xE6 0xE7 0xE8 0xE9 0xEA 0xEB 0xEC 0xED 0xEE 0xEF 0xF0 0xF1 0xF2 0xF3 0xF4 0xF5 0xF6 0xD7 0xF8 0xF9 0xFA 0xFB 0xFC 0xFD 0xFE 0xDF 0xE0 0xE1 0xE2 0xE3 0xE4 0xE5 0xE6 0xE7 0xE8 0xE9 0xEA 0xEB 0xEC 0xED 0xEE 0xEF 0xF0 0xF1 0xF2 0xF3 0xF4 0xF5 0xF6 0xF7 0xF8 0xF9 0xFA 0xFB 0xFC 0xFD 0xFE 0xFF 0x00 0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09 0x0A 0x0B 0x0C 0x0D 0x0E 0x0F 0x10 0x11 0x12 0x13 0x14 0x15 0x16 0x17 0x18 0x19 0x1A 0x1B 0x1C 0x1D 0x1E 0x1F 0x20 0x21 0x22 0x23 0x24 0x25 0x26 0x27 0x28 0x29 0x2A 0x2B 0x2C 0x2D 0x2E 0x2F 0x30 0x31 0x32 0x33 0x34 0x35 0x36 0x37 0x38 0x39 0x3A 0x3B 0x3C 0x3D 0x3E 0x3F 0x40 0x41 0x42 0x43 0x44 0x45 0x46 0x47 0x48 0x49 0x4A 0x4B 0x4C 0x4D 0x4E 0x4F 0x50 0x51 0x52 0x53 0x54 0x55 0x56 0x57 0x58 0x59 0x5A 0x5B 0x5C 0x5D 0x5E 0x5F 0x60 0x41 0x42 0x43 0x44 0x45 0x46 0x47 0x48 0x49 0x4A 0x4B 0x4C 0x4D 0x4E 0x4F 0x50 0x51 0x52 0x53 0x54 0x55 0x56 0x57 0x58 0x59 0x5A 0x7B 0x7C 0x7D 0x7E 0x7F 0x80 0x81 0x82 0x83 0x84 0x85 0x86 0x87 0x88 0x89 0x8A 0x8B 0x8C 0x8D 0x8E 0x8F 0x90 0x91 0x92 0x93 0x94 0x95 0x96 0x97 0x98 0x99 0x8A 0x9B 0x8C 0x8D 0x8E 0x8F 0xA0 0xA1 0xA2 0xA3 0xA4 0xA5 0xA6 0xA7 0xA8 0xA9 0xAA 0xAB 0xAC 0xAD 0xAE 0xAF 0xB0 0xB1 0xB2 0xA3 0xB4 0xB5 0xB6 0xB7 0xB8 0xA5 0xAA 0xBB 0xBC 0xBD 0xBC 0xAF 0xC0 0xC1 0xC2 0xC3 0xC4 0xC5 0xC6 0xC7 0xC8 0xC9 0xCA 0xCB 0xCC 0xCD 0xCE 0xCF 0xD0 0xD1 0xD2 0xD3 0xD4 0xD5 0xD6 0xD7 0xD8 0xD9 0xDA 0xDB 0xDC 0xDD 0xDE 0xDF 0xC0 0xC1 0xC2 0xC3 0xC4 0xC5 0xC6 0xC7 0xC8 0xC9 0xCA 0xCB 0xCC 0xCD 0xCE 0xCF 0xD0 0xD1 0xD2 0xD3 0xD4 0xD5 0xD6 0xF7 0xD8 0xD9 0xDA 0xDB 0xDC 0xDD 0xDE 0xFF ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/locales/cp1250_braces����������������������������������������������������������������0000775�0000000�0000000�00000005202�13554550454�0017143�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������. . 0x00 0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09 0x0A 0x0B 0x0C 0x0D 0x0E 0x0F 0x10 0x11 0x12 0x13 0x14 0x15 0x16 0x17 0x18 0x19 0x1A 0x1B 0x1C 0x1D 0x1E 0x1F 0x20 0x21 0x22 0x23 0x24 0x25 0x26 0x27 0x28 0x29 0x2A 0x2B 0x2C 0x2D 0x2E 0x2F 0x30 0x31 0x32 0x33 0x34 0x35 0x36 0x37 0x38 0x39 0x3A 0x3B 0x3C 0x3D 0x3E 0x3F 0x40 0x61 0x62 0x63 0x64 0x65 0x66 0x67 0x68 0x69 0x6A 0x6B 0x6C 0x6D 0x6E 0x6F 0x70 0x71 0x72 0x73 0x74 0x75 0x76 0x77 0x78 0x79 0x7A 0x7B 0x7C 0x7D 0x5E 0x5F 0x60 0x61 0x62 0x63 0x64 0x65 0x66 0x67 0x68 0x69 0x6A 0x6B 0x6C 0x6D 0x6E 0x6F 0x70 0x71 0x72 0x73 0x74 0x75 0x76 0x77 0x78 0x79 0x7A 0x7B 0x7C 0x7D 0x7E 0x7F 0x80 0x81 0x82 0x83 0x84 0x85 0x86 0x87 0x88 0x89 0x9A 0x8B 0x9C 0x9D 0x9E 0x9F 0x90 0x91 0x92 0x93 0x94 0x95 0x96 0x97 0x98 0x99 0x9A 0x9B 0x9C 0x9D 0x9E 0x9F 0xA0 0xA1 0xA2 0xB3 0xA4 0xB9 0xA6 0xA7 0xA8 0xA9 0xBA 0xAB 0xAC 0xAD 0xAE 0xBF 0xB0 0xB1 0xB2 0xB3 0xB4 0xB5 0xB6 0xB7 0xB8 0xB9 0xBA 0xBB 0xBE 0xBD 0xBE 0xBF 0xE0 0xE1 0xE2 0xE3 0xE4 0xE5 0xE6 0xE7 0xE8 0xE9 0xEA 0xEB 0xEC 0xED 0xEE 0xEF 0xF0 0xF1 0xF2 0xF3 0xF4 0xF5 0xF6 0xD7 0xF8 0xF9 0xFA 0xFB 0xFC 0xFD 0xFE 0xDF 0xE0 0xE1 0xE2 0xE3 0xE4 0xE5 0xE6 0xE7 0xE8 0xE9 0xEA 0xEB 0xEC 0xED 0xEE 0xEF 0xF0 0xF1 0xF2 0xF3 0xF4 0xF5 0xF6 0xF7 0xF8 0xF9 0xFA 0xFB 0xFC 0xFD 0xFE 0xFF 0x00 0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09 0x0A 0x0B 0x0C 0x0D 0x0E 0x0F 0x10 0x11 0x12 0x13 0x14 0x15 0x16 0x17 0x18 0x19 0x1A 0x1B 0x1C 0x1D 0x1E 0x1F 0x20 0x21 0x22 0x23 0x24 0x25 0x26 0x27 0x28 0x29 0x2A 0x2B 0x2C 0x2D 0x2E 0x2F 0x30 0x31 0x32 0x33 0x34 0x35 0x36 0x37 0x38 0x39 0x3A 0x3B 0x3C 0x3D 0x3E 0x3F 0x40 0x41 0x42 0x43 0x44 0x45 0x46 0x47 0x48 0x49 0x4A 0x4B 0x4C 0x4D 0x4E 0x4F 0x50 0x51 0x52 0x53 0x54 0x55 0x56 0x57 0x58 0x59 0x5A 0x5B 0x5C 0x5D 0x5E 0x5F 0x60 0x41 0x42 0x43 0x44 0x45 0x46 0x47 0x48 0x49 0x4A 0x4B 0x4C 0x4D 0x4E 0x4F 0x50 0x51 0x52 0x53 0x54 0x55 0x56 0x57 0x58 0x59 0x5A 0x5B 0x5C 0x5D 0x7E 0x7F 0x80 0x81 0x82 0x83 0x84 0x85 0x86 0x87 0x88 0x89 0x8A 0x8B 0x8C 0x8D 0x8E 0x8F 0x90 0x91 0x92 0x93 0x94 0x95 0x96 0x97 0x98 0x99 0x8A 0x9B 0x8C 0x8D 0x8E 0x8F 0xA0 0xA1 0xA2 0xA3 0xA4 0xA5 0xA6 0xA7 0xA8 0xA9 0xAA 0xAB 0xAC 0xAD 0xAE 0xAF 0xB0 0xB1 0xB2 0xA3 0xB4 0xB5 0xB6 0xB7 0xB8 0xA5 0xAA 0xBB 0xBC 0xBD 0xBC 0xAF 0xC0 0xC1 0xC2 0xC3 0xC4 0xC5 0xC6 0xC7 0xC8 0xC9 0xCA 0xCB 0xCC 0xCD 0xCE 0xCF 0xD0 0xD1 0xD2 0xD3 0xD4 0xD5 0xD6 0xD7 0xD8 0xD9 0xDA 0xDB 0xDC 0xDD 0xDE 0xDF 0xC0 0xC1 0xC2 0xC3 0xC4 0xC5 0xC6 0xC7 0xC8 0xC9 0xCA 0xCB 0xCC 0xCD 0xCE 0xCF 0xD0 0xD1 0xD2 0xD3 0xD4 0xD5 0xD6 0xF7 0xD8 0xD9 0xDA 0xDB 0xDC 0xDD 0xDE 0xFF ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/locales/cp1251�����������������������������������������������������������������������0000775�0000000�0000000�00000005225�13554550454�0015632�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������. . 0x00 0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09 0x0A 0x0B 0x0C 0x0D 0x0E 0x0F 0x10 0x11 0x12 0x13 0x14 0x15 0x16 0x17 0x18 0x19 0x1A 0x1B 0x1C 0x1D 0x1E 0x1F 0x20 0x21 0x22 0x23 0x24 0x25 0x26 0x27 0x28 0x29 0x2A 0x2B 0x2C 0x2D 0x2E 0x2F 0x30 0x31 0x32 0x33 0x34 0x35 0x36 0x37 0x38 0x39 0x3A 0x3B 0x3C 0x3D 0x3E 0x3F 0x40 0x61 0x62 0x63 0x64 0x65 0x66 0x67 0x68 0x69 0x6A 0x6B 0x6C 0x6D 0x6E 0x6F 0x70 0x71 0x72 0x73 0x74 0x75 0x76 0x77 0x78 0x79 0x7A 0x5B 0x5C 0x5D 0x5E 0x5F 0x60 0x61 0x62 0x63 0x64 0x65 0x66 0x67 0x68 0x69 0x6A 0x6B 0x6C 0x6D 0x6E 0x6F 0x70 0x71 0x72 0x73 0x74 0x75 0x76 0x77 0x78 0x79 0x7A 0x7B 0x7C 0x7D 0x7E 0x7F 0x90 0x83 0x82 0x83 0x84 0x85 0x86 0x87 0x88 0x89 0x9A 0x8B 0x9C 0x9D 0x9E 0x9F 0x90 0x91 0x92 0x93 0x94 0x95 0x96 0x97 0x98 0x99 0x9A 0x9B 0x9C 0x9D 0x9E 0x9F 0xA0 0xA2 0xA2 0xBC 0xA4 0xB4 0xA6 0xA7 0xB8 0xA9 0xBA 0xAB 0xAC 0xAD 0xAE 0xBF 0xB0 0xB1 0xB3 0xB3 0xB4 0xB5 0xB6 0xB7 0xB8 0xB9 0xBA 0xBB 0xBC 0xBE 0xBE 0xBF 0xE0 0xE1 0xE2 0xE3 0xE4 0xE5 0xE6 0xE7 0xE8 0xE9 0xEA 0xEB 0xEC 0xED 0xEE 0xEF 0xF0 0xF1 0xF2 0xF3 0xF4 0xF5 0xF6 0xF7 0xF8 0xF9 0xFA 0xFB 0xFC 0xFD 0xFE 0xFF 0xE0 0xE1 0xE2 0xE3 0xE4 0xE5 0xE6 0xE7 0xE8 0xE9 0xEA 0xEB 0xEC 0xED 0xEE 0xEF 0xF0 0xF1 0xF2 0xF3 0xF4 0xF5 0xF6 0xF7 0xF8 0xF9 0xFA 0xFB 0xFC 0xFD 0xFE 0xFF 0x00 0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09 0x0A 0x0B 0x0C 0x0D 0x0E 0x0F 0x10 0x11 0x12 0x13 0x14 0x15 0x16 0x17 0x18 0x19 0x1A 0x1B 0x1C 0x1D 0x1E 0x1F 0x20 0x21 0x22 0x23 0x24 0x25 0x26 0x27 0x28 0x29 0x2A 0x2B 0x2C 0x2D 0x2E 0x2F 0x30 0x31 0x32 0x33 0x34 0x35 0x36 0x37 0x38 0x39 0x3A 0x3B 0x3C 0x3D 0x3E 0x3F 0x40 0x41 0x42 0x43 0x44 0x45 0x46 0x47 0x48 0x49 0x4A 0x4B 0x4C 0x4D 0x4E 0x4F 0x50 0x51 0x52 0x53 0x54 0x55 0x56 0x57 0x58 0x59 0x5A 0x5B 0x5C 0x5D 0x5E 0x5F 0x60 0x41 0x42 0x43 0x44 0x45 0x46 0x47 0x48 0x49 0x4A 0x4B 0x4C 0x4D 0x4E 0x4F 0x50 0x51 0x52 0x53 0x54 0x55 0x56 0x57 0x58 0x59 0x5A 0x7B 0x7C 0x7D 0x7E 0x7F 0x80 0x81 0x82 0x81 0x84 0x85 0x86 0x87 0x88 0x89 0x8A 0x8B 0x8C 0x8D 0x8E 0x8F 0x80 0x91 0x92 0x93 0x94 0x95 0x96 0x97 0x98 0x99 0x8A 0x9B 0x8C 0x8D 0x8E 0x8F 0xA0 0xA1 0xA1 0xA3 0xA4 0xA5 0xA6 0xA7 0xA8 0xA9 0xAA 0xAB 0xAC 0xAD 0xAE 0xAF 0xB0 0xB1 0xB2 0xB2 0xA5 0xB5 0xB6 0xB7 0xA8 0xB9 0xAA 0xBB 0xA3 0xBD 0xBD 0xAF 0xC0 0xC1 0xC2 0xC3 0xC4 0xC5 0xC6 0xC7 0xC8 0xC9 0xCA 0xCB 0xCC 0xCD 0xCE 0xCF 0xD0 0xD1 0xD2 0xD3 0xD4 0xD5 0xD6 0xD7 0xD8 0xD9 0xDA 0xDB 0xDC 0xDD 0xDE 0xDF 0xC0 0xC1 0xC2 0xC3 0xC4 0xC5 0xC6 0xC7 0xC8 0xC9 0xCA 0xCB 0xCC 0xCD 0xCE 0xCF 0xD0 0xD1 0xD2 0xD3 0xD4 0xD5 0xD6 0xD7 0xD8 0xD9 0xDA 0xDB 0xDC 0xDD 0xDE 0xDF ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/locales/cp1251_braces����������������������������������������������������������������0000775�0000000�0000000�00000005225�13554550454�0017151�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������. . 0x00 0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09 0x0A 0x0B 0x0C 0x0D 0x0E 0x0F 0x10 0x11 0x12 0x13 0x14 0x15 0x16 0x17 0x18 0x19 0x1A 0x1B 0x1C 0x1D 0x1E 0x1F 0x20 0x21 0x22 0x23 0x24 0x25 0x26 0x27 0x28 0x29 0x2A 0x2B 0x2C 0x2D 0x2E 0x2F 0x30 0x31 0x32 0x33 0x34 0x35 0x36 0x37 0x38 0x39 0x3A 0x3B 0x3C 0x3D 0x3E 0x3F 0x40 0x61 0x62 0x63 0x64 0x65 0x66 0x67 0x68 0x69 0x6A 0x6B 0x6C 0x6D 0x6E 0x6F 0x70 0x71 0x72 0x73 0x74 0x75 0x76 0x77 0x78 0x79 0x7A 0x7B 0x7C 0x7D 0x5E 0x5F 0x60 0x61 0x62 0x63 0x64 0x65 0x66 0x67 0x68 0x69 0x6A 0x6B 0x6C 0x6D 0x6E 0x6F 0x70 0x71 0x72 0x73 0x74 0x75 0x76 0x77 0x78 0x79 0x7A 0x7B 0x7C 0x7D 0x7E 0x7F 0x90 0x83 0x82 0x83 0x84 0x85 0x86 0x87 0x88 0x89 0x9A 0x8B 0x9C 0x9D 0x9E 0x9F 0x90 0x91 0x92 0x93 0x94 0x95 0x96 0x97 0x98 0x99 0x9A 0x9B 0x9C 0x9D 0x9E 0x9F 0xA0 0xA2 0xA2 0xBC 0xA4 0xB4 0xA6 0xA7 0xB8 0xA9 0xBA 0xAB 0xAC 0xAD 0xAE 0xBF 0xB0 0xB1 0xB3 0xB3 0xB4 0xB5 0xB6 0xB7 0xB8 0xB9 0xBA 0xBB 0xBC 0xBE 0xBE 0xBF 0xE0 0xE1 0xE2 0xE3 0xE4 0xE5 0xE6 0xE7 0xE8 0xE9 0xEA 0xEB 0xEC 0xED 0xEE 0xEF 0xF0 0xF1 0xF2 0xF3 0xF4 0xF5 0xF6 0xF7 0xF8 0xF9 0xFA 0xFB 0xFC 0xFD 0xFE 0xFF 0xE0 0xE1 0xE2 0xE3 0xE4 0xE5 0xE6 0xE7 0xE8 0xE9 0xEA 0xEB 0xEC 0xED 0xEE 0xEF 0xF0 0xF1 0xF2 0xF3 0xF4 0xF5 0xF6 0xF7 0xF8 0xF9 0xFA 0xFB 0xFC 0xFD 0xFE 0xFF 0x00 0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09 0x0A 0x0B 0x0C 0x0D 0x0E 0x0F 0x10 0x11 0x12 0x13 0x14 0x15 0x16 0x17 0x18 0x19 0x1A 0x1B 0x1C 0x1D 0x1E 0x1F 0x20 0x21 0x22 0x23 0x24 0x25 0x26 0x27 0x28 0x29 0x2A 0x2B 0x2C 0x2D 0x2E 0x2F 0x30 0x31 0x32 0x33 0x34 0x35 0x36 0x37 0x38 0x39 0x3A 0x3B 0x3C 0x3D 0x3E 0x3F 0x40 0x41 0x42 0x43 0x44 0x45 0x46 0x47 0x48 0x49 0x4A 0x4B 0x4C 0x4D 0x4E 0x4F 0x50 0x51 0x52 0x53 0x54 0x55 0x56 0x57 0x58 0x59 0x5A 0x5B 0x5C 0x5D 0x5E 0x5F 0x60 0x41 0x42 0x43 0x44 0x45 0x46 0x47 0x48 0x49 0x4A 0x4B 0x4C 0x4D 0x4E 0x4F 0x50 0x51 0x52 0x53 0x54 0x55 0x56 0x57 0x58 0x59 0x5A 0x5B 0x5C 0x5D 0x7E 0x7F 0x80 0x81 0x82 0x81 0x84 0x85 0x86 0x87 0x88 0x89 0x8A 0x8B 0x8C 0x8D 0x8E 0x8F 0x80 0x91 0x92 0x93 0x94 0x95 0x96 0x97 0x98 0x99 0x8A 0x9B 0x8C 0x8D 0x8E 0x8F 0xA0 0xA1 0xA1 0xA3 0xA4 0xA5 0xA6 0xA7 0xA8 0xA9 0xAA 0xAB 0xAC 0xAD 0xAE 0xAF 0xB0 0xB1 0xB2 0xB2 0xA5 0xB5 0xB6 0xB7 0xA8 0xB9 0xAA 0xBB 0xA3 0xBD 0xBD 0xAF 0xC0 0xC1 0xC2 0xC3 0xC4 0xC5 0xC6 0xC7 0xC8 0xC9 0xCA 0xCB 0xCC 0xCD 0xCE 0xCF 0xD0 0xD1 0xD2 0xD3 0xD4 0xD5 0xD6 0xD7 0xD8 0xD9 0xDA 0xDB 0xDC 0xDD 0xDE 0xDF 0xC0 0xC1 0xC2 0xC3 0xC4 0xC5 0xC6 0xC7 0xC8 0xC9 0xCA 0xCB 0xCC 0xCD 0xCE 0xCF 0xD0 0xD1 0xD2 0xD3 0xD4 0xD5 0xD6 0xD7 0xD8 0xD9 0xDA 0xDB 0xDC 0xDD 0xDE 0xDF ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/locales/cs_CZ.cp1250�����������������������������������������������������������������0000775�0000000�0000000�00000005064�13554550454�0016632�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������. . 0x00 0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09 0x0A 0x0B 0x0C 0x0D 0x0E 0x0F 0x10 0x11 0x12 0x13 0x14 0x15 0x16 0x17 0x18 0x19 0x1A 0x1B 0x1C 0x1D 0x1E 0x1F 0x20 0x21 0x22 0x23 0x24 0x25 0x26 0x27 0x28 0x29 0x2A 0x2B 0x2C 0x2D 0x2E 0x2F 0x30 0x31 0x32 0x33 0x34 0x35 0x36 0x37 0x38 0x39 0x3A 0x3B 0x3C 0x3D 0x3E 0x3F 0x40 0x61 0x62 0x63 0x64 0x65 0x66 0x67 0x68 0x69 0x6A 0x6B 0x6C 0x6D 0x6E 0x6F 0x70 0x71 0x72 0x73 0x74 0x75 0x76 0x77 0x78 0x79 0x7A 0x5B 0x5C 0x5D 0x5E 0x5F 0x60 0x61 0x62 0x63 0x64 0x65 0x66 0x67 0x68 0x69 0x6A 0x6B 0x6C 0x6D 0x6E 0x6F 0x70 0x71 0x72 0x73 0x74 0x75 0x76 0x77 0x78 0x79 0x7A 0x7B 0x7C 0x7D 0x7E 0x7F 0x80 0x81 0x82 0x83 0x84 0x85 0x86 0x87 0x88 0x89 0x9A 0x8B 0x9C 0x9D 0x9E 0x9F 0x90 0x91 0x92 0x93 0x94 0x95 0x96 0x97 0x98 0x99 0x9A 0x9B 0x9C 0x9D 0x9E 0x9F 0xA0 0xA1 0xA2 0xB3 0xA4 0xB9 0xA6 0xA7 0xA8 0xA9 0xBA 0xAB 0xAC 0xAD 0xAE 0xBF 0xB0 0xB1 0xB2 0xB3 0xB4 0xB5 0xB6 0xB7 0xB8 0xB9 0xBA 0xBB 0xBE 0xBD 0xBE 0xBF 0xE0 0xE1 0xE2 0xE3 0xE4 0xE5 0xE6 0xE7 0xE8 0xE9 0xEA 0xEB 0xEC 0xED 0xEE 0xEF 0xF0 0xF1 0xF2 0xF3 0xF4 0xF5 0xF6 0xD7 0xF8 0xF9 0xFA 0xFB 0xFC 0xFD 0xFE 0xDF 0xE0 0xE1 0xE2 0xE3 0xE4 0xE5 0xE6 0xE7 0xE8 0xE9 0xEA 0xEB 0xEC 0xED 0xEE 0xEF 0xF0 0xF1 0xF2 0xF3 0xF4 0xF5 0xF6 0xF7 0xF8 0xF9 0xFA 0xFB 0xFC 0xFD 0xFE 0xFF 0x00 0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09 0x0A 0x0B 0x0C 0x0D 0x0E 0x0F 0x10 0x11 0x12 0x13 0x14 0x15 0x16 0x17 0x18 0x19 0x1A 0x1B 0x1C 0x1D 0x1E 0x1F 0x20 0x21 0x22 0x23 0x24 0x25 0x26 0x27 0x28 0x29 0x2A 0x2B 0x2C 0x2D 0x2E 0x2F 0x30 0x31 0x32 0x33 0x34 0x35 0x36 0x37 0x38 0x39 0x3A 0x3B 0x3C 0x3D 0x3E 0x3F 0x40 0x41 0x42 0x43 0x44 0x45 0x46 0x47 0x48 0x49 0x4A 0x4B 0x4C 0x4D 0x4E 0x4F 0x50 0x51 0x52 0x53 0x54 0x55 0x56 0x57 0x58 0x59 0x5A 0x5B 0x5C 0x5D 0x5E 0x5F 0x60 0x41 0x42 0x43 0x44 0x45 0x46 0x47 0x48 0x49 0x4A 0x4B 0x4C 0x4D 0x4E 0x4F 0x50 0x51 0x52 0x53 0x54 0x55 0x56 0x57 0x58 0x59 0x5A 0x7B 0x7C 0x7D 0x7E 0x7F 0x80 0x81 0x82 0x83 0x84 0x85 0x86 0x87 0x88 0x89 0x8A 0x8B 0x8C 0x8D 0x8E 0x8F 0x90 0x91 0x92 0x93 0x94 0x95 0x96 0x97 0x98 0x99 0x8A 0x9B 0x8C 0x8D 0x8E 0x8F 0xA0 0xA1 0xA2 0xA3 0xA4 0xA5 0xA6 0xA7 0xA8 0xA9 0xAA 0xAB 0xAC 0xAD 0xAE 0xAF 0xB0 0xB1 0xB2 0xA3 0xB4 0xB5 0xB6 0xB7 0xB8 0xA5 0xAA 0xBB 0xBC 0xBD 0xBC 0xAF 0xC0 0xC1 0xC2 0xC3 0xC4 0xC5 0xC6 0xC7 0xC8 0xC9 0xCA 0xCB 0xCC 0xCD 0xCE 0xCF 0xD0 0xD1 0xD2 0xD3 0xD4 0xD5 0xD6 0xD7 0xD8 0xD9 0xDA 0xDB 0xDC 0xDD 0xDE 0xDF 0xC0 0xC1 0xC2 0xC3 0xC4 0xC5 0xC6 0xC7 0xC8 0xC9 0xCA 0xCB 0xCC 0xCD 0xCE 0xCF 0xD0 0xD1 0xD2 0xD3 0xD4 0xD5 0xD6 0xF7 0xD8 0xD9 0xDA 0xDB 0xDC 0xDD 0xDE 0xFF ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/locales/cs_CZ.cp1250_braces����������������������������������������������������������0000775�0000000�0000000�00000005064�13554550454�0020151�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������. . 0x00 0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09 0x0A 0x0B 0x0C 0x0D 0x0E 0x0F 0x10 0x11 0x12 0x13 0x14 0x15 0x16 0x17 0x18 0x19 0x1A 0x1B 0x1C 0x1D 0x1E 0x1F 0x20 0x21 0x22 0x23 0x24 0x25 0x26 0x27 0x28 0x29 0x2A 0x2B 0x2C 0x2D 0x2E 0x2F 0x30 0x31 0x32 0x33 0x34 0x35 0x36 0x37 0x38 0x39 0x3A 0x3B 0x3C 0x3D 0x3E 0x3F 0x40 0x61 0x62 0x63 0x64 0x65 0x66 0x67 0x68 0x69 0x6A 0x6B 0x6C 0x6D 0x6E 0x6F 0x70 0x71 0x72 0x73 0x74 0x75 0x76 0x77 0x78 0x79 0x7A 0x7B 0x7C 0x7D 0x5E 0x5F 0x60 0x61 0x62 0x63 0x64 0x65 0x66 0x67 0x68 0x69 0x6A 0x6B 0x6C 0x6D 0x6E 0x6F 0x70 0x71 0x72 0x73 0x74 0x75 0x76 0x77 0x78 0x79 0x7A 0x7B 0x7C 0x7D 0x7E 0x7F 0x80 0x81 0x82 0x83 0x84 0x85 0x86 0x87 0x88 0x89 0x9A 0x8B 0x9C 0x9D 0x9E 0x9F 0x90 0x91 0x92 0x93 0x94 0x95 0x96 0x97 0x98 0x99 0x9A 0x9B 0x9C 0x9D 0x9E 0x9F 0xA0 0xA1 0xA2 0xB3 0xA4 0xB9 0xA6 0xA7 0xA8 0xA9 0xBA 0xAB 0xAC 0xAD 0xAE 0xBF 0xB0 0xB1 0xB2 0xB3 0xB4 0xB5 0xB6 0xB7 0xB8 0xB9 0xBA 0xBB 0xBE 0xBD 0xBE 0xBF 0xE0 0xE1 0xE2 0xE3 0xE4 0xE5 0xE6 0xE7 0xE8 0xE9 0xEA 0xEB 0xEC 0xED 0xEE 0xEF 0xF0 0xF1 0xF2 0xF3 0xF4 0xF5 0xF6 0xD7 0xF8 0xF9 0xFA 0xFB 0xFC 0xFD 0xFE 0xDF 0xE0 0xE1 0xE2 0xE3 0xE4 0xE5 0xE6 0xE7 0xE8 0xE9 0xEA 0xEB 0xEC 0xED 0xEE 0xEF 0xF0 0xF1 0xF2 0xF3 0xF4 0xF5 0xF6 0xF7 0xF8 0xF9 0xFA 0xFB 0xFC 0xFD 0xFE 0xFF 0x00 0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09 0x0A 0x0B 0x0C 0x0D 0x0E 0x0F 0x10 0x11 0x12 0x13 0x14 0x15 0x16 0x17 0x18 0x19 0x1A 0x1B 0x1C 0x1D 0x1E 0x1F 0x20 0x21 0x22 0x23 0x24 0x25 0x26 0x27 0x28 0x29 0x2A 0x2B 0x2C 0x2D 0x2E 0x2F 0x30 0x31 0x32 0x33 0x34 0x35 0x36 0x37 0x38 0x39 0x3A 0x3B 0x3C 0x3D 0x3E 0x3F 0x40 0x41 0x42 0x43 0x44 0x45 0x46 0x47 0x48 0x49 0x4A 0x4B 0x4C 0x4D 0x4E 0x4F 0x50 0x51 0x52 0x53 0x54 0x55 0x56 0x57 0x58 0x59 0x5A 0x5B 0x5C 0x5D 0x5E 0x5F 0x60 0x41 0x42 0x43 0x44 0x45 0x46 0x47 0x48 0x49 0x4A 0x4B 0x4C 0x4D 0x4E 0x4F 0x50 0x51 0x52 0x53 0x54 0x55 0x56 0x57 0x58 0x59 0x5A 0x5B 0x5C 0x5D 0x7E 0x7F 0x80 0x81 0x82 0x83 0x84 0x85 0x86 0x87 0x88 0x89 0x8A 0x8B 0x8C 0x8D 0x8E 0x8F 0x90 0x91 0x92 0x93 0x94 0x95 0x96 0x97 0x98 0x99 0x8A 0x9B 0x8C 0x8D 0x8E 0x8F 0xA0 0xA1 0xA2 0xA3 0xA4 0xA5 0xA6 0xA7 0xA8 0xA9 0xAA 0xAB 0xAC 0xAD 0xAE 0xAF 0xB0 0xB1 0xB2 0xA3 0xB4 0xB5 0xB6 0xB7 0xB8 0xA5 0xAA 0xBB 0xBC 0xBD 0xBC 0xAF 0xC0 0xC1 0xC2 0xC3 0xC4 0xC5 0xC6 0xC7 0xC8 0xC9 0xCA 0xCB 0xCC 0xCD 0xCE 0xCF 0xD0 0xD1 0xD2 0xD3 0xD4 0xD5 0xD6 0xD7 0xD8 0xD9 0xDA 0xDB 0xDC 0xDD 0xDE 0xDF 0xC0 0xC1 0xC2 0xC3 0xC4 0xC5 0xC6 0xC7 0xC8 0xC9 0xCA 0xCB 0xCC 0xCD 0xCE 0xCF 0xD0 0xD1 0xD2 0xD3 0xD4 0xD5 0xD6 0xF7 0xD8 0xD9 0xDA 0xDB 0xDC 0xDD 0xDE 0xFF ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/locales/da_DK.iso88591���������������������������������������������������������������0000775�0000000�0000000�00000005020�13554550454�0017062�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������. . 0x00 0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09 0x0A 0x0B 0x0C 0x0D 0x0E 0x0F 0x10 0x11 0x12 0x13 0x14 0x15 0x16 0x17 0x18 0x19 0x1A 0x1B 0x1C 0x1D 0x1E 0x1F 0x20 0x21 0x22 0x23 0x24 0x25 0x26 0x27 0x28 0x29 0x2A 0x2B 0x2C 0x2D 0x2E 0x2F 0x30 0x31 0x32 0x33 0x34 0x35 0x36 0x37 0x38 0x39 0x3A 0x3B 0x3C 0x3D 0x3E 0x3F 0x40 0x61 0x62 0x63 0x64 0x65 0x66 0x67 0x68 0x69 0x6A 0x6B 0x6C 0x6D 0x6E 0x6F 0x70 0x71 0x72 0x73 0x74 0x75 0x76 0x77 0x78 0x79 0x7A 0x5B 0x5C 0x5D 0x5E 0x5F 0x60 0x61 0x62 0x63 0x64 0x65 0x66 0x67 0x68 0x69 0x6A 0x6B 0x6C 0x6D 0x6E 0x6F 0x70 0x71 0x72 0x73 0x74 0x75 0x76 0x77 0x78 0x79 0x7A 0x7B 0x7C 0x7D 0x7E 0x7F 0x80 0x81 0x82 0x83 0x84 0x85 0x86 0x87 0x88 0x89 0x8A 0x8B 0x8C 0x8D 0x8E 0x8F 0x90 0x91 0x92 0x93 0x94 0x95 0x96 0x97 0x98 0x99 0x9A 0x9B 0x9C 0x9D 0x9E 0x9F 0xA0 0xA1 0xA2 0xA3 0xA4 0xA5 0xA6 0xA7 0xA8 0xA9 0xAA 0xAB 0xAC 0xAD 0xAE 0xAF 0xB0 0xB1 0xB2 0xB3 0xB4 0xB5 0xB6 0xB7 0xB8 0xB9 0xBA 0xBB 0xBC 0xBD 0xBE 0xBF 0xE0 0xE1 0xE2 0xE3 0xE4 0xE5 0xE6 0xE7 0xE8 0xE9 0xEA 0xEB 0xEC 0xED 0xEE 0xEF 0xF0 0xF1 0xF2 0xF3 0xF4 0xF5 0xF6 0xD7 0xF8 0xF9 0xFA 0xFB 0xFC 0xFD 0xFE 0xDF 0xE0 0xE1 0xE2 0xE3 0xE4 0xE5 0xE6 0xE7 0xE8 0xE9 0xEA 0xEB 0xEC 0xED 0xEE 0xEF 0xF0 0xF1 0xF2 0xF3 0xF4 0xF5 0xF6 0xF7 0xF8 0xF9 0xFA 0xFB 0xFC 0xFD 0xFE 0xFF 0x00 0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09 0x0A 0x0B 0x0C 0x0D 0x0E 0x0F 0x10 0x11 0x12 0x13 0x14 0x15 0x16 0x17 0x18 0x19 0x1A 0x1B 0x1C 0x1D 0x1E 0x1F 0x20 0x21 0x22 0x23 0x24 0x25 0x26 0x27 0x28 0x29 0x2A 0x2B 0x2C 0x2D 0x2E 0x2F 0x30 0x31 0x32 0x33 0x34 0x35 0x36 0x37 0x38 0x39 0x3A 0x3B 0x3C 0x3D 0x3E 0x3F 0x40 0x41 0x42 0x43 0x44 0x45 0x46 0x47 0x48 0x49 0x4A 0x4B 0x4C 0x4D 0x4E 0x4F 0x50 0x51 0x52 0x53 0x54 0x55 0x56 0x57 0x58 0x59 0x5A 0x5B 0x5C 0x5D 0x5E 0x5F 0x60 0x41 0x42 0x43 0x44 0x45 0x46 0x47 0x48 0x49 0x4A 0x4B 0x4C 0x4D 0x4E 0x4F 0x50 0x51 0x52 0x53 0x54 0x55 0x56 0x57 0x58 0x59 0x5A 0x7B 0x7C 0x7D 0x7E 0x7F 0x80 0x81 0x82 0x83 0x84 0x85 0x86 0x87 0x88 0x89 0x8A 0x8B 0x8C 0x8D 0x8E 0x8F 0x90 0x91 0x92 0x93 0x94 0x95 0x96 0x97 0x98 0x99 0x9A 0x9B 0x9C 0x9D 0x9E 0x9F 0xA0 0xA1 0xA2 0xA3 0xA4 0xA5 0xA6 0xA7 0xA8 0xA9 0xAA 0xAB 0xAC 0xAD 0xAE 0xAF 0xB0 0xB1 0xB2 0xB3 0xB4 0xB5 0xB6 0xB7 0xB8 0xB9 0xBA 0xBB 0xBC 0xBD 0xBE 0xBF 0xC0 0xC1 0xC2 0xC3 0xC4 0xC5 0xC6 0xC7 0xC8 0xC9 0xCA 0xCB 0xCC 0xCD 0xCE 0xCF 0xD0 0xD1 0xD2 0xD3 0xD4 0xD5 0xD6 0xD7 0xD8 0xD9 0xDA 0xDB 0xDC 0xDD 0xDE 0xDF 0xC0 0xC1 0xC2 0xC3 0xC4 0xC5 0xC6 0xC7 0xC8 0xC9 0xCA 0xCB 0xCC 0xCD 0xCE 0xCF 0xD0 0xD1 0xD2 0xD3 0xD4 0xD5 0xD6 0xF7 0xD8 0xD9 0xDA 0xDB 0xDC 0xDD 0xDE 0xFF ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/locales/da_DK.iso88591_braces��������������������������������������������������������0000775�0000000�0000000�00000005020�13554550454�0020401�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������. . 0x00 0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09 0x0A 0x0B 0x0C 0x0D 0x0E 0x0F 0x10 0x11 0x12 0x13 0x14 0x15 0x16 0x17 0x18 0x19 0x1A 0x1B 0x1C 0x1D 0x1E 0x1F 0x20 0x21 0x22 0x23 0x24 0x25 0x26 0x27 0x28 0x29 0x2A 0x2B 0x2C 0x2D 0x2E 0x2F 0x30 0x31 0x32 0x33 0x34 0x35 0x36 0x37 0x38 0x39 0x3A 0x3B 0x3C 0x3D 0x3E 0x3F 0x40 0x61 0x62 0x63 0x64 0x65 0x66 0x67 0x68 0x69 0x6A 0x6B 0x6C 0x6D 0x6E 0x6F 0x70 0x71 0x72 0x73 0x74 0x75 0x76 0x77 0x78 0x79 0x7A 0x7B 0x7C 0x7D 0x5E 0x5F 0x60 0x61 0x62 0x63 0x64 0x65 0x66 0x67 0x68 0x69 0x6A 0x6B 0x6C 0x6D 0x6E 0x6F 0x70 0x71 0x72 0x73 0x74 0x75 0x76 0x77 0x78 0x79 0x7A 0x7B 0x7C 0x7D 0x7E 0x7F 0x80 0x81 0x82 0x83 0x84 0x85 0x86 0x87 0x88 0x89 0x8A 0x8B 0x8C 0x8D 0x8E 0x8F 0x90 0x91 0x92 0x93 0x94 0x95 0x96 0x97 0x98 0x99 0x9A 0x9B 0x9C 0x9D 0x9E 0x9F 0xA0 0xA1 0xA2 0xA3 0xA4 0xA5 0xA6 0xA7 0xA8 0xA9 0xAA 0xAB 0xAC 0xAD 0xAE 0xAF 0xB0 0xB1 0xB2 0xB3 0xB4 0xB5 0xB6 0xB7 0xB8 0xB9 0xBA 0xBB 0xBC 0xBD 0xBE 0xBF 0xE0 0xE1 0xE2 0xE3 0xE4 0xE5 0xE6 0xE7 0xE8 0xE9 0xEA 0xEB 0xEC 0xED 0xEE 0xEF 0xF0 0xF1 0xF2 0xF3 0xF4 0xF5 0xF6 0xD7 0xF8 0xF9 0xFA 0xFB 0xFC 0xFD 0xFE 0xDF 0xE0 0xE1 0xE2 0xE3 0xE4 0xE5 0xE6 0xE7 0xE8 0xE9 0xEA 0xEB 0xEC 0xED 0xEE 0xEF 0xF0 0xF1 0xF2 0xF3 0xF4 0xF5 0xF6 0xF7 0xF8 0xF9 0xFA 0xFB 0xFC 0xFD 0xFE 0xFF 0x00 0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09 0x0A 0x0B 0x0C 0x0D 0x0E 0x0F 0x10 0x11 0x12 0x13 0x14 0x15 0x16 0x17 0x18 0x19 0x1A 0x1B 0x1C 0x1D 0x1E 0x1F 0x20 0x21 0x22 0x23 0x24 0x25 0x26 0x27 0x28 0x29 0x2A 0x2B 0x2C 0x2D 0x2E 0x2F 0x30 0x31 0x32 0x33 0x34 0x35 0x36 0x37 0x38 0x39 0x3A 0x3B 0x3C 0x3D 0x3E 0x3F 0x40 0x41 0x42 0x43 0x44 0x45 0x46 0x47 0x48 0x49 0x4A 0x4B 0x4C 0x4D 0x4E 0x4F 0x50 0x51 0x52 0x53 0x54 0x55 0x56 0x57 0x58 0x59 0x5A 0x5B 0x5C 0x5D 0x5E 0x5F 0x60 0x41 0x42 0x43 0x44 0x45 0x46 0x47 0x48 0x49 0x4A 0x4B 0x4C 0x4D 0x4E 0x4F 0x50 0x51 0x52 0x53 0x54 0x55 0x56 0x57 0x58 0x59 0x5A 0x5B 0x5C 0x5D 0x7E 0x7F 0x80 0x81 0x82 0x83 0x84 0x85 0x86 0x87 0x88 0x89 0x8A 0x8B 0x8C 0x8D 0x8E 0x8F 0x90 0x91 0x92 0x93 0x94 0x95 0x96 0x97 0x98 0x99 0x9A 0x9B 0x9C 0x9D 0x9E 0x9F 0xA0 0xA1 0xA2 0xA3 0xA4 0xA5 0xA6 0xA7 0xA8 0xA9 0xAA 0xAB 0xAC 0xAD 0xAE 0xAF 0xB0 0xB1 0xB2 0xB3 0xB4 0xB5 0xB6 0xB7 0xB8 0xB9 0xBA 0xBB 0xBC 0xBD 0xBE 0xBF 0xC0 0xC1 0xC2 0xC3 0xC4 0xC5 0xC6 0xC7 0xC8 0xC9 0xCA 0xCB 0xCC 0xCD 0xCE 0xCF 0xD0 0xD1 0xD2 0xD3 0xD4 0xD5 0xD6 0xD7 0xD8 0xD9 0xDA 0xDB 0xDC 0xDD 0xDE 0xDF 0xC0 0xC1 0xC2 0xC3 0xC4 0xC5 0xC6 0xC7 0xC8 0xC9 0xCA 0xCB 0xCC 0xCD 0xCE 0xCF 0xD0 0xD1 0xD2 0xD3 0xD4 0xD5 0xD6 0xF7 0xD8 0xD9 0xDA 0xDB 0xDC 0xDD 0xDE 0xFF ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/locales/de_CH.iso88591���������������������������������������������������������������0000775�0000000�0000000�00000005020�13554550454�0017062�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������. . 0x00 0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09 0x0A 0x0B 0x0C 0x0D 0x0E 0x0F 0x10 0x11 0x12 0x13 0x14 0x15 0x16 0x17 0x18 0x19 0x1A 0x1B 0x1C 0x1D 0x1E 0x1F 0x20 0x21 0x22 0x23 0x24 0x25 0x26 0x27 0x28 0x29 0x2A 0x2B 0x2C 0x2D 0x2E 0x2F 0x30 0x31 0x32 0x33 0x34 0x35 0x36 0x37 0x38 0x39 0x3A 0x3B 0x3C 0x3D 0x3E 0x3F 0x40 0x61 0x62 0x63 0x64 0x65 0x66 0x67 0x68 0x69 0x6A 0x6B 0x6C 0x6D 0x6E 0x6F 0x70 0x71 0x72 0x73 0x74 0x75 0x76 0x77 0x78 0x79 0x7A 0x5B 0x5C 0x5D 0x5E 0x5F 0x60 0x61 0x62 0x63 0x64 0x65 0x66 0x67 0x68 0x69 0x6A 0x6B 0x6C 0x6D 0x6E 0x6F 0x70 0x71 0x72 0x73 0x74 0x75 0x76 0x77 0x78 0x79 0x7A 0x7B 0x7C 0x7D 0x7E 0x7F 0x80 0x81 0x82 0x83 0x84 0x85 0x86 0x87 0x88 0x89 0x8A 0x8B 0x8C 0x8D 0x8E 0x8F 0x90 0x91 0x92 0x93 0x94 0x95 0x96 0x97 0x98 0x99 0x9A 0x9B 0x9C 0x9D 0x9E 0x9F 0xA0 0xA1 0xA2 0xA3 0xA4 0xA5 0xA6 0xA7 0xA8 0xA9 0xAA 0xAB 0xAC 0xAD 0xAE 0xAF 0xB0 0xB1 0xB2 0xB3 0xB4 0xB5 0xB6 0xB7 0xB8 0xB9 0xBA 0xBB 0xBC 0xBD 0xBE 0xBF 0xE0 0xE1 0xE2 0xE3 0xE4 0xE5 0xE6 0xE7 0xE8 0xE9 0xEA 0xEB 0xEC 0xED 0xEE 0xEF 0xF0 0xF1 0xF2 0xF3 0xF4 0xF5 0xF6 0xD7 0xF8 0xF9 0xFA 0xFB 0xFC 0xFD 0xFE 0xDF 0xE0 0xE1 0xE2 0xE3 0xE4 0xE5 0xE6 0xE7 0xE8 0xE9 0xEA 0xEB 0xEC 0xED 0xEE 0xEF 0xF0 0xF1 0xF2 0xF3 0xF4 0xF5 0xF6 0xF7 0xF8 0xF9 0xFA 0xFB 0xFC 0xFD 0xFE 0xFF 0x00 0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09 0x0A 0x0B 0x0C 0x0D 0x0E 0x0F 0x10 0x11 0x12 0x13 0x14 0x15 0x16 0x17 0x18 0x19 0x1A 0x1B 0x1C 0x1D 0x1E 0x1F 0x20 0x21 0x22 0x23 0x24 0x25 0x26 0x27 0x28 0x29 0x2A 0x2B 0x2C 0x2D 0x2E 0x2F 0x30 0x31 0x32 0x33 0x34 0x35 0x36 0x37 0x38 0x39 0x3A 0x3B 0x3C 0x3D 0x3E 0x3F 0x40 0x41 0x42 0x43 0x44 0x45 0x46 0x47 0x48 0x49 0x4A 0x4B 0x4C 0x4D 0x4E 0x4F 0x50 0x51 0x52 0x53 0x54 0x55 0x56 0x57 0x58 0x59 0x5A 0x5B 0x5C 0x5D 0x5E 0x5F 0x60 0x41 0x42 0x43 0x44 0x45 0x46 0x47 0x48 0x49 0x4A 0x4B 0x4C 0x4D 0x4E 0x4F 0x50 0x51 0x52 0x53 0x54 0x55 0x56 0x57 0x58 0x59 0x5A 0x7B 0x7C 0x7D 0x7E 0x7F 0x80 0x81 0x82 0x83 0x84 0x85 0x86 0x87 0x88 0x89 0x8A 0x8B 0x8C 0x8D 0x8E 0x8F 0x90 0x91 0x92 0x93 0x94 0x95 0x96 0x97 0x98 0x99 0x9A 0x9B 0x9C 0x9D 0x9E 0x9F 0xA0 0xA1 0xA2 0xA3 0xA4 0xA5 0xA6 0xA7 0xA8 0xA9 0xAA 0xAB 0xAC 0xAD 0xAE 0xAF 0xB0 0xB1 0xB2 0xB3 0xB4 0xB5 0xB6 0xB7 0xB8 0xB9 0xBA 0xBB 0xBC 0xBD 0xBE 0xBF 0xC0 0xC1 0xC2 0xC3 0xC4 0xC5 0xC6 0xC7 0xC8 0xC9 0xCA 0xCB 0xCC 0xCD 0xCE 0xCF 0xD0 0xD1 0xD2 0xD3 0xD4 0xD5 0xD6 0xD7 0xD8 0xD9 0xDA 0xDB 0xDC 0xDD 0xDE 0xDF 0xC0 0xC1 0xC2 0xC3 0xC4 0xC5 0xC6 0xC7 0xC8 0xC9 0xCA 0xCB 0xCC 0xCD 0xCE 0xCF 0xD0 0xD1 0xD2 0xD3 0xD4 0xD5 0xD6 0xF7 0xD8 0xD9 0xDA 0xDB 0xDC 0xDD 0xDE 0xFF ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/locales/de_CH.iso88591_braces��������������������������������������������������������0000775�0000000�0000000�00000005020�13554550454�0020401�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������. . 0x00 0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09 0x0A 0x0B 0x0C 0x0D 0x0E 0x0F 0x10 0x11 0x12 0x13 0x14 0x15 0x16 0x17 0x18 0x19 0x1A 0x1B 0x1C 0x1D 0x1E 0x1F 0x20 0x21 0x22 0x23 0x24 0x25 0x26 0x27 0x28 0x29 0x2A 0x2B 0x2C 0x2D 0x2E 0x2F 0x30 0x31 0x32 0x33 0x34 0x35 0x36 0x37 0x38 0x39 0x3A 0x3B 0x3C 0x3D 0x3E 0x3F 0x40 0x61 0x62 0x63 0x64 0x65 0x66 0x67 0x68 0x69 0x6A 0x6B 0x6C 0x6D 0x6E 0x6F 0x70 0x71 0x72 0x73 0x74 0x75 0x76 0x77 0x78 0x79 0x7A 0x7B 0x7C 0x7D 0x5E 0x5F 0x60 0x61 0x62 0x63 0x64 0x65 0x66 0x67 0x68 0x69 0x6A 0x6B 0x6C 0x6D 0x6E 0x6F 0x70 0x71 0x72 0x73 0x74 0x75 0x76 0x77 0x78 0x79 0x7A 0x7B 0x7C 0x7D 0x7E 0x7F 0x80 0x81 0x82 0x83 0x84 0x85 0x86 0x87 0x88 0x89 0x8A 0x8B 0x8C 0x8D 0x8E 0x8F 0x90 0x91 0x92 0x93 0x94 0x95 0x96 0x97 0x98 0x99 0x9A 0x9B 0x9C 0x9D 0x9E 0x9F 0xA0 0xA1 0xA2 0xA3 0xA4 0xA5 0xA6 0xA7 0xA8 0xA9 0xAA 0xAB 0xAC 0xAD 0xAE 0xAF 0xB0 0xB1 0xB2 0xB3 0xB4 0xB5 0xB6 0xB7 0xB8 0xB9 0xBA 0xBB 0xBC 0xBD 0xBE 0xBF 0xE0 0xE1 0xE2 0xE3 0xE4 0xE5 0xE6 0xE7 0xE8 0xE9 0xEA 0xEB 0xEC 0xED 0xEE 0xEF 0xF0 0xF1 0xF2 0xF3 0xF4 0xF5 0xF6 0xD7 0xF8 0xF9 0xFA 0xFB 0xFC 0xFD 0xFE 0xDF 0xE0 0xE1 0xE2 0xE3 0xE4 0xE5 0xE6 0xE7 0xE8 0xE9 0xEA 0xEB 0xEC 0xED 0xEE 0xEF 0xF0 0xF1 0xF2 0xF3 0xF4 0xF5 0xF6 0xF7 0xF8 0xF9 0xFA 0xFB 0xFC 0xFD 0xFE 0xFF 0x00 0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09 0x0A 0x0B 0x0C 0x0D 0x0E 0x0F 0x10 0x11 0x12 0x13 0x14 0x15 0x16 0x17 0x18 0x19 0x1A 0x1B 0x1C 0x1D 0x1E 0x1F 0x20 0x21 0x22 0x23 0x24 0x25 0x26 0x27 0x28 0x29 0x2A 0x2B 0x2C 0x2D 0x2E 0x2F 0x30 0x31 0x32 0x33 0x34 0x35 0x36 0x37 0x38 0x39 0x3A 0x3B 0x3C 0x3D 0x3E 0x3F 0x40 0x41 0x42 0x43 0x44 0x45 0x46 0x47 0x48 0x49 0x4A 0x4B 0x4C 0x4D 0x4E 0x4F 0x50 0x51 0x52 0x53 0x54 0x55 0x56 0x57 0x58 0x59 0x5A 0x5B 0x5C 0x5D 0x5E 0x5F 0x60 0x41 0x42 0x43 0x44 0x45 0x46 0x47 0x48 0x49 0x4A 0x4B 0x4C 0x4D 0x4E 0x4F 0x50 0x51 0x52 0x53 0x54 0x55 0x56 0x57 0x58 0x59 0x5A 0x5B 0x5C 0x5D 0x7E 0x7F 0x80 0x81 0x82 0x83 0x84 0x85 0x86 0x87 0x88 0x89 0x8A 0x8B 0x8C 0x8D 0x8E 0x8F 0x90 0x91 0x92 0x93 0x94 0x95 0x96 0x97 0x98 0x99 0x9A 0x9B 0x9C 0x9D 0x9E 0x9F 0xA0 0xA1 0xA2 0xA3 0xA4 0xA5 0xA6 0xA7 0xA8 0xA9 0xAA 0xAB 0xAC 0xAD 0xAE 0xAF 0xB0 0xB1 0xB2 0xB3 0xB4 0xB5 0xB6 0xB7 0xB8 0xB9 0xBA 0xBB 0xBC 0xBD 0xBE 0xBF 0xC0 0xC1 0xC2 0xC3 0xC4 0xC5 0xC6 0xC7 0xC8 0xC9 0xCA 0xCB 0xCC 0xCD 0xCE 0xCF 0xD0 0xD1 0xD2 0xD3 0xD4 0xD5 0xD6 0xD7 0xD8 0xD9 0xDA 0xDB 0xDC 0xDD 0xDE 0xDF 0xC0 0xC1 0xC2 0xC3 0xC4 0xC5 0xC6 0xC7 0xC8 0xC9 0xCA 0xCB 0xCC 0xCD 0xCE 0xCF 0xD0 0xD1 0xD2 0xD3 0xD4 0xD5 0xD6 0xF7 0xD8 0xD9 0xDA 0xDB 0xDC 0xDD 0xDE 0xFF ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/locales/de_DE.iso88591���������������������������������������������������������������0000775�0000000�0000000�00000005021�13554550454�0017061�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������. . 0x00 0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09 0x0A 0x0B 0x0C 0x0D 0x0E 0x0F 0x10 0x11 0x12 0x13 0x14 0x15 0x16 0x17 0x18 0x19 0x1A 0x1B 0x1C 0x1D 0x1E 0x1F 0x20 0x21 0x22 0x23 0x24 0x25 0x26 0x27 0x28 0x29 0x2A 0x2B 0x2C 0x2D 0x2E 0x2F 0x30 0x31 0x32 0x33 0x34 0x35 0x36 0x37 0x38 0x39 0x3A 0x3B 0x3C 0x3D 0x3E 0x3F 0x40 0x61 0x62 0x63 0x64 0x65 0x66 0x67 0x68 0x69 0x6A 0x6B 0x6C 0x6D 0x6E 0x6F 0x70 0x71 0x72 0x73 0x74 0x75 0x76 0x77 0x78 0x79 0x7A 0x5B 0x5C 0x5D 0x5E 0x5F 0x60 0x61 0x62 0x63 0x64 0x65 0x66 0x67 0x68 0x69 0x6A 0x6B 0x6C 0x6D 0x6E 0x6F 0x70 0x71 0x72 0x73 0x74 0x75 0x76 0x77 0x78 0x79 0x7A 0x7B 0x7C 0x7D 0x7E 0x7F 0x80 0x81 0x82 0x83 0x84 0x85 0x86 0x87 0x88 0x89 0x8A 0x8B 0x8C 0x8D 0x8E 0x8F 0x90 0x91 0x92 0x93 0x94 0x95 0x96 0x97 0x98 0x99 0x9A 0x9B 0x9C 0x9D 0x9E 0x9F 0xA0 0xA1 0xA2 0xA3 0xA4 0xA5 0xA6 0xA7 0xA8 0xA9 0xAA 0xAB 0xAC 0xAD 0xAE 0xAF 0xB0 0xB1 0xB2 0xB3 0xB4 0xB5 0xB6 0xB7 0xB8 0xB9 0xBA 0xBB 0xBC 0xBD 0xBE 0xBF 0xE0 0xE1 0xE2 0xE3 0xE4 0xE5 0xE6 0xE7 0xE8 0xE9 0xEA 0xEB 0xEC 0xED 0xEE 0xEF 0xF0 0xF1 0xF2 0xF3 0xF4 0xF5 0xF6 0xD7 0xF8 0xF9 0xFA 0xFB 0xFC 0xFD 0xFE 0xDF 0xE0 0xE1 0xE2 0xE3 0xE4 0xE5 0xE6 0xE7 0xE8 0xE9 0xEA 0xEB 0xEC 0xED 0xEE 0xEF 0xF0 0xF1 0xF2 0xF3 0xF4 0xF5 0xF6 0xF7 0xF8 0xF9 0xFA 0xFB 0xFC 0xFD 0xFE 0xFF 0x00 0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09 0x0A 0x0B 0x0C 0x0D 0x0E 0x0F 0x10 0x11 0x12 0x13 0x14 0x15 0x16 0x17 0x18 0x19 0x1A 0x1B 0x1C 0x1D 0x1E 0x1F 0x20 0x21 0x22 0x23 0x24 0x25 0x26 0x27 0x28 0x29 0x2A 0x2B 0x2C 0x2D 0x2E 0x2F 0x30 0x31 0x32 0x33 0x34 0x35 0x36 0x37 0x38 0x39 0x3A 0x3B 0x3C 0x3D 0x3E 0x3F 0x40 0x41 0x42 0x43 0x44 0x45 0x46 0x47 0x48 0x49 0x4A 0x4B 0x4C 0x4D 0x4E 0x4F 0x50 0x51 0x52 0x53 0x54 0x55 0x56 0x57 0x58 0x59 0x5A 0x5B 0x5C 0x5D 0x5E 0x5F 0x60 0x41 0x42 0x43 0x44 0x45 0x46 0x47 0x48 0x49 0x4A 0x4B 0x4C 0x4D 0x4E 0x4F 0x50 0x51 0x52 0x53 0x54 0x55 0x56 0x57 0x58 0x59 0x5A 0x7B 0x7C 0x7D 0x7E 0x7F 0x80 0x81 0x82 0x83 0x84 0x85 0x86 0x87 0x88 0x89 0x8A 0x8B 0x8C 0x8D 0x8E 0x8F 0x90 0x91 0x92 0x93 0x94 0x95 0x96 0x97 0x98 0x99 0x9A 0x9B 0x9C 0x9D 0x9E 0x9F 0xA0 0xA1 0xA2 0xA3 0xA4 0xA5 0xA6 0xA7 0xA8 0xA9 0xAA 0xAB 0xAC 0xAD 0xAE 0xAF 0xB0 0xB1 0xB2 0xB3 0xB4 0xB5 0xB6 0xB7 0xB8 0xB9 0xBA 0xBB 0xBC 0xBD 0xBE 0xBF 0xC0 0xC1 0xC2 0xC3 0xC4 0xC5 0xC6 0xC7 0xC8 0xC9 0xCA 0xCB 0xCC 0xCD 0xCE 0xCF 0xD0 0xD1 0xD2 0xD3 0xD4 0xD5 0xD6 0xD7 0xD8 0xD9 0xDA 0xDB 0xDC 0xDD 0xDE 0xDF 0xC0 0xC1 0xC2 0xC3 0xC4 0xC5 0xC6 0xC7 0xC8 0xC9 0xCA 0xCB 0xCC 0xCD 0xCE 0xCF 0xD0 0xD1 0xD2 0xD3 0xD4 0xD5 0xD6 0xF7 0xD8 0xD9 0xDA 0xDB 0xDC 0xDD 0xDE 0xFF ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/locales/de_DE.iso88591_braces��������������������������������������������������������0000775�0000000�0000000�00000005021�13554550454�0020400�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������. . 0x00 0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09 0x0A 0x0B 0x0C 0x0D 0x0E 0x0F 0x10 0x11 0x12 0x13 0x14 0x15 0x16 0x17 0x18 0x19 0x1A 0x1B 0x1C 0x1D 0x1E 0x1F 0x20 0x21 0x22 0x23 0x24 0x25 0x26 0x27 0x28 0x29 0x2A 0x2B 0x2C 0x2D 0x2E 0x2F 0x30 0x31 0x32 0x33 0x34 0x35 0x36 0x37 0x38 0x39 0x3A 0x3B 0x3C 0x3D 0x3E 0x3F 0x40 0x61 0x62 0x63 0x64 0x65 0x66 0x67 0x68 0x69 0x6A 0x6B 0x6C 0x6D 0x6E 0x6F 0x70 0x71 0x72 0x73 0x74 0x75 0x76 0x77 0x78 0x79 0x7A 0x7B 0x7C 0x7D 0x5E 0x5F 0x60 0x61 0x62 0x63 0x64 0x65 0x66 0x67 0x68 0x69 0x6A 0x6B 0x6C 0x6D 0x6E 0x6F 0x70 0x71 0x72 0x73 0x74 0x75 0x76 0x77 0x78 0x79 0x7A 0x7B 0x7C 0x7D 0x7E 0x7F 0x80 0x81 0x82 0x83 0x84 0x85 0x86 0x87 0x88 0x89 0x8A 0x8B 0x8C 0x8D 0x8E 0x8F 0x90 0x91 0x92 0x93 0x94 0x95 0x96 0x97 0x98 0x99 0x9A 0x9B 0x9C 0x9D 0x9E 0x9F 0xA0 0xA1 0xA2 0xA3 0xA4 0xA5 0xA6 0xA7 0xA8 0xA9 0xAA 0xAB 0xAC 0xAD 0xAE 0xAF 0xB0 0xB1 0xB2 0xB3 0xB4 0xB5 0xB6 0xB7 0xB8 0xB9 0xBA 0xBB 0xBC 0xBD 0xBE 0xBF 0xE0 0xE1 0xE2 0xE3 0xE4 0xE5 0xE6 0xE7 0xE8 0xE9 0xEA 0xEB 0xEC 0xED 0xEE 0xEF 0xF0 0xF1 0xF2 0xF3 0xF4 0xF5 0xF6 0xD7 0xF8 0xF9 0xFA 0xFB 0xFC 0xFD 0xFE 0xDF 0xE0 0xE1 0xE2 0xE3 0xE4 0xE5 0xE6 0xE7 0xE8 0xE9 0xEA 0xEB 0xEC 0xED 0xEE 0xEF 0xF0 0xF1 0xF2 0xF3 0xF4 0xF5 0xF6 0xF7 0xF8 0xF9 0xFA 0xFB 0xFC 0xFD 0xFE 0xFF 0x00 0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09 0x0A 0x0B 0x0C 0x0D 0x0E 0x0F 0x10 0x11 0x12 0x13 0x14 0x15 0x16 0x17 0x18 0x19 0x1A 0x1B 0x1C 0x1D 0x1E 0x1F 0x20 0x21 0x22 0x23 0x24 0x25 0x26 0x27 0x28 0x29 0x2A 0x2B 0x2C 0x2D 0x2E 0x2F 0x30 0x31 0x32 0x33 0x34 0x35 0x36 0x37 0x38 0x39 0x3A 0x3B 0x3C 0x3D 0x3E 0x3F 0x40 0x41 0x42 0x43 0x44 0x45 0x46 0x47 0x48 0x49 0x4A 0x4B 0x4C 0x4D 0x4E 0x4F 0x50 0x51 0x52 0x53 0x54 0x55 0x56 0x57 0x58 0x59 0x5A 0x5B 0x5C 0x5D 0x5E 0x5F 0x60 0x41 0x42 0x43 0x44 0x45 0x46 0x47 0x48 0x49 0x4A 0x4B 0x4C 0x4D 0x4E 0x4F 0x50 0x51 0x52 0x53 0x54 0x55 0x56 0x57 0x58 0x59 0x5A 0x5B 0x5C 0x5D 0x7E 0x7F 0x80 0x81 0x82 0x83 0x84 0x85 0x86 0x87 0x88 0x89 0x8A 0x8B 0x8C 0x8D 0x8E 0x8F 0x90 0x91 0x92 0x93 0x94 0x95 0x96 0x97 0x98 0x99 0x9A 0x9B 0x9C 0x9D 0x9E 0x9F 0xA0 0xA1 0xA2 0xA3 0xA4 0xA5 0xA6 0xA7 0xA8 0xA9 0xAA 0xAB 0xAC 0xAD 0xAE 0xAF 0xB0 0xB1 0xB2 0xB3 0xB4 0xB5 0xB6 0xB7 0xB8 0xB9 0xBA 0xBB 0xBC 0xBD 0xBE 0xBF 0xC0 0xC1 0xC2 0xC3 0xC4 0xC5 0xC6 0xC7 0xC8 0xC9 0xCA 0xCB 0xCC 0xCD 0xCE 0xCF 0xD0 0xD1 0xD2 0xD3 0xD4 0xD5 0xD6 0xD7 0xD8 0xD9 0xDA 0xDB 0xDC 0xDD 0xDE 0xDF 0xC0 0xC1 0xC2 0xC3 0xC4 0xC5 0xC6 0xC7 0xC8 0xC9 0xCA 0xCB 0xCC 0xCD 0xCE 0xCF 0xD0 0xD1 0xD2 0xD3 0xD4 0xD5 0xD6 0xF7 0xD8 0xD9 0xDA 0xDB 0xDC 0xDD 0xDE 0xFF ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/locales/el_GR.iso88597���������������������������������������������������������������0000775�0000000�0000000�00000005143�13554550454�0017124�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������. . 0x00 0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09 0x0A 0x0B 0x0C 0x0D 0x0E 0x0F 0x10 0x11 0x12 0x13 0x14 0x15 0x16 0x17 0x18 0x19 0x1A 0x1B 0x1C 0x1D 0x1E 0x1F 0x20 0x21 0x22 0x23 0x24 0x25 0x26 0x27 0x28 0x29 0x2A 0x2B 0x2C 0x2D 0x2E 0x2F 0x30 0x31 0x32 0x33 0x34 0x35 0x36 0x37 0x38 0x39 0x3A 0x3B 0x3C 0x3D 0x3E 0x3F 0x40 0x61 0x62 0x63 0x64 0x65 0x66 0x67 0x68 0x69 0x6A 0x6B 0x6C 0x6D 0x6E 0x6F 0x70 0x71 0x72 0x73 0x74 0x75 0x76 0x77 0x78 0x79 0x7A 0x5B 0x5C 0x5D 0x5E 0x5F 0x60 0x61 0x62 0x63 0x64 0x65 0x66 0x67 0x68 0x69 0x6A 0x6B 0x6C 0x6D 0x6E 0x6F 0x70 0x71 0x72 0x73 0x74 0x75 0x76 0x77 0x78 0x79 0x7A 0x7B 0x7C 0x7D 0x7E 0x7F 0x80 0x81 0x82 0x83 0x84 0x85 0x86 0x87 0x88 0x89 0x8A 0x8B 0x8C 0x8D 0x8E 0x8F 0x90 0x91 0x92 0x93 0x94 0x95 0x96 0x97 0x98 0x99 0x9A 0x9B 0x9C 0x9D 0x9E 0x9F 0xA0 0xA1 0xA2 0xA3 0xA4 0xA5 0xA6 0xA7 0xA8 0xA9 0xAA 0xAB 0xAC 0xAD 0xAE 0xAF 0xB0 0xB1 0xB2 0xB3 0xB4 0xB5 0xDC 0xB7 0xDD 0xDE 0xDF 0xBB 0xFC 0xBD 0xFD 0xFE 0xC0 0xE1 0xE2 0xE3 0xE4 0xE5 0xE6 0xE7 0xE8 0xE9 0xEA 0xEB 0xEC 0xED 0xEE 0xEF 0xF0 0xF1 0xD2 0xF3 0xF4 0xF5 0xF6 0xF7 0xF8 0xF9 0xFA 0xFB 0xDC 0xDD 0xDE 0xDF 0xE0 0xE1 0xE2 0xE3 0xE4 0xE5 0xE6 0xE7 0xE8 0xE9 0xEA 0xEB 0xEC 0xED 0xEE 0xEF 0xF0 0xF1 0xF2 0xF3 0xF4 0xF5 0xF6 0xF7 0xF8 0xF9 0xFA 0xFB 0xFC 0xFD 0xFE 0xFF 0x00 0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09 0x0A 0x0B 0x0C 0x0D 0x0E 0x0F 0x10 0x11 0x12 0x13 0x14 0x15 0x16 0x17 0x18 0x19 0x1A 0x1B 0x1C 0x1D 0x1E 0x1F 0x20 0x21 0x22 0x23 0x24 0x25 0x26 0x27 0x28 0x29 0x2A 0x2B 0x2C 0x2D 0x2E 0x2F 0x30 0x31 0x32 0x33 0x34 0x35 0x36 0x37 0x38 0x39 0x3A 0x3B 0x3C 0x3D 0x3E 0x3F 0x40 0x41 0x42 0x43 0x44 0x45 0x46 0x47 0x48 0x49 0x4A 0x4B 0x4C 0x4D 0x4E 0x4F 0x50 0x51 0x52 0x53 0x54 0x55 0x56 0x57 0x58 0x59 0x5A 0x5B 0x5C 0x5D 0x5E 0x5F 0x60 0x41 0x42 0x43 0x44 0x45 0x46 0x47 0x48 0x49 0x4A 0x4B 0x4C 0x4D 0x4E 0x4F 0x50 0x51 0x52 0x53 0x54 0x55 0x56 0x57 0x58 0x59 0x5A 0x7B 0x7C 0x7D 0x7E 0x7F 0x80 0x81 0x82 0x83 0x84 0x85 0x86 0x87 0x88 0x89 0x8A 0x8B 0x8C 0x8D 0x8E 0x8F 0x90 0x91 0x92 0x93 0x94 0x95 0x96 0x97 0x98 0x99 0x9A 0x9B 0x9C 0x9D 0x9E 0x9F 0xA0 0xA1 0xA2 0xA3 0xA4 0xA5 0xA6 0xA7 0xA8 0xA9 0xAA 0xAB 0xAC 0xAD 0xAE 0xAF 0xB0 0xB1 0xB2 0xB3 0xB4 0xB5 0xB6 0xB7 0xB8 0xB9 0xBA 0xBB 0xBC 0xBD 0xBE 0xBF 0xC0 0xC1 0xC2 0xC3 0xC4 0xC5 0xC6 0xC7 0xC8 0xC9 0xCA 0xCB 0xCC 0xCD 0xCE 0xCF 0xD0 0xD1 0xD2 0xD3 0xD4 0xD5 0xD6 0xD7 0xD8 0xD9 0xDA 0xDB 0xB6 0xB8 0xB9 0xBA 0xE0 0xC1 0xC2 0xC3 0xC4 0xC5 0xC6 0xC7 0xC8 0xC9 0xCA 0xCB 0xCC 0xCD 0xCE 0xCF 0xD0 0xD1 0xD3 0xD3 0xD4 0xD5 0xD6 0xD7 0xD8 0xD9 0xDA 0xDB 0xBC 0xBE 0xBF 0xFF �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/locales/el_GR.iso88597_braces��������������������������������������������������������0000775�0000000�0000000�00000005143�13554550454�0020443�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������. . 0x00 0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09 0x0A 0x0B 0x0C 0x0D 0x0E 0x0F 0x10 0x11 0x12 0x13 0x14 0x15 0x16 0x17 0x18 0x19 0x1A 0x1B 0x1C 0x1D 0x1E 0x1F 0x20 0x21 0x22 0x23 0x24 0x25 0x26 0x27 0x28 0x29 0x2A 0x2B 0x2C 0x2D 0x2E 0x2F 0x30 0x31 0x32 0x33 0x34 0x35 0x36 0x37 0x38 0x39 0x3A 0x3B 0x3C 0x3D 0x3E 0x3F 0x40 0x61 0x62 0x63 0x64 0x65 0x66 0x67 0x68 0x69 0x6A 0x6B 0x6C 0x6D 0x6E 0x6F 0x70 0x71 0x72 0x73 0x74 0x75 0x76 0x77 0x78 0x79 0x7A 0x7B 0x7C 0x7D 0x5E 0x5F 0x60 0x61 0x62 0x63 0x64 0x65 0x66 0x67 0x68 0x69 0x6A 0x6B 0x6C 0x6D 0x6E 0x6F 0x70 0x71 0x72 0x73 0x74 0x75 0x76 0x77 0x78 0x79 0x7A 0x7B 0x7C 0x7D 0x7E 0x7F 0x80 0x81 0x82 0x83 0x84 0x85 0x86 0x87 0x88 0x89 0x8A 0x8B 0x8C 0x8D 0x8E 0x8F 0x90 0x91 0x92 0x93 0x94 0x95 0x96 0x97 0x98 0x99 0x9A 0x9B 0x9C 0x9D 0x9E 0x9F 0xA0 0xA1 0xA2 0xA3 0xA4 0xA5 0xA6 0xA7 0xA8 0xA9 0xAA 0xAB 0xAC 0xAD 0xAE 0xAF 0xB0 0xB1 0xB2 0xB3 0xB4 0xB5 0xDC 0xB7 0xDD 0xDE 0xDF 0xBB 0xFC 0xBD 0xFD 0xFE 0xC0 0xE1 0xE2 0xE3 0xE4 0xE5 0xE6 0xE7 0xE8 0xE9 0xEA 0xEB 0xEC 0xED 0xEE 0xEF 0xF0 0xF1 0xD2 0xF3 0xF4 0xF5 0xF6 0xF7 0xF8 0xF9 0xFA 0xFB 0xDC 0xDD 0xDE 0xDF 0xE0 0xE1 0xE2 0xE3 0xE4 0xE5 0xE6 0xE7 0xE8 0xE9 0xEA 0xEB 0xEC 0xED 0xEE 0xEF 0xF0 0xF1 0xF2 0xF3 0xF4 0xF5 0xF6 0xF7 0xF8 0xF9 0xFA 0xFB 0xFC 0xFD 0xFE 0xFF 0x00 0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09 0x0A 0x0B 0x0C 0x0D 0x0E 0x0F 0x10 0x11 0x12 0x13 0x14 0x15 0x16 0x17 0x18 0x19 0x1A 0x1B 0x1C 0x1D 0x1E 0x1F 0x20 0x21 0x22 0x23 0x24 0x25 0x26 0x27 0x28 0x29 0x2A 0x2B 0x2C 0x2D 0x2E 0x2F 0x30 0x31 0x32 0x33 0x34 0x35 0x36 0x37 0x38 0x39 0x3A 0x3B 0x3C 0x3D 0x3E 0x3F 0x40 0x41 0x42 0x43 0x44 0x45 0x46 0x47 0x48 0x49 0x4A 0x4B 0x4C 0x4D 0x4E 0x4F 0x50 0x51 0x52 0x53 0x54 0x55 0x56 0x57 0x58 0x59 0x5A 0x5B 0x5C 0x5D 0x5E 0x5F 0x60 0x41 0x42 0x43 0x44 0x45 0x46 0x47 0x48 0x49 0x4A 0x4B 0x4C 0x4D 0x4E 0x4F 0x50 0x51 0x52 0x53 0x54 0x55 0x56 0x57 0x58 0x59 0x5A 0x5B 0x5C 0x5D 0x7E 0x7F 0x80 0x81 0x82 0x83 0x84 0x85 0x86 0x87 0x88 0x89 0x8A 0x8B 0x8C 0x8D 0x8E 0x8F 0x90 0x91 0x92 0x93 0x94 0x95 0x96 0x97 0x98 0x99 0x9A 0x9B 0x9C 0x9D 0x9E 0x9F 0xA0 0xA1 0xA2 0xA3 0xA4 0xA5 0xA6 0xA7 0xA8 0xA9 0xAA 0xAB 0xAC 0xAD 0xAE 0xAF 0xB0 0xB1 0xB2 0xB3 0xB4 0xB5 0xB6 0xB7 0xB8 0xB9 0xBA 0xBB 0xBC 0xBD 0xBE 0xBF 0xC0 0xC1 0xC2 0xC3 0xC4 0xC5 0xC6 0xC7 0xC8 0xC9 0xCA 0xCB 0xCC 0xCD 0xCE 0xCF 0xD0 0xD1 0xD2 0xD3 0xD4 0xD5 0xD6 0xD7 0xD8 0xD9 0xDA 0xDB 0xB6 0xB8 0xB9 0xBA 0xE0 0xC1 0xC2 0xC3 0xC4 0xC5 0xC6 0xC7 0xC8 0xC9 0xCA 0xCB 0xCC 0xCD 0xCE 0xCF 0xD0 0xD1 0xD3 0xD3 0xD4 0xD5 0xD6 0xD7 0xD8 0xD9 0xDA 0xDB 0xBC 0xBE 0xBF 0xFF �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/locales/es_ES.iso88591���������������������������������������������������������������0000775�0000000�0000000�00000005034�13554550454�0017123�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������. . 0x00 0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09 0x0A 0x0B 0x0C 0x0D 0x0E 0x0F 0x10 0x11 0x12 0x13 0x14 0x15 0x16 0x17 0x18 0x19 0x1A 0x1B 0x1C 0x1D 0x1E 0x1F 0x20 0x21 0x22 0x23 0x24 0x25 0x26 0x27 0x28 0x29 0x2A 0x2B 0x2C 0x2D 0x2E 0x2F 0x30 0x31 0x32 0x33 0x34 0x35 0x36 0x37 0x38 0x39 0x3A 0x3B 0x3C 0x3D 0x3E 0x3F 0x40 0x61 0x62 0x63 0x64 0x65 0x66 0x67 0x68 0x69 0x6A 0x6B 0x6C 0x6D 0x6E 0x6F 0x70 0x71 0x72 0x73 0x74 0x75 0x76 0x77 0x78 0x79 0x7A 0x5B 0x5C 0x5D 0x5E 0x5F 0x60 0x61 0x62 0x63 0x64 0x65 0x66 0x67 0x68 0x69 0x6A 0x6B 0x6C 0x6D 0x6E 0x6F 0x70 0x71 0x72 0x73 0x74 0x75 0x76 0x77 0x78 0x79 0x7A 0x7B 0x7C 0x7D 0x7E 0x7F 0x80 0x81 0x82 0x83 0x84 0x85 0x86 0x87 0x88 0x89 0x8A 0x8B 0x8C 0x8D 0x8E 0x8F 0x90 0x91 0x92 0x93 0x94 0x95 0x96 0x97 0x98 0x99 0x9A 0x9B 0x9C 0x9D 0x9E 0x9F 0xA0 0xA1 0xA2 0xA3 0xA4 0xA5 0xA6 0xA7 0xA8 0xA9 0xAA 0xAB 0xAC 0xAD 0xAE 0xAF 0xB0 0xB1 0xB2 0xB3 0xB4 0xB5 0xB6 0xB7 0xB8 0xB9 0xBA 0xBB 0xBC 0xBD 0xBE 0xBF 0xE0 0xE1 0xE2 0xE3 0xE4 0xE5 0xE6 0xE7 0xE8 0xE9 0xEA 0xEB 0xEC 0xED 0xEE 0xEF 0xF0 0xF1 0xF2 0xF3 0xF4 0xF5 0xF6 0xD7 0xF8 0xF9 0xFA 0xFB 0xFC 0xFD 0xFE 0xDF 0xE0 0xE1 0xE2 0xE3 0xE4 0xE5 0xE6 0xE7 0xE8 0xE9 0xEA 0xEB 0xEC 0xED 0xEE 0xEF 0xF0 0xF1 0xF2 0xF3 0xF4 0xF5 0xF6 0xF7 0xF8 0xF9 0xFA 0xFB 0xFC 0xFD 0xFE 0xFF 0x00 0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09 0x0A 0x0B 0x0C 0x0D 0x0E 0x0F 0x10 0x11 0x12 0x13 0x14 0x15 0x16 0x17 0x18 0x19 0x1A 0x1B 0x1C 0x1D 0x1E 0x1F 0x20 0x21 0x22 0x23 0x24 0x25 0x26 0x27 0x28 0x29 0x2A 0x2B 0x2C 0x2D 0x2E 0x2F 0x30 0x31 0x32 0x33 0x34 0x35 0x36 0x37 0x38 0x39 0x3A 0x3B 0x3C 0x3D 0x3E 0x3F 0x40 0x41 0x42 0x43 0x44 0x45 0x46 0x47 0x48 0x49 0x4A 0x4B 0x4C 0x4D 0x4E 0x4F 0x50 0x51 0x52 0x53 0x54 0x55 0x56 0x57 0x58 0x59 0x5A 0x5B 0x5C 0x5D 0x5E 0x5F 0x60 0x41 0x42 0x43 0x44 0x45 0x46 0x47 0x48 0x49 0x4A 0x4B 0x4C 0x4D 0x4E 0x4F 0x50 0x51 0x52 0x53 0x54 0x55 0x56 0x57 0x58 0x59 0x5A 0x7B 0x7C 0x7D 0x7E 0x7F 0x80 0x81 0x82 0x83 0x84 0x85 0x86 0x87 0x88 0x89 0x8A 0x8B 0x8C 0x8D 0x8E 0x8F 0x90 0x91 0x92 0x93 0x94 0x95 0x96 0x97 0x98 0x99 0x9A 0x9B 0x9C 0x9D 0x9E 0x9F 0xA0 0xA1 0xA2 0xA3 0xA4 0xA5 0xA6 0xA7 0xA8 0xA9 0xAA 0xAB 0xAC 0xAD 0xAE 0xAF 0xB0 0xB1 0xB2 0xB3 0xB4 0xB5 0xB6 0xB7 0xB8 0xB9 0xBA 0xBB 0xBC 0xBD 0xBE 0xBF 0xC0 0xC1 0xC2 0xC3 0xC4 0xC5 0xC6 0xC7 0xC8 0xC9 0xCA 0xCB 0xCC 0xCD 0xCE 0xCF 0xD0 0xD1 0xD2 0xD3 0xD4 0xD5 0xD6 0xD7 0xD8 0xD9 0xDA 0xDB 0xDC 0xDD 0xDE 0xDF 0xC0 0xC1 0xC2 0xC3 0xC4 0xC5 0xC6 0xC7 0xC8 0xC9 0xCA 0xCB 0xCC 0xCD 0xCE 0xCF 0xD0 0xD1 0xD2 0xD3 0xD4 0xD5 0xD6 0xF7 0xD8 0xD9 0xDA 0xDB 0xDC 0xDD 0xDE 0xFF ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/locales/es_ES.iso88591_braces��������������������������������������������������������0000775�0000000�0000000�00000005034�13554550454�0020442�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������. . 0x00 0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09 0x0A 0x0B 0x0C 0x0D 0x0E 0x0F 0x10 0x11 0x12 0x13 0x14 0x15 0x16 0x17 0x18 0x19 0x1A 0x1B 0x1C 0x1D 0x1E 0x1F 0x20 0x21 0x22 0x23 0x24 0x25 0x26 0x27 0x28 0x29 0x2A 0x2B 0x2C 0x2D 0x2E 0x2F 0x30 0x31 0x32 0x33 0x34 0x35 0x36 0x37 0x38 0x39 0x3A 0x3B 0x3C 0x3D 0x3E 0x3F 0x40 0x61 0x62 0x63 0x64 0x65 0x66 0x67 0x68 0x69 0x6A 0x6B 0x6C 0x6D 0x6E 0x6F 0x70 0x71 0x72 0x73 0x74 0x75 0x76 0x77 0x78 0x79 0x7A 0x7B 0x7C 0x7D 0x5E 0x5F 0x60 0x61 0x62 0x63 0x64 0x65 0x66 0x67 0x68 0x69 0x6A 0x6B 0x6C 0x6D 0x6E 0x6F 0x70 0x71 0x72 0x73 0x74 0x75 0x76 0x77 0x78 0x79 0x7A 0x7B 0x7C 0x7D 0x7E 0x7F 0x80 0x81 0x82 0x83 0x84 0x85 0x86 0x87 0x88 0x89 0x8A 0x8B 0x8C 0x8D 0x8E 0x8F 0x90 0x91 0x92 0x93 0x94 0x95 0x96 0x97 0x98 0x99 0x9A 0x9B 0x9C 0x9D 0x9E 0x9F 0xA0 0xA1 0xA2 0xA3 0xA4 0xA5 0xA6 0xA7 0xA8 0xA9 0xAA 0xAB 0xAC 0xAD 0xAE 0xAF 0xB0 0xB1 0xB2 0xB3 0xB4 0xB5 0xB6 0xB7 0xB8 0xB9 0xBA 0xBB 0xBC 0xBD 0xBE 0xBF 0xE0 0xE1 0xE2 0xE3 0xE4 0xE5 0xE6 0xE7 0xE8 0xE9 0xEA 0xEB 0xEC 0xED 0xEE 0xEF 0xF0 0xF1 0xF2 0xF3 0xF4 0xF5 0xF6 0xD7 0xF8 0xF9 0xFA 0xFB 0xFC 0xFD 0xFE 0xDF 0xE0 0xE1 0xE2 0xE3 0xE4 0xE5 0xE6 0xE7 0xE8 0xE9 0xEA 0xEB 0xEC 0xED 0xEE 0xEF 0xF0 0xF1 0xF2 0xF3 0xF4 0xF5 0xF6 0xF7 0xF8 0xF9 0xFA 0xFB 0xFC 0xFD 0xFE 0xFF 0x00 0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09 0x0A 0x0B 0x0C 0x0D 0x0E 0x0F 0x10 0x11 0x12 0x13 0x14 0x15 0x16 0x17 0x18 0x19 0x1A 0x1B 0x1C 0x1D 0x1E 0x1F 0x20 0x21 0x22 0x23 0x24 0x25 0x26 0x27 0x28 0x29 0x2A 0x2B 0x2C 0x2D 0x2E 0x2F 0x30 0x31 0x32 0x33 0x34 0x35 0x36 0x37 0x38 0x39 0x3A 0x3B 0x3C 0x3D 0x3E 0x3F 0x40 0x41 0x42 0x43 0x44 0x45 0x46 0x47 0x48 0x49 0x4A 0x4B 0x4C 0x4D 0x4E 0x4F 0x50 0x51 0x52 0x53 0x54 0x55 0x56 0x57 0x58 0x59 0x5A 0x5B 0x5C 0x5D 0x5E 0x5F 0x60 0x41 0x42 0x43 0x44 0x45 0x46 0x47 0x48 0x49 0x4A 0x4B 0x4C 0x4D 0x4E 0x4F 0x50 0x51 0x52 0x53 0x54 0x55 0x56 0x57 0x58 0x59 0x5A 0x5B 0x5C 0x5D 0x7E 0x7F 0x80 0x81 0x82 0x83 0x84 0x85 0x86 0x87 0x88 0x89 0x8A 0x8B 0x8C 0x8D 0x8E 0x8F 0x90 0x91 0x92 0x93 0x94 0x95 0x96 0x97 0x98 0x99 0x9A 0x9B 0x9C 0x9D 0x9E 0x9F 0xA0 0xA1 0xA2 0xA3 0xA4 0xA5 0xA6 0xA7 0xA8 0xA9 0xAA 0xAB 0xAC 0xAD 0xAE 0xAF 0xB0 0xB1 0xB2 0xB3 0xB4 0xB5 0xB6 0xB7 0xB8 0xB9 0xBA 0xBB 0xBC 0xBD 0xBE 0xBF 0xC0 0xC1 0xC2 0xC3 0xC4 0xC5 0xC6 0xC7 0xC8 0xC9 0xCA 0xCB 0xCC 0xCD 0xCE 0xCF 0xD0 0xD1 0xD2 0xD3 0xD4 0xD5 0xD6 0xD7 0xD8 0xD9 0xDA 0xDB 0xDC 0xDD 0xDE 0xDF 0xC0 0xC1 0xC2 0xC3 0xC4 0xC5 0xC6 0xC7 0xC8 0xC9 0xCA 0xCB 0xCC 0xCD 0xCE 0xCF 0xD0 0xD1 0xD2 0xD3 0xD4 0xD5 0xD6 0xF7 0xD8 0xD9 0xDA 0xDB 0xDC 0xDD 0xDE 0xFF ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/locales/fr_FR.iso88591���������������������������������������������������������������0000775�0000000�0000000�00000005057�13554550454�0017130�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������. . 0x00 0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09 0x0A 0x0B 0x0C 0x0D 0x0E 0x0F 0x10 0x11 0x12 0x13 0x14 0x15 0x16 0x17 0x18 0x19 0x1A 0x1B 0x1C 0x1D 0x1E 0x1F 0x20 0x21 0x22 0x23 0x24 0x25 0x26 0x27 0x28 0x29 0x2A 0x2B 0x2C 0x2D 0x2E 0x2F 0x30 0x31 0x32 0x33 0x34 0x35 0x36 0x37 0x38 0x39 0x3A 0x3B 0x3C 0x3D 0x3E 0x3F 0x40 0x61 0x62 0x63 0x64 0x65 0x66 0x67 0x68 0x69 0x6A 0x6B 0x6C 0x6D 0x6E 0x6F 0x70 0x71 0x72 0x73 0x74 0x75 0x76 0x77 0x78 0x79 0x7A 0x5B 0x5C 0x5D 0x5E 0x5F 0x60 0x61 0x62 0x63 0x64 0x65 0x66 0x67 0x68 0x69 0x6A 0x6B 0x6C 0x6D 0x6E 0x6F 0x70 0x71 0x72 0x73 0x74 0x75 0x76 0x77 0x78 0x79 0x7A 0x7B 0x7C 0x7D 0x7E 0x7F 0x80 0x81 0x82 0x83 0x84 0x85 0x86 0x87 0x88 0x89 0x8A 0x8B 0x8C 0x8D 0x8E 0x8F 0x90 0x91 0x92 0x93 0x94 0x95 0x96 0x97 0x98 0x99 0x9A 0x9B 0x9C 0x9D 0x9E 0x9F 0xA0 0xA1 0xA2 0xA3 0xA4 0xA5 0xA6 0xA7 0xA8 0xA9 0xAA 0xAB 0xAC 0xAD 0xAE 0xAF 0xB0 0xB1 0xB2 0xB3 0xB4 0xB5 0xB6 0xB7 0xB8 0xB9 0xBA 0xBB 0xBC 0xBD 0xBE 0xBF 0xE0 0xE1 0xE2 0xE3 0xE4 0xE5 0xE6 0xE7 0xE8 0xE9 0xEA 0xEB 0xEC 0xED 0xEE 0xEF 0xF0 0xF1 0xF2 0xF3 0xF4 0xF5 0xF6 0xD7 0xF8 0xF9 0xFA 0xFB 0xFC 0xFD 0xFE 0xDF 0xE0 0xE1 0xE2 0xE3 0xE4 0xE5 0xE6 0xE7 0xE8 0xE9 0xEA 0xEB 0xEC 0xED 0xEE 0xEF 0xF0 0xF1 0xF2 0xF3 0xF4 0xF5 0xF6 0xF7 0xF8 0xF9 0xFA 0xFB 0xFC 0xFD 0xFE 0xFF 0x00 0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09 0x0A 0x0B 0x0C 0x0D 0x0E 0x0F 0x10 0x11 0x12 0x13 0x14 0x15 0x16 0x17 0x18 0x19 0x1A 0x1B 0x1C 0x1D 0x1E 0x1F 0x20 0x21 0x22 0x23 0x24 0x25 0x26 0x27 0x28 0x29 0x2A 0x2B 0x2C 0x2D 0x2E 0x2F 0x30 0x31 0x32 0x33 0x34 0x35 0x36 0x37 0x38 0x39 0x3A 0x3B 0x3C 0x3D 0x3E 0x3F 0x40 0x41 0x42 0x43 0x44 0x45 0x46 0x47 0x48 0x49 0x4A 0x4B 0x4C 0x4D 0x4E 0x4F 0x50 0x51 0x52 0x53 0x54 0x55 0x56 0x57 0x58 0x59 0x5A 0x5B 0x5C 0x5D 0x5E 0x5F 0x60 0x41 0x42 0x43 0x44 0x45 0x46 0x47 0x48 0x49 0x4A 0x4B 0x4C 0x4D 0x4E 0x4F 0x50 0x51 0x52 0x53 0x54 0x55 0x56 0x57 0x58 0x59 0x5A 0x7B 0x7C 0x7D 0x7E 0x7F 0x80 0x81 0x82 0x83 0x84 0x85 0x86 0x87 0x88 0x89 0x8A 0x8B 0x8C 0x8D 0x8E 0x8F 0x90 0x91 0x92 0x93 0x94 0x95 0x96 0x97 0x98 0x99 0x9A 0x9B 0x9C 0x9D 0x9E 0x9F 0xA0 0xA1 0xA2 0xA3 0xA4 0xA5 0xA6 0xA7 0xA8 0xA9 0xAA 0xAB 0xAC 0xAD 0xAE 0xAF 0xB0 0xB1 0xB2 0xB3 0xB4 0xB5 0xB6 0xB7 0xB8 0xB9 0xBA 0xBB 0xBC 0xBD 0xBE 0xBF 0xC0 0xC1 0xC2 0xC3 0xC4 0xC5 0xC6 0xC7 0xC8 0xC9 0xCA 0xCB 0xCC 0xCD 0xCE 0xCF 0xD0 0xD1 0xD2 0xD3 0xD4 0xD5 0xD6 0xD7 0xD8 0xD9 0xDA 0xDB 0xDC 0xDD 0xDE 0xDF 0xC0 0xC1 0xC2 0xC3 0xC4 0xC5 0xC6 0xC7 0xC8 0xC9 0xCA 0xCB 0xCC 0xCD 0xCE 0xCF 0xD0 0xD1 0xD2 0xD3 0xD4 0xD5 0xD6 0xF7 0xD8 0xD9 0xDA 0xDB 0xDC 0xDD 0xDE 0xFF ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/locales/fr_FR.iso88591_braces��������������������������������������������������������0000775�0000000�0000000�00000005057�13554550454�0020447�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������. . 0x00 0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09 0x0A 0x0B 0x0C 0x0D 0x0E 0x0F 0x10 0x11 0x12 0x13 0x14 0x15 0x16 0x17 0x18 0x19 0x1A 0x1B 0x1C 0x1D 0x1E 0x1F 0x20 0x21 0x22 0x23 0x24 0x25 0x26 0x27 0x28 0x29 0x2A 0x2B 0x2C 0x2D 0x2E 0x2F 0x30 0x31 0x32 0x33 0x34 0x35 0x36 0x37 0x38 0x39 0x3A 0x3B 0x3C 0x3D 0x3E 0x3F 0x40 0x61 0x62 0x63 0x64 0x65 0x66 0x67 0x68 0x69 0x6A 0x6B 0x6C 0x6D 0x6E 0x6F 0x70 0x71 0x72 0x73 0x74 0x75 0x76 0x77 0x78 0x79 0x7A 0x7B 0x7C 0x7D 0x5E 0x5F 0x60 0x61 0x62 0x63 0x64 0x65 0x66 0x67 0x68 0x69 0x6A 0x6B 0x6C 0x6D 0x6E 0x6F 0x70 0x71 0x72 0x73 0x74 0x75 0x76 0x77 0x78 0x79 0x7A 0x7B 0x7C 0x7D 0x7E 0x7F 0x80 0x81 0x82 0x83 0x84 0x85 0x86 0x87 0x88 0x89 0x8A 0x8B 0x8C 0x8D 0x8E 0x8F 0x90 0x91 0x92 0x93 0x94 0x95 0x96 0x97 0x98 0x99 0x9A 0x9B 0x9C 0x9D 0x9E 0x9F 0xA0 0xA1 0xA2 0xA3 0xA4 0xA5 0xA6 0xA7 0xA8 0xA9 0xAA 0xAB 0xAC 0xAD 0xAE 0xAF 0xB0 0xB1 0xB2 0xB3 0xB4 0xB5 0xB6 0xB7 0xB8 0xB9 0xBA 0xBB 0xBC 0xBD 0xBE 0xBF 0xE0 0xE1 0xE2 0xE3 0xE4 0xE5 0xE6 0xE7 0xE8 0xE9 0xEA 0xEB 0xEC 0xED 0xEE 0xEF 0xF0 0xF1 0xF2 0xF3 0xF4 0xF5 0xF6 0xD7 0xF8 0xF9 0xFA 0xFB 0xFC 0xFD 0xFE 0xDF 0xE0 0xE1 0xE2 0xE3 0xE4 0xE5 0xE6 0xE7 0xE8 0xE9 0xEA 0xEB 0xEC 0xED 0xEE 0xEF 0xF0 0xF1 0xF2 0xF3 0xF4 0xF5 0xF6 0xF7 0xF8 0xF9 0xFA 0xFB 0xFC 0xFD 0xFE 0xFF 0x00 0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09 0x0A 0x0B 0x0C 0x0D 0x0E 0x0F 0x10 0x11 0x12 0x13 0x14 0x15 0x16 0x17 0x18 0x19 0x1A 0x1B 0x1C 0x1D 0x1E 0x1F 0x20 0x21 0x22 0x23 0x24 0x25 0x26 0x27 0x28 0x29 0x2A 0x2B 0x2C 0x2D 0x2E 0x2F 0x30 0x31 0x32 0x33 0x34 0x35 0x36 0x37 0x38 0x39 0x3A 0x3B 0x3C 0x3D 0x3E 0x3F 0x40 0x41 0x42 0x43 0x44 0x45 0x46 0x47 0x48 0x49 0x4A 0x4B 0x4C 0x4D 0x4E 0x4F 0x50 0x51 0x52 0x53 0x54 0x55 0x56 0x57 0x58 0x59 0x5A 0x5B 0x5C 0x5D 0x5E 0x5F 0x60 0x41 0x42 0x43 0x44 0x45 0x46 0x47 0x48 0x49 0x4A 0x4B 0x4C 0x4D 0x4E 0x4F 0x50 0x51 0x52 0x53 0x54 0x55 0x56 0x57 0x58 0x59 0x5A 0x5B 0x5C 0x5D 0x7E 0x7F 0x80 0x81 0x82 0x83 0x84 0x85 0x86 0x87 0x88 0x89 0x8A 0x8B 0x8C 0x8D 0x8E 0x8F 0x90 0x91 0x92 0x93 0x94 0x95 0x96 0x97 0x98 0x99 0x9A 0x9B 0x9C 0x9D 0x9E 0x9F 0xA0 0xA1 0xA2 0xA3 0xA4 0xA5 0xA6 0xA7 0xA8 0xA9 0xAA 0xAB 0xAC 0xAD 0xAE 0xAF 0xB0 0xB1 0xB2 0xB3 0xB4 0xB5 0xB6 0xB7 0xB8 0xB9 0xBA 0xBB 0xBC 0xBD 0xBE 0xBF 0xC0 0xC1 0xC2 0xC3 0xC4 0xC5 0xC6 0xC7 0xC8 0xC9 0xCA 0xCB 0xCC 0xCD 0xCE 0xCF 0xD0 0xD1 0xD2 0xD3 0xD4 0xD5 0xD6 0xD7 0xD8 0xD9 0xDA 0xDB 0xDC 0xDD 0xDE 0xDF 0xC0 0xC1 0xC2 0xC3 0xC4 0xC5 0xC6 0xC7 0xC8 0xC9 0xCA 0xCB 0xCC 0xCD 0xCE 0xCF 0xD0 0xD1 0xD2 0xD3 0xD4 0xD5 0xD6 0xF7 0xD8 0xD9 0xDA 0xDB 0xDC 0xDD 0xDE 0xFF ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/locales/hu_HU.iso88592���������������������������������������������������������������0000775�0000000�0000000�00000005042�13554550454�0017135�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������. . 0x00 0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09 0x0A 0x0B 0x0C 0x0D 0x0E 0x0F 0x10 0x11 0x12 0x13 0x14 0x15 0x16 0x17 0x18 0x19 0x1A 0x1B 0x1C 0x1D 0x1E 0x1F 0x20 0x21 0x22 0x23 0x24 0x25 0x26 0x27 0x28 0x29 0x2A 0x2B 0x2C 0x2D 0x2E 0x2F 0x30 0x31 0x32 0x33 0x34 0x35 0x36 0x37 0x38 0x39 0x3A 0x3B 0x3C 0x3D 0x3E 0x3F 0x40 0x61 0x62 0x63 0x64 0x65 0x66 0x67 0x68 0x69 0x6A 0x6B 0x6C 0x6D 0x6E 0x6F 0x70 0x71 0x72 0x73 0x74 0x75 0x76 0x77 0x78 0x79 0x7A 0x5B 0x5C 0x5D 0x5E 0x5F 0x60 0x61 0x62 0x63 0x64 0x65 0x66 0x67 0x68 0x69 0x6A 0x6B 0x6C 0x6D 0x6E 0x6F 0x70 0x71 0x72 0x73 0x74 0x75 0x76 0x77 0x78 0x79 0x7A 0x7B 0x7C 0x7D 0x7E 0x7F 0x80 0x81 0x82 0x83 0x84 0x85 0x86 0x87 0x88 0x89 0x8A 0x8B 0x8C 0x8D 0x8E 0x8F 0x90 0x91 0x92 0x93 0x94 0x95 0x96 0x97 0x98 0x99 0x9A 0x9B 0x9C 0x9D 0x9E 0x9F 0xA0 0xB1 0xA2 0xB3 0xA4 0xB5 0xB6 0xA7 0xA8 0xB9 0xBA 0xBB 0xBC 0xAD 0xBE 0xBF 0xB0 0xB1 0xB2 0xB3 0xB4 0xB5 0xB6 0xB7 0xB8 0xB9 0xBA 0xBB 0xBC 0xBD 0xBE 0xBF 0xE0 0xE1 0xE2 0xE3 0xE4 0xE5 0xE6 0xE7 0xE8 0xE9 0xEA 0xEB 0xEC 0xED 0xEE 0xEF 0xF0 0xF1 0xF2 0xF3 0xF4 0xF5 0xF6 0xD7 0xF8 0xF9 0xFA 0xFB 0xFC 0xFD 0xFE 0xDF 0xE0 0xE1 0xE2 0xE3 0xE4 0xE5 0xE6 0xE7 0xE8 0xE9 0xEA 0xEB 0xEC 0xED 0xEE 0xEF 0xF0 0xF1 0xF2 0xF3 0xF4 0xF5 0xF6 0xF7 0xF8 0xF9 0xFA 0xFB 0xFC 0xFD 0xFE 0xFF 0x00 0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09 0x0A 0x0B 0x0C 0x0D 0x0E 0x0F 0x10 0x11 0x12 0x13 0x14 0x15 0x16 0x17 0x18 0x19 0x1A 0x1B 0x1C 0x1D 0x1E 0x1F 0x20 0x21 0x22 0x23 0x24 0x25 0x26 0x27 0x28 0x29 0x2A 0x2B 0x2C 0x2D 0x2E 0x2F 0x30 0x31 0x32 0x33 0x34 0x35 0x36 0x37 0x38 0x39 0x3A 0x3B 0x3C 0x3D 0x3E 0x3F 0x40 0x41 0x42 0x43 0x44 0x45 0x46 0x47 0x48 0x49 0x4A 0x4B 0x4C 0x4D 0x4E 0x4F 0x50 0x51 0x52 0x53 0x54 0x55 0x56 0x57 0x58 0x59 0x5A 0x5B 0x5C 0x5D 0x5E 0x5F 0x60 0x41 0x42 0x43 0x44 0x45 0x46 0x47 0x48 0x49 0x4A 0x4B 0x4C 0x4D 0x4E 0x4F 0x50 0x51 0x52 0x53 0x54 0x55 0x56 0x57 0x58 0x59 0x5A 0x7B 0x7C 0x7D 0x7E 0x7F 0x80 0x81 0x82 0x83 0x84 0x85 0x86 0x87 0x88 0x89 0x8A 0x8B 0x8C 0x8D 0x8E 0x8F 0x90 0x91 0x92 0x93 0x94 0x95 0x96 0x97 0x98 0x99 0x9A 0x9B 0x9C 0x9D 0x9E 0x9F 0xA0 0xA1 0xA2 0xA3 0xA4 0xA5 0xA6 0xA7 0xA8 0xA9 0xAA 0xAB 0xAC 0xAD 0xAE 0xAF 0xB0 0xA1 0xB2 0xA3 0xB4 0xA5 0xA6 0xB7 0xB8 0xA9 0xAA 0xAB 0xAC 0xBD 0xAE 0xAF 0xC0 0xC1 0xC2 0xC3 0xC4 0xC5 0xC6 0xC7 0xC8 0xC9 0xCA 0xCB 0xCC 0xCD 0xCE 0xCF 0xD0 0xD1 0xD2 0xD3 0xD4 0xD5 0xD6 0xD7 0xD8 0xD9 0xDA 0xDB 0xDC 0xDD 0xDE 0xDF 0xC0 0xC1 0xC2 0xC3 0xC4 0xC5 0xC6 0xC7 0xC8 0xC9 0xCA 0xCB 0xCC 0xCD 0xCE 0xCF 0xD0 0xD1 0xD2 0xD3 0xD4 0xD5 0xD6 0xF7 0xD8 0xD9 0xDA 0xDB 0xDC 0xDD 0xDE 0xFF ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/locales/hu_HU.iso88592_braces��������������������������������������������������������0000775�0000000�0000000�00000005042�13554550454�0020454�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������. . 0x00 0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09 0x0A 0x0B 0x0C 0x0D 0x0E 0x0F 0x10 0x11 0x12 0x13 0x14 0x15 0x16 0x17 0x18 0x19 0x1A 0x1B 0x1C 0x1D 0x1E 0x1F 0x20 0x21 0x22 0x23 0x24 0x25 0x26 0x27 0x28 0x29 0x2A 0x2B 0x2C 0x2D 0x2E 0x2F 0x30 0x31 0x32 0x33 0x34 0x35 0x36 0x37 0x38 0x39 0x3A 0x3B 0x3C 0x3D 0x3E 0x3F 0x40 0x61 0x62 0x63 0x64 0x65 0x66 0x67 0x68 0x69 0x6A 0x6B 0x6C 0x6D 0x6E 0x6F 0x70 0x71 0x72 0x73 0x74 0x75 0x76 0x77 0x78 0x79 0x7A 0x7B 0x7C 0x7D 0x5E 0x5F 0x60 0x61 0x62 0x63 0x64 0x65 0x66 0x67 0x68 0x69 0x6A 0x6B 0x6C 0x6D 0x6E 0x6F 0x70 0x71 0x72 0x73 0x74 0x75 0x76 0x77 0x78 0x79 0x7A 0x7B 0x7C 0x7D 0x7E 0x7F 0x80 0x81 0x82 0x83 0x84 0x85 0x86 0x87 0x88 0x89 0x8A 0x8B 0x8C 0x8D 0x8E 0x8F 0x90 0x91 0x92 0x93 0x94 0x95 0x96 0x97 0x98 0x99 0x9A 0x9B 0x9C 0x9D 0x9E 0x9F 0xA0 0xB1 0xA2 0xB3 0xA4 0xB5 0xB6 0xA7 0xA8 0xB9 0xBA 0xBB 0xBC 0xAD 0xBE 0xBF 0xB0 0xB1 0xB2 0xB3 0xB4 0xB5 0xB6 0xB7 0xB8 0xB9 0xBA 0xBB 0xBC 0xBD 0xBE 0xBF 0xE0 0xE1 0xE2 0xE3 0xE4 0xE5 0xE6 0xE7 0xE8 0xE9 0xEA 0xEB 0xEC 0xED 0xEE 0xEF 0xF0 0xF1 0xF2 0xF3 0xF4 0xF5 0xF6 0xD7 0xF8 0xF9 0xFA 0xFB 0xFC 0xFD 0xFE 0xDF 0xE0 0xE1 0xE2 0xE3 0xE4 0xE5 0xE6 0xE7 0xE8 0xE9 0xEA 0xEB 0xEC 0xED 0xEE 0xEF 0xF0 0xF1 0xF2 0xF3 0xF4 0xF5 0xF6 0xF7 0xF8 0xF9 0xFA 0xFB 0xFC 0xFD 0xFE 0xFF 0x00 0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09 0x0A 0x0B 0x0C 0x0D 0x0E 0x0F 0x10 0x11 0x12 0x13 0x14 0x15 0x16 0x17 0x18 0x19 0x1A 0x1B 0x1C 0x1D 0x1E 0x1F 0x20 0x21 0x22 0x23 0x24 0x25 0x26 0x27 0x28 0x29 0x2A 0x2B 0x2C 0x2D 0x2E 0x2F 0x30 0x31 0x32 0x33 0x34 0x35 0x36 0x37 0x38 0x39 0x3A 0x3B 0x3C 0x3D 0x3E 0x3F 0x40 0x41 0x42 0x43 0x44 0x45 0x46 0x47 0x48 0x49 0x4A 0x4B 0x4C 0x4D 0x4E 0x4F 0x50 0x51 0x52 0x53 0x54 0x55 0x56 0x57 0x58 0x59 0x5A 0x5B 0x5C 0x5D 0x5E 0x5F 0x60 0x41 0x42 0x43 0x44 0x45 0x46 0x47 0x48 0x49 0x4A 0x4B 0x4C 0x4D 0x4E 0x4F 0x50 0x51 0x52 0x53 0x54 0x55 0x56 0x57 0x58 0x59 0x5A 0x5B 0x5C 0x5D 0x7E 0x7F 0x80 0x81 0x82 0x83 0x84 0x85 0x86 0x87 0x88 0x89 0x8A 0x8B 0x8C 0x8D 0x8E 0x8F 0x90 0x91 0x92 0x93 0x94 0x95 0x96 0x97 0x98 0x99 0x9A 0x9B 0x9C 0x9D 0x9E 0x9F 0xA0 0xA1 0xA2 0xA3 0xA4 0xA5 0xA6 0xA7 0xA8 0xA9 0xAA 0xAB 0xAC 0xAD 0xAE 0xAF 0xB0 0xA1 0xB2 0xA3 0xB4 0xA5 0xA6 0xB7 0xB8 0xA9 0xAA 0xAB 0xAC 0xBD 0xAE 0xAF 0xC0 0xC1 0xC2 0xC3 0xC4 0xC5 0xC6 0xC7 0xC8 0xC9 0xCA 0xCB 0xCC 0xCD 0xCE 0xCF 0xD0 0xD1 0xD2 0xD3 0xD4 0xD5 0xD6 0xD7 0xD8 0xD9 0xDA 0xDB 0xDC 0xDD 0xDE 0xDF 0xC0 0xC1 0xC2 0xC3 0xC4 0xC5 0xC6 0xC7 0xC8 0xC9 0xCA 0xCB 0xCC 0xCD 0xCE 0xCF 0xD0 0xD1 0xD2 0xD3 0xD4 0xD5 0xD6 0xF7 0xD8 0xD9 0xDA 0xDB 0xDC 0xDD 0xDE 0xFF ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/locales/is_IS.iso88591���������������������������������������������������������������0000775�0000000�0000000�00000005042�13554550454�0017132�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������. . 0x00 0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09 0x0A 0x0B 0x0C 0x0D 0x0E 0x0F 0x10 0x11 0x12 0x13 0x14 0x15 0x16 0x17 0x18 0x19 0x1A 0x1B 0x1C 0x1D 0x1E 0x1F 0x20 0x21 0x22 0x23 0x24 0x25 0x26 0x27 0x28 0x29 0x2A 0x2B 0x2C 0x2D 0x2E 0x2F 0x30 0x31 0x32 0x33 0x34 0x35 0x36 0x37 0x38 0x39 0x3A 0x3B 0x3C 0x3D 0x3E 0x3F 0x40 0x61 0x62 0x63 0x64 0x65 0x66 0x67 0x68 0x69 0x6A 0x6B 0x6C 0x6D 0x6E 0x6F 0x70 0x71 0x72 0x73 0x74 0x75 0x76 0x77 0x78 0x79 0x7A 0x5B 0x5C 0x5D 0x5E 0x5F 0x60 0x61 0x62 0x63 0x64 0x65 0x66 0x67 0x68 0x69 0x6A 0x6B 0x6C 0x6D 0x6E 0x6F 0x70 0x71 0x72 0x73 0x74 0x75 0x76 0x77 0x78 0x79 0x7A 0x7B 0x7C 0x7D 0x7E 0x7F 0x80 0x81 0x82 0x83 0x84 0x85 0x86 0x87 0x88 0x89 0x8A 0x8B 0x8C 0x8D 0x8E 0x8F 0x90 0x91 0x92 0x93 0x94 0x95 0x96 0x97 0x98 0x99 0x9A 0x9B 0x9C 0x9D 0x9E 0x9F 0xA0 0xA1 0xA2 0xA3 0xA4 0xA5 0xA6 0xA7 0xA8 0xA9 0xAA 0xAB 0xAC 0xAD 0xAE 0xAF 0xB0 0xB1 0xB2 0xB3 0xB4 0xB5 0xB6 0xB7 0xB8 0xB9 0xBA 0xBB 0xBC 0xBD 0xBE 0xBF 0xE0 0xE1 0xE2 0xE3 0xE4 0xE5 0xE6 0xE7 0xE8 0xE9 0xEA 0xEB 0xEC 0xED 0xEE 0xEF 0xF0 0xF1 0xF2 0xF3 0xF4 0xF5 0xF6 0xD7 0xF8 0xF9 0xFA 0xFB 0xFC 0xFD 0xFE 0xDF 0xE0 0xE1 0xE2 0xE3 0xE4 0xE5 0xE6 0xE7 0xE8 0xE9 0xEA 0xEB 0xEC 0xED 0xEE 0xEF 0xF0 0xF1 0xF2 0xF3 0xF4 0xF5 0xF6 0xF7 0xF8 0xF9 0xFA 0xFB 0xFC 0xFD 0xFE 0xFF 0x00 0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09 0x0A 0x0B 0x0C 0x0D 0x0E 0x0F 0x10 0x11 0x12 0x13 0x14 0x15 0x16 0x17 0x18 0x19 0x1A 0x1B 0x1C 0x1D 0x1E 0x1F 0x20 0x21 0x22 0x23 0x24 0x25 0x26 0x27 0x28 0x29 0x2A 0x2B 0x2C 0x2D 0x2E 0x2F 0x30 0x31 0x32 0x33 0x34 0x35 0x36 0x37 0x38 0x39 0x3A 0x3B 0x3C 0x3D 0x3E 0x3F 0x40 0x41 0x42 0x43 0x44 0x45 0x46 0x47 0x48 0x49 0x4A 0x4B 0x4C 0x4D 0x4E 0x4F 0x50 0x51 0x52 0x53 0x54 0x55 0x56 0x57 0x58 0x59 0x5A 0x5B 0x5C 0x5D 0x5E 0x5F 0x60 0x41 0x42 0x43 0x44 0x45 0x46 0x47 0x48 0x49 0x4A 0x4B 0x4C 0x4D 0x4E 0x4F 0x50 0x51 0x52 0x53 0x54 0x55 0x56 0x57 0x58 0x59 0x5A 0x7B 0x7C 0x7D 0x7E 0x7F 0x80 0x81 0x82 0x83 0x84 0x85 0x86 0x87 0x88 0x89 0x8A 0x8B 0x8C 0x8D 0x8E 0x8F 0x90 0x91 0x92 0x93 0x94 0x95 0x96 0x97 0x98 0x99 0x9A 0x9B 0x9C 0x9D 0x9E 0x9F 0xA0 0xA1 0xA2 0xA3 0xA4 0xA5 0xA6 0xA7 0xA8 0xA9 0xAA 0xAB 0xAC 0xAD 0xAE 0xAF 0xB0 0xB1 0xB2 0xB3 0xB4 0xB5 0xB6 0xB7 0xB8 0xB9 0xBA 0xBB 0xBC 0xBD 0xBE 0xBF 0xC0 0xC1 0xC2 0xC3 0xC4 0xC5 0xC6 0xC7 0xC8 0xC9 0xCA 0xCB 0xCC 0xCD 0xCE 0xCF 0xD0 0xD1 0xD2 0xD3 0xD4 0xD5 0xD6 0xD7 0xD8 0xD9 0xDA 0xDB 0xDC 0xDD 0xDE 0xDF 0xC0 0xC1 0xC2 0xC3 0xC4 0xC5 0xC6 0xC7 0xC8 0xC9 0xCA 0xCB 0xCC 0xCD 0xCE 0xCF 0xD0 0xD1 0xD2 0xD3 0xD4 0xD5 0xD6 0xF7 0xD8 0xD9 0xDA 0xDB 0xDC 0xDD 0xDE 0xFF ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/locales/is_IS.iso88591_braces��������������������������������������������������������0000775�0000000�0000000�00000005042�13554550454�0020451�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������. . 0x00 0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09 0x0A 0x0B 0x0C 0x0D 0x0E 0x0F 0x10 0x11 0x12 0x13 0x14 0x15 0x16 0x17 0x18 0x19 0x1A 0x1B 0x1C 0x1D 0x1E 0x1F 0x20 0x21 0x22 0x23 0x24 0x25 0x26 0x27 0x28 0x29 0x2A 0x2B 0x2C 0x2D 0x2E 0x2F 0x30 0x31 0x32 0x33 0x34 0x35 0x36 0x37 0x38 0x39 0x3A 0x3B 0x3C 0x3D 0x3E 0x3F 0x40 0x61 0x62 0x63 0x64 0x65 0x66 0x67 0x68 0x69 0x6A 0x6B 0x6C 0x6D 0x6E 0x6F 0x70 0x71 0x72 0x73 0x74 0x75 0x76 0x77 0x78 0x79 0x7A 0x7B 0x7C 0x7D 0x5E 0x5F 0x60 0x61 0x62 0x63 0x64 0x65 0x66 0x67 0x68 0x69 0x6A 0x6B 0x6C 0x6D 0x6E 0x6F 0x70 0x71 0x72 0x73 0x74 0x75 0x76 0x77 0x78 0x79 0x7A 0x7B 0x7C 0x7D 0x7E 0x7F 0x80 0x81 0x82 0x83 0x84 0x85 0x86 0x87 0x88 0x89 0x8A 0x8B 0x8C 0x8D 0x8E 0x8F 0x90 0x91 0x92 0x93 0x94 0x95 0x96 0x97 0x98 0x99 0x9A 0x9B 0x9C 0x9D 0x9E 0x9F 0xA0 0xA1 0xA2 0xA3 0xA4 0xA5 0xA6 0xA7 0xA8 0xA9 0xAA 0xAB 0xAC 0xAD 0xAE 0xAF 0xB0 0xB1 0xB2 0xB3 0xB4 0xB5 0xB6 0xB7 0xB8 0xB9 0xBA 0xBB 0xBC 0xBD 0xBE 0xBF 0xE0 0xE1 0xE2 0xE3 0xE4 0xE5 0xE6 0xE7 0xE8 0xE9 0xEA 0xEB 0xEC 0xED 0xEE 0xEF 0xF0 0xF1 0xF2 0xF3 0xF4 0xF5 0xF6 0xD7 0xF8 0xF9 0xFA 0xFB 0xFC 0xFD 0xFE 0xDF 0xE0 0xE1 0xE2 0xE3 0xE4 0xE5 0xE6 0xE7 0xE8 0xE9 0xEA 0xEB 0xEC 0xED 0xEE 0xEF 0xF0 0xF1 0xF2 0xF3 0xF4 0xF5 0xF6 0xF7 0xF8 0xF9 0xFA 0xFB 0xFC 0xFD 0xFE 0xFF 0x00 0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09 0x0A 0x0B 0x0C 0x0D 0x0E 0x0F 0x10 0x11 0x12 0x13 0x14 0x15 0x16 0x17 0x18 0x19 0x1A 0x1B 0x1C 0x1D 0x1E 0x1F 0x20 0x21 0x22 0x23 0x24 0x25 0x26 0x27 0x28 0x29 0x2A 0x2B 0x2C 0x2D 0x2E 0x2F 0x30 0x31 0x32 0x33 0x34 0x35 0x36 0x37 0x38 0x39 0x3A 0x3B 0x3C 0x3D 0x3E 0x3F 0x40 0x41 0x42 0x43 0x44 0x45 0x46 0x47 0x48 0x49 0x4A 0x4B 0x4C 0x4D 0x4E 0x4F 0x50 0x51 0x52 0x53 0x54 0x55 0x56 0x57 0x58 0x59 0x5A 0x5B 0x5C 0x5D 0x5E 0x5F 0x60 0x41 0x42 0x43 0x44 0x45 0x46 0x47 0x48 0x49 0x4A 0x4B 0x4C 0x4D 0x4E 0x4F 0x50 0x51 0x52 0x53 0x54 0x55 0x56 0x57 0x58 0x59 0x5A 0x5B 0x5C 0x5D 0x7E 0x7F 0x80 0x81 0x82 0x83 0x84 0x85 0x86 0x87 0x88 0x89 0x8A 0x8B 0x8C 0x8D 0x8E 0x8F 0x90 0x91 0x92 0x93 0x94 0x95 0x96 0x97 0x98 0x99 0x9A 0x9B 0x9C 0x9D 0x9E 0x9F 0xA0 0xA1 0xA2 0xA3 0xA4 0xA5 0xA6 0xA7 0xA8 0xA9 0xAA 0xAB 0xAC 0xAD 0xAE 0xAF 0xB0 0xB1 0xB2 0xB3 0xB4 0xB5 0xB6 0xB7 0xB8 0xB9 0xBA 0xBB 0xBC 0xBD 0xBE 0xBF 0xC0 0xC1 0xC2 0xC3 0xC4 0xC5 0xC6 0xC7 0xC8 0xC9 0xCA 0xCB 0xCC 0xCD 0xCE 0xCF 0xD0 0xD1 0xD2 0xD3 0xD4 0xD5 0xD6 0xD7 0xD8 0xD9 0xDA 0xDB 0xDC 0xDD 0xDE 0xDF 0xC0 0xC1 0xC2 0xC3 0xC4 0xC5 0xC6 0xC7 0xC8 0xC9 0xCA 0xCB 0xCC 0xCD 0xCE 0xCF 0xD0 0xD1 0xD2 0xD3 0xD4 0xD5 0xD6 0xF7 0xD8 0xD9 0xDA 0xDB 0xDC 0xDD 0xDE 0xFF ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/locales/iso88591���������������������������������������������������������������������0000775�0000000�0000000�00000005146�13554550454�0016132�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������. . 0x00 0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09 0x0A 0x0B 0x0C 0x0D 0x0E 0x0F 0x10 0x11 0x12 0x13 0x14 0x15 0x16 0x17 0x18 0x19 0x1A 0x1B 0x1C 0x1D 0x1E 0x1F 0x20 0x21 0x22 0x23 0x24 0x25 0x26 0x27 0x28 0x29 0x2A 0x2B 0x2C 0x2D 0x2E 0x2F 0x30 0x31 0x32 0x33 0x34 0x35 0x36 0x37 0x38 0x39 0x3A 0x3B 0x3C 0x3D 0x3E 0x3F 0x40 0x61 0x62 0x63 0x64 0x65 0x66 0x67 0x68 0x69 0x6A 0x6B 0x6C 0x6D 0x6E 0x6F 0x70 0x71 0x72 0x73 0x74 0x75 0x76 0x77 0x78 0x79 0x7A 0x5B 0x5C 0x5D 0x5E 0x5F 0x60 0x61 0x62 0x63 0x64 0x65 0x66 0x67 0x68 0x69 0x6A 0x6B 0x6C 0x6D 0x6E 0x6F 0x70 0x71 0x72 0x73 0x74 0x75 0x76 0x77 0x78 0x79 0x7A 0x7B 0x7C 0x7D 0x7E 0x7F 0x80 0x81 0x82 0x83 0x84 0x85 0x86 0x87 0x88 0x89 0x8A 0x8B 0x8C 0x8D 0x8E 0x8F 0x90 0x91 0x92 0x93 0x94 0x95 0x96 0x97 0x98 0x99 0x9A 0x9B 0x9C 0x9D 0x9E 0x9F 0xA0 0xA1 0xA2 0xA3 0xA4 0xA5 0xA6 0xA7 0xA8 0xA9 0xAA 0xAB 0xAC 0xAD 0xAE 0xAF 0xB0 0xB1 0xB2 0xB3 0xB4 0xB5 0xB6 0xB7 0xB8 0xB9 0xBA 0xBB 0xBC 0xBD 0xBE 0xBF 0xE0 0xE1 0xE2 0xE3 0xE4 0xE5 0xE6 0xE7 0xE8 0xE9 0xEA 0xEB 0xEC 0xED 0xEE 0xEF 0xF0 0xF1 0xF2 0xF3 0xF4 0xF5 0xF6 0xD7 0xF8 0xF9 0xFA 0xFB 0xFC 0xFD 0xFE 0xDF 0xE0 0xE1 0xE2 0xE3 0xE4 0xE5 0xE6 0xE7 0xE8 0xE9 0xEA 0xEB 0xEC 0xED 0xEE 0xEF 0xF0 0xF1 0xF2 0xF3 0xF4 0xF5 0xF6 0xF7 0xF8 0xF9 0xFA 0xFB 0xFC 0xFD 0xFE 0xFF 0x00 0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09 0x0A 0x0B 0x0C 0x0D 0x0E 0x0F 0x10 0x11 0x12 0x13 0x14 0x15 0x16 0x17 0x18 0x19 0x1A 0x1B 0x1C 0x1D 0x1E 0x1F 0x20 0x21 0x22 0x23 0x24 0x25 0x26 0x27 0x28 0x29 0x2A 0x2B 0x2C 0x2D 0x2E 0x2F 0x30 0x31 0x32 0x33 0x34 0x35 0x36 0x37 0x38 0x39 0x3A 0x3B 0x3C 0x3D 0x3E 0x3F 0x40 0x41 0x42 0x43 0x44 0x45 0x46 0x47 0x48 0x49 0x4A 0x4B 0x4C 0x4D 0x4E 0x4F 0x50 0x51 0x52 0x53 0x54 0x55 0x56 0x57 0x58 0x59 0x5A 0x5B 0x5C 0x5D 0x5E 0x5F 0x60 0x41 0x42 0x43 0x44 0x45 0x46 0x47 0x48 0x49 0x4A 0x4B 0x4C 0x4D 0x4E 0x4F 0x50 0x51 0x52 0x53 0x54 0x55 0x56 0x57 0x58 0x59 0x5A 0x7B 0x7C 0x7D 0x7E 0x7F 0x80 0x81 0x82 0x83 0x84 0x85 0x86 0x87 0x88 0x89 0x8A 0x8B 0x8C 0x8D 0x8E 0x8F 0x90 0x91 0x92 0x93 0x94 0x95 0x96 0x97 0x98 0x99 0x9A 0x9B 0x9C 0x9D 0x9E 0x9F 0xA0 0xA1 0xA2 0xA3 0xA4 0xA5 0xA6 0xA7 0xA8 0xA9 0xAA 0xAB 0xAC 0xAD 0xAE 0xAF 0xB0 0xB1 0xB2 0xB3 0xB4 0xB5 0xB6 0xB7 0xB8 0xB9 0xBA 0xBB 0xBC 0xBD 0xBE 0xBF 0xC0 0xC1 0xC2 0xC3 0xC4 0xC5 0xC6 0xC7 0xC8 0xC9 0xCA 0xCB 0xCC 0xCD 0xCE 0xCF 0xD0 0xD1 0xD2 0xD3 0xD4 0xD5 0xD6 0xD7 0xD8 0xD9 0xDA 0xDB 0xDC 0xDD 0xDE 0xDF 0xC0 0xC1 0xC2 0xC3 0xC4 0xC5 0xC6 0xC7 0xC8 0xC9 0xCA 0xCB 0xCC 0xCD 0xCE 0xCF 0xD0 0xD1 0xD2 0xD3 0xD4 0xD5 0xD6 0xF7 0xD8 0xD9 0xDA 0xDB 0xDC 0xDD 0xDE 0xFF ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/locales/iso88591_braces��������������������������������������������������������������0000775�0000000�0000000�00000005146�13554550454�0017451�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������. . 0x00 0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09 0x0A 0x0B 0x0C 0x0D 0x0E 0x0F 0x10 0x11 0x12 0x13 0x14 0x15 0x16 0x17 0x18 0x19 0x1A 0x1B 0x1C 0x1D 0x1E 0x1F 0x20 0x21 0x22 0x23 0x24 0x25 0x26 0x27 0x28 0x29 0x2A 0x2B 0x2C 0x2D 0x2E 0x2F 0x30 0x31 0x32 0x33 0x34 0x35 0x36 0x37 0x38 0x39 0x3A 0x3B 0x3C 0x3D 0x3E 0x3F 0x40 0x61 0x62 0x63 0x64 0x65 0x66 0x67 0x68 0x69 0x6A 0x6B 0x6C 0x6D 0x6E 0x6F 0x70 0x71 0x72 0x73 0x74 0x75 0x76 0x77 0x78 0x79 0x7A 0x7B 0x7C 0x7D 0x5E 0x5F 0x60 0x61 0x62 0x63 0x64 0x65 0x66 0x67 0x68 0x69 0x6A 0x6B 0x6C 0x6D 0x6E 0x6F 0x70 0x71 0x72 0x73 0x74 0x75 0x76 0x77 0x78 0x79 0x7A 0x7B 0x7C 0x7D 0x7E 0x7F 0x80 0x81 0x82 0x83 0x84 0x85 0x86 0x87 0x88 0x89 0x8A 0x8B 0x8C 0x8D 0x8E 0x8F 0x90 0x91 0x92 0x93 0x94 0x95 0x96 0x97 0x98 0x99 0x9A 0x9B 0x9C 0x9D 0x9E 0x9F 0xA0 0xA1 0xA2 0xA3 0xA4 0xA5 0xA6 0xA7 0xA8 0xA9 0xAA 0xAB 0xAC 0xAD 0xAE 0xAF 0xB0 0xB1 0xB2 0xB3 0xB4 0xB5 0xB6 0xB7 0xB8 0xB9 0xBA 0xBB 0xBC 0xBD 0xBE 0xBF 0xE0 0xE1 0xE2 0xE3 0xE4 0xE5 0xE6 0xE7 0xE8 0xE9 0xEA 0xEB 0xEC 0xED 0xEE 0xEF 0xF0 0xF1 0xF2 0xF3 0xF4 0xF5 0xF6 0xD7 0xF8 0xF9 0xFA 0xFB 0xFC 0xFD 0xFE 0xDF 0xE0 0xE1 0xE2 0xE3 0xE4 0xE5 0xE6 0xE7 0xE8 0xE9 0xEA 0xEB 0xEC 0xED 0xEE 0xEF 0xF0 0xF1 0xF2 0xF3 0xF4 0xF5 0xF6 0xF7 0xF8 0xF9 0xFA 0xFB 0xFC 0xFD 0xFE 0xFF 0x00 0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09 0x0A 0x0B 0x0C 0x0D 0x0E 0x0F 0x10 0x11 0x12 0x13 0x14 0x15 0x16 0x17 0x18 0x19 0x1A 0x1B 0x1C 0x1D 0x1E 0x1F 0x20 0x21 0x22 0x23 0x24 0x25 0x26 0x27 0x28 0x29 0x2A 0x2B 0x2C 0x2D 0x2E 0x2F 0x30 0x31 0x32 0x33 0x34 0x35 0x36 0x37 0x38 0x39 0x3A 0x3B 0x3C 0x3D 0x3E 0x3F 0x40 0x41 0x42 0x43 0x44 0x45 0x46 0x47 0x48 0x49 0x4A 0x4B 0x4C 0x4D 0x4E 0x4F 0x50 0x51 0x52 0x53 0x54 0x55 0x56 0x57 0x58 0x59 0x5A 0x5B 0x5C 0x5D 0x5E 0x5F 0x60 0x41 0x42 0x43 0x44 0x45 0x46 0x47 0x48 0x49 0x4A 0x4B 0x4C 0x4D 0x4E 0x4F 0x50 0x51 0x52 0x53 0x54 0x55 0x56 0x57 0x58 0x59 0x5A 0x5B 0x5C 0x5D 0x7E 0x7F 0x80 0x81 0x82 0x83 0x84 0x85 0x86 0x87 0x88 0x89 0x8A 0x8B 0x8C 0x8D 0x8E 0x8F 0x90 0x91 0x92 0x93 0x94 0x95 0x96 0x97 0x98 0x99 0x9A 0x9B 0x9C 0x9D 0x9E 0x9F 0xA0 0xA1 0xA2 0xA3 0xA4 0xA5 0xA6 0xA7 0xA8 0xA9 0xAA 0xAB 0xAC 0xAD 0xAE 0xAF 0xB0 0xB1 0xB2 0xB3 0xB4 0xB5 0xB6 0xB7 0xB8 0xB9 0xBA 0xBB 0xBC 0xBD 0xBE 0xBF 0xC0 0xC1 0xC2 0xC3 0xC4 0xC5 0xC6 0xC7 0xC8 0xC9 0xCA 0xCB 0xCC 0xCD 0xCE 0xCF 0xD0 0xD1 0xD2 0xD3 0xD4 0xD5 0xD6 0xD7 0xD8 0xD9 0xDA 0xDB 0xDC 0xDD 0xDE 0xDF 0xC0 0xC1 0xC2 0xC3 0xC4 0xC5 0xC6 0xC7 0xC8 0xC9 0xCA 0xCB 0xCC 0xCD 0xCE 0xCF 0xD0 0xD1 0xD2 0xD3 0xD4 0xD5 0xD6 0xF7 0xD8 0xD9 0xDA 0xDB 0xDC 0xDD 0xDE 0xFF ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/locales/iso88592���������������������������������������������������������������������0000775�0000000�0000000�00000005201�13554550454�0016123�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������. . 0x00 0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09 0x0A 0x0B 0x0C 0x0D 0x0E 0x0F 0x10 0x11 0x12 0x13 0x14 0x15 0x16 0x17 0x18 0x19 0x1A 0x1B 0x1C 0x1D 0x1E 0x1F 0x20 0x21 0x22 0x23 0x24 0x25 0x26 0x27 0x28 0x29 0x2A 0x2B 0x2C 0x2D 0x2E 0x2F 0x30 0x31 0x32 0x33 0x34 0x35 0x36 0x37 0x38 0x39 0x3A 0x3B 0x3C 0x3D 0x3E 0x3F 0x40 0x61 0x62 0x63 0x64 0x65 0x66 0x67 0x68 0x69 0x6A 0x6B 0x6C 0x6D 0x6E 0x6F 0x70 0x71 0x72 0x73 0x74 0x75 0x76 0x77 0x78 0x79 0x7A 0x5B 0x5C 0x5D 0x5E 0x5F 0x60 0x61 0x62 0x63 0x64 0x65 0x66 0x67 0x68 0x69 0x6A 0x6B 0x6C 0x6D 0x6E 0x6F 0x70 0x71 0x72 0x73 0x74 0x75 0x76 0x77 0x78 0x79 0x7A 0x7B 0x7C 0x7D 0x7E 0x7F 0x80 0x81 0x82 0x83 0x84 0x85 0x86 0x87 0x88 0x89 0x8A 0x8B 0x8C 0x8D 0x8E 0x8F 0x90 0x91 0x92 0x93 0x94 0x95 0x96 0x97 0x98 0x99 0x9A 0x9B 0x9C 0x9D 0x9E 0x9F 0xA0 0xB1 0xA2 0xB3 0xA4 0xB5 0xB6 0xA7 0xA8 0xB9 0xBA 0xBB 0xBC 0xAD 0xBE 0xBF 0xB0 0xB1 0xB2 0xB3 0xB4 0xB5 0xB6 0xB7 0xB8 0xB9 0xBA 0xBB 0xBC 0xBD 0xBE 0xBF 0xE0 0xE1 0xE2 0xE3 0xE4 0xE5 0xE6 0xE7 0xE8 0xE9 0xEA 0xEB 0xEC 0xED 0xEE 0xEF 0xF0 0xF1 0xF2 0xF3 0xF4 0xF5 0xF6 0xD7 0xF8 0xF9 0xFA 0xFB 0xFC 0xFD 0xFE 0xDF 0xE0 0xE1 0xE2 0xE3 0xE4 0xE5 0xE6 0xE7 0xE8 0xE9 0xEA 0xEB 0xEC 0xED 0xEE 0xEF 0xF0 0xF1 0xF2 0xF3 0xF4 0xF5 0xF6 0xF7 0xF8 0xF9 0xFA 0xFB 0xFC 0xFD 0xFE 0xFF 0x00 0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09 0x0A 0x0B 0x0C 0x0D 0x0E 0x0F 0x10 0x11 0x12 0x13 0x14 0x15 0x16 0x17 0x18 0x19 0x1A 0x1B 0x1C 0x1D 0x1E 0x1F 0x20 0x21 0x22 0x23 0x24 0x25 0x26 0x27 0x28 0x29 0x2A 0x2B 0x2C 0x2D 0x2E 0x2F 0x30 0x31 0x32 0x33 0x34 0x35 0x36 0x37 0x38 0x39 0x3A 0x3B 0x3C 0x3D 0x3E 0x3F 0x40 0x41 0x42 0x43 0x44 0x45 0x46 0x47 0x48 0x49 0x4A 0x4B 0x4C 0x4D 0x4E 0x4F 0x50 0x51 0x52 0x53 0x54 0x55 0x56 0x57 0x58 0x59 0x5A 0x5B 0x5C 0x5D 0x5E 0x5F 0x60 0x41 0x42 0x43 0x44 0x45 0x46 0x47 0x48 0x49 0x4A 0x4B 0x4C 0x4D 0x4E 0x4F 0x50 0x51 0x52 0x53 0x54 0x55 0x56 0x57 0x58 0x59 0x5A 0x7B 0x7C 0x7D 0x7E 0x7F 0x80 0x81 0x82 0x83 0x84 0x85 0x86 0x87 0x88 0x89 0x8A 0x8B 0x8C 0x8D 0x8E 0x8F 0x90 0x91 0x92 0x93 0x94 0x95 0x96 0x97 0x98 0x99 0x9A 0x9B 0x9C 0x9D 0x9E 0x9F 0xA0 0xA1 0xA2 0xA3 0xA4 0xA5 0xA6 0xA7 0xA8 0xA9 0xAA 0xAB 0xAC 0xAD 0xAE 0xAF 0xB0 0xA1 0xB2 0xA3 0xB4 0xA5 0xA6 0xB7 0xB8 0xA9 0xAA 0xAB 0xAC 0xBD 0xAE 0xAF 0xC0 0xC1 0xC2 0xC3 0xC4 0xC5 0xC6 0xC7 0xC8 0xC9 0xCA 0xCB 0xCC 0xCD 0xCE 0xCF 0xD0 0xD1 0xD2 0xD3 0xD4 0xD5 0xD6 0xD7 0xD8 0xD9 0xDA 0xDB 0xDC 0xDD 0xDE 0xDF 0xC0 0xC1 0xC2 0xC3 0xC4 0xC5 0xC6 0xC7 0xC8 0xC9 0xCA 0xCB 0xCC 0xCD 0xCE 0xCF 0xD0 0xD1 0xD2 0xD3 0xD4 0xD5 0xD6 0xF7 0xD8 0xD9 0xDA 0xDB 0xDC 0xDD 0xDE 0xFF �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/locales/iso88592_braces��������������������������������������������������������������0000775�0000000�0000000�00000005201�13554550454�0017442�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������. . 0x00 0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09 0x0A 0x0B 0x0C 0x0D 0x0E 0x0F 0x10 0x11 0x12 0x13 0x14 0x15 0x16 0x17 0x18 0x19 0x1A 0x1B 0x1C 0x1D 0x1E 0x1F 0x20 0x21 0x22 0x23 0x24 0x25 0x26 0x27 0x28 0x29 0x2A 0x2B 0x2C 0x2D 0x2E 0x2F 0x30 0x31 0x32 0x33 0x34 0x35 0x36 0x37 0x38 0x39 0x3A 0x3B 0x3C 0x3D 0x3E 0x3F 0x40 0x61 0x62 0x63 0x64 0x65 0x66 0x67 0x68 0x69 0x6A 0x6B 0x6C 0x6D 0x6E 0x6F 0x70 0x71 0x72 0x73 0x74 0x75 0x76 0x77 0x78 0x79 0x7A 0x7B 0x7C 0x7D 0x5E 0x5F 0x60 0x61 0x62 0x63 0x64 0x65 0x66 0x67 0x68 0x69 0x6A 0x6B 0x6C 0x6D 0x6E 0x6F 0x70 0x71 0x72 0x73 0x74 0x75 0x76 0x77 0x78 0x79 0x7A 0x7B 0x7C 0x7D 0x7E 0x7F 0x80 0x81 0x82 0x83 0x84 0x85 0x86 0x87 0x88 0x89 0x8A 0x8B 0x8C 0x8D 0x8E 0x8F 0x90 0x91 0x92 0x93 0x94 0x95 0x96 0x97 0x98 0x99 0x9A 0x9B 0x9C 0x9D 0x9E 0x9F 0xA0 0xB1 0xA2 0xB3 0xA4 0xB5 0xB6 0xA7 0xA8 0xB9 0xBA 0xBB 0xBC 0xAD 0xBE 0xBF 0xB0 0xB1 0xB2 0xB3 0xB4 0xB5 0xB6 0xB7 0xB8 0xB9 0xBA 0xBB 0xBC 0xBD 0xBE 0xBF 0xE0 0xE1 0xE2 0xE3 0xE4 0xE5 0xE6 0xE7 0xE8 0xE9 0xEA 0xEB 0xEC 0xED 0xEE 0xEF 0xF0 0xF1 0xF2 0xF3 0xF4 0xF5 0xF6 0xD7 0xF8 0xF9 0xFA 0xFB 0xFC 0xFD 0xFE 0xDF 0xE0 0xE1 0xE2 0xE3 0xE4 0xE5 0xE6 0xE7 0xE8 0xE9 0xEA 0xEB 0xEC 0xED 0xEE 0xEF 0xF0 0xF1 0xF2 0xF3 0xF4 0xF5 0xF6 0xF7 0xF8 0xF9 0xFA 0xFB 0xFC 0xFD 0xFE 0xFF 0x00 0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09 0x0A 0x0B 0x0C 0x0D 0x0E 0x0F 0x10 0x11 0x12 0x13 0x14 0x15 0x16 0x17 0x18 0x19 0x1A 0x1B 0x1C 0x1D 0x1E 0x1F 0x20 0x21 0x22 0x23 0x24 0x25 0x26 0x27 0x28 0x29 0x2A 0x2B 0x2C 0x2D 0x2E 0x2F 0x30 0x31 0x32 0x33 0x34 0x35 0x36 0x37 0x38 0x39 0x3A 0x3B 0x3C 0x3D 0x3E 0x3F 0x40 0x41 0x42 0x43 0x44 0x45 0x46 0x47 0x48 0x49 0x4A 0x4B 0x4C 0x4D 0x4E 0x4F 0x50 0x51 0x52 0x53 0x54 0x55 0x56 0x57 0x58 0x59 0x5A 0x5B 0x5C 0x5D 0x5E 0x5F 0x60 0x41 0x42 0x43 0x44 0x45 0x46 0x47 0x48 0x49 0x4A 0x4B 0x4C 0x4D 0x4E 0x4F 0x50 0x51 0x52 0x53 0x54 0x55 0x56 0x57 0x58 0x59 0x5A 0x5B 0x5C 0x5D 0x7E 0x7F 0x80 0x81 0x82 0x83 0x84 0x85 0x86 0x87 0x88 0x89 0x8A 0x8B 0x8C 0x8D 0x8E 0x8F 0x90 0x91 0x92 0x93 0x94 0x95 0x96 0x97 0x98 0x99 0x9A 0x9B 0x9C 0x9D 0x9E 0x9F 0xA0 0xA1 0xA2 0xA3 0xA4 0xA5 0xA6 0xA7 0xA8 0xA9 0xAA 0xAB 0xAC 0xAD 0xAE 0xAF 0xB0 0xA1 0xB2 0xA3 0xB4 0xA5 0xA6 0xB7 0xB8 0xA9 0xAA 0xAB 0xAC 0xBD 0xAE 0xAF 0xC0 0xC1 0xC2 0xC3 0xC4 0xC5 0xC6 0xC7 0xC8 0xC9 0xCA 0xCB 0xCC 0xCD 0xCE 0xCF 0xD0 0xD1 0xD2 0xD3 0xD4 0xD5 0xD6 0xD7 0xD8 0xD9 0xDA 0xDB 0xDC 0xDD 0xDE 0xDF 0xC0 0xC1 0xC2 0xC3 0xC4 0xC5 0xC6 0xC7 0xC8 0xC9 0xCA 0xCB 0xCC 0xCD 0xCE 0xCF 0xD0 0xD1 0xD2 0xD3 0xD4 0xD5 0xD6 0xF7 0xD8 0xD9 0xDA 0xDB 0xDC 0xDD 0xDE 0xFF �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/locales/iso88597���������������������������������������������������������������������0000775�0000000�0000000�00000005156�13554550454�0016141�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������. . 0x00 0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09 0x0A 0x0B 0x0C 0x0D 0x0E 0x0F 0x10 0x11 0x12 0x13 0x14 0x15 0x16 0x17 0x18 0x19 0x1A 0x1B 0x1C 0x1D 0x1E 0x1F 0x20 0x21 0x22 0x23 0x24 0x25 0x26 0x27 0x28 0x29 0x2A 0x2B 0x2C 0x2D 0x2E 0x2F 0x30 0x31 0x32 0x33 0x34 0x35 0x36 0x37 0x38 0x39 0x3A 0x3B 0x3C 0x3D 0x3E 0x3F 0x40 0x61 0x62 0x63 0x64 0x65 0x66 0x67 0x68 0x69 0x6A 0x6B 0x6C 0x6D 0x6E 0x6F 0x70 0x71 0x72 0x73 0x74 0x75 0x76 0x77 0x78 0x79 0x7A 0x5B 0x5C 0x5D 0x5E 0x5F 0x60 0x61 0x62 0x63 0x64 0x65 0x66 0x67 0x68 0x69 0x6A 0x6B 0x6C 0x6D 0x6E 0x6F 0x70 0x71 0x72 0x73 0x74 0x75 0x76 0x77 0x78 0x79 0x7A 0x7B 0x7C 0x7D 0x7E 0x7F 0x80 0x81 0x82 0x83 0x84 0x85 0x86 0x87 0x88 0x89 0x8A 0x8B 0x8C 0x8D 0x8E 0x8F 0x90 0x91 0x92 0x93 0x94 0x95 0x96 0x97 0x98 0x99 0x9A 0x9B 0x9C 0x9D 0x9E 0x9F 0xA0 0xA1 0xA2 0xA3 0xA4 0xA5 0xA6 0xA7 0xA8 0xA9 0xAA 0xAB 0xAC 0xAD 0xAE 0xAF 0xB0 0xB1 0xB2 0xB3 0xB4 0xB5 0xDC 0xB7 0xDD 0xDE 0xDF 0xBB 0xFC 0xBD 0xFD 0xFE 0xC0 0xE1 0xE2 0xE3 0xE4 0xE5 0xE6 0xE7 0xE8 0xE9 0xEA 0xEB 0xEC 0xED 0xEE 0xEF 0xF0 0xF1 0xD2 0xF3 0xF4 0xF5 0xF6 0xF7 0xF8 0xF9 0xFA 0xFB 0xDC 0xDD 0xDE 0xDF 0xE0 0xE1 0xE2 0xE3 0xE4 0xE5 0xE6 0xE7 0xE8 0xE9 0xEA 0xEB 0xEC 0xED 0xEE 0xEF 0xF0 0xF1 0xF2 0xF3 0xF4 0xF5 0xF6 0xF7 0xF8 0xF9 0xFA 0xFB 0xFC 0xFD 0xFE 0xFF 0x00 0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09 0x0A 0x0B 0x0C 0x0D 0x0E 0x0F 0x10 0x11 0x12 0x13 0x14 0x15 0x16 0x17 0x18 0x19 0x1A 0x1B 0x1C 0x1D 0x1E 0x1F 0x20 0x21 0x22 0x23 0x24 0x25 0x26 0x27 0x28 0x29 0x2A 0x2B 0x2C 0x2D 0x2E 0x2F 0x30 0x31 0x32 0x33 0x34 0x35 0x36 0x37 0x38 0x39 0x3A 0x3B 0x3C 0x3D 0x3E 0x3F 0x40 0x41 0x42 0x43 0x44 0x45 0x46 0x47 0x48 0x49 0x4A 0x4B 0x4C 0x4D 0x4E 0x4F 0x50 0x51 0x52 0x53 0x54 0x55 0x56 0x57 0x58 0x59 0x5A 0x5B 0x5C 0x5D 0x5E 0x5F 0x60 0x41 0x42 0x43 0x44 0x45 0x46 0x47 0x48 0x49 0x4A 0x4B 0x4C 0x4D 0x4E 0x4F 0x50 0x51 0x52 0x53 0x54 0x55 0x56 0x57 0x58 0x59 0x5A 0x7B 0x7C 0x7D 0x7E 0x7F 0x80 0x81 0x82 0x83 0x84 0x85 0x86 0x87 0x88 0x89 0x8A 0x8B 0x8C 0x8D 0x8E 0x8F 0x90 0x91 0x92 0x93 0x94 0x95 0x96 0x97 0x98 0x99 0x9A 0x9B 0x9C 0x9D 0x9E 0x9F 0xA0 0xA1 0xA2 0xA3 0xA4 0xA5 0xA6 0xA7 0xA8 0xA9 0xAA 0xAB 0xAC 0xAD 0xAE 0xAF 0xB0 0xB1 0xB2 0xB3 0xB4 0xB5 0xB6 0xB7 0xB8 0xB9 0xBA 0xBB 0xBC 0xBD 0xBE 0xBF 0xC0 0xC1 0xC2 0xC3 0xC4 0xC5 0xC6 0xC7 0xC8 0xC9 0xCA 0xCB 0xCC 0xCD 0xCE 0xCF 0xD0 0xD1 0xD2 0xD3 0xD4 0xD5 0xD6 0xD7 0xD8 0xD9 0xDA 0xDB 0xB6 0xB8 0xB9 0xBA 0xE0 0xC1 0xC2 0xC3 0xC4 0xC5 0xC6 0xC7 0xC8 0xC9 0xCA 0xCB 0xCC 0xCD 0xCE 0xCF 0xD0 0xD1 0xD3 0xD3 0xD4 0xD5 0xD6 0xD7 0xD8 0xD9 0xDA 0xDB 0xBC 0xBE 0xBF 0xFF ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/locales/iso88597_braces��������������������������������������������������������������0000775�0000000�0000000�00000005156�13554550454�0017460�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������. . 0x00 0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09 0x0A 0x0B 0x0C 0x0D 0x0E 0x0F 0x10 0x11 0x12 0x13 0x14 0x15 0x16 0x17 0x18 0x19 0x1A 0x1B 0x1C 0x1D 0x1E 0x1F 0x20 0x21 0x22 0x23 0x24 0x25 0x26 0x27 0x28 0x29 0x2A 0x2B 0x2C 0x2D 0x2E 0x2F 0x30 0x31 0x32 0x33 0x34 0x35 0x36 0x37 0x38 0x39 0x3A 0x3B 0x3C 0x3D 0x3E 0x3F 0x40 0x61 0x62 0x63 0x64 0x65 0x66 0x67 0x68 0x69 0x6A 0x6B 0x6C 0x6D 0x6E 0x6F 0x70 0x71 0x72 0x73 0x74 0x75 0x76 0x77 0x78 0x79 0x7A 0x7B 0x7C 0x7D 0x5E 0x5F 0x60 0x61 0x62 0x63 0x64 0x65 0x66 0x67 0x68 0x69 0x6A 0x6B 0x6C 0x6D 0x6E 0x6F 0x70 0x71 0x72 0x73 0x74 0x75 0x76 0x77 0x78 0x79 0x7A 0x7B 0x7C 0x7D 0x7E 0x7F 0x80 0x81 0x82 0x83 0x84 0x85 0x86 0x87 0x88 0x89 0x8A 0x8B 0x8C 0x8D 0x8E 0x8F 0x90 0x91 0x92 0x93 0x94 0x95 0x96 0x97 0x98 0x99 0x9A 0x9B 0x9C 0x9D 0x9E 0x9F 0xA0 0xA1 0xA2 0xA3 0xA4 0xA5 0xA6 0xA7 0xA8 0xA9 0xAA 0xAB 0xAC 0xAD 0xAE 0xAF 0xB0 0xB1 0xB2 0xB3 0xB4 0xB5 0xDC 0xB7 0xDD 0xDE 0xDF 0xBB 0xFC 0xBD 0xFD 0xFE 0xC0 0xE1 0xE2 0xE3 0xE4 0xE5 0xE6 0xE7 0xE8 0xE9 0xEA 0xEB 0xEC 0xED 0xEE 0xEF 0xF0 0xF1 0xD2 0xF3 0xF4 0xF5 0xF6 0xF7 0xF8 0xF9 0xFA 0xFB 0xDC 0xDD 0xDE 0xDF 0xE0 0xE1 0xE2 0xE3 0xE4 0xE5 0xE6 0xE7 0xE8 0xE9 0xEA 0xEB 0xEC 0xED 0xEE 0xEF 0xF0 0xF1 0xF2 0xF3 0xF4 0xF5 0xF6 0xF7 0xF8 0xF9 0xFA 0xFB 0xFC 0xFD 0xFE 0xFF 0x00 0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09 0x0A 0x0B 0x0C 0x0D 0x0E 0x0F 0x10 0x11 0x12 0x13 0x14 0x15 0x16 0x17 0x18 0x19 0x1A 0x1B 0x1C 0x1D 0x1E 0x1F 0x20 0x21 0x22 0x23 0x24 0x25 0x26 0x27 0x28 0x29 0x2A 0x2B 0x2C 0x2D 0x2E 0x2F 0x30 0x31 0x32 0x33 0x34 0x35 0x36 0x37 0x38 0x39 0x3A 0x3B 0x3C 0x3D 0x3E 0x3F 0x40 0x41 0x42 0x43 0x44 0x45 0x46 0x47 0x48 0x49 0x4A 0x4B 0x4C 0x4D 0x4E 0x4F 0x50 0x51 0x52 0x53 0x54 0x55 0x56 0x57 0x58 0x59 0x5A 0x5B 0x5C 0x5D 0x5E 0x5F 0x60 0x41 0x42 0x43 0x44 0x45 0x46 0x47 0x48 0x49 0x4A 0x4B 0x4C 0x4D 0x4E 0x4F 0x50 0x51 0x52 0x53 0x54 0x55 0x56 0x57 0x58 0x59 0x5A 0x5B 0x5C 0x5D 0x7E 0x7F 0x80 0x81 0x82 0x83 0x84 0x85 0x86 0x87 0x88 0x89 0x8A 0x8B 0x8C 0x8D 0x8E 0x8F 0x90 0x91 0x92 0x93 0x94 0x95 0x96 0x97 0x98 0x99 0x9A 0x9B 0x9C 0x9D 0x9E 0x9F 0xA0 0xA1 0xA2 0xA3 0xA4 0xA5 0xA6 0xA7 0xA8 0xA9 0xAA 0xAB 0xAC 0xAD 0xAE 0xAF 0xB0 0xB1 0xB2 0xB3 0xB4 0xB5 0xB6 0xB7 0xB8 0xB9 0xBA 0xBB 0xBC 0xBD 0xBE 0xBF 0xC0 0xC1 0xC2 0xC3 0xC4 0xC5 0xC6 0xC7 0xC8 0xC9 0xCA 0xCB 0xCC 0xCD 0xCE 0xCF 0xD0 0xD1 0xD2 0xD3 0xD4 0xD5 0xD6 0xD7 0xD8 0xD9 0xDA 0xDB 0xB6 0xB8 0xB9 0xBA 0xE0 0xC1 0xC2 0xC3 0xC4 0xC5 0xC6 0xC7 0xC8 0xC9 0xCA 0xCB 0xCC 0xCD 0xCE 0xCF 0xD0 0xD1 0xD3 0xD3 0xD4 0xD5 0xD6 0xD7 0xD8 0xD9 0xDA 0xDB 0xBC 0xBE 0xBF 0xFF ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/locales/iso88599���������������������������������������������������������������������0000775�0000000�0000000�00000005146�13554550454�0016142�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������. . 0x00 0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09 0x0A 0x0B 0x0C 0x0D 0x0E 0x0F 0x10 0x11 0x12 0x13 0x14 0x15 0x16 0x17 0x18 0x19 0x1A 0x1B 0x1C 0x1D 0x1E 0x1F 0x20 0x21 0x22 0x23 0x24 0x25 0x26 0x27 0x28 0x29 0x2A 0x2B 0x2C 0x2D 0x2E 0x2F 0x30 0x31 0x32 0x33 0x34 0x35 0x36 0x37 0x38 0x39 0x3A 0x3B 0x3C 0x3D 0x3E 0x3F 0x40 0x61 0x62 0x63 0x64 0x65 0x66 0x67 0x68 0xFD 0x6A 0x6B 0x6C 0x6D 0x6E 0x6F 0x70 0x71 0x72 0x73 0x74 0x75 0x76 0x77 0x78 0x79 0x7A 0x5B 0x5C 0x5D 0x5E 0x5F 0x60 0x61 0x62 0x63 0x64 0x65 0x66 0x67 0x68 0x69 0x6A 0x6B 0x6C 0x6D 0x6E 0x6F 0x70 0x71 0x72 0x73 0x74 0x75 0x76 0x77 0x78 0x79 0x7A 0x7B 0x7C 0x7D 0x7E 0x7F 0x80 0x81 0x82 0x83 0x84 0x85 0x86 0x87 0x88 0x89 0x8A 0x8B 0x8C 0x8D 0x8E 0x8F 0x90 0x91 0x92 0x93 0x94 0x95 0x96 0x97 0x98 0x99 0x9A 0x9B 0x9C 0x9D 0x9E 0x9F 0xA0 0xA1 0xA2 0xA3 0xA4 0xA5 0xA6 0xA7 0xA8 0xA9 0xAA 0xAB 0xAC 0xAD 0xAE 0xAF 0xB0 0xB1 0xB2 0xB3 0xB4 0xB5 0xB6 0xB7 0xB8 0xB9 0xBA 0xBB 0xBC 0xBD 0xBE 0xBF 0xE0 0xE1 0xE2 0xE3 0xE4 0xE5 0xE6 0xE7 0xE8 0xE9 0xEA 0xEB 0xEC 0xED 0xEE 0xEF 0xF0 0xF1 0xF2 0xF3 0xF4 0xF5 0xF6 0xD7 0xF8 0xF9 0xFA 0xFB 0xFC 0x69 0xFE 0xDF 0xE0 0xE1 0xE2 0xE3 0xE4 0xE5 0xE6 0xE7 0xE8 0xE9 0xEA 0xEB 0xEC 0xED 0xEE 0xEF 0xF0 0xF1 0xF2 0xF3 0xF4 0xF5 0xF6 0xF7 0xF8 0xF9 0xFA 0xFB 0xFC 0xFD 0xFE 0xFF 0x00 0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09 0x0A 0x0B 0x0C 0x0D 0x0E 0x0F 0x10 0x11 0x12 0x13 0x14 0x15 0x16 0x17 0x18 0x19 0x1A 0x1B 0x1C 0x1D 0x1E 0x1F 0x20 0x21 0x22 0x23 0x24 0x25 0x26 0x27 0x28 0x29 0x2A 0x2B 0x2C 0x2D 0x2E 0x2F 0x30 0x31 0x32 0x33 0x34 0x35 0x36 0x37 0x38 0x39 0x3A 0x3B 0x3C 0x3D 0x3E 0x3F 0x40 0x41 0x42 0x43 0x44 0x45 0x46 0x47 0x48 0x49 0x4A 0x4B 0x4C 0x4D 0x4E 0x4F 0x50 0x51 0x52 0x53 0x54 0x55 0x56 0x57 0x58 0x59 0x5A 0x5B 0x5C 0x5D 0x5E 0x5F 0x60 0x41 0x42 0x43 0x44 0x45 0x46 0x47 0x48 0xDD 0x4A 0x4B 0x4C 0x4D 0x4E 0x4F 0x50 0x51 0x52 0x53 0x54 0x55 0x56 0x57 0x58 0x59 0x5A 0x7B 0x7C 0x7D 0x7E 0x7F 0x80 0x81 0x82 0x83 0x84 0x85 0x86 0x87 0x88 0x89 0x8A 0x8B 0x8C 0x8D 0x8E 0x8F 0x90 0x91 0x92 0x93 0x94 0x95 0x96 0x97 0x98 0x99 0x9A 0x9B 0x9C 0x9D 0x9E 0x9F 0xA0 0xA1 0xA2 0xA3 0xA4 0xA5 0xA6 0xA7 0xA8 0xA9 0xAA 0xAB 0xAC 0xAD 0xAE 0xAF 0xB0 0xB1 0xB2 0xB3 0xB4 0xB5 0xB6 0xB7 0xB8 0xB9 0xBA 0xBB 0xBC 0xBD 0xBE 0xBF 0xC0 0xC1 0xC2 0xC3 0xC4 0xC5 0xC6 0xC7 0xC8 0xC9 0xCA 0xCB 0xCC 0xCD 0xCE 0xCF 0xD0 0xD1 0xD2 0xD3 0xD4 0xD5 0xD6 0xD7 0xD8 0xD9 0xDA 0xDB 0xDC 0xDD 0xDE 0xDF 0xC0 0xC1 0xC2 0xC3 0xC4 0xC5 0xC6 0xC7 0xC8 0xC9 0xCA 0xCB 0xCC 0xCD 0xCE 0xCF 0xD0 0xD1 0xD2 0xD3 0xD4 0xD5 0xD6 0xF7 0xD8 0xD9 0xDA 0xDB 0xDC 0x49 0xDE 0xFF ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/locales/iso88599_braces��������������������������������������������������������������0000775�0000000�0000000�00000005146�13554550454�0017461�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������. . 0x00 0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09 0x0A 0x0B 0x0C 0x0D 0x0E 0x0F 0x10 0x11 0x12 0x13 0x14 0x15 0x16 0x17 0x18 0x19 0x1A 0x1B 0x1C 0x1D 0x1E 0x1F 0x20 0x21 0x22 0x23 0x24 0x25 0x26 0x27 0x28 0x29 0x2A 0x2B 0x2C 0x2D 0x2E 0x2F 0x30 0x31 0x32 0x33 0x34 0x35 0x36 0x37 0x38 0x39 0x3A 0x3B 0x3C 0x3D 0x3E 0x3F 0x40 0x61 0x62 0x63 0x64 0x65 0x66 0x67 0x68 0xFD 0x6A 0x6B 0x6C 0x6D 0x6E 0x6F 0x70 0x71 0x72 0x73 0x74 0x75 0x76 0x77 0x78 0x79 0x7A 0x7B 0x7C 0x7D 0x5E 0x5F 0x60 0x61 0x62 0x63 0x64 0x65 0x66 0x67 0x68 0x69 0x6A 0x6B 0x6C 0x6D 0x6E 0x6F 0x70 0x71 0x72 0x73 0x74 0x75 0x76 0x77 0x78 0x79 0x7A 0x7B 0x7C 0x7D 0x7E 0x7F 0x80 0x81 0x82 0x83 0x84 0x85 0x86 0x87 0x88 0x89 0x8A 0x8B 0x8C 0x8D 0x8E 0x8F 0x90 0x91 0x92 0x93 0x94 0x95 0x96 0x97 0x98 0x99 0x9A 0x9B 0x9C 0x9D 0x9E 0x9F 0xA0 0xA1 0xA2 0xA3 0xA4 0xA5 0xA6 0xA7 0xA8 0xA9 0xAA 0xAB 0xAC 0xAD 0xAE 0xAF 0xB0 0xB1 0xB2 0xB3 0xB4 0xB5 0xB6 0xB7 0xB8 0xB9 0xBA 0xBB 0xBC 0xBD 0xBE 0xBF 0xE0 0xE1 0xE2 0xE3 0xE4 0xE5 0xE6 0xE7 0xE8 0xE9 0xEA 0xEB 0xEC 0xED 0xEE 0xEF 0xF0 0xF1 0xF2 0xF3 0xF4 0xF5 0xF6 0xD7 0xF8 0xF9 0xFA 0xFB 0xFC 0x69 0xFE 0xDF 0xE0 0xE1 0xE2 0xE3 0xE4 0xE5 0xE6 0xE7 0xE8 0xE9 0xEA 0xEB 0xEC 0xED 0xEE 0xEF 0xF0 0xF1 0xF2 0xF3 0xF4 0xF5 0xF6 0xF7 0xF8 0xF9 0xFA 0xFB 0xFC 0xFD 0xFE 0xFF 0x00 0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09 0x0A 0x0B 0x0C 0x0D 0x0E 0x0F 0x10 0x11 0x12 0x13 0x14 0x15 0x16 0x17 0x18 0x19 0x1A 0x1B 0x1C 0x1D 0x1E 0x1F 0x20 0x21 0x22 0x23 0x24 0x25 0x26 0x27 0x28 0x29 0x2A 0x2B 0x2C 0x2D 0x2E 0x2F 0x30 0x31 0x32 0x33 0x34 0x35 0x36 0x37 0x38 0x39 0x3A 0x3B 0x3C 0x3D 0x3E 0x3F 0x40 0x41 0x42 0x43 0x44 0x45 0x46 0x47 0x48 0x49 0x4A 0x4B 0x4C 0x4D 0x4E 0x4F 0x50 0x51 0x52 0x53 0x54 0x55 0x56 0x57 0x58 0x59 0x5A 0x5B 0x5C 0x5D 0x5E 0x5F 0x60 0x41 0x42 0x43 0x44 0x45 0x46 0x47 0x48 0xDD 0x4A 0x4B 0x4C 0x4D 0x4E 0x4F 0x50 0x51 0x52 0x53 0x54 0x55 0x56 0x57 0x58 0x59 0x5A 0x5B 0x5C 0x5D 0x7E 0x7F 0x80 0x81 0x82 0x83 0x84 0x85 0x86 0x87 0x88 0x89 0x8A 0x8B 0x8C 0x8D 0x8E 0x8F 0x90 0x91 0x92 0x93 0x94 0x95 0x96 0x97 0x98 0x99 0x9A 0x9B 0x9C 0x9D 0x9E 0x9F 0xA0 0xA1 0xA2 0xA3 0xA4 0xA5 0xA6 0xA7 0xA8 0xA9 0xAA 0xAB 0xAC 0xAD 0xAE 0xAF 0xB0 0xB1 0xB2 0xB3 0xB4 0xB5 0xB6 0xB7 0xB8 0xB9 0xBA 0xBB 0xBC 0xBD 0xBE 0xBF 0xC0 0xC1 0xC2 0xC3 0xC4 0xC5 0xC6 0xC7 0xC8 0xC9 0xCA 0xCB 0xCC 0xCD 0xCE 0xCF 0xD0 0xD1 0xD2 0xD3 0xD4 0xD5 0xD6 0xD7 0xD8 0xD9 0xDA 0xDB 0xDC 0xDD 0xDE 0xDF 0xC0 0xC1 0xC2 0xC3 0xC4 0xC5 0xC6 0xC7 0xC8 0xC9 0xCA 0xCB 0xCC 0xCD 0xCE 0xCF 0xD0 0xD1 0xD2 0xD3 0xD4 0xD5 0xD6 0xF7 0xD8 0xD9 0xDA 0xDB 0xDC 0x49 0xDE 0xFF ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/locales/it_IT.iso88591���������������������������������������������������������������0000775�0000000�0000000�00000005042�13554550454�0017134�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������. . 0x00 0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09 0x0A 0x0B 0x0C 0x0D 0x0E 0x0F 0x10 0x11 0x12 0x13 0x14 0x15 0x16 0x17 0x18 0x19 0x1A 0x1B 0x1C 0x1D 0x1E 0x1F 0x20 0x21 0x22 0x23 0x24 0x25 0x26 0x27 0x28 0x29 0x2A 0x2B 0x2C 0x2D 0x2E 0x2F 0x30 0x31 0x32 0x33 0x34 0x35 0x36 0x37 0x38 0x39 0x3A 0x3B 0x3C 0x3D 0x3E 0x3F 0x40 0x61 0x62 0x63 0x64 0x65 0x66 0x67 0x68 0x69 0x6A 0x6B 0x6C 0x6D 0x6E 0x6F 0x70 0x71 0x72 0x73 0x74 0x75 0x76 0x77 0x78 0x79 0x7A 0x5B 0x5C 0x5D 0x5E 0x5F 0x60 0x61 0x62 0x63 0x64 0x65 0x66 0x67 0x68 0x69 0x6A 0x6B 0x6C 0x6D 0x6E 0x6F 0x70 0x71 0x72 0x73 0x74 0x75 0x76 0x77 0x78 0x79 0x7A 0x7B 0x7C 0x7D 0x7E 0x7F 0x80 0x81 0x82 0x83 0x84 0x85 0x86 0x87 0x88 0x89 0x8A 0x8B 0x8C 0x8D 0x8E 0x8F 0x90 0x91 0x92 0x93 0x94 0x95 0x96 0x97 0x98 0x99 0x9A 0x9B 0x9C 0x9D 0x9E 0x9F 0xA0 0xA1 0xA2 0xA3 0xA4 0xA5 0xA6 0xA7 0xA8 0xA9 0xAA 0xAB 0xAC 0xAD 0xAE 0xAF 0xB0 0xB1 0xB2 0xB3 0xB4 0xB5 0xB6 0xB7 0xB8 0xB9 0xBA 0xBB 0xBC 0xBD 0xBE 0xBF 0xE0 0xE1 0xE2 0xE3 0xE4 0xE5 0xE6 0xE7 0xE8 0xE9 0xEA 0xEB 0xEC 0xED 0xEE 0xEF 0xF0 0xF1 0xF2 0xF3 0xF4 0xF5 0xF6 0xD7 0xF8 0xF9 0xFA 0xFB 0xFC 0xFD 0xFE 0xDF 0xE0 0xE1 0xE2 0xE3 0xE4 0xE5 0xE6 0xE7 0xE8 0xE9 0xEA 0xEB 0xEC 0xED 0xEE 0xEF 0xF0 0xF1 0xF2 0xF3 0xF4 0xF5 0xF6 0xF7 0xF8 0xF9 0xFA 0xFB 0xFC 0xFD 0xFE 0xFF 0x00 0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09 0x0A 0x0B 0x0C 0x0D 0x0E 0x0F 0x10 0x11 0x12 0x13 0x14 0x15 0x16 0x17 0x18 0x19 0x1A 0x1B 0x1C 0x1D 0x1E 0x1F 0x20 0x21 0x22 0x23 0x24 0x25 0x26 0x27 0x28 0x29 0x2A 0x2B 0x2C 0x2D 0x2E 0x2F 0x30 0x31 0x32 0x33 0x34 0x35 0x36 0x37 0x38 0x39 0x3A 0x3B 0x3C 0x3D 0x3E 0x3F 0x40 0x41 0x42 0x43 0x44 0x45 0x46 0x47 0x48 0x49 0x4A 0x4B 0x4C 0x4D 0x4E 0x4F 0x50 0x51 0x52 0x53 0x54 0x55 0x56 0x57 0x58 0x59 0x5A 0x5B 0x5C 0x5D 0x5E 0x5F 0x60 0x41 0x42 0x43 0x44 0x45 0x46 0x47 0x48 0x49 0x4A 0x4B 0x4C 0x4D 0x4E 0x4F 0x50 0x51 0x52 0x53 0x54 0x55 0x56 0x57 0x58 0x59 0x5A 0x7B 0x7C 0x7D 0x7E 0x7F 0x80 0x81 0x82 0x83 0x84 0x85 0x86 0x87 0x88 0x89 0x8A 0x8B 0x8C 0x8D 0x8E 0x8F 0x90 0x91 0x92 0x93 0x94 0x95 0x96 0x97 0x98 0x99 0x9A 0x9B 0x9C 0x9D 0x9E 0x9F 0xA0 0xA1 0xA2 0xA3 0xA4 0xA5 0xA6 0xA7 0xA8 0xA9 0xAA 0xAB 0xAC 0xAD 0xAE 0xAF 0xB0 0xB1 0xB2 0xB3 0xB4 0xB5 0xB6 0xB7 0xB8 0xB9 0xBA 0xBB 0xBC 0xBD 0xBE 0xBF 0xC0 0xC1 0xC2 0xC3 0xC4 0xC5 0xC6 0xC7 0xC8 0xC9 0xCA 0xCB 0xCC 0xCD 0xCE 0xCF 0xD0 0xD1 0xD2 0xD3 0xD4 0xD5 0xD6 0xD7 0xD8 0xD9 0xDA 0xDB 0xDC 0xDD 0xDE 0xDF 0xC0 0xC1 0xC2 0xC3 0xC4 0xC5 0xC6 0xC7 0xC8 0xC9 0xCA 0xCB 0xCC 0xCD 0xCE 0xCF 0xD0 0xD1 0xD2 0xD3 0xD4 0xD5 0xD6 0xF7 0xD8 0xD9 0xDA 0xDB 0xDC 0xDD 0xDE 0xFF ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/locales/it_IT.iso88591_braces��������������������������������������������������������0000775�0000000�0000000�00000005042�13554550454�0020453�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������. . 0x00 0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09 0x0A 0x0B 0x0C 0x0D 0x0E 0x0F 0x10 0x11 0x12 0x13 0x14 0x15 0x16 0x17 0x18 0x19 0x1A 0x1B 0x1C 0x1D 0x1E 0x1F 0x20 0x21 0x22 0x23 0x24 0x25 0x26 0x27 0x28 0x29 0x2A 0x2B 0x2C 0x2D 0x2E 0x2F 0x30 0x31 0x32 0x33 0x34 0x35 0x36 0x37 0x38 0x39 0x3A 0x3B 0x3C 0x3D 0x3E 0x3F 0x40 0x61 0x62 0x63 0x64 0x65 0x66 0x67 0x68 0x69 0x6A 0x6B 0x6C 0x6D 0x6E 0x6F 0x70 0x71 0x72 0x73 0x74 0x75 0x76 0x77 0x78 0x79 0x7A 0x7B 0x7C 0x7D 0x5E 0x5F 0x60 0x61 0x62 0x63 0x64 0x65 0x66 0x67 0x68 0x69 0x6A 0x6B 0x6C 0x6D 0x6E 0x6F 0x70 0x71 0x72 0x73 0x74 0x75 0x76 0x77 0x78 0x79 0x7A 0x7B 0x7C 0x7D 0x7E 0x7F 0x80 0x81 0x82 0x83 0x84 0x85 0x86 0x87 0x88 0x89 0x8A 0x8B 0x8C 0x8D 0x8E 0x8F 0x90 0x91 0x92 0x93 0x94 0x95 0x96 0x97 0x98 0x99 0x9A 0x9B 0x9C 0x9D 0x9E 0x9F 0xA0 0xA1 0xA2 0xA3 0xA4 0xA5 0xA6 0xA7 0xA8 0xA9 0xAA 0xAB 0xAC 0xAD 0xAE 0xAF 0xB0 0xB1 0xB2 0xB3 0xB4 0xB5 0xB6 0xB7 0xB8 0xB9 0xBA 0xBB 0xBC 0xBD 0xBE 0xBF 0xE0 0xE1 0xE2 0xE3 0xE4 0xE5 0xE6 0xE7 0xE8 0xE9 0xEA 0xEB 0xEC 0xED 0xEE 0xEF 0xF0 0xF1 0xF2 0xF3 0xF4 0xF5 0xF6 0xD7 0xF8 0xF9 0xFA 0xFB 0xFC 0xFD 0xFE 0xDF 0xE0 0xE1 0xE2 0xE3 0xE4 0xE5 0xE6 0xE7 0xE8 0xE9 0xEA 0xEB 0xEC 0xED 0xEE 0xEF 0xF0 0xF1 0xF2 0xF3 0xF4 0xF5 0xF6 0xF7 0xF8 0xF9 0xFA 0xFB 0xFC 0xFD 0xFE 0xFF 0x00 0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09 0x0A 0x0B 0x0C 0x0D 0x0E 0x0F 0x10 0x11 0x12 0x13 0x14 0x15 0x16 0x17 0x18 0x19 0x1A 0x1B 0x1C 0x1D 0x1E 0x1F 0x20 0x21 0x22 0x23 0x24 0x25 0x26 0x27 0x28 0x29 0x2A 0x2B 0x2C 0x2D 0x2E 0x2F 0x30 0x31 0x32 0x33 0x34 0x35 0x36 0x37 0x38 0x39 0x3A 0x3B 0x3C 0x3D 0x3E 0x3F 0x40 0x41 0x42 0x43 0x44 0x45 0x46 0x47 0x48 0x49 0x4A 0x4B 0x4C 0x4D 0x4E 0x4F 0x50 0x51 0x52 0x53 0x54 0x55 0x56 0x57 0x58 0x59 0x5A 0x5B 0x5C 0x5D 0x5E 0x5F 0x60 0x41 0x42 0x43 0x44 0x45 0x46 0x47 0x48 0x49 0x4A 0x4B 0x4C 0x4D 0x4E 0x4F 0x50 0x51 0x52 0x53 0x54 0x55 0x56 0x57 0x58 0x59 0x5A 0x5B 0x5C 0x5D 0x7E 0x7F 0x80 0x81 0x82 0x83 0x84 0x85 0x86 0x87 0x88 0x89 0x8A 0x8B 0x8C 0x8D 0x8E 0x8F 0x90 0x91 0x92 0x93 0x94 0x95 0x96 0x97 0x98 0x99 0x9A 0x9B 0x9C 0x9D 0x9E 0x9F 0xA0 0xA1 0xA2 0xA3 0xA4 0xA5 0xA6 0xA7 0xA8 0xA9 0xAA 0xAB 0xAC 0xAD 0xAE 0xAF 0xB0 0xB1 0xB2 0xB3 0xB4 0xB5 0xB6 0xB7 0xB8 0xB9 0xBA 0xBB 0xBC 0xBD 0xBE 0xBF 0xC0 0xC1 0xC2 0xC3 0xC4 0xC5 0xC6 0xC7 0xC8 0xC9 0xCA 0xCB 0xCC 0xCD 0xCE 0xCF 0xD0 0xD1 0xD2 0xD3 0xD4 0xD5 0xD6 0xD7 0xD8 0xD9 0xDA 0xDB 0xDC 0xDD 0xDE 0xDF 0xC0 0xC1 0xC2 0xC3 0xC4 0xC5 0xC6 0xC7 0xC8 0xC9 0xCA 0xCB 0xCC 0xCD 0xCE 0xCF 0xD0 0xD1 0xD2 0xD3 0xD4 0xD5 0xD6 0xF7 0xD8 0xD9 0xDA 0xDB 0xDC 0xDD 0xDE 0xFF ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/locales/nl_NL.iso88591���������������������������������������������������������������0000775�0000000�0000000�00000005015�13554550454�0017126�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������. . 0x00 0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09 0x0A 0x0B 0x0C 0x0D 0x0E 0x0F 0x10 0x11 0x12 0x13 0x14 0x15 0x16 0x17 0x18 0x19 0x1A 0x1B 0x1C 0x1D 0x1E 0x1F 0x20 0x21 0x22 0x23 0x24 0x25 0x26 0x27 0x28 0x29 0x2A 0x2B 0x2C 0x2D 0x2E 0x2F 0x30 0x31 0x32 0x33 0x34 0x35 0x36 0x37 0x38 0x39 0x3A 0x3B 0x3C 0x3D 0x3E 0x3F 0x40 0x61 0x62 0x63 0x64 0x65 0x66 0x67 0x68 0x69 0x6A 0x6B 0x6C 0x6D 0x6E 0x6F 0x70 0x71 0x72 0x73 0x74 0x75 0x76 0x77 0x78 0x79 0x7A 0x5B 0x5C 0x5D 0x5E 0x5F 0x60 0x61 0x62 0x63 0x64 0x65 0x66 0x67 0x68 0x69 0x6A 0x6B 0x6C 0x6D 0x6E 0x6F 0x70 0x71 0x72 0x73 0x74 0x75 0x76 0x77 0x78 0x79 0x7A 0x7B 0x7C 0x7D 0x7E 0x7F 0x80 0x81 0x82 0x83 0x84 0x85 0x86 0x87 0x88 0x89 0x8A 0x8B 0x8C 0x8D 0x8E 0x8F 0x90 0x91 0x92 0x93 0x94 0x95 0x96 0x97 0x98 0x99 0x9A 0x9B 0x9C 0x9D 0x9E 0x9F 0xA0 0xA1 0xA2 0xA3 0xA4 0xA5 0xA6 0xA7 0xA8 0xA9 0xAA 0xAB 0xAC 0xAD 0xAE 0xAF 0xB0 0xB1 0xB2 0xB3 0xB4 0xB5 0xB6 0xB7 0xB8 0xB9 0xBA 0xBB 0xBC 0xBD 0xBE 0xBF 0xE0 0xE1 0xE2 0xE3 0xE4 0xE5 0xE6 0xE7 0xE8 0xE9 0xEA 0xEB 0xEC 0xED 0xEE 0xEF 0xF0 0xF1 0xF2 0xF3 0xF4 0xF5 0xF6 0xD7 0xF8 0xF9 0xFA 0xFB 0xFC 0xFD 0xFE 0xDF 0xE0 0xE1 0xE2 0xE3 0xE4 0xE5 0xE6 0xE7 0xE8 0xE9 0xEA 0xEB 0xEC 0xED 0xEE 0xEF 0xF0 0xF1 0xF2 0xF3 0xF4 0xF5 0xF6 0xF7 0xF8 0xF9 0xFA 0xFB 0xFC 0xFD 0xFE 0xFF 0x00 0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09 0x0A 0x0B 0x0C 0x0D 0x0E 0x0F 0x10 0x11 0x12 0x13 0x14 0x15 0x16 0x17 0x18 0x19 0x1A 0x1B 0x1C 0x1D 0x1E 0x1F 0x20 0x21 0x22 0x23 0x24 0x25 0x26 0x27 0x28 0x29 0x2A 0x2B 0x2C 0x2D 0x2E 0x2F 0x30 0x31 0x32 0x33 0x34 0x35 0x36 0x37 0x38 0x39 0x3A 0x3B 0x3C 0x3D 0x3E 0x3F 0x40 0x41 0x42 0x43 0x44 0x45 0x46 0x47 0x48 0x49 0x4A 0x4B 0x4C 0x4D 0x4E 0x4F 0x50 0x51 0x52 0x53 0x54 0x55 0x56 0x57 0x58 0x59 0x5A 0x5B 0x5C 0x5D 0x5E 0x5F 0x60 0x41 0x42 0x43 0x44 0x45 0x46 0x47 0x48 0x49 0x4A 0x4B 0x4C 0x4D 0x4E 0x4F 0x50 0x51 0x52 0x53 0x54 0x55 0x56 0x57 0x58 0x59 0x5A 0x7B 0x7C 0x7D 0x7E 0x7F 0x80 0x81 0x82 0x83 0x84 0x85 0x86 0x87 0x88 0x89 0x8A 0x8B 0x8C 0x8D 0x8E 0x8F 0x90 0x91 0x92 0x93 0x94 0x95 0x96 0x97 0x98 0x99 0x9A 0x9B 0x9C 0x9D 0x9E 0x9F 0xA0 0xA1 0xA2 0xA3 0xA4 0xA5 0xA6 0xA7 0xA8 0xA9 0xAA 0xAB 0xAC 0xAD 0xAE 0xAF 0xB0 0xB1 0xB2 0xB3 0xB4 0xB5 0xB6 0xB7 0xB8 0xB9 0xBA 0xBB 0xBC 0xBD 0xBE 0xBF 0xC0 0xC1 0xC2 0xC3 0xC4 0xC5 0xC6 0xC7 0xC8 0xC9 0xCA 0xCB 0xCC 0xCD 0xCE 0xCF 0xD0 0xD1 0xD2 0xD3 0xD4 0xD5 0xD6 0xD7 0xD8 0xD9 0xDA 0xDB 0xDC 0xDD 0xDE 0xDF 0xC0 0xC1 0xC2 0xC3 0xC4 0xC5 0xC6 0xC7 0xC8 0xC9 0xCA 0xCB 0xCC 0xCD 0xCE 0xCF 0xD0 0xD1 0xD2 0xD3 0xD4 0xD5 0xD6 0xF7 0xD8 0xD9 0xDA 0xDB 0xDC 0xDD 0xDE 0xFF �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/locales/nl_NL.iso88591_braces��������������������������������������������������������0000775�0000000�0000000�00000005015�13554550454�0020445�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������. . 0x00 0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09 0x0A 0x0B 0x0C 0x0D 0x0E 0x0F 0x10 0x11 0x12 0x13 0x14 0x15 0x16 0x17 0x18 0x19 0x1A 0x1B 0x1C 0x1D 0x1E 0x1F 0x20 0x21 0x22 0x23 0x24 0x25 0x26 0x27 0x28 0x29 0x2A 0x2B 0x2C 0x2D 0x2E 0x2F 0x30 0x31 0x32 0x33 0x34 0x35 0x36 0x37 0x38 0x39 0x3A 0x3B 0x3C 0x3D 0x3E 0x3F 0x40 0x61 0x62 0x63 0x64 0x65 0x66 0x67 0x68 0x69 0x6A 0x6B 0x6C 0x6D 0x6E 0x6F 0x70 0x71 0x72 0x73 0x74 0x75 0x76 0x77 0x78 0x79 0x7A 0x7B 0x7C 0x7D 0x5E 0x5F 0x60 0x61 0x62 0x63 0x64 0x65 0x66 0x67 0x68 0x69 0x6A 0x6B 0x6C 0x6D 0x6E 0x6F 0x70 0x71 0x72 0x73 0x74 0x75 0x76 0x77 0x78 0x79 0x7A 0x7B 0x7C 0x7D 0x7E 0x7F 0x80 0x81 0x82 0x83 0x84 0x85 0x86 0x87 0x88 0x89 0x8A 0x8B 0x8C 0x8D 0x8E 0x8F 0x90 0x91 0x92 0x93 0x94 0x95 0x96 0x97 0x98 0x99 0x9A 0x9B 0x9C 0x9D 0x9E 0x9F 0xA0 0xA1 0xA2 0xA3 0xA4 0xA5 0xA6 0xA7 0xA8 0xA9 0xAA 0xAB 0xAC 0xAD 0xAE 0xAF 0xB0 0xB1 0xB2 0xB3 0xB4 0xB5 0xB6 0xB7 0xB8 0xB9 0xBA 0xBB 0xBC 0xBD 0xBE 0xBF 0xE0 0xE1 0xE2 0xE3 0xE4 0xE5 0xE6 0xE7 0xE8 0xE9 0xEA 0xEB 0xEC 0xED 0xEE 0xEF 0xF0 0xF1 0xF2 0xF3 0xF4 0xF5 0xF6 0xD7 0xF8 0xF9 0xFA 0xFB 0xFC 0xFD 0xFE 0xDF 0xE0 0xE1 0xE2 0xE3 0xE4 0xE5 0xE6 0xE7 0xE8 0xE9 0xEA 0xEB 0xEC 0xED 0xEE 0xEF 0xF0 0xF1 0xF2 0xF3 0xF4 0xF5 0xF6 0xF7 0xF8 0xF9 0xFA 0xFB 0xFC 0xFD 0xFE 0xFF 0x00 0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09 0x0A 0x0B 0x0C 0x0D 0x0E 0x0F 0x10 0x11 0x12 0x13 0x14 0x15 0x16 0x17 0x18 0x19 0x1A 0x1B 0x1C 0x1D 0x1E 0x1F 0x20 0x21 0x22 0x23 0x24 0x25 0x26 0x27 0x28 0x29 0x2A 0x2B 0x2C 0x2D 0x2E 0x2F 0x30 0x31 0x32 0x33 0x34 0x35 0x36 0x37 0x38 0x39 0x3A 0x3B 0x3C 0x3D 0x3E 0x3F 0x40 0x41 0x42 0x43 0x44 0x45 0x46 0x47 0x48 0x49 0x4A 0x4B 0x4C 0x4D 0x4E 0x4F 0x50 0x51 0x52 0x53 0x54 0x55 0x56 0x57 0x58 0x59 0x5A 0x5B 0x5C 0x5D 0x5E 0x5F 0x60 0x41 0x42 0x43 0x44 0x45 0x46 0x47 0x48 0x49 0x4A 0x4B 0x4C 0x4D 0x4E 0x4F 0x50 0x51 0x52 0x53 0x54 0x55 0x56 0x57 0x58 0x59 0x5A 0x5B 0x5C 0x5D 0x7E 0x7F 0x80 0x81 0x82 0x83 0x84 0x85 0x86 0x87 0x88 0x89 0x8A 0x8B 0x8C 0x8D 0x8E 0x8F 0x90 0x91 0x92 0x93 0x94 0x95 0x96 0x97 0x98 0x99 0x9A 0x9B 0x9C 0x9D 0x9E 0x9F 0xA0 0xA1 0xA2 0xA3 0xA4 0xA5 0xA6 0xA7 0xA8 0xA9 0xAA 0xAB 0xAC 0xAD 0xAE 0xAF 0xB0 0xB1 0xB2 0xB3 0xB4 0xB5 0xB6 0xB7 0xB8 0xB9 0xBA 0xBB 0xBC 0xBD 0xBE 0xBF 0xC0 0xC1 0xC2 0xC3 0xC4 0xC5 0xC6 0xC7 0xC8 0xC9 0xCA 0xCB 0xCC 0xCD 0xCE 0xCF 0xD0 0xD1 0xD2 0xD3 0xD4 0xD5 0xD6 0xD7 0xD8 0xD9 0xDA 0xDB 0xDC 0xDD 0xDE 0xDF 0xC0 0xC1 0xC2 0xC3 0xC4 0xC5 0xC6 0xC7 0xC8 0xC9 0xCA 0xCB 0xCC 0xCD 0xCE 0xCF 0xD0 0xD1 0xD2 0xD3 0xD4 0xD5 0xD6 0xF7 0xD8 0xD9 0xDA 0xDB 0xDC 0xDD 0xDE 0xFF �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/locales/pl_PL.cp1250�����������������������������������������������������������������0000775�0000000�0000000�00000005042�13554550454�0016633�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������.󜿟ʣӌ . 0x00 0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09 0x0A 0x0B 0x0C 0x0D 0x0E 0x0F 0x10 0x11 0x12 0x13 0x14 0x15 0x16 0x17 0x18 0x19 0x1A 0x1B 0x1C 0x1D 0x1E 0x1F 0x20 0x21 0x22 0x23 0x24 0x25 0x26 0x27 0x28 0x29 0x2A 0x2B 0x2C 0x2D 0x2E 0x2F 0x30 0x31 0x32 0x33 0x34 0x35 0x36 0x37 0x38 0x39 0x3A 0x3B 0x3C 0x3D 0x3E 0x3F 0x40 0x61 0x62 0x63 0x64 0x65 0x66 0x67 0x68 0x69 0x6A 0x6B 0x6C 0x6D 0x6E 0x6F 0x70 0x71 0x72 0x73 0x74 0x75 0x76 0x77 0x78 0x79 0x7A 0x5B 0x5C 0x5D 0x5E 0x5F 0x60 0x61 0x62 0x63 0x64 0x65 0x66 0x67 0x68 0x69 0x6A 0x6B 0x6C 0x6D 0x6E 0x6F 0x70 0x71 0x72 0x73 0x74 0x75 0x76 0x77 0x78 0x79 0x7A 0x7B 0x7C 0x7D 0x7E 0x7F 0x80 0x81 0x82 0x83 0x84 0x85 0x86 0x87 0x88 0x89 0x9A 0x8B 0x9C 0x9D 0x9E 0x9F 0x90 0x91 0x92 0x93 0x94 0x95 0x96 0x97 0x98 0x99 0x9A 0x9B 0x9C 0x9D 0x9E 0x9F 0xA0 0xA1 0xA2 0xB3 0xA4 0xB9 0xA6 0xA7 0xA8 0xA9 0xBA 0xAB 0xAC 0xAD 0xAE 0xBF 0xB0 0xB1 0xB2 0xB3 0xB4 0xB5 0xB6 0xB7 0xB8 0xB9 0xBA 0xBB 0xBE 0xBD 0xBE 0xBF 0xE0 0xE1 0xE2 0xE3 0xE4 0xE5 0xE6 0xE7 0xE8 0xE9 0xEA 0xEB 0xEC 0xED 0xEE 0xEF 0xF0 0xF1 0xF2 0xF3 0xF4 0xF5 0xF6 0xD7 0xF8 0xF9 0xFA 0xFB 0xFC 0xFD 0xFE 0xDF 0xE0 0xE1 0xE2 0xE3 0xE4 0xE5 0xE6 0xE7 0xE8 0xE9 0xEA 0xEB 0xEC 0xED 0xEE 0xEF 0xF0 0xF1 0xF2 0xF3 0xF4 0xF5 0xF6 0xF7 0xF8 0xF9 0xFA 0xFB 0xFC 0xFD 0xFE 0xFF 0x00 0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09 0x0A 0x0B 0x0C 0x0D 0x0E 0x0F 0x10 0x11 0x12 0x13 0x14 0x15 0x16 0x17 0x18 0x19 0x1A 0x1B 0x1C 0x1D 0x1E 0x1F 0x20 0x21 0x22 0x23 0x24 0x25 0x26 0x27 0x28 0x29 0x2A 0x2B 0x2C 0x2D 0x2E 0x2F 0x30 0x31 0x32 0x33 0x34 0x35 0x36 0x37 0x38 0x39 0x3A 0x3B 0x3C 0x3D 0x3E 0x3F 0x40 0x41 0x42 0x43 0x44 0x45 0x46 0x47 0x48 0x49 0x4A 0x4B 0x4C 0x4D 0x4E 0x4F 0x50 0x51 0x52 0x53 0x54 0x55 0x56 0x57 0x58 0x59 0x5A 0x5B 0x5C 0x5D 0x5E 0x5F 0x60 0x41 0x42 0x43 0x44 0x45 0x46 0x47 0x48 0x49 0x4A 0x4B 0x4C 0x4D 0x4E 0x4F 0x50 0x51 0x52 0x53 0x54 0x55 0x56 0x57 0x58 0x59 0x5A 0x7B 0x7C 0x7D 0x7E 0x7F 0x80 0x81 0x82 0x83 0x84 0x85 0x86 0x87 0x88 0x89 0x8A 0x8B 0x8C 0x8D 0x8E 0x8F 0x90 0x91 0x92 0x93 0x94 0x95 0x96 0x97 0x98 0x99 0x8A 0x9B 0x8C 0x8D 0x8E 0x8F 0xA0 0xA1 0xA2 0xA3 0xA4 0xA5 0xA6 0xA7 0xA8 0xA9 0xAA 0xAB 0xAC 0xAD 0xAE 0xAF 0xB0 0xB1 0xB2 0xA3 0xB4 0xB5 0xB6 0xB7 0xB8 0xA5 0xAA 0xBB 0xBC 0xBD 0xBC 0xAF 0xC0 0xC1 0xC2 0xC3 0xC4 0xC5 0xC6 0xC7 0xC8 0xC9 0xCA 0xCB 0xCC 0xCD 0xCE 0xCF 0xD0 0xD1 0xD2 0xD3 0xD4 0xD5 0xD6 0xD7 0xD8 0xD9 0xDA 0xDB 0xDC 0xDD 0xDE 0xDF 0xC0 0xC1 0xC2 0xC3 0xC4 0xC5 0xC6 0xC7 0xC8 0xC9 0xCA 0xCB 0xCC 0xCD 0xCE 0xCF 0xD0 0xD1 0xD2 0xD3 0xD4 0xD5 0xD6 0xF7 0xD8 0xD9 0xDA 0xDB 0xDC 0xDD 0xDE 0xFF ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/locales/pl_PL.cp1250_braces����������������������������������������������������������0000775�0000000�0000000�00000005042�13554550454�0020152�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������.󜿟ʣӌ . 0x00 0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09 0x0A 0x0B 0x0C 0x0D 0x0E 0x0F 0x10 0x11 0x12 0x13 0x14 0x15 0x16 0x17 0x18 0x19 0x1A 0x1B 0x1C 0x1D 0x1E 0x1F 0x20 0x21 0x22 0x23 0x24 0x25 0x26 0x27 0x28 0x29 0x2A 0x2B 0x2C 0x2D 0x2E 0x2F 0x30 0x31 0x32 0x33 0x34 0x35 0x36 0x37 0x38 0x39 0x3A 0x3B 0x3C 0x3D 0x3E 0x3F 0x40 0x61 0x62 0x63 0x64 0x65 0x66 0x67 0x68 0x69 0x6A 0x6B 0x6C 0x6D 0x6E 0x6F 0x70 0x71 0x72 0x73 0x74 0x75 0x76 0x77 0x78 0x79 0x7A 0x7B 0x7C 0x7D 0x5E 0x5F 0x60 0x61 0x62 0x63 0x64 0x65 0x66 0x67 0x68 0x69 0x6A 0x6B 0x6C 0x6D 0x6E 0x6F 0x70 0x71 0x72 0x73 0x74 0x75 0x76 0x77 0x78 0x79 0x7A 0x7B 0x7C 0x7D 0x7E 0x7F 0x80 0x81 0x82 0x83 0x84 0x85 0x86 0x87 0x88 0x89 0x9A 0x8B 0x9C 0x9D 0x9E 0x9F 0x90 0x91 0x92 0x93 0x94 0x95 0x96 0x97 0x98 0x99 0x9A 0x9B 0x9C 0x9D 0x9E 0x9F 0xA0 0xA1 0xA2 0xB3 0xA4 0xB9 0xA6 0xA7 0xA8 0xA9 0xBA 0xAB 0xAC 0xAD 0xAE 0xBF 0xB0 0xB1 0xB2 0xB3 0xB4 0xB5 0xB6 0xB7 0xB8 0xB9 0xBA 0xBB 0xBE 0xBD 0xBE 0xBF 0xE0 0xE1 0xE2 0xE3 0xE4 0xE5 0xE6 0xE7 0xE8 0xE9 0xEA 0xEB 0xEC 0xED 0xEE 0xEF 0xF0 0xF1 0xF2 0xF3 0xF4 0xF5 0xF6 0xD7 0xF8 0xF9 0xFA 0xFB 0xFC 0xFD 0xFE 0xDF 0xE0 0xE1 0xE2 0xE3 0xE4 0xE5 0xE6 0xE7 0xE8 0xE9 0xEA 0xEB 0xEC 0xED 0xEE 0xEF 0xF0 0xF1 0xF2 0xF3 0xF4 0xF5 0xF6 0xF7 0xF8 0xF9 0xFA 0xFB 0xFC 0xFD 0xFE 0xFF 0x00 0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09 0x0A 0x0B 0x0C 0x0D 0x0E 0x0F 0x10 0x11 0x12 0x13 0x14 0x15 0x16 0x17 0x18 0x19 0x1A 0x1B 0x1C 0x1D 0x1E 0x1F 0x20 0x21 0x22 0x23 0x24 0x25 0x26 0x27 0x28 0x29 0x2A 0x2B 0x2C 0x2D 0x2E 0x2F 0x30 0x31 0x32 0x33 0x34 0x35 0x36 0x37 0x38 0x39 0x3A 0x3B 0x3C 0x3D 0x3E 0x3F 0x40 0x41 0x42 0x43 0x44 0x45 0x46 0x47 0x48 0x49 0x4A 0x4B 0x4C 0x4D 0x4E 0x4F 0x50 0x51 0x52 0x53 0x54 0x55 0x56 0x57 0x58 0x59 0x5A 0x5B 0x5C 0x5D 0x5E 0x5F 0x60 0x41 0x42 0x43 0x44 0x45 0x46 0x47 0x48 0x49 0x4A 0x4B 0x4C 0x4D 0x4E 0x4F 0x50 0x51 0x52 0x53 0x54 0x55 0x56 0x57 0x58 0x59 0x5A 0x5B 0x5C 0x5D 0x7E 0x7F 0x80 0x81 0x82 0x83 0x84 0x85 0x86 0x87 0x88 0x89 0x8A 0x8B 0x8C 0x8D 0x8E 0x8F 0x90 0x91 0x92 0x93 0x94 0x95 0x96 0x97 0x98 0x99 0x8A 0x9B 0x8C 0x8D 0x8E 0x8F 0xA0 0xA1 0xA2 0xA3 0xA4 0xA5 0xA6 0xA7 0xA8 0xA9 0xAA 0xAB 0xAC 0xAD 0xAE 0xAF 0xB0 0xB1 0xB2 0xA3 0xB4 0xB5 0xB6 0xB7 0xB8 0xA5 0xAA 0xBB 0xBC 0xBD 0xBC 0xAF 0xC0 0xC1 0xC2 0xC3 0xC4 0xC5 0xC6 0xC7 0xC8 0xC9 0xCA 0xCB 0xCC 0xCD 0xCE 0xCF 0xD0 0xD1 0xD2 0xD3 0xD4 0xD5 0xD6 0xD7 0xD8 0xD9 0xDA 0xDB 0xDC 0xDD 0xDE 0xDF 0xC0 0xC1 0xC2 0xC3 0xC4 0xC5 0xC6 0xC7 0xC8 0xC9 0xCA 0xCB 0xCC 0xCD 0xCE 0xCF 0xD0 0xD1 0xD2 0xD3 0xD4 0xD5 0xD6 0xF7 0xD8 0xD9 0xDA 0xDB 0xDC 0xDD 0xDE 0xFF ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/locales/pl_PL.iso88592���������������������������������������������������������������0000775�0000000�0000000�00000005042�13554550454�0017133�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������.󶿼ʣӦ . 0x00 0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09 0x0A 0x0B 0x0C 0x0D 0x0E 0x0F 0x10 0x11 0x12 0x13 0x14 0x15 0x16 0x17 0x18 0x19 0x1A 0x1B 0x1C 0x1D 0x1E 0x1F 0x20 0x21 0x22 0x23 0x24 0x25 0x26 0x27 0x28 0x29 0x2A 0x2B 0x2C 0x2D 0x2E 0x2F 0x30 0x31 0x32 0x33 0x34 0x35 0x36 0x37 0x38 0x39 0x3A 0x3B 0x3C 0x3D 0x3E 0x3F 0x40 0x61 0x62 0x63 0x64 0x65 0x66 0x67 0x68 0x69 0x6A 0x6B 0x6C 0x6D 0x6E 0x6F 0x70 0x71 0x72 0x73 0x74 0x75 0x76 0x77 0x78 0x79 0x7A 0x5B 0x5C 0x5D 0x5E 0x5F 0x60 0x61 0x62 0x63 0x64 0x65 0x66 0x67 0x68 0x69 0x6A 0x6B 0x6C 0x6D 0x6E 0x6F 0x70 0x71 0x72 0x73 0x74 0x75 0x76 0x77 0x78 0x79 0x7A 0x7B 0x7C 0x7D 0x7E 0x7F 0x80 0x81 0x82 0x83 0x84 0x85 0x86 0x87 0x88 0x89 0x8A 0x8B 0x8C 0x8D 0x8E 0x8F 0x90 0x91 0x92 0x93 0x94 0x95 0x96 0x97 0x98 0x99 0x9A 0x9B 0x9C 0x9D 0x9E 0x9F 0xA0 0xB1 0xA2 0xB3 0xA4 0xB5 0xB6 0xA7 0xA8 0xB9 0xBA 0xBB 0xBC 0xAD 0xBE 0xBF 0xB0 0xB1 0xB2 0xB3 0xB4 0xB5 0xB6 0xB7 0xB8 0xB9 0xBA 0xBB 0xBC 0xBD 0xBE 0xBF 0xE0 0xE1 0xE2 0xE3 0xE4 0xE5 0xE6 0xE7 0xE8 0xE9 0xEA 0xEB 0xEC 0xED 0xEE 0xEF 0xF0 0xF1 0xF2 0xF3 0xF4 0xF5 0xF6 0xD7 0xF8 0xF9 0xFA 0xFB 0xFC 0xFD 0xFE 0xDF 0xE0 0xE1 0xE2 0xE3 0xE4 0xE5 0xE6 0xE7 0xE8 0xE9 0xEA 0xEB 0xEC 0xED 0xEE 0xEF 0xF0 0xF1 0xF2 0xF3 0xF4 0xF5 0xF6 0xF7 0xF8 0xF9 0xFA 0xFB 0xFC 0xFD 0xFE 0xFF 0x00 0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09 0x0A 0x0B 0x0C 0x0D 0x0E 0x0F 0x10 0x11 0x12 0x13 0x14 0x15 0x16 0x17 0x18 0x19 0x1A 0x1B 0x1C 0x1D 0x1E 0x1F 0x20 0x21 0x22 0x23 0x24 0x25 0x26 0x27 0x28 0x29 0x2A 0x2B 0x2C 0x2D 0x2E 0x2F 0x30 0x31 0x32 0x33 0x34 0x35 0x36 0x37 0x38 0x39 0x3A 0x3B 0x3C 0x3D 0x3E 0x3F 0x40 0x41 0x42 0x43 0x44 0x45 0x46 0x47 0x48 0x49 0x4A 0x4B 0x4C 0x4D 0x4E 0x4F 0x50 0x51 0x52 0x53 0x54 0x55 0x56 0x57 0x58 0x59 0x5A 0x5B 0x5C 0x5D 0x5E 0x5F 0x60 0x41 0x42 0x43 0x44 0x45 0x46 0x47 0x48 0x49 0x4A 0x4B 0x4C 0x4D 0x4E 0x4F 0x50 0x51 0x52 0x53 0x54 0x55 0x56 0x57 0x58 0x59 0x5A 0x7B 0x7C 0x7D 0x7E 0x7F 0x80 0x81 0x82 0x83 0x84 0x85 0x86 0x87 0x88 0x89 0x8A 0x8B 0x8C 0x8D 0x8E 0x8F 0x90 0x91 0x92 0x93 0x94 0x95 0x96 0x97 0x98 0x99 0x9A 0x9B 0x9C 0x9D 0x9E 0x9F 0xA0 0xA1 0xA2 0xA3 0xA4 0xA5 0xA6 0xA7 0xA8 0xA9 0xAA 0xAB 0xAC 0xAD 0xAE 0xAF 0xB0 0xA1 0xB2 0xA3 0xB4 0xA5 0xA6 0xB7 0xB8 0xA9 0xAA 0xAB 0xAC 0xBD 0xAE 0xAF 0xC0 0xC1 0xC2 0xC3 0xC4 0xC5 0xC6 0xC7 0xC8 0xC9 0xCA 0xCB 0xCC 0xCD 0xCE 0xCF 0xD0 0xD1 0xD2 0xD3 0xD4 0xD5 0xD6 0xD7 0xD8 0xD9 0xDA 0xDB 0xDC 0xDD 0xDE 0xDF 0xC0 0xC1 0xC2 0xC3 0xC4 0xC5 0xC6 0xC7 0xC8 0xC9 0xCA 0xCB 0xCC 0xCD 0xCE 0xCF 0xD0 0xD1 0xD2 0xD3 0xD4 0xD5 0xD6 0xF7 0xD8 0xD9 0xDA 0xDB 0xDC 0xDD 0xDE 0xFF ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/locales/pl_PL.iso88592_braces��������������������������������������������������������0000775�0000000�0000000�00000005042�13554550454�0020452�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������.󶿼ʣӦ . 0x00 0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09 0x0A 0x0B 0x0C 0x0D 0x0E 0x0F 0x10 0x11 0x12 0x13 0x14 0x15 0x16 0x17 0x18 0x19 0x1A 0x1B 0x1C 0x1D 0x1E 0x1F 0x20 0x21 0x22 0x23 0x24 0x25 0x26 0x27 0x28 0x29 0x2A 0x2B 0x2C 0x2D 0x2E 0x2F 0x30 0x31 0x32 0x33 0x34 0x35 0x36 0x37 0x38 0x39 0x3A 0x3B 0x3C 0x3D 0x3E 0x3F 0x40 0x61 0x62 0x63 0x64 0x65 0x66 0x67 0x68 0x69 0x6A 0x6B 0x6C 0x6D 0x6E 0x6F 0x70 0x71 0x72 0x73 0x74 0x75 0x76 0x77 0x78 0x79 0x7A 0x7B 0x7C 0x7D 0x5E 0x5F 0x60 0x61 0x62 0x63 0x64 0x65 0x66 0x67 0x68 0x69 0x6A 0x6B 0x6C 0x6D 0x6E 0x6F 0x70 0x71 0x72 0x73 0x74 0x75 0x76 0x77 0x78 0x79 0x7A 0x7B 0x7C 0x7D 0x7E 0x7F 0x80 0x81 0x82 0x83 0x84 0x85 0x86 0x87 0x88 0x89 0x8A 0x8B 0x8C 0x8D 0x8E 0x8F 0x90 0x91 0x92 0x93 0x94 0x95 0x96 0x97 0x98 0x99 0x9A 0x9B 0x9C 0x9D 0x9E 0x9F 0xA0 0xB1 0xA2 0xB3 0xA4 0xB5 0xB6 0xA7 0xA8 0xB9 0xBA 0xBB 0xBC 0xAD 0xBE 0xBF 0xB0 0xB1 0xB2 0xB3 0xB4 0xB5 0xB6 0xB7 0xB8 0xB9 0xBA 0xBB 0xBC 0xBD 0xBE 0xBF 0xE0 0xE1 0xE2 0xE3 0xE4 0xE5 0xE6 0xE7 0xE8 0xE9 0xEA 0xEB 0xEC 0xED 0xEE 0xEF 0xF0 0xF1 0xF2 0xF3 0xF4 0xF5 0xF6 0xD7 0xF8 0xF9 0xFA 0xFB 0xFC 0xFD 0xFE 0xDF 0xE0 0xE1 0xE2 0xE3 0xE4 0xE5 0xE6 0xE7 0xE8 0xE9 0xEA 0xEB 0xEC 0xED 0xEE 0xEF 0xF0 0xF1 0xF2 0xF3 0xF4 0xF5 0xF6 0xF7 0xF8 0xF9 0xFA 0xFB 0xFC 0xFD 0xFE 0xFF 0x00 0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09 0x0A 0x0B 0x0C 0x0D 0x0E 0x0F 0x10 0x11 0x12 0x13 0x14 0x15 0x16 0x17 0x18 0x19 0x1A 0x1B 0x1C 0x1D 0x1E 0x1F 0x20 0x21 0x22 0x23 0x24 0x25 0x26 0x27 0x28 0x29 0x2A 0x2B 0x2C 0x2D 0x2E 0x2F 0x30 0x31 0x32 0x33 0x34 0x35 0x36 0x37 0x38 0x39 0x3A 0x3B 0x3C 0x3D 0x3E 0x3F 0x40 0x41 0x42 0x43 0x44 0x45 0x46 0x47 0x48 0x49 0x4A 0x4B 0x4C 0x4D 0x4E 0x4F 0x50 0x51 0x52 0x53 0x54 0x55 0x56 0x57 0x58 0x59 0x5A 0x5B 0x5C 0x5D 0x5E 0x5F 0x60 0x41 0x42 0x43 0x44 0x45 0x46 0x47 0x48 0x49 0x4A 0x4B 0x4C 0x4D 0x4E 0x4F 0x50 0x51 0x52 0x53 0x54 0x55 0x56 0x57 0x58 0x59 0x5A 0x5B 0x5C 0x5D 0x7E 0x7F 0x80 0x81 0x82 0x83 0x84 0x85 0x86 0x87 0x88 0x89 0x8A 0x8B 0x8C 0x8D 0x8E 0x8F 0x90 0x91 0x92 0x93 0x94 0x95 0x96 0x97 0x98 0x99 0x9A 0x9B 0x9C 0x9D 0x9E 0x9F 0xA0 0xA1 0xA2 0xA3 0xA4 0xA5 0xA6 0xA7 0xA8 0xA9 0xAA 0xAB 0xAC 0xAD 0xAE 0xAF 0xB0 0xA1 0xB2 0xA3 0xB4 0xA5 0xA6 0xB7 0xB8 0xA9 0xAA 0xAB 0xAC 0xBD 0xAE 0xAF 0xC0 0xC1 0xC2 0xC3 0xC4 0xC5 0xC6 0xC7 0xC8 0xC9 0xCA 0xCB 0xCC 0xCD 0xCE 0xCF 0xD0 0xD1 0xD2 0xD3 0xD4 0xD5 0xD6 0xD7 0xD8 0xD9 0xDA 0xDB 0xDC 0xDD 0xDE 0xDF 0xC0 0xC1 0xC2 0xC3 0xC4 0xC5 0xC6 0xC7 0xC8 0xC9 0xCA 0xCB 0xCC 0xCD 0xCE 0xCF 0xD0 0xD1 0xD2 0xD3 0xD4 0xD5 0xD6 0xF7 0xD8 0xD9 0xDA 0xDB 0xDC 0xDD 0xDE 0xFF ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/locales/readme.txt�������������������������������������������������������������������0000775�0000000�0000000�00000003510�13554550454�0016765�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������Here you can find locales configuration files. (!) The idea and several locale files are derived from Bynets UnrealIRCd distribution (See https://bynets.org) *** File structure *** Each file consists of 5-7 lines: 1: List of additional allowed characters 2: List of additional allowed multibyte characters ranges. In form: Sa_1 Ea_1 Sa_2 Ea_2 Sb_1 Eb_1 Sb_2 Eb_2... Total numbers count should be dividend of 4 Sx_1 Start of highest byte Ex_1 End of highest byte Sx_2 Start of lowest byte Ex_2 End of lowest byte 3: List of additional characters that should be treated as upper-case 4: 255 characters table - to-lower case conversion table. Can be usefull for example for comparing nicknames that contains similar-looking characters with different codes. 5: 255 characters table - to-upper case conversion table. Can be usefull for example for comparing nicknames that contains similar-looking characters with different codes. 6: List of additional UTF-8 allowed characters 7: List of additional UTF-8 ranges (character followed by 1-byte "range"). 8: List of additional UTF-8 ranges (i.e. start1, end1, start2, end2,... UTF8-characters between each start-end pair assumed valid). *** Line format *** Each line can be list of characters or decimal/hexadecimal/octal codes divided by spaces or commas in form like: 0 1 2 / 00 01 02 / 0x01 0x02 0x03... or 'a', 'b', 'c' or combined: x01, 002 'a', 'b', 'c', It is also possible to write plain-text line of characters. In this case it should begin with a . (dot) character. For example: .abcdefABCDEF23432*&^* In this case every character of line except first dot specifies one character-code for table *** Notice *** "bynets" directory contains tables from Bynets' UnrealIRCd distribution. You might find them useful. *** TODO *** - UTF-8 collation rules (Inapplieable to InspIRCd atm). ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/locales/ro_RO.iso88592���������������������������������������������������������������0000775�0000000�0000000�00000005026�13554550454�0017147�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������. . 0x00 0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09 0x0A 0x0B 0x0C 0x0D 0x0E 0x0F 0x10 0x11 0x12 0x13 0x14 0x15 0x16 0x17 0x18 0x19 0x1A 0x1B 0x1C 0x1D 0x1E 0x1F 0x20 0x21 0x22 0x23 0x24 0x25 0x26 0x27 0x28 0x29 0x2A 0x2B 0x2C 0x2D 0x2E 0x2F 0x30 0x31 0x32 0x33 0x34 0x35 0x36 0x37 0x38 0x39 0x3A 0x3B 0x3C 0x3D 0x3E 0x3F 0x40 0x61 0x62 0x63 0x64 0x65 0x66 0x67 0x68 0x69 0x6A 0x6B 0x6C 0x6D 0x6E 0x6F 0x70 0x71 0x72 0x73 0x74 0x75 0x76 0x77 0x78 0x79 0x7A 0x5B 0x5C 0x5D 0x5E 0x5F 0x60 0x61 0x62 0x63 0x64 0x65 0x66 0x67 0x68 0x69 0x6A 0x6B 0x6C 0x6D 0x6E 0x6F 0x70 0x71 0x72 0x73 0x74 0x75 0x76 0x77 0x78 0x79 0x7A 0x7B 0x7C 0x7D 0x7E 0x7F 0x80 0x81 0x82 0x83 0x84 0x85 0x86 0x87 0x88 0x89 0x8A 0x8B 0x8C 0x8D 0x8E 0x8F 0x90 0x91 0x92 0x93 0x94 0x95 0x96 0x97 0x98 0x99 0x9A 0x9B 0x9C 0x9D 0x9E 0x9F 0xA0 0xB1 0xA2 0xB3 0xA4 0xB5 0xB6 0xA7 0xA8 0xB9 0xBA 0xBB 0xBC 0xAD 0xBE 0xBF 0xB0 0xB1 0xB2 0xB3 0xB4 0xB5 0xB6 0xB7 0xB8 0xB9 0xBA 0xBB 0xBC 0xBD 0xBE 0xBF 0xE0 0xE1 0xE2 0xE3 0xE4 0xE5 0xE6 0xE7 0xE8 0xE9 0xEA 0xEB 0xEC 0xED 0xEE 0xEF 0xF0 0xF1 0xF2 0xF3 0xF4 0xF5 0xF6 0xD7 0xF8 0xF9 0xFA 0xFB 0xFC 0xFD 0xFE 0xDF 0xE0 0xE1 0xE2 0xE3 0xE4 0xE5 0xE6 0xE7 0xE8 0xE9 0xEA 0xEB 0xEC 0xED 0xEE 0xEF 0xF0 0xF1 0xF2 0xF3 0xF4 0xF5 0xF6 0xF7 0xF8 0xF9 0xFA 0xFB 0xFC 0xFD 0xFE 0xFF 0x00 0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09 0x0A 0x0B 0x0C 0x0D 0x0E 0x0F 0x10 0x11 0x12 0x13 0x14 0x15 0x16 0x17 0x18 0x19 0x1A 0x1B 0x1C 0x1D 0x1E 0x1F 0x20 0x21 0x22 0x23 0x24 0x25 0x26 0x27 0x28 0x29 0x2A 0x2B 0x2C 0x2D 0x2E 0x2F 0x30 0x31 0x32 0x33 0x34 0x35 0x36 0x37 0x38 0x39 0x3A 0x3B 0x3C 0x3D 0x3E 0x3F 0x40 0x41 0x42 0x43 0x44 0x45 0x46 0x47 0x48 0x49 0x4A 0x4B 0x4C 0x4D 0x4E 0x4F 0x50 0x51 0x52 0x53 0x54 0x55 0x56 0x57 0x58 0x59 0x5A 0x5B 0x5C 0x5D 0x5E 0x5F 0x60 0x41 0x42 0x43 0x44 0x45 0x46 0x47 0x48 0x49 0x4A 0x4B 0x4C 0x4D 0x4E 0x4F 0x50 0x51 0x52 0x53 0x54 0x55 0x56 0x57 0x58 0x59 0x5A 0x7B 0x7C 0x7D 0x7E 0x7F 0x80 0x81 0x82 0x83 0x84 0x85 0x86 0x87 0x88 0x89 0x8A 0x8B 0x8C 0x8D 0x8E 0x8F 0x90 0x91 0x92 0x93 0x94 0x95 0x96 0x97 0x98 0x99 0x9A 0x9B 0x9C 0x9D 0x9E 0x9F 0xA0 0xA1 0xA2 0xA3 0xA4 0xA5 0xA6 0xA7 0xA8 0xA9 0xAA 0xAB 0xAC 0xAD 0xAE 0xAF 0xB0 0xA1 0xB2 0xA3 0xB4 0xA5 0xA6 0xB7 0xB8 0xA9 0xAA 0xAB 0xAC 0xBD 0xAE 0xAF 0xC0 0xC1 0xC2 0xC3 0xC4 0xC5 0xC6 0xC7 0xC8 0xC9 0xCA 0xCB 0xCC 0xCD 0xCE 0xCF 0xD0 0xD1 0xD2 0xD3 0xD4 0xD5 0xD6 0xD7 0xD8 0xD9 0xDA 0xDB 0xDC 0xDD 0xDE 0xDF 0xC0 0xC1 0xC2 0xC3 0xC4 0xC5 0xC6 0xC7 0xC8 0xC9 0xCA 0xCB 0xCC 0xCD 0xCE 0xCF 0xD0 0xD1 0xD2 0xD3 0xD4 0xD5 0xD6 0xF7 0xD8 0xD9 0xDA 0xDB 0xDC 0xDD 0xDE 0xFF ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/locales/ro_RO.iso88592_braces��������������������������������������������������������0000775�0000000�0000000�00000005026�13554550454�0020466�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������. . 0x00 0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09 0x0A 0x0B 0x0C 0x0D 0x0E 0x0F 0x10 0x11 0x12 0x13 0x14 0x15 0x16 0x17 0x18 0x19 0x1A 0x1B 0x1C 0x1D 0x1E 0x1F 0x20 0x21 0x22 0x23 0x24 0x25 0x26 0x27 0x28 0x29 0x2A 0x2B 0x2C 0x2D 0x2E 0x2F 0x30 0x31 0x32 0x33 0x34 0x35 0x36 0x37 0x38 0x39 0x3A 0x3B 0x3C 0x3D 0x3E 0x3F 0x40 0x61 0x62 0x63 0x64 0x65 0x66 0x67 0x68 0x69 0x6A 0x6B 0x6C 0x6D 0x6E 0x6F 0x70 0x71 0x72 0x73 0x74 0x75 0x76 0x77 0x78 0x79 0x7A 0x7B 0x7C 0x7D 0x5E 0x5F 0x60 0x61 0x62 0x63 0x64 0x65 0x66 0x67 0x68 0x69 0x6A 0x6B 0x6C 0x6D 0x6E 0x6F 0x70 0x71 0x72 0x73 0x74 0x75 0x76 0x77 0x78 0x79 0x7A 0x7B 0x7C 0x7D 0x7E 0x7F 0x80 0x81 0x82 0x83 0x84 0x85 0x86 0x87 0x88 0x89 0x8A 0x8B 0x8C 0x8D 0x8E 0x8F 0x90 0x91 0x92 0x93 0x94 0x95 0x96 0x97 0x98 0x99 0x9A 0x9B 0x9C 0x9D 0x9E 0x9F 0xA0 0xB1 0xA2 0xB3 0xA4 0xB5 0xB6 0xA7 0xA8 0xB9 0xBA 0xBB 0xBC 0xAD 0xBE 0xBF 0xB0 0xB1 0xB2 0xB3 0xB4 0xB5 0xB6 0xB7 0xB8 0xB9 0xBA 0xBB 0xBC 0xBD 0xBE 0xBF 0xE0 0xE1 0xE2 0xE3 0xE4 0xE5 0xE6 0xE7 0xE8 0xE9 0xEA 0xEB 0xEC 0xED 0xEE 0xEF 0xF0 0xF1 0xF2 0xF3 0xF4 0xF5 0xF6 0xD7 0xF8 0xF9 0xFA 0xFB 0xFC 0xFD 0xFE 0xDF 0xE0 0xE1 0xE2 0xE3 0xE4 0xE5 0xE6 0xE7 0xE8 0xE9 0xEA 0xEB 0xEC 0xED 0xEE 0xEF 0xF0 0xF1 0xF2 0xF3 0xF4 0xF5 0xF6 0xF7 0xF8 0xF9 0xFA 0xFB 0xFC 0xFD 0xFE 0xFF 0x00 0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09 0x0A 0x0B 0x0C 0x0D 0x0E 0x0F 0x10 0x11 0x12 0x13 0x14 0x15 0x16 0x17 0x18 0x19 0x1A 0x1B 0x1C 0x1D 0x1E 0x1F 0x20 0x21 0x22 0x23 0x24 0x25 0x26 0x27 0x28 0x29 0x2A 0x2B 0x2C 0x2D 0x2E 0x2F 0x30 0x31 0x32 0x33 0x34 0x35 0x36 0x37 0x38 0x39 0x3A 0x3B 0x3C 0x3D 0x3E 0x3F 0x40 0x41 0x42 0x43 0x44 0x45 0x46 0x47 0x48 0x49 0x4A 0x4B 0x4C 0x4D 0x4E 0x4F 0x50 0x51 0x52 0x53 0x54 0x55 0x56 0x57 0x58 0x59 0x5A 0x5B 0x5C 0x5D 0x5E 0x5F 0x60 0x41 0x42 0x43 0x44 0x45 0x46 0x47 0x48 0x49 0x4A 0x4B 0x4C 0x4D 0x4E 0x4F 0x50 0x51 0x52 0x53 0x54 0x55 0x56 0x57 0x58 0x59 0x5A 0x5B 0x5C 0x5D 0x7E 0x7F 0x80 0x81 0x82 0x83 0x84 0x85 0x86 0x87 0x88 0x89 0x8A 0x8B 0x8C 0x8D 0x8E 0x8F 0x90 0x91 0x92 0x93 0x94 0x95 0x96 0x97 0x98 0x99 0x9A 0x9B 0x9C 0x9D 0x9E 0x9F 0xA0 0xA1 0xA2 0xA3 0xA4 0xA5 0xA6 0xA7 0xA8 0xA9 0xAA 0xAB 0xAC 0xAD 0xAE 0xAF 0xB0 0xA1 0xB2 0xA3 0xB4 0xA5 0xA6 0xB7 0xB8 0xA9 0xAA 0xAB 0xAC 0xBD 0xAE 0xAF 0xC0 0xC1 0xC2 0xC3 0xC4 0xC5 0xC6 0xC7 0xC8 0xC9 0xCA 0xCB 0xCC 0xCD 0xCE 0xCF 0xD0 0xD1 0xD2 0xD3 0xD4 0xD5 0xD6 0xD7 0xD8 0xD9 0xDA 0xDB 0xDC 0xDD 0xDE 0xDF 0xC0 0xC1 0xC2 0xC3 0xC4 0xC5 0xC6 0xC7 0xC8 0xC9 0xCA 0xCB 0xCC 0xCD 0xCE 0xCF 0xD0 0xD1 0xD2 0xD3 0xD4 0xD5 0xD6 0xF7 0xD8 0xD9 0xDA 0xDB 0xDC 0xDD 0xDE 0xFF ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/locales/ru_RU.cp1251�����������������������������������������������������������������0000775�0000000�0000000�00000005152�13554550454�0016664�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������. . 0x00 0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09 0x0A 0x0B 0x0C 0x0D 0x0E 0x0F 0x10 0x11 0x12 0x13 0x14 0x15 0x16 0x17 0x18 0x19 0x1A 0x1B 0x1C 0x1D 0x1E 0x1F 0x20 0x21 0x22 0x23 0x24 0x25 0x26 0x27 0x28 0x29 0x2A 0x2B 0x2C 0x2D 0x2E 0x2F 0x30 0x31 0x32 0x33 0x34 0x35 0x36 0x37 0x38 0x39 0x3A 0x3B 0x3C 0x3D 0x3E 0x3F 0x40 0x61 0x62 0x63 0x64 0x65 0x66 0x67 0x68 0x69 0x6A 0x6B 0x6C 0x6D 0x6E 0x6F 0x70 0x71 0x72 0x73 0x74 0x75 0x76 0x77 0x78 0x79 0x7A 0x5B 0x5C 0x5D 0x5E 0x5F 0x60 0x61 0x62 0x63 0x64 0x65 0x66 0x67 0x68 0x69 0x6A 0x6B 0x6C 0x6D 0x6E 0x6F 0x70 0x71 0x72 0x73 0x74 0x75 0x76 0x77 0x78 0x79 0x7A 0x7B 0x7C 0x7D 0x7E 0x7F 0x90 0x83 0x82 0x83 0x84 0x85 0x86 0x87 0x88 0x89 0x9A 0x8B 0x9C 0x9D 0x9E 0x9F 0x90 0x91 0x92 0x93 0x94 0x95 0x96 0x97 0x98 0x99 0x9A 0x9B 0x9C 0x9D 0x9E 0x9F 0xA0 0xA2 0xA2 0xBC 0xA4 0xB4 0xA6 0xA7 0xB8 0xA9 0xBA 0xAB 0xAC 0xAD 0xAE 0xBF 0xB0 0xB1 0xB3 0xB3 0xB4 0xB5 0xB6 0xB7 0xB8 0xB9 0xBA 0xBB 0xBC 0xBE 0xBE 0xBF 0xE0 0xE1 0xE2 0xE3 0xE4 0xE5 0xE6 0xE7 0xE8 0xE9 0xEA 0xEB 0xEC 0xED 0xEE 0xEF 0xF0 0xF1 0xF2 0xF3 0xF4 0xF5 0xF6 0xF7 0xF8 0xF9 0xFA 0xFB 0xFC 0xFD 0xFE 0xFF 0xE0 0xE1 0xE2 0xE3 0xE4 0xE5 0xE6 0xE7 0xE8 0xE9 0xEA 0xEB 0xEC 0xED 0xEE 0xEF 0xF0 0xF1 0xF2 0xF3 0xF4 0xF5 0xF6 0xF7 0xF8 0xF9 0xFA 0xFB 0xFC 0xFD 0xFE 0xFF 0x00 0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09 0x0A 0x0B 0x0C 0x0D 0x0E 0x0F 0x10 0x11 0x12 0x13 0x14 0x15 0x16 0x17 0x18 0x19 0x1A 0x1B 0x1C 0x1D 0x1E 0x1F 0x20 0x21 0x22 0x23 0x24 0x25 0x26 0x27 0x28 0x29 0x2A 0x2B 0x2C 0x2D 0x2E 0x2F 0x30 0x31 0x32 0x33 0x34 0x35 0x36 0x37 0x38 0x39 0x3A 0x3B 0x3C 0x3D 0x3E 0x3F 0x40 0x41 0x42 0x43 0x44 0x45 0x46 0x47 0x48 0x49 0x4A 0x4B 0x4C 0x4D 0x4E 0x4F 0x50 0x51 0x52 0x53 0x54 0x55 0x56 0x57 0x58 0x59 0x5A 0x5B 0x5C 0x5D 0x5E 0x5F 0x60 0x41 0x42 0x43 0x44 0x45 0x46 0x47 0x48 0x49 0x4A 0x4B 0x4C 0x4D 0x4E 0x4F 0x50 0x51 0x52 0x53 0x54 0x55 0x56 0x57 0x58 0x59 0x5A 0x7B 0x7C 0x7D 0x7E 0x7F 0x80 0x81 0x82 0x81 0x84 0x85 0x86 0x87 0x88 0x89 0x8A 0x8B 0x8C 0x8D 0x8E 0x8F 0x80 0x91 0x92 0x93 0x94 0x95 0x96 0x97 0x98 0x99 0x8A 0x9B 0x8C 0x8D 0x8E 0x8F 0xA0 0xA1 0xA1 0xA3 0xA4 0xA5 0xA6 0xA7 0xA8 0xA9 0xAA 0xAB 0xAC 0xAD 0xAE 0xAF 0xB0 0xB1 0xB2 0xB2 0xA5 0xB5 0xB6 0xB7 0xA8 0xB9 0xAA 0xBB 0xA3 0xBD 0xBD 0xAF 0xC0 0xC1 0xC2 0xC3 0xC4 0xC5 0xC6 0xC7 0xC8 0xC9 0xCA 0xCB 0xCC 0xCD 0xCE 0xCF 0xD0 0xD1 0xD2 0xD3 0xD4 0xD5 0xD6 0xD7 0xD8 0xD9 0xDA 0xDB 0xDC 0xDD 0xDE 0xDF 0xC0 0xC1 0xC2 0xC3 0xC4 0xC5 0xC6 0xC7 0xC8 0xC9 0xCA 0xCB 0xCC 0xCD 0xCE 0xCF 0xD0 0xD1 0xD2 0xD3 0xD4 0xD5 0xD6 0xD7 0xD8 0xD9 0xDA 0xDB 0xDC 0xDD 0xDE 0xDF ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/locales/ru_RU.cp1251_braces����������������������������������������������������������0000775�0000000�0000000�00000005152�13554550454�0020203�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������. . 0x00 0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09 0x0A 0x0B 0x0C 0x0D 0x0E 0x0F 0x10 0x11 0x12 0x13 0x14 0x15 0x16 0x17 0x18 0x19 0x1A 0x1B 0x1C 0x1D 0x1E 0x1F 0x20 0x21 0x22 0x23 0x24 0x25 0x26 0x27 0x28 0x29 0x2A 0x2B 0x2C 0x2D 0x2E 0x2F 0x30 0x31 0x32 0x33 0x34 0x35 0x36 0x37 0x38 0x39 0x3A 0x3B 0x3C 0x3D 0x3E 0x3F 0x40 0x61 0x62 0x63 0x64 0x65 0x66 0x67 0x68 0x69 0x6A 0x6B 0x6C 0x6D 0x6E 0x6F 0x70 0x71 0x72 0x73 0x74 0x75 0x76 0x77 0x78 0x79 0x7A 0x7B 0x7C 0x7D 0x5E 0x5F 0x60 0x61 0x62 0x63 0x64 0x65 0x66 0x67 0x68 0x69 0x6A 0x6B 0x6C 0x6D 0x6E 0x6F 0x70 0x71 0x72 0x73 0x74 0x75 0x76 0x77 0x78 0x79 0x7A 0x7B 0x7C 0x7D 0x7E 0x7F 0x90 0x83 0x82 0x83 0x84 0x85 0x86 0x87 0x88 0x89 0x9A 0x8B 0x9C 0x9D 0x9E 0x9F 0x90 0x91 0x92 0x93 0x94 0x95 0x96 0x97 0x98 0x99 0x9A 0x9B 0x9C 0x9D 0x9E 0x9F 0xA0 0xA2 0xA2 0xBC 0xA4 0xB4 0xA6 0xA7 0xB8 0xA9 0xBA 0xAB 0xAC 0xAD 0xAE 0xBF 0xB0 0xB1 0xB3 0xB3 0xB4 0xB5 0xB6 0xB7 0xB8 0xB9 0xBA 0xBB 0xBC 0xBE 0xBE 0xBF 0xE0 0xE1 0xE2 0xE3 0xE4 0xE5 0xE6 0xE7 0xE8 0xE9 0xEA 0xEB 0xEC 0xED 0xEE 0xEF 0xF0 0xF1 0xF2 0xF3 0xF4 0xF5 0xF6 0xF7 0xF8 0xF9 0xFA 0xFB 0xFC 0xFD 0xFE 0xFF 0xE0 0xE1 0xE2 0xE3 0xE4 0xE5 0xE6 0xE7 0xE8 0xE9 0xEA 0xEB 0xEC 0xED 0xEE 0xEF 0xF0 0xF1 0xF2 0xF3 0xF4 0xF5 0xF6 0xF7 0xF8 0xF9 0xFA 0xFB 0xFC 0xFD 0xFE 0xFF 0x00 0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09 0x0A 0x0B 0x0C 0x0D 0x0E 0x0F 0x10 0x11 0x12 0x13 0x14 0x15 0x16 0x17 0x18 0x19 0x1A 0x1B 0x1C 0x1D 0x1E 0x1F 0x20 0x21 0x22 0x23 0x24 0x25 0x26 0x27 0x28 0x29 0x2A 0x2B 0x2C 0x2D 0x2E 0x2F 0x30 0x31 0x32 0x33 0x34 0x35 0x36 0x37 0x38 0x39 0x3A 0x3B 0x3C 0x3D 0x3E 0x3F 0x40 0x41 0x42 0x43 0x44 0x45 0x46 0x47 0x48 0x49 0x4A 0x4B 0x4C 0x4D 0x4E 0x4F 0x50 0x51 0x52 0x53 0x54 0x55 0x56 0x57 0x58 0x59 0x5A 0x5B 0x5C 0x5D 0x5E 0x5F 0x60 0x41 0x42 0x43 0x44 0x45 0x46 0x47 0x48 0x49 0x4A 0x4B 0x4C 0x4D 0x4E 0x4F 0x50 0x51 0x52 0x53 0x54 0x55 0x56 0x57 0x58 0x59 0x5A 0x5B 0x5C 0x5D 0x7E 0x7F 0x80 0x81 0x82 0x81 0x84 0x85 0x86 0x87 0x88 0x89 0x8A 0x8B 0x8C 0x8D 0x8E 0x8F 0x80 0x91 0x92 0x93 0x94 0x95 0x96 0x97 0x98 0x99 0x8A 0x9B 0x8C 0x8D 0x8E 0x8F 0xA0 0xA1 0xA1 0xA3 0xA4 0xA5 0xA6 0xA7 0xA8 0xA9 0xAA 0xAB 0xAC 0xAD 0xAE 0xAF 0xB0 0xB1 0xB2 0xB2 0xA5 0xB5 0xB6 0xB7 0xA8 0xB9 0xAA 0xBB 0xA3 0xBD 0xBD 0xAF 0xC0 0xC1 0xC2 0xC3 0xC4 0xC5 0xC6 0xC7 0xC8 0xC9 0xCA 0xCB 0xCC 0xCD 0xCE 0xCF 0xD0 0xD1 0xD2 0xD3 0xD4 0xD5 0xD6 0xD7 0xD8 0xD9 0xDA 0xDB 0xDC 0xDD 0xDE 0xDF 0xC0 0xC1 0xC2 0xC3 0xC4 0xC5 0xC6 0xC7 0xC8 0xC9 0xCA 0xCB 0xCC 0xCD 0xCE 0xCF 0xD0 0xD1 0xD2 0xD3 0xD4 0xD5 0xD6 0xD7 0xD8 0xD9 0xDA 0xDB 0xDC 0xDD 0xDE 0xDF ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/locales/ru_RU.koi8r������������������������������������������������������������������0000775�0000000�0000000�00000005152�13554550454�0017005�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������. . 0x00 0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09 0x0A 0x0B 0x0C 0x0D 0x0E 0x0F 0x10 0x11 0x12 0x13 0x14 0x15 0x16 0x17 0x18 0x19 0x1A 0x1B 0x1C 0x1D 0x1E 0x1F 0x20 0x21 0x22 0x23 0x24 0x25 0x26 0x27 0x28 0x29 0x2A 0x2B 0x2C 0x2D 0x2E 0x2F 0x30 0x31 0x32 0x33 0x34 0x35 0x36 0x37 0x38 0x39 0x3A 0x3B 0x3C 0x3D 0x3E 0x3F 0x40 0x61 0x62 0x63 0x64 0x65 0x66 0x67 0x68 0x69 0x6A 0x6B 0x6C 0x6D 0x6E 0x6F 0x70 0x71 0x72 0x73 0x74 0x75 0x76 0x77 0x78 0x79 0x7A 0x5B 0x5C 0x5D 0x5E 0x5F 0x60 0x61 0x62 0x63 0x64 0x65 0x66 0x67 0x68 0x69 0x6A 0x6B 0x6C 0x6D 0x6E 0x6F 0x70 0x71 0x72 0x73 0x74 0x75 0x76 0x77 0x78 0x79 0x7A 0x7B 0x7C 0x7D 0x7E 0x7F 0x80 0x81 0x82 0x83 0x84 0x85 0x86 0x87 0x88 0x89 0x8A 0x8B 0x8C 0x8D 0x8E 0x8F 0x90 0x91 0x92 0x93 0x94 0x95 0x96 0x97 0x98 0x99 0x9A 0x9B 0x9C 0x9D 0x9E 0x9F 0xA0 0xA1 0xA2 0xA3 0xA4 0xA5 0xA6 0xA7 0xA8 0xA9 0xAA 0xAB 0xAC 0xAD 0xAE 0xAF 0xB0 0xB1 0xB2 0xA3 0xB4 0xB5 0xB6 0xB7 0xB8 0xB9 0xBA 0xBB 0xBC 0xBD 0xBE 0xBF 0xC0 0xC1 0xC2 0xC3 0xC4 0xC5 0xC6 0xC7 0xC8 0xC9 0xCA 0xCB 0xCC 0xCD 0xCE 0xCF 0xD0 0xD1 0xD2 0xD3 0xD4 0xD5 0xD6 0xD7 0xD8 0xD9 0xDA 0xDB 0xDC 0xDD 0xDE 0xDF 0xC0 0xC1 0xC2 0xC3 0xC4 0xC5 0xC6 0xC7 0xC8 0xC9 0xCA 0xCB 0xCC 0xCD 0xCE 0xCF 0xD0 0xD1 0xD2 0xD3 0xD4 0xD5 0xD6 0xD7 0xD8 0xD9 0xDA 0xDB 0xDC 0xDD 0xDE 0xDF 0x00 0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09 0x0A 0x0B 0x0C 0x0D 0x0E 0x0F 0x10 0x11 0x12 0x13 0x14 0x15 0x16 0x17 0x18 0x19 0x1A 0x1B 0x1C 0x1D 0x1E 0x1F 0x20 0x21 0x22 0x23 0x24 0x25 0x26 0x27 0x28 0x29 0x2A 0x2B 0x2C 0x2D 0x2E 0x2F 0x30 0x31 0x32 0x33 0x34 0x35 0x36 0x37 0x38 0x39 0x3A 0x3B 0x3C 0x3D 0x3E 0x3F 0x40 0x41 0x42 0x43 0x44 0x45 0x46 0x47 0x48 0x49 0x4A 0x4B 0x4C 0x4D 0x4E 0x4F 0x50 0x51 0x52 0x53 0x54 0x55 0x56 0x57 0x58 0x59 0x5A 0x5B 0x5C 0x5D 0x5E 0x5F 0x60 0x41 0x42 0x43 0x44 0x45 0x46 0x47 0x48 0x49 0x4A 0x4B 0x4C 0x4D 0x4E 0x4F 0x50 0x51 0x52 0x53 0x54 0x55 0x56 0x57 0x58 0x59 0x5A 0x7B 0x7C 0x7D 0x7E 0x7F 0x80 0x81 0x82 0x83 0x84 0x85 0x86 0x87 0x88 0x89 0x8A 0x8B 0x8C 0x8D 0x8E 0x8F 0x90 0x91 0x92 0x93 0x94 0x95 0x96 0x97 0x98 0x99 0x9A 0x9B 0x9C 0x9D 0x9E 0x9F 0xA0 0xA1 0xA2 0xB3 0xA4 0xA5 0xA6 0xA7 0xA8 0xA9 0xAA 0xAB 0xAC 0xAD 0xAE 0xAF 0xB0 0xB1 0xB2 0xB3 0xB4 0xB5 0xB6 0xB7 0xB8 0xB9 0xBA 0xBB 0xBC 0xBD 0xBE 0xBF 0xE0 0xE1 0xE2 0xE3 0xE4 0xE5 0xE6 0xE7 0xE8 0xE9 0xEA 0xEB 0xEC 0xED 0xEE 0xEF 0xF0 0xF1 0xF2 0xF3 0xF4 0xF5 0xF6 0xF7 0xF8 0xF9 0xFA 0xFB 0xFC 0xFD 0xFE 0xFF 0xE0 0xE1 0xE2 0xE3 0xE4 0xE5 0xE6 0xE7 0xE8 0xE9 0xEA 0xEB 0xEC 0xED 0xEE 0xEF 0xF0 0xF1 0xF2 0xF3 0xF4 0xF5 0xF6 0xF7 0xF8 0xF9 0xFA 0xFB 0xFC 0xFD 0xFE 0xFF ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/locales/ru_RU.koi8r_braces�����������������������������������������������������������0000775�0000000�0000000�00000005152�13554550454�0020324�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������. . 0x00 0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09 0x0A 0x0B 0x0C 0x0D 0x0E 0x0F 0x10 0x11 0x12 0x13 0x14 0x15 0x16 0x17 0x18 0x19 0x1A 0x1B 0x1C 0x1D 0x1E 0x1F 0x20 0x21 0x22 0x23 0x24 0x25 0x26 0x27 0x28 0x29 0x2A 0x2B 0x2C 0x2D 0x2E 0x2F 0x30 0x31 0x32 0x33 0x34 0x35 0x36 0x37 0x38 0x39 0x3A 0x3B 0x3C 0x3D 0x3E 0x3F 0x40 0x61 0x62 0x63 0x64 0x65 0x66 0x67 0x68 0x69 0x6A 0x6B 0x6C 0x6D 0x6E 0x6F 0x70 0x71 0x72 0x73 0x74 0x75 0x76 0x77 0x78 0x79 0x7A 0x7B 0x7C 0x7D 0x5E 0x5F 0x60 0x61 0x62 0x63 0x64 0x65 0x66 0x67 0x68 0x69 0x6A 0x6B 0x6C 0x6D 0x6E 0x6F 0x70 0x71 0x72 0x73 0x74 0x75 0x76 0x77 0x78 0x79 0x7A 0x7B 0x7C 0x7D 0x7E 0x7F 0x80 0x81 0x82 0x83 0x84 0x85 0x86 0x87 0x88 0x89 0x8A 0x8B 0x8C 0x8D 0x8E 0x8F 0x90 0x91 0x92 0x93 0x94 0x95 0x96 0x97 0x98 0x99 0x9A 0x9B 0x9C 0x9D 0x9E 0x9F 0xA0 0xA1 0xA2 0xA3 0xA4 0xA5 0xA6 0xA7 0xA8 0xA9 0xAA 0xAB 0xAC 0xAD 0xAE 0xAF 0xB0 0xB1 0xB2 0xA3 0xB4 0xB5 0xB6 0xB7 0xB8 0xB9 0xBA 0xBB 0xBC 0xBD 0xBE 0xBF 0xC0 0xC1 0xC2 0xC3 0xC4 0xC5 0xC6 0xC7 0xC8 0xC9 0xCA 0xCB 0xCC 0xCD 0xCE 0xCF 0xD0 0xD1 0xD2 0xD3 0xD4 0xD5 0xD6 0xD7 0xD8 0xD9 0xDA 0xDB 0xDC 0xDD 0xDE 0xDF 0xC0 0xC1 0xC2 0xC3 0xC4 0xC5 0xC6 0xC7 0xC8 0xC9 0xCA 0xCB 0xCC 0xCD 0xCE 0xCF 0xD0 0xD1 0xD2 0xD3 0xD4 0xD5 0xD6 0xD7 0xD8 0xD9 0xDA 0xDB 0xDC 0xDD 0xDE 0xDF 0x00 0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09 0x0A 0x0B 0x0C 0x0D 0x0E 0x0F 0x10 0x11 0x12 0x13 0x14 0x15 0x16 0x17 0x18 0x19 0x1A 0x1B 0x1C 0x1D 0x1E 0x1F 0x20 0x21 0x22 0x23 0x24 0x25 0x26 0x27 0x28 0x29 0x2A 0x2B 0x2C 0x2D 0x2E 0x2F 0x30 0x31 0x32 0x33 0x34 0x35 0x36 0x37 0x38 0x39 0x3A 0x3B 0x3C 0x3D 0x3E 0x3F 0x40 0x41 0x42 0x43 0x44 0x45 0x46 0x47 0x48 0x49 0x4A 0x4B 0x4C 0x4D 0x4E 0x4F 0x50 0x51 0x52 0x53 0x54 0x55 0x56 0x57 0x58 0x59 0x5A 0x5B 0x5C 0x5D 0x5E 0x5F 0x60 0x41 0x42 0x43 0x44 0x45 0x46 0x47 0x48 0x49 0x4A 0x4B 0x4C 0x4D 0x4E 0x4F 0x50 0x51 0x52 0x53 0x54 0x55 0x56 0x57 0x58 0x59 0x5A 0x5B 0x5C 0x5D 0x7E 0x7F 0x80 0x81 0x82 0x83 0x84 0x85 0x86 0x87 0x88 0x89 0x8A 0x8B 0x8C 0x8D 0x8E 0x8F 0x90 0x91 0x92 0x93 0x94 0x95 0x96 0x97 0x98 0x99 0x9A 0x9B 0x9C 0x9D 0x9E 0x9F 0xA0 0xA1 0xA2 0xB3 0xA4 0xA5 0xA6 0xA7 0xA8 0xA9 0xAA 0xAB 0xAC 0xAD 0xAE 0xAF 0xB0 0xB1 0xB2 0xB3 0xB4 0xB5 0xB6 0xB7 0xB8 0xB9 0xBA 0xBB 0xBC 0xBD 0xBE 0xBF 0xE0 0xE1 0xE2 0xE3 0xE4 0xE5 0xE6 0xE7 0xE8 0xE9 0xEA 0xEB 0xEC 0xED 0xEE 0xEF 0xF0 0xF1 0xF2 0xF3 0xF4 0xF5 0xF6 0xF7 0xF8 0xF9 0xFA 0xFB 0xFC 0xFD 0xFE 0xFF 0xE0 0xE1 0xE2 0xE3 0xE4 0xE5 0xE6 0xE7 0xE8 0xE9 0xEA 0xEB 0xEC 0xED 0xEE 0xEF 0xF0 0xF1 0xF2 0xF3 0xF4 0xF5 0xF6 0xF7 0xF8 0xF9 0xFA 0xFB 0xFC 0xFD 0xFE 0xFF ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/locales/russian-utf8-ranges����������������������������������������������������������0000775�0000000�0000000�00000000066�13554550454�0020542�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������ xD0 x81 x01 xD1 x91 x01 xD0 x90 x30 xD1 x80 x10 ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/locales/sk_SK.cp1250�����������������������������������������������������������������0000775�0000000�0000000�00000005060�13554550454�0016637�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������. . 0x00 0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09 0x0A 0x0B 0x0C 0x0D 0x0E 0x0F 0x10 0x11 0x12 0x13 0x14 0x15 0x16 0x17 0x18 0x19 0x1A 0x1B 0x1C 0x1D 0x1E 0x1F 0x20 0x21 0x22 0x23 0x24 0x25 0x26 0x27 0x28 0x29 0x2A 0x2B 0x2C 0x2D 0x2E 0x2F 0x30 0x31 0x32 0x33 0x34 0x35 0x36 0x37 0x38 0x39 0x3A 0x3B 0x3C 0x3D 0x3E 0x3F 0x40 0x61 0x62 0x63 0x64 0x65 0x66 0x67 0x68 0x69 0x6A 0x6B 0x6C 0x6D 0x6E 0x6F 0x70 0x71 0x72 0x73 0x74 0x75 0x76 0x77 0x78 0x79 0x7A 0x5B 0x5C 0x5D 0x5E 0x5F 0x60 0x61 0x62 0x63 0x64 0x65 0x66 0x67 0x68 0x69 0x6A 0x6B 0x6C 0x6D 0x6E 0x6F 0x70 0x71 0x72 0x73 0x74 0x75 0x76 0x77 0x78 0x79 0x7A 0x7B 0x7C 0x7D 0x7E 0x7F 0x80 0x81 0x82 0x83 0x84 0x85 0x86 0x87 0x88 0x89 0x9A 0x8B 0x9C 0x9D 0x9E 0x9F 0x90 0x91 0x92 0x93 0x94 0x95 0x96 0x97 0x98 0x99 0x9A 0x9B 0x9C 0x9D 0x9E 0x9F 0xA0 0xA1 0xA2 0xB3 0xA4 0xB9 0xA6 0xA7 0xA8 0xA9 0xBA 0xAB 0xAC 0xAD 0xAE 0xBF 0xB0 0xB1 0xB2 0xB3 0xB4 0xB5 0xB6 0xB7 0xB8 0xB9 0xBA 0xBB 0xBE 0xBD 0xBE 0xBF 0xE0 0xE1 0xE2 0xE3 0xE4 0xE5 0xE6 0xE7 0xE8 0xE9 0xEA 0xEB 0xEC 0xED 0xEE 0xEF 0xF0 0xF1 0xF2 0xF3 0xF4 0xF5 0xF6 0xD7 0xF8 0xF9 0xFA 0xFB 0xFC 0xFD 0xFE 0xDF 0xE0 0xE1 0xE2 0xE3 0xE4 0xE5 0xE6 0xE7 0xE8 0xE9 0xEA 0xEB 0xEC 0xED 0xEE 0xEF 0xF0 0xF1 0xF2 0xF3 0xF4 0xF5 0xF6 0xF7 0xF8 0xF9 0xFA 0xFB 0xFC 0xFD 0xFE 0xFF 0x00 0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09 0x0A 0x0B 0x0C 0x0D 0x0E 0x0F 0x10 0x11 0x12 0x13 0x14 0x15 0x16 0x17 0x18 0x19 0x1A 0x1B 0x1C 0x1D 0x1E 0x1F 0x20 0x21 0x22 0x23 0x24 0x25 0x26 0x27 0x28 0x29 0x2A 0x2B 0x2C 0x2D 0x2E 0x2F 0x30 0x31 0x32 0x33 0x34 0x35 0x36 0x37 0x38 0x39 0x3A 0x3B 0x3C 0x3D 0x3E 0x3F 0x40 0x41 0x42 0x43 0x44 0x45 0x46 0x47 0x48 0x49 0x4A 0x4B 0x4C 0x4D 0x4E 0x4F 0x50 0x51 0x52 0x53 0x54 0x55 0x56 0x57 0x58 0x59 0x5A 0x5B 0x5C 0x5D 0x5E 0x5F 0x60 0x41 0x42 0x43 0x44 0x45 0x46 0x47 0x48 0x49 0x4A 0x4B 0x4C 0x4D 0x4E 0x4F 0x50 0x51 0x52 0x53 0x54 0x55 0x56 0x57 0x58 0x59 0x5A 0x7B 0x7C 0x7D 0x7E 0x7F 0x80 0x81 0x82 0x83 0x84 0x85 0x86 0x87 0x88 0x89 0x8A 0x8B 0x8C 0x8D 0x8E 0x8F 0x90 0x91 0x92 0x93 0x94 0x95 0x96 0x97 0x98 0x99 0x8A 0x9B 0x8C 0x8D 0x8E 0x8F 0xA0 0xA1 0xA2 0xA3 0xA4 0xA5 0xA6 0xA7 0xA8 0xA9 0xAA 0xAB 0xAC 0xAD 0xAE 0xAF 0xB0 0xB1 0xB2 0xA3 0xB4 0xB5 0xB6 0xB7 0xB8 0xA5 0xAA 0xBB 0xBC 0xBD 0xBC 0xAF 0xC0 0xC1 0xC2 0xC3 0xC4 0xC5 0xC6 0xC7 0xC8 0xC9 0xCA 0xCB 0xCC 0xCD 0xCE 0xCF 0xD0 0xD1 0xD2 0xD3 0xD4 0xD5 0xD6 0xD7 0xD8 0xD9 0xDA 0xDB 0xDC 0xDD 0xDE 0xDF 0xC0 0xC1 0xC2 0xC3 0xC4 0xC5 0xC6 0xC7 0xC8 0xC9 0xCA 0xCB 0xCC 0xCD 0xCE 0xCF 0xD0 0xD1 0xD2 0xD3 0xD4 0xD5 0xD6 0xF7 0xD8 0xD9 0xDA 0xDB 0xDC 0xDD 0xDE 0xFF ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/locales/sk_SK.cp1250_braces����������������������������������������������������������0000775�0000000�0000000�00000005060�13554550454�0020156�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������. . 0x00 0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09 0x0A 0x0B 0x0C 0x0D 0x0E 0x0F 0x10 0x11 0x12 0x13 0x14 0x15 0x16 0x17 0x18 0x19 0x1A 0x1B 0x1C 0x1D 0x1E 0x1F 0x20 0x21 0x22 0x23 0x24 0x25 0x26 0x27 0x28 0x29 0x2A 0x2B 0x2C 0x2D 0x2E 0x2F 0x30 0x31 0x32 0x33 0x34 0x35 0x36 0x37 0x38 0x39 0x3A 0x3B 0x3C 0x3D 0x3E 0x3F 0x40 0x61 0x62 0x63 0x64 0x65 0x66 0x67 0x68 0x69 0x6A 0x6B 0x6C 0x6D 0x6E 0x6F 0x70 0x71 0x72 0x73 0x74 0x75 0x76 0x77 0x78 0x79 0x7A 0x7B 0x7C 0x7D 0x5E 0x5F 0x60 0x61 0x62 0x63 0x64 0x65 0x66 0x67 0x68 0x69 0x6A 0x6B 0x6C 0x6D 0x6E 0x6F 0x70 0x71 0x72 0x73 0x74 0x75 0x76 0x77 0x78 0x79 0x7A 0x7B 0x7C 0x7D 0x7E 0x7F 0x80 0x81 0x82 0x83 0x84 0x85 0x86 0x87 0x88 0x89 0x9A 0x8B 0x9C 0x9D 0x9E 0x9F 0x90 0x91 0x92 0x93 0x94 0x95 0x96 0x97 0x98 0x99 0x9A 0x9B 0x9C 0x9D 0x9E 0x9F 0xA0 0xA1 0xA2 0xB3 0xA4 0xB9 0xA6 0xA7 0xA8 0xA9 0xBA 0xAB 0xAC 0xAD 0xAE 0xBF 0xB0 0xB1 0xB2 0xB3 0xB4 0xB5 0xB6 0xB7 0xB8 0xB9 0xBA 0xBB 0xBE 0xBD 0xBE 0xBF 0xE0 0xE1 0xE2 0xE3 0xE4 0xE5 0xE6 0xE7 0xE8 0xE9 0xEA 0xEB 0xEC 0xED 0xEE 0xEF 0xF0 0xF1 0xF2 0xF3 0xF4 0xF5 0xF6 0xD7 0xF8 0xF9 0xFA 0xFB 0xFC 0xFD 0xFE 0xDF 0xE0 0xE1 0xE2 0xE3 0xE4 0xE5 0xE6 0xE7 0xE8 0xE9 0xEA 0xEB 0xEC 0xED 0xEE 0xEF 0xF0 0xF1 0xF2 0xF3 0xF4 0xF5 0xF6 0xF7 0xF8 0xF9 0xFA 0xFB 0xFC 0xFD 0xFE 0xFF 0x00 0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09 0x0A 0x0B 0x0C 0x0D 0x0E 0x0F 0x10 0x11 0x12 0x13 0x14 0x15 0x16 0x17 0x18 0x19 0x1A 0x1B 0x1C 0x1D 0x1E 0x1F 0x20 0x21 0x22 0x23 0x24 0x25 0x26 0x27 0x28 0x29 0x2A 0x2B 0x2C 0x2D 0x2E 0x2F 0x30 0x31 0x32 0x33 0x34 0x35 0x36 0x37 0x38 0x39 0x3A 0x3B 0x3C 0x3D 0x3E 0x3F 0x40 0x41 0x42 0x43 0x44 0x45 0x46 0x47 0x48 0x49 0x4A 0x4B 0x4C 0x4D 0x4E 0x4F 0x50 0x51 0x52 0x53 0x54 0x55 0x56 0x57 0x58 0x59 0x5A 0x5B 0x5C 0x5D 0x5E 0x5F 0x60 0x41 0x42 0x43 0x44 0x45 0x46 0x47 0x48 0x49 0x4A 0x4B 0x4C 0x4D 0x4E 0x4F 0x50 0x51 0x52 0x53 0x54 0x55 0x56 0x57 0x58 0x59 0x5A 0x5B 0x5C 0x5D 0x7E 0x7F 0x80 0x81 0x82 0x83 0x84 0x85 0x86 0x87 0x88 0x89 0x8A 0x8B 0x8C 0x8D 0x8E 0x8F 0x90 0x91 0x92 0x93 0x94 0x95 0x96 0x97 0x98 0x99 0x8A 0x9B 0x8C 0x8D 0x8E 0x8F 0xA0 0xA1 0xA2 0xA3 0xA4 0xA5 0xA6 0xA7 0xA8 0xA9 0xAA 0xAB 0xAC 0xAD 0xAE 0xAF 0xB0 0xB1 0xB2 0xA3 0xB4 0xB5 0xB6 0xB7 0xB8 0xA5 0xAA 0xBB 0xBC 0xBD 0xBC 0xAF 0xC0 0xC1 0xC2 0xC3 0xC4 0xC5 0xC6 0xC7 0xC8 0xC9 0xCA 0xCB 0xCC 0xCD 0xCE 0xCF 0xD0 0xD1 0xD2 0xD3 0xD4 0xD5 0xD6 0xD7 0xD8 0xD9 0xDA 0xDB 0xDC 0xDD 0xDE 0xDF 0xC0 0xC1 0xC2 0xC3 0xC4 0xC5 0xC6 0xC7 0xC8 0xC9 0xCA 0xCB 0xCC 0xCD 0xCE 0xCF 0xD0 0xD1 0xD2 0xD3 0xD4 0xD5 0xD6 0xF7 0xD8 0xD9 0xDA 0xDB 0xDC 0xDD 0xDE 0xFF ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/locales/sv_SE.iso88591���������������������������������������������������������������0000775�0000000�0000000�00000005020�13554550454�0017137�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������. . 0x00 0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09 0x0A 0x0B 0x0C 0x0D 0x0E 0x0F 0x10 0x11 0x12 0x13 0x14 0x15 0x16 0x17 0x18 0x19 0x1A 0x1B 0x1C 0x1D 0x1E 0x1F 0x20 0x21 0x22 0x23 0x24 0x25 0x26 0x27 0x28 0x29 0x2A 0x2B 0x2C 0x2D 0x2E 0x2F 0x30 0x31 0x32 0x33 0x34 0x35 0x36 0x37 0x38 0x39 0x3A 0x3B 0x3C 0x3D 0x3E 0x3F 0x40 0x61 0x62 0x63 0x64 0x65 0x66 0x67 0x68 0x69 0x6A 0x6B 0x6C 0x6D 0x6E 0x6F 0x70 0x71 0x72 0x73 0x74 0x75 0x76 0x77 0x78 0x79 0x7A 0x5B 0x5C 0x5D 0x5E 0x5F 0x60 0x61 0x62 0x63 0x64 0x65 0x66 0x67 0x68 0x69 0x6A 0x6B 0x6C 0x6D 0x6E 0x6F 0x70 0x71 0x72 0x73 0x74 0x75 0x76 0x77 0x78 0x79 0x7A 0x7B 0x7C 0x7D 0x7E 0x7F 0x80 0x81 0x82 0x83 0x84 0x85 0x86 0x87 0x88 0x89 0x8A 0x8B 0x8C 0x8D 0x8E 0x8F 0x90 0x91 0x92 0x93 0x94 0x95 0x96 0x97 0x98 0x99 0x9A 0x9B 0x9C 0x9D 0x9E 0x9F 0xA0 0xA1 0xA2 0xA3 0xA4 0xA5 0xA6 0xA7 0xA8 0xA9 0xAA 0xAB 0xAC 0xAD 0xAE 0xAF 0xB0 0xB1 0xB2 0xB3 0xB4 0xB5 0xB6 0xB7 0xB8 0xB9 0xBA 0xBB 0xBC 0xBD 0xBE 0xBF 0xE0 0xE1 0xE2 0xE3 0xE4 0xE5 0xE6 0xE7 0xE8 0xE9 0xEA 0xEB 0xEC 0xED 0xEE 0xEF 0xF0 0xF1 0xF2 0xF3 0xF4 0xF5 0xF6 0xD7 0xF8 0xF9 0xFA 0xFB 0xFC 0xFD 0xFE 0xDF 0xE0 0xE1 0xE2 0xE3 0xE4 0xE5 0xE6 0xE7 0xE8 0xE9 0xEA 0xEB 0xEC 0xED 0xEE 0xEF 0xF0 0xF1 0xF2 0xF3 0xF4 0xF5 0xF6 0xF7 0xF8 0xF9 0xFA 0xFB 0xFC 0xFD 0xFE 0xFF 0x00 0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09 0x0A 0x0B 0x0C 0x0D 0x0E 0x0F 0x10 0x11 0x12 0x13 0x14 0x15 0x16 0x17 0x18 0x19 0x1A 0x1B 0x1C 0x1D 0x1E 0x1F 0x20 0x21 0x22 0x23 0x24 0x25 0x26 0x27 0x28 0x29 0x2A 0x2B 0x2C 0x2D 0x2E 0x2F 0x30 0x31 0x32 0x33 0x34 0x35 0x36 0x37 0x38 0x39 0x3A 0x3B 0x3C 0x3D 0x3E 0x3F 0x40 0x41 0x42 0x43 0x44 0x45 0x46 0x47 0x48 0x49 0x4A 0x4B 0x4C 0x4D 0x4E 0x4F 0x50 0x51 0x52 0x53 0x54 0x55 0x56 0x57 0x58 0x59 0x5A 0x5B 0x5C 0x5D 0x5E 0x5F 0x60 0x41 0x42 0x43 0x44 0x45 0x46 0x47 0x48 0x49 0x4A 0x4B 0x4C 0x4D 0x4E 0x4F 0x50 0x51 0x52 0x53 0x54 0x55 0x56 0x57 0x58 0x59 0x5A 0x7B 0x7C 0x7D 0x7E 0x7F 0x80 0x81 0x82 0x83 0x84 0x85 0x86 0x87 0x88 0x89 0x8A 0x8B 0x8C 0x8D 0x8E 0x8F 0x90 0x91 0x92 0x93 0x94 0x95 0x96 0x97 0x98 0x99 0x9A 0x9B 0x9C 0x9D 0x9E 0x9F 0xA0 0xA1 0xA2 0xA3 0xA4 0xA5 0xA6 0xA7 0xA8 0xA9 0xAA 0xAB 0xAC 0xAD 0xAE 0xAF 0xB0 0xB1 0xB2 0xB3 0xB4 0xB5 0xB6 0xB7 0xB8 0xB9 0xBA 0xBB 0xBC 0xBD 0xBE 0xBF 0xC0 0xC1 0xC2 0xC3 0xC4 0xC5 0xC6 0xC7 0xC8 0xC9 0xCA 0xCB 0xCC 0xCD 0xCE 0xCF 0xD0 0xD1 0xD2 0xD3 0xD4 0xD5 0xD6 0xD7 0xD8 0xD9 0xDA 0xDB 0xDC 0xDD 0xDE 0xDF 0xC0 0xC1 0xC2 0xC3 0xC4 0xC5 0xC6 0xC7 0xC8 0xC9 0xCA 0xCB 0xCC 0xCD 0xCE 0xCF 0xD0 0xD1 0xD2 0xD3 0xD4 0xD5 0xD6 0xF7 0xD8 0xD9 0xDA 0xDB 0xDC 0xDD 0xDE 0xFF ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/locales/sv_SE.iso88591_braces��������������������������������������������������������0000775�0000000�0000000�00000005020�13554550454�0020456�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������. . 0x00 0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09 0x0A 0x0B 0x0C 0x0D 0x0E 0x0F 0x10 0x11 0x12 0x13 0x14 0x15 0x16 0x17 0x18 0x19 0x1A 0x1B 0x1C 0x1D 0x1E 0x1F 0x20 0x21 0x22 0x23 0x24 0x25 0x26 0x27 0x28 0x29 0x2A 0x2B 0x2C 0x2D 0x2E 0x2F 0x30 0x31 0x32 0x33 0x34 0x35 0x36 0x37 0x38 0x39 0x3A 0x3B 0x3C 0x3D 0x3E 0x3F 0x40 0x61 0x62 0x63 0x64 0x65 0x66 0x67 0x68 0x69 0x6A 0x6B 0x6C 0x6D 0x6E 0x6F 0x70 0x71 0x72 0x73 0x74 0x75 0x76 0x77 0x78 0x79 0x7A 0x7B 0x7C 0x7D 0x5E 0x5F 0x60 0x61 0x62 0x63 0x64 0x65 0x66 0x67 0x68 0x69 0x6A 0x6B 0x6C 0x6D 0x6E 0x6F 0x70 0x71 0x72 0x73 0x74 0x75 0x76 0x77 0x78 0x79 0x7A 0x7B 0x7C 0x7D 0x7E 0x7F 0x80 0x81 0x82 0x83 0x84 0x85 0x86 0x87 0x88 0x89 0x8A 0x8B 0x8C 0x8D 0x8E 0x8F 0x90 0x91 0x92 0x93 0x94 0x95 0x96 0x97 0x98 0x99 0x9A 0x9B 0x9C 0x9D 0x9E 0x9F 0xA0 0xA1 0xA2 0xA3 0xA4 0xA5 0xA6 0xA7 0xA8 0xA9 0xAA 0xAB 0xAC 0xAD 0xAE 0xAF 0xB0 0xB1 0xB2 0xB3 0xB4 0xB5 0xB6 0xB7 0xB8 0xB9 0xBA 0xBB 0xBC 0xBD 0xBE 0xBF 0xE0 0xE1 0xE2 0xE3 0xE4 0xE5 0xE6 0xE7 0xE8 0xE9 0xEA 0xEB 0xEC 0xED 0xEE 0xEF 0xF0 0xF1 0xF2 0xF3 0xF4 0xF5 0xF6 0xD7 0xF8 0xF9 0xFA 0xFB 0xFC 0xFD 0xFE 0xDF 0xE0 0xE1 0xE2 0xE3 0xE4 0xE5 0xE6 0xE7 0xE8 0xE9 0xEA 0xEB 0xEC 0xED 0xEE 0xEF 0xF0 0xF1 0xF2 0xF3 0xF4 0xF5 0xF6 0xF7 0xF8 0xF9 0xFA 0xFB 0xFC 0xFD 0xFE 0xFF 0x00 0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09 0x0A 0x0B 0x0C 0x0D 0x0E 0x0F 0x10 0x11 0x12 0x13 0x14 0x15 0x16 0x17 0x18 0x19 0x1A 0x1B 0x1C 0x1D 0x1E 0x1F 0x20 0x21 0x22 0x23 0x24 0x25 0x26 0x27 0x28 0x29 0x2A 0x2B 0x2C 0x2D 0x2E 0x2F 0x30 0x31 0x32 0x33 0x34 0x35 0x36 0x37 0x38 0x39 0x3A 0x3B 0x3C 0x3D 0x3E 0x3F 0x40 0x41 0x42 0x43 0x44 0x45 0x46 0x47 0x48 0x49 0x4A 0x4B 0x4C 0x4D 0x4E 0x4F 0x50 0x51 0x52 0x53 0x54 0x55 0x56 0x57 0x58 0x59 0x5A 0x5B 0x5C 0x5D 0x5E 0x5F 0x60 0x41 0x42 0x43 0x44 0x45 0x46 0x47 0x48 0x49 0x4A 0x4B 0x4C 0x4D 0x4E 0x4F 0x50 0x51 0x52 0x53 0x54 0x55 0x56 0x57 0x58 0x59 0x5A 0x5B 0x5C 0x5D 0x7E 0x7F 0x80 0x81 0x82 0x83 0x84 0x85 0x86 0x87 0x88 0x89 0x8A 0x8B 0x8C 0x8D 0x8E 0x8F 0x90 0x91 0x92 0x93 0x94 0x95 0x96 0x97 0x98 0x99 0x9A 0x9B 0x9C 0x9D 0x9E 0x9F 0xA0 0xA1 0xA2 0xA3 0xA4 0xA5 0xA6 0xA7 0xA8 0xA9 0xAA 0xAB 0xAC 0xAD 0xAE 0xAF 0xB0 0xB1 0xB2 0xB3 0xB4 0xB5 0xB6 0xB7 0xB8 0xB9 0xBA 0xBB 0xBC 0xBD 0xBE 0xBF 0xC0 0xC1 0xC2 0xC3 0xC4 0xC5 0xC6 0xC7 0xC8 0xC9 0xCA 0xCB 0xCC 0xCD 0xCE 0xCF 0xD0 0xD1 0xD2 0xD3 0xD4 0xD5 0xD6 0xD7 0xD8 0xD9 0xDA 0xDB 0xDC 0xDD 0xDE 0xDF 0xC0 0xC1 0xC2 0xC3 0xC4 0xC5 0xC6 0xC7 0xC8 0xC9 0xCA 0xCB 0xCC 0xCD 0xCE 0xCF 0xD0 0xD1 0xD2 0xD3 0xD4 0xD5 0xD6 0xF7 0xD8 0xD9 0xDA 0xDB 0xDC 0xDD 0xDE 0xFF ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/locales/tr_TR.iso88599���������������������������������������������������������������0000775�0000000�0000000�00000005027�13554550454�0017171�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������. . 0x00 0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09 0x0A 0x0B 0x0C 0x0D 0x0E 0x0F 0x10 0x11 0x12 0x13 0x14 0x15 0x16 0x17 0x18 0x19 0x1A 0x1B 0x1C 0x1D 0x1E 0x1F 0x20 0x21 0x22 0x23 0x24 0x25 0x26 0x27 0x28 0x29 0x2A 0x2B 0x2C 0x2D 0x2E 0x2F 0x30 0x31 0x32 0x33 0x34 0x35 0x36 0x37 0x38 0x39 0x3A 0x3B 0x3C 0x3D 0x3E 0x3F 0x40 0x61 0x62 0x63 0x64 0x65 0x66 0x67 0x68 0xFD 0x6A 0x6B 0x6C 0x6D 0x6E 0x6F 0x70 0x71 0x72 0x73 0x74 0x75 0x76 0x77 0x78 0x79 0x7A 0x5B 0x5C 0x5D 0x5E 0x5F 0x60 0x61 0x62 0x63 0x64 0x65 0x66 0x67 0x68 0x69 0x6A 0x6B 0x6C 0x6D 0x6E 0x6F 0x70 0x71 0x72 0x73 0x74 0x75 0x76 0x77 0x78 0x79 0x7A 0x7B 0x7C 0x7D 0x7E 0x7F 0x80 0x81 0x82 0x83 0x84 0x85 0x86 0x87 0x88 0x89 0x8A 0x8B 0x8C 0x8D 0x8E 0x8F 0x90 0x91 0x92 0x93 0x94 0x95 0x96 0x97 0x98 0x99 0x9A 0x9B 0x9C 0x9D 0x9E 0x9F 0xA0 0xA1 0xA2 0xA3 0xA4 0xA5 0xA6 0xA7 0xA8 0xA9 0xAA 0xAB 0xAC 0xAD 0xAE 0xAF 0xB0 0xB1 0xB2 0xB3 0xB4 0xB5 0xB6 0xB7 0xB8 0xB9 0xBA 0xBB 0xBC 0xBD 0xBE 0xBF 0xE0 0xE1 0xE2 0xE3 0xE4 0xE5 0xE6 0xE7 0xE8 0xE9 0xEA 0xEB 0xEC 0xED 0xEE 0xEF 0xF0 0xF1 0xF2 0xF3 0xF4 0xF5 0xF6 0xD7 0xF8 0xF9 0xFA 0xFB 0xFC 0x69 0xFE 0xDF 0xE0 0xE1 0xE2 0xE3 0xE4 0xE5 0xE6 0xE7 0xE8 0xE9 0xEA 0xEB 0xEC 0xED 0xEE 0xEF 0xF0 0xF1 0xF2 0xF3 0xF4 0xF5 0xF6 0xF7 0xF8 0xF9 0xFA 0xFB 0xFC 0xFD 0xFE 0xFF 0x00 0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09 0x0A 0x0B 0x0C 0x0D 0x0E 0x0F 0x10 0x11 0x12 0x13 0x14 0x15 0x16 0x17 0x18 0x19 0x1A 0x1B 0x1C 0x1D 0x1E 0x1F 0x20 0x21 0x22 0x23 0x24 0x25 0x26 0x27 0x28 0x29 0x2A 0x2B 0x2C 0x2D 0x2E 0x2F 0x30 0x31 0x32 0x33 0x34 0x35 0x36 0x37 0x38 0x39 0x3A 0x3B 0x3C 0x3D 0x3E 0x3F 0x40 0x41 0x42 0x43 0x44 0x45 0x46 0x47 0x48 0x49 0x4A 0x4B 0x4C 0x4D 0x4E 0x4F 0x50 0x51 0x52 0x53 0x54 0x55 0x56 0x57 0x58 0x59 0x5A 0x5B 0x5C 0x5D 0x5E 0x5F 0x60 0x41 0x42 0x43 0x44 0x45 0x46 0x47 0x48 0xDD 0x4A 0x4B 0x4C 0x4D 0x4E 0x4F 0x50 0x51 0x52 0x53 0x54 0x55 0x56 0x57 0x58 0x59 0x5A 0x7B 0x7C 0x7D 0x7E 0x7F 0x80 0x81 0x82 0x83 0x84 0x85 0x86 0x87 0x88 0x89 0x8A 0x8B 0x8C 0x8D 0x8E 0x8F 0x90 0x91 0x92 0x93 0x94 0x95 0x96 0x97 0x98 0x99 0x9A 0x9B 0x9C 0x9D 0x9E 0x9F 0xA0 0xA1 0xA2 0xA3 0xA4 0xA5 0xA6 0xA7 0xA8 0xA9 0xAA 0xAB 0xAC 0xAD 0xAE 0xAF 0xB0 0xB1 0xB2 0xB3 0xB4 0xB5 0xB6 0xB7 0xB8 0xB9 0xBA 0xBB 0xBC 0xBD 0xBE 0xBF 0xC0 0xC1 0xC2 0xC3 0xC4 0xC5 0xC6 0xC7 0xC8 0xC9 0xCA 0xCB 0xCC 0xCD 0xCE 0xCF 0xD0 0xD1 0xD2 0xD3 0xD4 0xD5 0xD6 0xD7 0xD8 0xD9 0xDA 0xDB 0xDC 0xDD 0xDE 0xDF 0xC0 0xC1 0xC2 0xC3 0xC4 0xC5 0xC6 0xC7 0xC8 0xC9 0xCA 0xCB 0xCC 0xCD 0xCE 0xCF 0xD0 0xD1 0xD2 0xD3 0xD4 0xD5 0xD6 0xF7 0xD8 0xD9 0xDA 0xDB 0xDC 0x49 0xDE 0xFF ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/locales/tr_TR.iso88599_braces��������������������������������������������������������0000775�0000000�0000000�00000005027�13554550454�0020510�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������. . 0x00 0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09 0x0A 0x0B 0x0C 0x0D 0x0E 0x0F 0x10 0x11 0x12 0x13 0x14 0x15 0x16 0x17 0x18 0x19 0x1A 0x1B 0x1C 0x1D 0x1E 0x1F 0x20 0x21 0x22 0x23 0x24 0x25 0x26 0x27 0x28 0x29 0x2A 0x2B 0x2C 0x2D 0x2E 0x2F 0x30 0x31 0x32 0x33 0x34 0x35 0x36 0x37 0x38 0x39 0x3A 0x3B 0x3C 0x3D 0x3E 0x3F 0x40 0x61 0x62 0x63 0x64 0x65 0x66 0x67 0x68 0xFD 0x6A 0x6B 0x6C 0x6D 0x6E 0x6F 0x70 0x71 0x72 0x73 0x74 0x75 0x76 0x77 0x78 0x79 0x7A 0x7B 0x7C 0x7D 0x5E 0x5F 0x60 0x61 0x62 0x63 0x64 0x65 0x66 0x67 0x68 0x69 0x6A 0x6B 0x6C 0x6D 0x6E 0x6F 0x70 0x71 0x72 0x73 0x74 0x75 0x76 0x77 0x78 0x79 0x7A 0x7B 0x7C 0x7D 0x7E 0x7F 0x80 0x81 0x82 0x83 0x84 0x85 0x86 0x87 0x88 0x89 0x8A 0x8B 0x8C 0x8D 0x8E 0x8F 0x90 0x91 0x92 0x93 0x94 0x95 0x96 0x97 0x98 0x99 0x9A 0x9B 0x9C 0x9D 0x9E 0x9F 0xA0 0xA1 0xA2 0xA3 0xA4 0xA5 0xA6 0xA7 0xA8 0xA9 0xAA 0xAB 0xAC 0xAD 0xAE 0xAF 0xB0 0xB1 0xB2 0xB3 0xB4 0xB5 0xB6 0xB7 0xB8 0xB9 0xBA 0xBB 0xBC 0xBD 0xBE 0xBF 0xE0 0xE1 0xE2 0xE3 0xE4 0xE5 0xE6 0xE7 0xE8 0xE9 0xEA 0xEB 0xEC 0xED 0xEE 0xEF 0xF0 0xF1 0xF2 0xF3 0xF4 0xF5 0xF6 0xD7 0xF8 0xF9 0xFA 0xFB 0xFC 0x69 0xFE 0xDF 0xE0 0xE1 0xE2 0xE3 0xE4 0xE5 0xE6 0xE7 0xE8 0xE9 0xEA 0xEB 0xEC 0xED 0xEE 0xEF 0xF0 0xF1 0xF2 0xF3 0xF4 0xF5 0xF6 0xF7 0xF8 0xF9 0xFA 0xFB 0xFC 0xFD 0xFE 0xFF 0x00 0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09 0x0A 0x0B 0x0C 0x0D 0x0E 0x0F 0x10 0x11 0x12 0x13 0x14 0x15 0x16 0x17 0x18 0x19 0x1A 0x1B 0x1C 0x1D 0x1E 0x1F 0x20 0x21 0x22 0x23 0x24 0x25 0x26 0x27 0x28 0x29 0x2A 0x2B 0x2C 0x2D 0x2E 0x2F 0x30 0x31 0x32 0x33 0x34 0x35 0x36 0x37 0x38 0x39 0x3A 0x3B 0x3C 0x3D 0x3E 0x3F 0x40 0x41 0x42 0x43 0x44 0x45 0x46 0x47 0x48 0x49 0x4A 0x4B 0x4C 0x4D 0x4E 0x4F 0x50 0x51 0x52 0x53 0x54 0x55 0x56 0x57 0x58 0x59 0x5A 0x5B 0x5C 0x5D 0x5E 0x5F 0x60 0x41 0x42 0x43 0x44 0x45 0x46 0x47 0x48 0xDD 0x4A 0x4B 0x4C 0x4D 0x4E 0x4F 0x50 0x51 0x52 0x53 0x54 0x55 0x56 0x57 0x58 0x59 0x5A 0x5B 0x5C 0x5D 0x7E 0x7F 0x80 0x81 0x82 0x83 0x84 0x85 0x86 0x87 0x88 0x89 0x8A 0x8B 0x8C 0x8D 0x8E 0x8F 0x90 0x91 0x92 0x93 0x94 0x95 0x96 0x97 0x98 0x99 0x9A 0x9B 0x9C 0x9D 0x9E 0x9F 0xA0 0xA1 0xA2 0xA3 0xA4 0xA5 0xA6 0xA7 0xA8 0xA9 0xAA 0xAB 0xAC 0xAD 0xAE 0xAF 0xB0 0xB1 0xB2 0xB3 0xB4 0xB5 0xB6 0xB7 0xB8 0xB9 0xBA 0xBB 0xBC 0xBD 0xBE 0xBF 0xC0 0xC1 0xC2 0xC3 0xC4 0xC5 0xC6 0xC7 0xC8 0xC9 0xCA 0xCB 0xCC 0xCD 0xCE 0xCF 0xD0 0xD1 0xD2 0xD3 0xD4 0xD5 0xD6 0xD7 0xD8 0xD9 0xDA 0xDB 0xDC 0xDD 0xDE 0xDF 0xC0 0xC1 0xC2 0xC3 0xC4 0xC5 0xC6 0xC7 0xC8 0xC9 0xCA 0xCB 0xCC 0xCD 0xCE 0xCF 0xD0 0xD1 0xD2 0xD3 0xD4 0xD5 0xD6 0xF7 0xD8 0xD9 0xDA 0xDB 0xDC 0x49 0xDE 0xFF ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/make/��������������������������������������������������������������������������������0000775�0000000�0000000�00000000000�13554550454�0014260�5����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/make/calcdep.pl����������������������������������������������������������������������0000775�0000000�0000000�00000013562�13554550454�0016222�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������#!/usr/bin/env perl # # InspIRCd -- Internet Relay Chat Daemon # # 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 # 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/>. # BEGIN { push @INC, $ENV{SOURCEPATH}; require 5.10.0; unless (-f 'configure') { print "Error: $0 must be run from the main source directory!\n"; exit 1; } } use strict; use warnings FATAL => qw(all); use File::Basename qw(basename); use make::common; use constant { BUILDPATH => $ENV{BUILDPATH}, SOURCEPATH => $ENV{SOURCEPATH} }; sub find_output; sub gendep($); sub dep_cpp($$$); sub dep_so($); sub dep_dir($$); sub run(); my %f2dep; run; exit 0; sub run() { create_directory(BUILDPATH, 0770) or die "Could not create build directory: $!"; chdir BUILDPATH or die "Could not open build directory: $!"; unlink 'include'; symlink "${\SOURCEPATH}/include", 'include'; mkdir $_ for qw/bin modules obj/; open MAKE, '>real.mk' or die "Could not write real.mk: $!"; chdir "${\SOURCEPATH}/src"; run_dynamic(); close MAKE; } sub run_dynamic() { print MAKE <<END; # DO NOT EDIT THIS FILE # It is autogenerated by make/calcdep.pl, and will be overwritten # every time you rerun make in the main directory VPATH = \$(SOURCEPATH)/src bad-target: \@echo "This Makefile must be run by a sub-make from the source" \@echo "in order to set the correct environment variables" \@exit 1 all: inspircd modules END my(@core_deps, @modlist); for my $file (<*.cpp>, <socketengines/*.cpp>, "threadengines/threadengine_pthread.cpp") { my $out = find_output $file; dep_cpp $file, $out, 'gen-o'; next if $file =~ m#^socketengines/# && $file ne "socketengines/socketengine_$ENV{SOCKETENGINE}.cpp"; # Having a module in the src directory is a bad idea because it will be linked to the core binary if ($file =~ /^(m|core)_.*\.cpp/) { my $correctsubdir = ($file =~ /^m_/ ? "modules" : "coremods"); print "Error: module $file is in the src directory, put it in src/$correctsubdir instead!\n"; exit 1; } push @core_deps, $out; } foreach my $directory (qw(coremods modules)) { opendir(my $moddir, $directory); for my $file (sort readdir $moddir) { next if $file =~ /^\./; if ($directory eq 'modules' && -e "modules/extra/$file" && !-l "modules/$file") { # Incorrect symlink? print "Replacing symlink for $file found in modules/extra\n"; rename "modules/$file", "modules/$file~"; symlink "extra/$file", "modules/$file"; } if ($file =~ /^(?:core|m)_/ && -d "$directory/$file" && dep_dir "$directory/$file", "modules/$file") { mkdir "${\BUILDPATH}/obj/$file"; push @modlist, "modules/$file.so"; } if ($file =~ /^.*\.cpp$/) { my $out = dep_so "$directory/$file"; push @modlist, $out; } } } my $core_mk = join ' ', @core_deps; my $mods = join ' ', @modlist; print MAKE <<END; bin/inspircd: $core_mk @\$(SOURCEPATH)/make/unit-cc.pl core-ld \$\@ \$^ \$> inspircd: bin/inspircd modules: $mods .PHONY: all bad-target inspircd modules END } sub find_output { my $file = shift; my($path,$base) = $file =~ m#^((?:.*/)?)([^/]+)\.cpp# or die "Bad file $file"; if ($path eq 'modules/' || $path eq 'coremods/') { return "modules/$base.so"; } elsif ($path eq '' || $path eq 'modes/' || $path =~ /^[a-z]+engines\/$/) { return "obj/$base.o"; } elsif ($path =~ m#modules/(m_.*)/# || $path =~ m#coremods/(core_.*)/#) { return "obj/$1/$base.o"; } else { die "Can't determine output for $file"; } } sub gendep($) { my $f = shift; my $basedir = $f =~ m#(.*)/# ? $1 : '.'; return $f2dep{$f} if exists $f2dep{$f}; $f2dep{$f} = ''; my %dep; my $link = readlink $f; if (defined $link) { $link = "$basedir/$link" unless $link =~ m#^/#; $dep{$link}++; } open my $in, '<', $f or die "Could not read $f"; while (<$in>) { if (/^\s*#\s*include\s*"([^"]+)"/) { my $inc = $1; next if $inc eq 'config.h' && $f eq '../include/inspircd.h'; my $found = 0; for my $loc ("$basedir/$inc", "../include/$inc") { next unless -e $loc; $found++; $dep{$_}++ for split / /, gendep $loc; $loc =~ s#^\.\./##; $dep{$loc}++; } if ($found == 0 && $inc ne 'inspircd_win32wrapper.h') { print STDERR "WARNING: could not find header $inc for $f\n"; } elsif ($found > 1 && $basedir ne '../include') { print STDERR "WARNING: ambiguous include $inc in $f\n"; } } } close $in; $f2dep{$f} = join ' ', sort keys %dep; $f2dep{$f}; } sub dep_cpp($$$) { my($file, $out, $type) = @_; gendep $file; print MAKE "$out: $file $f2dep{$file}\n"; print MAKE "\t@\$(SOURCEPATH)/make/unit-cc.pl $type \$\@ \$(SOURCEPATH)/src/$file \$>\n"; } sub dep_so($) { my($file) = @_; my $out = find_output $file; my $name = basename $out, '.so'; print MAKE ".PHONY: $name\n"; print MAKE "$name: $out\n"; dep_cpp $file, $out, 'gen-so'; return $out; } sub dep_dir($$) { my($dir, $outdir) = @_; my @ofiles; opendir DIR, $dir; for my $file (sort readdir DIR) { next unless $file =~ /(.*)\.cpp$/; my $ofile = find_output "$dir/$file"; dep_cpp "$dir/$file", $ofile, 'gen-o'; push @ofiles, $ofile; } closedir DIR; if (@ofiles) { my $ofiles = join ' ', @ofiles; my $name = basename $outdir; print MAKE ".PHONY: $name\n"; print MAKE "$name: $outdir.so\n"; print MAKE "$outdir.so: $ofiles\n"; print MAKE "\t@\$(SOURCEPATH)/make/unit-cc.pl link-dir \$\@ ${\SOURCEPATH}/src/$dir \$^ \$>\n"; return 1; } else { return 0; } } ����������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/make/common.pm�����������������������������������������������������������������������0000664�0000000�0000000�00000007103�13554550454�0016107�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������# # InspIRCd -- Internet Relay Chat Daemon # # Copyright (C) 2013-2017 Peter Powell <petpow@saberuk.com> # # This file is part of InspIRCd. InspIRCd is free software: you can # redistribute it and/or modify it under the terms of the GNU General Public # License as published by the Free Software Foundation, version 2. # # This program is distributed in the hope that it will be useful, but WITHOUT # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS # FOR A PARTICULAR PURPOSE. See the GNU General Public License for more # details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see <http://www.gnu.org/licenses/>. # BEGIN { require 5.10.0; } package make::common; use feature ':5.10'; use strict; use warnings FATAL => qw(all); use Exporter qw(import); use File::Path qw(mkpath); use File::Spec::Functions qw(rel2abs); use make::console; our @EXPORT = qw(create_directory get_cpu_count get_version read_config_file write_config_file); sub create_directory($$) { my ($location, $permissions) = @_; return eval { mkpath($location, 0, $permissions); return 1; } // 0; } sub get_version { state %version; return %version if %version; # Attempt to retrieve version information from src/version.sh chomp(my $vf = `sh src/version.sh 2>/dev/null`); if ($vf =~ /^InspIRCd-([0-9]+)\.([0-9]+)\.([0-9]+)(?:-(\w+))?$/) { %version = ( MAJOR => $1, MINOR => $2, PATCH => $3, LABEL => $4 ); } # Attempt to retrieve missing version information from Git chomp(my $gr = `git describe --tags 2>/dev/null`); if ($gr =~ /^v([0-9]+)\.([0-9]+)\.([0-9]+)(?:[a-z]+\d+)?(?:-\d+-g(\w+))?$/) { $version{MAJOR} //= $1; $version{MINOR} //= $2; $version{PATCH} //= $3; $version{LABEL} = $4 if defined $4; } # If the user has specified a distribution label then we use it in # place of the label from src/version.sh or Git. $version{REAL_LABEL} = $version{LABEL}; $version{LABEL} = shift // $version{LABEL}; # If any of these fields are missing then the user has deleted the # version file and is not running from Git. Fill in the fields with # dummy data so we don't get into trouble with undef values later. $version{MAJOR} //= '0'; $version{MINOR} //= '0'; $version{PATCH} //= '0'; # If there is no label then the user is using a stable release which # does not have a label attached. if (defined $version{LABEL}) { $version{FULL} = "$version{MAJOR}.$version{MINOR}.$version{PATCH}-$version{LABEL}" } else { $version{LABEL} = 'release'; $version{FULL} = "$version{MAJOR}.$version{MINOR}.$version{PATCH}" } return %version; } sub get_cpu_count { my $count = 1; if ($^O =~ /bsd/) { $count = `sysctl -n hw.ncpu 2>/dev/null` || 1; } elsif ($^O eq 'darwin') { $count = `sysctl -n hw.activecpu 2>/dev/null` || 1; } elsif ($^O eq 'linux') { $count = `getconf _NPROCESSORS_ONLN 2>/dev/null` || 1; } elsif ($^O eq 'solaris') { $count = `psrinfo -p 2>/dev/null` || 1; } chomp($count); return $count; } sub read_config_file($) { my $path = shift; my %config; open(my $fh, $path) or return %config; while (my $line = <$fh>) { next if $line =~ /^\s*($|\#)/; my ($key, $value) = ($line =~ /^(\S+)(?:\s(.*))?$/); $config{$key} = $value; } close $fh; return %config; } sub write_config_file($%) { my $path = shift; my %config = @_; open(my $fh, '>', $path) or print_error "unable to write to $path: $!"; while (my ($key, $value) = each %config) { $value //= ''; say $fh "$key $value"; } close $fh; } 1; �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/make/configure.pm��������������������������������������������������������������������0000664�0000000�0000000�00000026506�13554550454�0016610�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������# # InspIRCd -- Internet Relay Chat Daemon # # Copyright (C) 2012-2017 Peter Powell <petpow@saberuk.com> # Copyright (C) 2008 Robin Burchell <robin+git@viroteck.net> # Copyright (C) 2007-2008 Craig Edwards <craigedwards@brainbox.cc> # Copyright (C) 2008 Thomas Stagner <aquanight@inspircd.org> # Copyright (C) 2007 Dennis Friis <peavey@inspircd.org> # # This file is part of InspIRCd. InspIRCd is free software: you can # redistribute it and/or modify it under the terms of the GNU General Public # License as published by the Free Software Foundation, version 2. # # This program is distributed in the hope that it will be useful, but WITHOUT # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS # FOR A PARTICULAR PURPOSE. See the GNU General Public License for more # details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see <http://www.gnu.org/licenses/>. # BEGIN { require 5.10.0; } package make::configure; use feature ':5.10'; use strict; use warnings FATAL => qw(all); use Cwd qw(getcwd); use Exporter qw(import); use File::Basename qw(basename dirname); use File::Spec::Functions qw(catdir catfile); use make::common; use make::console; use constant CONFIGURE_ROOT => dirname dirname __FILE__; use constant CONFIGURE_DIRECTORY => catdir(CONFIGURE_ROOT, '.configure'); use constant CONFIGURE_CACHE_FILE => catfile(CONFIGURE_DIRECTORY, 'cache.cfg'); use constant CONFIGURE_CACHE_VERSION => '1'; use constant CONFIGURE_ERROR_PIPE => $ENV{INSPIRCD_VERBOSE} ? '' : '1>/dev/null 2>/dev/null'; our @EXPORT = qw(CONFIGURE_CACHE_FILE CONFIGURE_CACHE_VERSION cmd_clean cmd_help cmd_update run_test test_file test_header write_configure_cache get_compiler_info find_compiler parse_templates); sub __get_socketengines { my @socketengines; foreach (<src/socketengines/socketengine_*.cpp>) { s/src\/socketengines\/socketengine_(\w+)\.cpp/$1/; push @socketengines, $1; } return @socketengines; } # TODO: when buildtool is done this can be mostly removed with # the remainder being merged into parse_templates. sub __get_template_settings($$$) { # These are actually hash references my ($config, $compiler, $version) = @_; # Start off by populating with the config my %settings = %$config; # Compiler information while (my ($key, $value) = each %{$compiler}) { $settings{'COMPILER_' . $key} = $value; } # Version information while (my ($key, $value) = each %{$version}) { $settings{'VERSION_' . $key} = $value; } # Miscellaneous information $settings{CONFIGURE_DIRECTORY} = CONFIGURE_DIRECTORY; $settings{CONFIGURE_CACHE_FILE} = CONFIGURE_CACHE_FILE; $settings{SYSTEM_NAME} = lc $^O; return %settings; } sub __test_compiler($) { my $compiler = shift; return 0 unless run_test("`$compiler`", !system "$compiler -v ${\CONFIGURE_ERROR_PIPE}"); return 0 unless run_test("`$compiler`", test_file($compiler, 'compiler.cpp', '-fno-rtti'), 'compatible'); return 1; } sub cmd_clean { unlink CONFIGURE_CACHE_FILE; } sub cmd_help { my $PWD = getcwd(); my $SELIST = join ', ', __get_socketengines(); print <<EOH; Usage: $0 [options] When no options are specified, configure runs in interactive mode and you must specify any required values manually. If one or more options are specified, non-interactive configuration is started and any omitted values are defaulted. PATH OPTIONS --system Automatically set up the installation paths for system-wide installation. --prefix=[dir] The root install directory. If this is set then all subdirectories will be adjusted accordingly. [$PWD/run] --binary-dir=[dir] The location where the main server binary is stored. [$PWD/run/bin] --config-dir=[dir] The location where the configuration files and SSL certificates are stored. [$PWD/run/conf] --data-dir=[dir] The location where the data files, such as the pid file, are stored. [$PWD/run/data] --example-dir=[dir] The location where the example configuration files and SQL schemas are stored. [$PWD/run/conf/examples] --log-dir=[dir] The location where the log files are stored. [$PWD/run/logs] --manual-dir=[dir] The location where the manual files are stored. [$PWD/run/manuals] --module-dir=[dir] The location where the loadable modules are stored. [$PWD/run/modules] --script-dir=[dir] The location where the scripts, such as the init scripts, are stored. [$PWD/run] EXTRA MODULE OPTIONS --enable-extras=[extras] Enables a comma separated list of extra modules. --disable-extras=[extras] Disables a comma separated list of extra modules. --list-extras Shows the availability status of all extra modules. MISC OPTIONS --clean Remove the configuration cache file and start the interactive configuration wizard. --disable-auto-extras Disables automatically enabling extra modules for which the dependencies are available. --disable-interactive Disables the interactive configuration wizard. --distribution-label=[text] Sets a distribution specific version label in the build configuration. --gid=[id|name] Sets the group to run InspIRCd as. --help Show this message and exit. --socketengine=[name] Sets the socket engine to be used. Possible values are $SELIST. --uid=[id|name] Sets the user to run InspIRCd as. --update Updates the build environment with the settings from the cache. FLAGS CXX=[name] Sets the C++ compiler to use when building the server. If not specified then the build system will search for c++, g++, clang++ or icpc. If you have any problems with configuring InspIRCd then visit our IRC channel at irc.inspircd.org #InspIRCd for support. EOH exit 0; } sub cmd_update { print_error "You have not run $0 before. Please do this before trying to update the generated files." unless -f CONFIGURE_CACHE_FILE; say 'Updating...'; my %config = read_config_file(CONFIGURE_CACHE_FILE); my %compiler = get_compiler_info($config{CXX}); my %version = get_version $config{DISTRIBUTION}; parse_templates(\%config, \%compiler, \%version); say 'Update complete!'; exit 0; } sub run_test($$;$) { my ($what, $result, $adjective) = @_; $adjective //= 'available'; print_format "Checking whether <|GREEN $what|> is $adjective ... "; print_format $result ? "<|GREEN yes|>\n" : "<|RED no|>\n"; return $result; } sub test_file($$;$) { my ($compiler, $file, $args) = @_; my $status = 0; $args //= ''; $status ||= system "$compiler -o __test_$file ${\CONFIGURE_ROOT}/make/test/$file $args ${\CONFIGURE_ERROR_PIPE}"; $status ||= system "./__test_$file ${\CONFIGURE_ERROR_PIPE}"; unlink "./__test_$file"; return !$status; } sub test_header($$;$) { my ($compiler, $header, $args) = @_; $args //= ''; open(my $fh, "| $compiler -E - $args ${\CONFIGURE_ERROR_PIPE}") or return 0; print $fh "#include <$header>"; close $fh; return !$?; } sub write_configure_cache(%) { unless (-e CONFIGURE_DIRECTORY) { print_format "Creating <|GREEN ${\CONFIGURE_DIRECTORY}|> ...\n"; create_directory CONFIGURE_DIRECTORY, 0750 or print_error "unable to create ${\CONFIGURE_DIRECTORY}: $!"; } print_format "Writing <|GREEN ${\CONFIGURE_CACHE_FILE}|> ...\n"; my %config = @_; write_config_file CONFIGURE_CACHE_FILE, %config; } sub get_compiler_info($) { my $binary = shift; my %info = (NAME => 'Unknown', VERSION => '0.0'); return %info if system "$binary -o __compiler_info ${\CONFIGURE_ROOT}/make/test/compiler_info.cpp ${\CONFIGURE_ERROR_PIPE}"; open(my $fh, '-|', './__compiler_info 2>/dev/null'); while (my $line = <$fh>) { $info{$1} = $2 if $line =~ /^([A-Z]+)\s(.+)$/; } close $fh; unlink './__compiler_info'; return %info; } sub find_compiler { my @compilers = qw(c++ g++ clang++ icpc); foreach my $compiler (shift // @compilers) { return $compiler if __test_compiler $compiler; return "xcrun $compiler" if $^O eq 'darwin' && __test_compiler "xcrun $compiler"; } } sub parse_templates($$$) { # These are actually hash references my ($config, $compiler, $version) = @_; # Collect settings to be used when generating files my %settings = __get_template_settings($config, $compiler, $version); # Iterate through files in make/template. foreach (<make/template/*>) { print_format "Parsing <|GREEN $_|> ...\n"; open(my $fh, $_) or print_error "unable to read $_: $!"; my (@lines, $mode, @platforms, @targets); # First pass: parse template variables and directives. while (my $line = <$fh>) { chomp $line; # Does this line match a variable? while ($line =~ /(@(\w+?)@)/) { my ($variable, $name) = ($1, $2); if (defined $settings{$name}) { $line =~ s/\Q$variable\E/$settings{$name}/; } else { print_warning "unknown template variable '$name' in $_!"; last; } } # Does this line match a directive? if ($line =~ /^(\s*)%(\w+)\s+(.+)$/) { if ($2 eq 'define') { if ($settings{$3}) { push @lines, "#$1define $3"; } else { push @lines, "#$1undef $3"; } } elsif ($2 eq 'mode') { $mode = oct $3; } elsif ($2 eq 'platform') { push @platforms, $3; } elsif ($2 eq 'target') { push @targets, $3 } else { print_warning "unknown template command '$2' in $_!"; push @lines, $line; } next; } push @lines, $line; } close $fh; # Only proceed if this file should be templated on this platform. if ($#platforms < 0 || grep { $_ eq $^O } @platforms) { # Add a default target if the template has not defined one. unless (@targets) { push @targets, catfile(CONFIGURE_DIRECTORY, basename $_); } # Write the templated files to disk. for my $target (@targets) { # Create the directory if it doesn't already exist. my $directory = dirname $target; unless (-e $directory) { print_format "Creating <|GREEN $directory|> ...\n"; create_directory $directory, 0750 or print_error "unable to create $directory: $!"; }; # Write the template file. print_format "Writing <|GREEN $target|> ...\n"; open(my $fh, '>', $target) or print_error "unable to write $target: $!"; foreach (@lines) { say $fh $_; } close $fh; # Set file permissions. if (defined $mode) { chmod $mode, $target; } } } } } 1; ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/make/console.pm����������������������������������������������������������������������0000664�0000000�0000000�00000010155�13554550454�0016262�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������# # InspIRCd -- Internet Relay Chat Daemon # # Copyright (C) 2014-2017 Peter Powell <petpow@saberuk.com> # # This file is part of InspIRCd. InspIRCd is free software: you can # redistribute it and/or modify it under the terms of the GNU General Public # License as published by the Free Software Foundation, version 2. # # This program is distributed in the hope that it will be useful, but WITHOUT # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS # FOR A PARTICULAR PURPOSE. See the GNU General Public License for more # details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see <http://www.gnu.org/licenses/>. # package make::console; BEGIN { require 5.10.0; } use feature ':5.10'; use strict; use warnings FATAL => qw(all); use Class::Struct qw(struct); use Exporter qw(import); use File::Path qw(mkpath); use File::Spec::Functions qw(rel2abs); our @EXPORT = qw(command execute_command print_format print_error print_warning prompt_bool prompt_dir prompt_string); my %FORMAT_CODES = ( DEFAULT => "\e[0m", BOLD => "\e[1m", UNDERLINE => "\e[4m", RED => "\e[1;31m", GREEN => "\e[1;32m", YELLOW => "\e[1;33m", BLUE => "\e[1;34m" ); my %commands; struct 'command' => { 'callback' => '$', 'description' => '$', }; sub __console_format($$) { my ($name, $data) = @_; return $data unless -t STDOUT; return $FORMAT_CODES{uc $name} . $data . $FORMAT_CODES{DEFAULT}; } sub print_format($;$) { my $message = shift; my $stream = shift // *STDOUT; while ($message =~ /(<\|(\S+)\s(.*?)\|>)/) { my $formatted = __console_format $2, $3; $message =~ s/\Q$1\E/$formatted/; } print { $stream } $message; } sub print_error { print_format "<|RED Error:|> ", *STDERR; for my $line (@_) { print_format "$line\n", *STDERR; } exit 1; } sub print_warning { print_format "<|YELLOW Warning:|> ", *STDERR; for my $line (@_) { print_format "$line\n", *STDERR; } } sub prompt_bool($$$) { my ($interactive, $question, $default) = @_; while (1) { my $answer = prompt_string($interactive, $question, $default ? 'yes' : 'no'); return 1 if $answer =~ /^y(?:es)?$/i; return 0 if $answer =~ /^no?$/i; print_warning "\"$answer\" is not \"yes\" or \"no\". Please try again.\n"; } } sub prompt_dir($$$;$) { my ($interactive, $question, $default, $create_now) = @_; my ($answer, $create); do { $answer = rel2abs(prompt_string($interactive, $question, $default)); $create = prompt_bool($interactive && !-d $answer, "$answer does not exist. Create it?", 'y'); if ($create && $create_now) { unless (create_directory $answer, 0750) { print_warning "unable to create $answer: $!\n"; $create = 0; } } } while (!$create); return $answer; } sub prompt_string($$$) { my ($interactive, $question, $default) = @_; return $default unless $interactive; print_format "$question\n"; print_format "[<|GREEN $default|>] => "; chomp(my $answer = <STDIN>); say ''; return $answer ? $answer : $default; } sub command($$$) { my ($name, $description, $callback) = @_; $commands{$name} = command->new; $commands{$name}->callback($callback); $commands{$name}->description($description); } sub command_alias($$) { my ($source, $target) = @_; command $source, undef, sub(@) { execute_command $target, @_; }; } sub execute_command(@) { my $command = defined $_[0] ? lc shift : 'help'; if ($command eq 'help') { print_format "<|GREEN Usage:|> $0 <<|UNDERLINE COMMAND|>> [<|UNDERLINE OPTIONS...|>]\n\n"; print_format "<|GREEN Commands:|>\n"; for my $key (sort keys %commands) { next unless defined $commands{$key}->description; my $name = sprintf "%-15s", $key; my $description = $commands{$key}->description; print_format " <|BOLD $name|> # $description\n"; } exit 0; } elsif (!$commands{$command}) { print_error "no command called <|BOLD $command|> exists!", "See <|BOLD $0 help|> for a list of commands."; } else { return $commands{$command}->callback->(@_); } } 1; �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/make/directive.pm��������������������������������������������������������������������0000664�0000000�0000000�00000024440�13554550454�0016600�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������# # InspIRCd -- Internet Relay Chat Daemon # # Copyright (C) 2016 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/>. # package make::directive; BEGIN { require 5.10.0; } use feature ':5.10'; use strict; use warnings FATAL => qw(all); use File::Basename qw(basename dirname); use File::Spec::Functions qw(catdir); use Exporter qw(import); use make::configure; use make::console; use constant DIRECTIVE_ERROR_PIPE => $ENV{INSPIRCD_VERBOSE} ? '' : '2>/dev/null'; use constant VENDOR_DIRECTORY => catdir(dirname(dirname(__FILE__)), 'vendor'); our @EXPORT = qw(get_directive execute_functions); sub get_directive($$;$) { my ($file, $property, $default) = @_; open(my $fh, $file) or return $default; my $value = ''; while (<$fh>) { if ($_ =~ /^\/\* \$(\S+): (.+) \*\/$/ || $_ =~ /^\/\/\/ \$(\S+): (.+)/) { next unless $1 eq $property; $value .= ' ' . execute_functions($file, $1, $2); } } close $fh; # Strip all extraneous whitespace. $value =~ s/^\s+|\s+$//g; return $value || $default; } sub execute_functions($$$) { my ($file, $name, $line) = @_; # NOTE: we have to use 'our' instead of 'my' here because of a Perl bug. for (our @parameters = (); $line =~ /([a-z_]+)\((?:\s*"([^"]*)(?{push @parameters, $2})"\s*)*\)/; undef @parameters) { my $sub = make::directive->can("__function_$1"); print_error "unknown $name directive '$1' in $file!" unless $sub; # Call the subroutine and replace the function. my $result = $sub->($file, @parameters); if (defined $result) { $line = $` . $result . $'; next; } # If the subroutine returns undef then it is a sign that we should # disregard the rest of the line and stop processing it. $line = $`; } return $line; } sub __environment { my ($prefix, $suffix) = @_; $suffix =~ s/[-.]/_/g; $suffix =~ s/[^A-Za-z0-9_]//g; return $prefix . uc $suffix; } sub __module { my $file = shift; my $name = basename $file, '.cpp'; $name =~ s/^m_//; return $name; } sub __error { my ($file, @message) = @_; push @message, ''; # If we have package details then suggest to the user that they check # that they have the packages installed.= my $dependencies = get_directive($file, 'PackageInfo'); if (defined $dependencies) { my @packages = sort grep { /^\S+$/ } split /\s/, $dependencies; push @message, 'You should make sure you have the following packages installed:'; for (@packages) { push @message, " * $_"; } } else { push @message, 'You should make sure that you have all of the required dependencies'; push @message, 'for this module installed.'; } push @message, ''; # If we have author information then tell the user to report the bug # to them. Otherwise, assume it is a bundled module and tell the user # to report it to the InspIRCd issue tracker. my $author = get_directive($file, 'ModAuthor'); if (defined $author) { push @message, 'If you believe this error to be a bug then you can try to contact the'; push @message, 'author of this module:'; my $author_mail = get_directive($file, 'ModAuthorMail'); if (defined $author_mail) { push @message, " * $author <$author_mail>"; } else { push @message, " * $author"; } } else { push @message, 'If you believe this error to be a bug then you can file a bug report'; push @message, 'at https://github.com/inspircd/inspircd/issues'; push @message, ''; push @message, 'You can also refer to the documentation page for this module at'; push @message, "https://docs.inspircd.org/3/modules/${\__module $file}"; } push @message, ''; push @message, 'If you would like help with fixing this problem then visit our IRC'; push @message, 'channel at irc.inspircd.org #InspIRCd for support.'; push @message, ''; print_error @message; } sub __function_error { my ($file, @messages) = @_; __error $file, @messages; } sub __function_execute { my ($file, $command, $environment, $defaults) = @_; # Try to execute the command... chomp(my $result = `$command ${\DIRECTIVE_ERROR_PIPE}`); unless ($?) { print_format "Execution of `<|GREEN $command|>` succeeded: <|BOLD $result|>\n"; return $result; } # If looking up with pkg-config fails then check the environment... if (defined $environment && $environment ne '') { $environment = __environment 'INSPIRCD_', $environment; if (defined $ENV{$environment}) { print_format "Execution of `<|GREEN $command|>` failed; using the environment: <|BOLD $ENV{$environment}|>\n"; return $ENV{$environment}; } } # If all else fails then look for the defaults.. if (defined $defaults) { print_format "Execution of `<|GREEN $command|>` failed; using the defaults: <|BOLD $defaults|>\n"; return $defaults; } # Executing the command failed and we don't have any defaults so give up. __error $file, "`<|GREEN $command|>` exited with a non-zero exit code!"; } sub __function_find_compiler_flags { my ($file, $name, $defaults) = @_; # Try to look up the compiler flags with pkg-config... chomp(my $flags = `pkg-config --cflags $name ${\DIRECTIVE_ERROR_PIPE}`); unless ($?) { print_format "Found the <|GREEN $name|> compiler flags for <|GREEN ${\__module $file}|> using pkg-config: <|BOLD $flags|>\n"; return $flags; } # If looking up with pkg-config fails then check the environment... my $key = __environment 'INSPIRCD_CXXFLAGS_', $name; if (defined $ENV{$key}) { print_format "Found the <|GREEN $name|> compiler flags for <|GREEN ${\__module $file}|> using the environment: <|BOLD $ENV{$key}|>\n"; return $ENV{$key}; } # If all else fails then look for the defaults.. if (defined $defaults) { print_format "Using the default <|GREEN $name|> compiler flags for <|GREEN ${\__module $file}|>: <|BOLD $defaults|>\n"; return $defaults; } # We can't find it via pkg-config, via the environment, or via the defaults so give up. __error $file, "unable to find the <|GREEN $name|> compiler flags for <|GREEN ${\__module $file}|>!"; } sub __function_find_linker_flags { my ($file, $name, $defaults) = @_; # Try to look up the linker flags with pkg-config... chomp(my $flags = `pkg-config --libs $name ${\DIRECTIVE_ERROR_PIPE}`); unless ($?) { print_format "Found the <|GREEN $name|> linker flags for <|GREEN ${\__module $file}|> using pkg-config: <|BOLD $flags|>\n"; return $flags; } # If looking up with pkg-config fails then check the environment... my $key = __environment 'INSPIRCD_CXXFLAGS_', $name; if (defined $ENV{$key}) { print_format "Found the <|GREEN $name|> linker flags for <|GREEN ${\__module $file}|> using the environment: <|BOLD $ENV{$key}|>\n"; return $ENV{$key}; } # If all else fails then look for the defaults.. if (defined $defaults) { print_format "Using the default <|GREEN $name|> linker flags for <|GREEN ${\__module $file}|>: <|BOLD $defaults|>\n"; return $defaults; } # We can't find it via pkg-config, via the environment, or via the defaults so give up. __error $file, "unable to find the <|GREEN $name|> linker flags for <|GREEN ${\__module $file}|>!"; } sub __function_require_compiler { my ($file, $name, $minimum, $maximum) = @_; # Look up information about the compiler. return undef unless $ENV{CXX}; my %compiler = get_compiler_info($ENV{CXX}); # Check whether the current compiler is suitable. return undef unless $compiler{NAME} eq $name; return undef if defined $minimum && $compiler{VERSION} < $minimum; return undef if defined $maximum && $compiler{VERSION} > $maximum; # Requirement directives don't change anything directly. return ""; } sub __function_require_system { my ($file, $name, $minimum, $maximum) = @_; my ($system, $version); # Linux is special and can be compared by distribution names. if ($^O eq 'linux' && $name ne 'linux') { chomp($system = lc `lsb_release --id --short 2>/dev/null`); chomp($version = lc `lsb_release --release --short 2>/dev/null`); } # Gather information on the system if we don't have it already. chomp($system ||= lc `uname -s 2>/dev/null`); chomp($version ||= lc `uname -r 2>/dev/null`); # We only care about the important bit of the version number so trim the rest. $version =~ s/^(\d+\.\d+).+/$1/; # Check whether the current system is suitable. return undef if $name ne $system; return undef if defined $minimum && $version < $minimum; return undef if defined $maximum && $version > $maximum; # Requirement directives don't change anything directly. return ""; } sub __function_require_version { my ($file, $name, $minimum, $maximum) = @_; # If pkg-config isn't installed then we can't do anything here. if (system "pkg-config --exists $name ${\DIRECTIVE_ERROR_PIPE}") { print_warning "unable to look up the version of <|GREEN $name|> using pkg-config!"; return undef; } # Check with pkg-config whether we have the required version. return undef if defined $minimum && system "pkg-config --atleast-version $minimum $name"; return undef if defined $maximum && system "pkg-config --max-version $maximum $name"; # Requirement directives don't change anything directly. return ""; } sub __function_vendor_directory { my ($file, $name) = @_; # Try to look the directory up in the environment... my $key = __environment 'INSPIRCD_VENDOR_', $name; if (defined $ENV{$key}) { print_format "Found the <|GREEN $name|> vendor directory for <|GREEN ${\__module $file}|> using the environment: <|BOLD $ENV{$key}|>\n"; return $ENV{$key}; } my $directory = catdir(VENDOR_DIRECTORY, $name); if (-d $directory) { print_format "Using the default <|GREEN $name|> vendor directory for <|GREEN ${\__module $file}|>: <|BOLD $directory|>\n"; return $directory; } # We can't find it via the environment or via the filesystem so give up. __error $file, "unable to find the <|GREEN $name|> vendor directory for <|GREEN ${\__module $file}|>!"; } sub __function_warning { my ($file, @messages) = @_; print_warning @messages; } 1; ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/make/template/�����������������������������������������������������������������������0000775�0000000�0000000�00000000000�13554550454�0016073�5����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/make/template/bsd.mk�����������������������������������������������������������������0000664�0000000�0000000�00000002525�13554550454�0017200�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������%platform darwin %platform freebsd %platform netbsd %platform openbsd %target Makefile # # InspIRCd -- Internet Relay Chat Daemon # # Copyright (C) 2017 Peter Powell <petpow@saberuk.com> # # This file is part of InspIRCd. InspIRCd is free software: you can # redistribute it and/or modify it under the terms of the GNU General Public # License as published by the Free Software Foundation, version 2. # # This program is distributed in the hope that it will be useful, but WITHOUT # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS # FOR A PARTICULAR PURPOSE. See the GNU General Public License for more # details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see <http://www.gnu.org/licenses/>. # # This file will be installed as `Makefile` on BSD derivatives. When a user runs # BSD Make it will be picked up as the default makefile even on systems like # OpenBSD which have removed BSDMakefile support. If they run GNU Make then it # will ignore this file and run GNUmakefile instead. all clean configureclean debug deinstall distclean help install: @echo "InspIRCd no longer supports BSD Make. You should install GNU Make instead." @echo "If this is problematic for you then please contact us via our IRC channel" @echo "at irc.inspircd.org #InspIRCd." @exit 1 ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/make/template/config.h���������������������������������������������������������������0000664�0000000�0000000�00000004160�13554550454�0017512�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * InspIRCd -- Internet Relay Chat Daemon * * Copyright (C) 2014 Peter Powell <petpow@saberuk.com> * * This file is part of InspIRCd. InspIRCd is free software: you can * redistribute it and/or modify it under the terms of the GNU General Public * License as published by the Free Software Foundation, version 2. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once /*** The branch version that is shown to unprivileged users. */ #define INSPIRCD_BRANCH "InspIRCd-@VERSION_MAJOR@" /*** The full version that is shown to privileged users. */ #define INSPIRCD_VERSION "InspIRCd-@VERSION_FULL@" /*** Determines whether this version of InspIRCd is older than the requested version. */ #define INSPIRCD_VERSION_BEFORE(MAJOR, MINOR) (((@VERSION_MAJOR@ << 8) | @VERSION_MINOR@) < ((MAJOR << 8) | (MINOR))) /*** Determines whether this version of InspIRCd is equal to or newer than the requested version. */ #define INSPIRCD_VERSION_SINCE(MAJOR, MINOR) (((@VERSION_MAJOR@ << 16) | @VERSION_MINOR@) >= ((MAJOR << 8) | (MINOR))) /*** The default location that config files are stored in. */ #define INSPIRCD_CONFIG_PATH "@CONFIG_DIR@" /*** The default location that data files are stored in. */ #define INSPIRCD_DATA_PATH "@DATA_DIR@" /*** The default location that log files are stored in. */ #define INSPIRCD_LOG_PATH "@LOG_DIR@" /*** The default location that module files are stored in. */ #define INSPIRCD_MODULE_PATH "@MODULE_DIR@" #ifndef _WIN32 %target include/config.h /*** Whether the arc4random_buf() function was available at compile time. */ %define HAS_ARC4RANDOM_BUF /*** Whether the clock_gettime() function was available at compile time. */ %define HAS_CLOCK_GETTIME /*** Whether the eventfd() function was available at compile time. */ %define HAS_EVENTFD #endif ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/make/template/inspircd���������������������������������������������������������������0000664�0000000�0000000�00000032352�13554550454�0017636�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������%mode 0750 #!/usr/bin/env perl # # InspIRCd -- Internet Relay Chat Daemon # # 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 # 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/>. # # InspIRCd Start up the InspIRCd Internet Relay Chat Daemon # # chkconfig: 2345 55 25 # description: InspIRCd -- Internet Relay Chat Daemon # # processname: inspircd use strict; use POSIX; use Fcntl; # From http://refspecs.linuxbase.org/LSB_4.1.0/LSB-Core-generic/LSB-Core-generic/iniscrptact.html use constant { STATUS_EXIT_SUCCESS => 0, STATUS_EXIT_DEAD_WITH_PIDFILE => 1, STATUS_EXIT_DEAD_WITH_LOCKFILE => 2, STATUS_EXIT_NOT_RUNNING => 3, STATUS_EXIT_UNKNOWN => 4, GENERIC_EXIT_SUCCESS => 0, GENERIC_EXIT_UNSPECIFIED => 1, GENERIC_EXIT_INVALID_ARGUMENTS => 2, GENERIC_EXIT_UNIMPLEMENTED => 3, GENERIC_EXIT_INSUFFICIENT_PRIVILEGE => 4, GENERIC_EXIT_NOT_INSTALLED => 5, GENERIC_EXIT_NOT_CONFIGURED => 6, GENERIC_EXIT_NOT_RUNNING => 7 }; my $scriptpath = "@SCRIPT_DIR@"; my $basepath = "@BASE_DIR@"; my $confpath = "@CONFIG_DIR@"; my $binpath = "@BINARY_DIR@"; my $runpath = "@BASE_DIR@"; my $datadir = "@DATA_DIR@"; my $valgrindlogpath = "$basepath/valgrindlogs"; my $executable = "inspircd"; my $version = "@VERSION_FULL@"; my $uid = "@UID@"; my @gdbargs = ( '--eval-command', 'handle SIGPIPE pass nostop noprint', '--eval-command', 'handle SIGHUP pass nostop noprint', '--eval-command', 'run', '--args', "$binpath/$executable", qw(--nofork --nolog --debug) ); sub expand_fragment($$) { my ($base, $fragment) = @_; if ($fragment =~ /^\//) { return $fragment; } else { return "$base/$fragment"; } } if (!(grep { $_ eq '--runasroot' } @ARGV) && ($< == 0 || $> == 0)) { if ($uid !~ /^\d+$/) { # Named UID, look it up $uid = getpwnam $uid; } if (!$uid) { die "Cannot find a valid UID to change to"; } # drop root if we were configured with an ircd UID $< = $uid; $> = $uid; if ($< == 0 || $> == 0) { die "Could not drop root: $!"; } } our($pid,$pidfile); # Lets see what they want to do.. Set the variable (Cause i'm a lazy coder) my $arg = shift(@ARGV); my $conf; for my $a (@ARGV) { if ($a =~ m/^--config=(.*)$/) { $conf = $1; last; } } if (!defined $conf) { $conf = expand_fragment $confpath, "inspircd.conf"; push @ARGV, '--config='.$conf; } getpidfile($conf); # System for naming script command subs: # cmd_<name> - Normal command for use by users. # dev_<name> - Developer commands. # hid_<name> - Hidden commands (ie Cheese-Sandwich) # Ideally command subs shouldn't return. my $subname = $arg; $subname =~ s/-/_/g; my $sub = main->can("cmd_$subname") || main->can("dev_$subname") || main->can("hid_$subname"); if (!defined($sub)) { print STDERR "Invalid command or none given.\n"; cmd_help(); exit GENERIC_EXIT_UNIMPLEMENTED; } else { exit $sub->(@ARGV); # Error code passed through return value } sub cmd_help() { my @subs = grep { $_ =~ m/^(cmd|dev)_/ && defined(main->can($_)) } keys(%::); my @cmds = grep /^cmd_/, @subs; my @devs = grep /^dev_/, @subs; local $_; $_ =~ s/^(cmd|dev)_// foreach (@cmds, @devs); $_ =~ s/_/-/g foreach (@cmds, @devs); print STDERR "Usage: ./inspircd (" . join("|", @cmds) . ")\n"; print STDERR "Developer arguments: (" . join("|", @devs) . ")\n"; exit GENERIC_EXIT_SUCCESS; } sub cmd_status() { if (getstatus() == 1) { my $pid = getprocessid(); print "InspIRCd is running (PID: $pid)\n"; exit STATUS_EXIT_SUCCESS; } else { print "InspIRCd is not running. (Or PID File not found)\n"; exit STATUS_EXIT_NOT_RUNNING; } } sub cmd_rehash() { if (getstatus() == 1) { my $pid = getprocessid(); system("kill -HUP $pid >/dev/null 2>&1"); print "InspIRCd rehashed (pid: $pid).\n"; exit GENERIC_EXIT_SUCCESS; } else { print "InspIRCd is not running. (Or PID File not found)\n"; exit GENERIC_EXIT_NOT_RUNNING; } } sub cmd_cron() { if (getstatus() == 0) { goto &cmd_start(@_); } exit GENERIC_EXIT_UNSPECIFIED; } sub cmd_version() { print "InspIRCd version: $version\n"; exit GENERIC_EXIT_SUCCESS; } sub cmd_restart(@) { cmd_stop(); unlink($pidfile) if (-e $pidfile); goto &cmd_start(@_); } sub hid_cheese_sandwich() { print "Creating Cheese Sandwich..\n"; print "Done.\n"; exit GENERIC_EXIT_SUCCESS; } sub cmd_start(@) { # Check to see its not 'running' already. if (getstatus() == 1) { print "InspIRCd is already running.\n"; exit GENERIC_EXIT_SUCCESS; } # If we are still alive here.. Try starting the IRCd.. chdir $runpath; print "$binpath/$executable doesn't exist\n" and return 0 unless(-e "$binpath/$executable"); print "$binpath/$executable is not executable\n" and return 0 unless(-f "$binpath/$executable" && -x "$binpath/$executable"); exec "$binpath/$executable", @_; die "Failed to start IRCd: $!\n"; } sub dev_debug(@) { # Check to see its not 'running' already. if (getstatus() == 1) { print "InspIRCd is already running.\n"; return 0; } chdir $runpath; print "$binpath/$executable doesn't exist\n" and return 0 unless(-e "$binpath/$executable"); print "$binpath/$executable is not executable\n" and return 0 unless(-f "$binpath/$executable" && -x "$binpath/$executable"); # Check we have gdb checkgdb(); # If we are still alive here.. Try starting the IRCd.. exec 'gdb', @gdbargs, @_; die "Failed to start GDB: $!\n"; } sub dev_screendebug(@) { # Check to see its not 'running' already. if (getstatus() == 1) { print "InspIRCd is already running.\n"; return 0; } chdir $runpath; print "$binpath/$executable doesn't exist\n" and return 0 unless(-e "$binpath/$executable"); #Check we have gdb checkgdb(); checkscreen(); # If we are still alive here.. Try starting the IRCd.. print "Starting InspIRCd in `screen`, type `screen -r` when the ircd crashes to view the gdb output and get a backtrace.\n"; print "Once you're inside the screen session press ^C + d to re-detach from the session\n"; exec qw(screen -m -d gdb), @gdbargs, @_; die "Failed to start screen: $!\n"; } sub dev_valdebug(@) { # Check to see its not 'running' already. if (getstatus() == 1) { print "InspIRCd is already running.\n"; return 0; } chdir $runpath; print "$binpath/$executable doesn't exist\n" and return 0 unless(-e "$binpath/$executable"); print "$binpath/$executable is not executable\n" and return 0 unless(-f "$binpath/$executable" && -x "$binpath/$executable"); # Check we have valgrind and gdb checkvalgrind(); checkgdb(); # If we are still alive here.. Try starting the IRCd.. # May want to do something with these args at some point: --suppressions=.inspircd.sup --gen-suppressions=yes # Could be useful when we want to stop it complaining about things we're sure aren't issues. exec qw(valgrind -v --tool=memcheck --leak-check=yes --db-attach=yes --num-callers=30), "$binpath/$executable", qw(--nofork --debug --nolog), @_; die "Failed to start valgrind: $!\n"; } sub dev_valdebug_unattended(@) { # NOTE: To make sure valgrind generates coredumps, set soft core limit in /etc/security/limits.conf to unlimited # Check to see its not 'running' already. if (getstatus() == 1) { print "InspIRCd is already running.\n"; return 0; } chdir $runpath; print "$binpath/$executable doesn't exist\n" and return 0 unless(-e "$binpath/$executable"); print "$binpath/$executable is not executable\n" and return 0 unless(-f "$binpath/$executable" && -x "$binpath/$executable"); # Check we have valgrind and gdb checkvalgrind(); checkgdb(); # If we are still alive here.. Try starting the IRCd.. # # NOTE: Saving the debug log (redirected stdout), while useful, is a potential security risk AND one hell of a spacehog. DO NOT SAVE THIS WHERE EVERYONE HAS ACCESS! # Redirect stdout to /dev/null if you're worried about the security. # my $pid = fork; if ($pid == 0) { POSIX::setsid(); -d $valgrindlogpath or mkdir $valgrindlogpath or die "Cannot create $valgrindlogpath: $!\n"; -e "$binpath/valgrind.sup" or do { open my $f, '>', "$binpath/valgrind.sup"; }; my $suffix = strftime("%Y%m%d-%H%M%S", localtime(time)) . ".$$"; open STDIN, '<', '/dev/null' or die "Can't redirect STDIN to /dev/null: $!\n"; sysopen STDOUT, "$valgrindlogpath/out.$suffix", O_WRONLY | O_CREAT | O_NOCTTY | O_APPEND, 0600 or die "Can't open $valgrindlogpath/out.$suffix: $!\n"; sysopen STDERR, "$valgrindlogpath/valdebug.$suffix", O_WRONLY | O_CREAT | O_NOCTTY | O_APPEND, 0666 or die "Can't open $valgrindlogpath/valdebug.$suffix: $!\n"; # May want to do something with these args at some point: --suppressions=.inspircd.sup --gen-suppressions=yes # Could be useful when we want to stop it complaining about things we're sure aren't issues. exec qw(valgrind -v --tool=memcheck --leak-check=full --show-reachable=yes --num-callers=30 --track-fds=yes), "--suppressions=$binpath/valgrind.sup", qw(--gen-suppressions=all), qw(--leak-resolution=med --time-stamp=yes --log-fd=2 --), "$binpath/$executable", qw(--nofork --debug --nolog), @_; die "Can't execute valgrind: $!\n"; } } sub dev_screenvaldebug(@) { # Check to see its not 'running' already. if (getstatus() == 1) { print "InspIRCd is already running.\n"; return 0; } chdir $runpath; print "$binpath/$executable doesn't exist\n" and return 0 unless(-e "$binpath/$executable"); print "$binpath/$executable is not executable\n" and return 0 unless(-f "$binpath/$executable" && -x "$binpath/$executable"); #Check we have gdb checkvalgrind(); checkgdb(); checkscreen(); # If we are still alive here.. Try starting the IRCd.. print "Starting InspIRCd in `screen`, type `screen -r` when the ircd crashes to view the valgrind and gdb output and get a backtrace.\n"; print "Once you're inside the screen session press ^C + d to re-detach from the session\n"; exec qw(screen -m -d valgrind -v --tool=memcheck --leak-check=yes --db-attach=yes --num-callers=30), "$binpath/$executable", qw(--nofork --debug --nolog), @_; die "Failed to start screen: $!\n"; } sub cmd_stop() { if (getstatus() == 0) { print "InspIRCd is not running. (Or PID File not found)\n"; return GENERIC_EXIT_SUCCESS; } # Get to here, we have something to kill. my $pid = getprocessid(); print "Stopping InspIRCd (pid: $pid)...\n"; my $maxwait = (`ps -o command $pid 2>/dev/null` =~ /valgrind/i) ? 90 : 15; kill TERM => $pid or die "Cannot terminate IRCd: $!\n"; for (1..$maxwait) { sleep 1; if (getstatus() == 0) { print "InspIRCd Stopped.\n"; return GENERIC_EXIT_SUCCESS; } } print "InspIRCd not dying quietly -- forcing kill\n"; kill KILL => $pid; return GENERIC_EXIT_SUCCESS; } ### # Generic Helper Functions. ### # GetPidfile Version 2 - Now With Include Support.. # I beg for months for include support in insp, then.. # when it is added, it comes around and BITES ME IN THE ASS, # because i then have to code support into this script.. Evil. # Craig got bitten in the ass again -- # in 1.1 beta the include file is manditory, therefore # if we cant find it, default to %conf%/inspircd.pid. # Note, this also contains a fix for when the pid file is # defined, but defined in a comment (line starts with #) # -- Brain my %filesparsed; sub getpidfile { my ($file) = @_; # Before we start, do we have a PID already? (Should never occur) if ($pid ne "") { return; } # Expand any relative paths. $file = expand_fragment $confpath, $file; # Have we checked this file before? return if $filesparsed{$file}; $filesparsed{$file} = 1; # Open the File.. open INFILE, '<', $file or return; # Grab entire file contents.. my(@lines) = <INFILE>; # Close the file close INFILE; # remove trailing spaces chomp(@lines); for my $i (@lines) { # clean it up $i =~ s/[^=]+=\s(.*)/\1/; # Does this file have a pid? if (($i =~ /<pid file=\"(\S+)\">/i) && ($i !~ /^#/)) { # Set the PID file and return. $pidfile = expand_fragment $datadir, $1; return; } } # If we get here, NO PID FILE! -- Check for includes for my $i (@lines) { $i =~ s/[^=]+=\s(.*)/\1/; if (($i =~ s/\<include file=\"(.+?)\"\>//i) && ($i !~ /^#/)) { # Decend into that file, and check for PIDs.. (that sounds like an STD ;/) getpidfile($1); # Was a PID found? if ($pidfile ne "") { # Yes, Return. return; } } } # End of includes / No includes found. Using default. $pidfile = $datadir . "/inspircd.pid"; } sub getstatus { my $pid = getprocessid(); return 0 if $pid == 0; return kill 0, $pid; } sub getprocessid { my $pid = 0; open PIDFILE, '<', $pidfile or return 0; while(<PIDFILE>) { /^(\d+)$/ and $pid = $1; } close PIDFILE; return $pid; } sub checkvalgrind { unless(`valgrind --version`) { print "Couldn't start valgrind: $!\n"; exit GENERIC_EXIT_UNSPECIFIED; } } sub checkgdb { unless(`gdb --version`) { print "Couldn't start gdb: $!\n"; exit GENERIC_EXIT_UNSPECIFIED; } } sub checkscreen { unless(`screen --version`) { print "Couldn't start screen: $!\n"; exit GENERIC_EXIT_UNSPECIFIED; } } ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/make/template/inspircd-genssl.1������������������������������������������������������0000664�0000000�0000000�00000002627�13554550454�0021270�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������.\" .\" InspIRCd -- Internet Relay Chat Daemon .\" .\" Copyright (C) 2014 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/>. .\" .TH "InspIRCd" "1" "June 2014" "InspIRCd @VERSION_FULL@" "InspIRCd Manual" .SH "NAME" \t\fBInspIRCd\fR - \fIthe\fR stable, high-performance and modular Internet Relay Chat Daemon .BR .SH "SYNOPSIS" \t\fBinspircd-genssl\fR [ auto | gnutls | openssl ] .SH "OPTIONS" .TP .B "auto" .br Looks for both GnuTLS and OpenSSL and uses the first one which is available for certificate generation. .TP .B "gnutls" .br Generates certificates using GnuTLS. .TP .br .B "openssl" Generates certificates using OpenSSL. .SH "SUPPORT" IRC support for InspIRCd can be found at ircs://irc.inspircd.org/inspircd. Bug reports and feature requests can be filed at https://github.com/inspircd/inspircd/issues. ���������������������������������������������������������������������������������������������������������inspircd-3.4.0/make/template/inspircd.1�������������������������������������������������������������0000664�0000000�0000000�00000005437�13554550454�0020001�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������.\" .\" InspIRCd -- Internet Relay Chat Daemon .\" .\" Copyright (C) 2014 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/>. .\" .TH "InspIRCd" "1" "June 2014" "InspIRCd @VERSION_FULL@" "InspIRCd Manual" .SH "NAME" \t\fBInspIRCd\fR - \fIthe\fR stable, high-performance and modular Internet Relay Chat Daemon .BR .SH "SYNOPSIS" \t\fBinspircd\fR [--config <file>] [--debug] [--nofork] [--nolog] [--nopid] [--runasroot] [--version] .SH "OPTIONS" .TP .B "--config <file>" .br Sets the path to the main configuration file. Defaults to \fI@CONFIG_DIR@/inspircd.conf\fR. .TP .B "--debug" .br Log verbosely to the standard output stream. .TP .B "--nofork" .br Don't fork into the background after starting up. .TP .B "--nolog" .br Don't write to log files. .TP .B "--nopid" .br Don't write to the PID file. .TP .B "--runasroot" .br Allow the server to start as root (not recommended). .TP .B "--version" .br Displays the InspIRCd version and exits. .SH "EXIT STATUS" .TP .B "0 (EXIT_STATUS_NOERROR)" .br The server exited cleanly. .TP .B "1 (EXIT_STATUS_DIE)" .br The server exited because the DIE command was executed. .TP .B "2 (EXIT_STATUS_CONFIG)" .br The server exited because of a configuration file error. .TP .B "3 (EXIT_STATUS_LOG)" .br The server exited because of a log file error. .TP .B "4 (EXIT_STATUS_FORK)" .br The server exited because it was unable to fork into the background. .TP .B "5 (EXIT_STATUS_ARGV)" .br The server exited because an invalid argument was passed to it on the command line. .TP .B "6 (EXIT_STATUS_PID)" .br The server exited because it was unable to write to the PID file. .TP .B "7 (EXIT_STATUS_SOCKETENGINE)" .br The server exited because it was unable to initialize the @SOCKETENGINE@ socket engine. .TP .B "8 (EXIT_STATUS_ROOT)" .br The server exited because the user tried to start as root without \fI--runasroot\fR. .TP .B "9 (EXIT_STATUS_MODULE)" .br The server exited because it was unable to load a module on first run. .TP .B "10 (EXIT_STATUS_SIGTERM)" .br The server exited because it received SIGTERM. .SH "SUPPORT" IRC support for InspIRCd can be found at ircs://irc.inspircd.org/inspircd. Bug reports and feature requests can be filed at https://github.com/inspircd/inspircd/issues. ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/make/template/inspircd.service�������������������������������������������������������0000664�0000000�0000000�00000002066�13554550454�0021274�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������%platform linux # # InspIRCd -- Internet Relay Chat Daemon # # Copyright (C) 2014 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/>. # [Unit] After=network.target Description=InspIRCd - Internet Relay Chat Daemon Requires=network.target [Service] ExecReload=@SCRIPT_DIR@/inspircd rehash ExecStart=@SCRIPT_DIR@/inspircd start ExecStop=@SCRIPT_DIR@/inspircd stop PIDFile=@DATA_DIR@/inspircd.pid Restart=on-failure Type=forking User=@USER@ Group=@GROUP@ [Install] WantedBy=multi-user.target ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/make/template/main.mk����������������������������������������������������������������0000664�0000000�0000000�00000024255�13554550454�0017360�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������%target GNUmakefile # # InspIRCd -- Internet Relay Chat Daemon # # 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 # 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/>. # # # InspIRCd Main Makefile # # This file is automagically generated by configure, from # make/template/main.mk. Any changes made to the generated # files will go away whenever it is regenerated! # # Please do not edit unless you know what you're doing. # CXX = @CXX@ COMPILER = @COMPILER_NAME@ SYSTEM = @SYSTEM_NAME@ BUILDPATH ?= $(dir $(realpath $(firstword $(MAKEFILE_LIST))))/build/@COMPILER_NAME@-@COMPILER_VERSION@ SOCKETENGINE = @SOCKETENGINE@ CORECXXFLAGS = -fPIC -fvisibility=hidden -fvisibility-inlines-hidden -pipe -Iinclude -Wall -Wextra -Wfatal-errors -Wno-unused-parameter -Wshadow LDLIBS = -lstdc++ CORELDFLAGS = -rdynamic -L. PICLDFLAGS = -fPIC -shared -rdynamic BASE = "$(DESTDIR)@BASE_DIR@" BINPATH = "$(DESTDIR)@BINARY_DIR@" CONPATH = "$(DESTDIR)@CONFIG_DIR@" DATPATH = "$(DESTDIR)@DATA_DIR@" EXAPATH = "$(DESTDIR)@EXAMPLE_DIR@" LOGPATH = "$(DESTDIR)@LOG_DIR@" MANPATH = "$(DESTDIR)@MANUAL_DIR@" MODPATH = "$(DESTDIR)@MODULE_DIR@" SCRPATH = "$(DESTDIR)@SCRIPT_DIR@" INSTALL ?= install INSTMODE_DIR ?= 0755 INSTMODE_BIN ?= 0755 INSTMODE_TXT ?= 0644 INSTMODE_PRV ?= 0640 ifneq ($(COMPILER), ICC) CORECXXFLAGS += -Woverloaded-virtual -Wshadow ifneq ($(SYSTEM), openbsd) CORECXXFLAGS += -pedantic -Wformat=2 -Wmissing-format-attribute -Wno-format-nonliteral endif endif ifneq ($(SYSTEM), darwin) LDLIBS += -pthread endif ifeq ($(SYSTEM), linux) LDLIBS += -ldl -lrt endif ifeq ($(SYSTEM), gnukfreebsd) LDLIBS += -ldl -lrt endif ifeq ($(SYSTEM), gnu) LDLIBS += -ldl -lrt endif ifeq ($(SYSTEM), solaris) LDLIBS += -lsocket -lnsl -lrt -lresolv endif ifeq ($(SYSTEM), darwin) LDLIBS += -ldl CORELDFLAGS = -dynamic -bind_at_load -L. PICLDFLAGS = -fPIC -shared -twolevel_namespace -undefined dynamic_lookup endif ifeq ($(SYSTEM), haiku) LDLIBS = -lnetwork -lstdc++ CORELDFLAGS = -L. PICLDFLAGS = -fPIC -shared endif ifndef INSPIRCD_DEBUG INSPIRCD_DEBUG=0 endif DBGOK=0 ifeq ($(INSPIRCD_DEBUG), 0) CORECXXFLAGS += -fno-rtti -O2 ifeq ($(COMPILER), GCC) CORECXXFLAGS += -g1 endif HEADER = std-header DBGOK=1 endif ifeq ($(INSPIRCD_DEBUG), 1) CORECXXFLAGS += -O0 -g3 -Werror -DINSPIRCD_ENABLE_RTTI HEADER = debug-header DBGOK=1 endif ifeq ($(INSPIRCD_DEBUG), 2) CORECXXFLAGS += -fno-rtti -O2 -g3 HEADER = debug-header DBGOK=1 endif ifeq ($(INSPIRCD_DEBUG), 3) CORECXXFLAGS += -fno-rtti -O0 -g0 -Werror HEADER = std-header DBGOK=1 endif FOOTER = finishmessage MAKEFLAGS += --no-print-directory SOURCEPATH = $(shell pwd) ifndef INSPIRCD_VERBOSE MAKEFLAGS += --silent endif # Append any flags set in the environment after the base flags so # that they can be overridden if necessary. CORECXXFLAGS += $(CPPFLAGS) $(CXXFLAGS) CORELDFLAGS += $(LDFLAGS) PICLDFLAGS += $(LDFLAGS) export BUILDPATH export CORECXXFLAGS export CORELDFLAGS export CXX export INSPIRCD_VERBOSE export LDLIBS export PICLDFLAGS export SOCKETENGINE export SOURCEPATH # Default target TARGET = all ifdef INSPIRCD_TARGET HEADER = mod-header FOOTER = mod-footer TARGET = $(INSPIRCD_TARGET) endif ifeq ($(DBGOK), 0) HEADER = unknown-debug-level endif all: $(FOOTER) target: $(HEADER) $(MAKEENV) perl make/calcdep.pl cd "$(BUILDPATH)"; $(MAKEENV) $(MAKE) -f real.mk $(TARGET) debug: @${MAKE} INSPIRCD_DEBUG=1 all debug-header: @echo "*************************************" @echo "* BUILDING WITH DEBUG SYMBOLS *" @echo "* *" @echo "* This will take a *long* time. *" @echo "* Please be aware that this build *" @echo "* will consume a very large amount *" @echo "* of disk space (~350MB), and may *" @echo "* run slower. Use the debug build *" @echo "* for module development or if you *" @echo "* are experiencing problems. *" @echo "* *" @echo "*************************************" mod-header: @echo 'Building specific targets:' mod-footer: target @echo 'To install, copy $(BUILDPATH)/$(TARGET) to $(MODPATH)' @echo 'Or, run "make install"' std-header: @echo "*************************************" @echo "* BUILDING INSPIRCD *" @echo "* *" @echo "* This will take a *long* time. *" @echo "* Why not read our docs at *" @echo "* https://docs.inspircd.org *" @echo "* while you wait for Make to run? *" @echo "*************************************" finishmessage: target @echo "" @echo "*************************************" @echo "* BUILD COMPLETE! *" @echo "* *" @echo "* To install InspIRCd, type: *" @echo "* 'make install' *" @echo "*************************************" install: target @-$(INSTALL) -d -g @GID@ -o @UID@ -m $(INSTMODE_DIR) $(BASE) @-$(INSTALL) -d -g @GID@ -o @UID@ -m $(INSTMODE_DIR) $(BINPATH) @-$(INSTALL) -d -g @GID@ -o @UID@ -m $(INSTMODE_DIR) $(CONPATH) @-$(INSTALL) -d -g @GID@ -o @UID@ -m $(INSTMODE_DIR) $(DATPATH) @-$(INSTALL) -d -g @GID@ -o @UID@ -m $(INSTMODE_DIR) $(EXAPATH)/providers @-$(INSTALL) -d -g @GID@ -o @UID@ -m $(INSTMODE_DIR) $(EXAPATH)/services @-$(INSTALL) -d -g @GID@ -o @UID@ -m $(INSTMODE_DIR) $(EXAPATH)/sql @-$(INSTALL) -d -g @GID@ -o @UID@ -m $(INSTMODE_DIR) $(LOGPATH) @-$(INSTALL) -d -g @GID@ -o @UID@ -m $(INSTMODE_DIR) $(MANPATH) @-$(INSTALL) -d -g @GID@ -o @UID@ -m $(INSTMODE_DIR) $(MODPATH) @-$(INSTALL) -d -g @GID@ -o @UID@ -m $(INSTMODE_DIR) $(SCRPATH) -$(INSTALL) -g @GID@ -o @UID@ -m $(INSTMODE_BIN) "$(BUILDPATH)/bin/inspircd" $(BINPATH) -$(INSTALL) -g @GID@ -o @UID@ -m $(INSTMODE_BIN) "$(BUILDPATH)/modules/"*.so $(MODPATH) -$(INSTALL) -g @GID@ -o @UID@ -m $(INSTMODE_BIN) @CONFIGURE_DIRECTORY@/inspircd $(SCRPATH) 2>/dev/null ifeq ($(SYSTEM), darwin) -$(INSTALL) -g @GID@ -o @UID@ -m $(INSTMODE_BIN) @CONFIGURE_DIRECTORY@/org.inspircd.plist $(SCRPATH) 2>/dev/null endif ifeq ($(SYSTEM), linux) -$(INSTALL) -g @GID@ -o @UID@ -m $(INSTMODE_TXT) @CONFIGURE_DIRECTORY@/inspircd.service $(SCRPATH) 2>/dev/null endif -$(INSTALL) -g @GID@ -o @UID@ -m $(INSTMODE_TXT) @CONFIGURE_DIRECTORY@/inspircd.1 $(MANPATH) 2>/dev/null -$(INSTALL) -g @GID@ -o @UID@ -m $(INSTMODE_TXT) @CONFIGURE_DIRECTORY@/inspircd-genssl.1 $(MANPATH) 2>/dev/null -$(INSTALL) -g @GID@ -o @UID@ -m $(INSTMODE_BIN) tools/genssl $(BINPATH)/inspircd-genssl 2>/dev/null -$(INSTALL) -g @GID@ -o @UID@ -m $(INSTMODE_TXT) docs/conf/*.example $(EXAPATH) -$(INSTALL) -g @GID@ -o @UID@ -m $(INSTMODE_TXT) docs/conf/providers/*.example $(EXAPATH)/providers -$(INSTALL) -g @GID@ -o @UID@ -m $(INSTMODE_TXT) docs/conf/services/*.example $(EXAPATH)/services -$(INSTALL) -g @GID@ -o @UID@ -m $(INSTMODE_TXT) docs/sql/*.sql $(EXAPATH)/sql -$(INSTALL) -g @GID@ -o @UID@ -m $(INSTMODE_PRV) *.pem $(CONPATH) 2>/dev/null @echo "" @echo "*************************************" @echo "* INSTALL COMPLETE! *" @echo "*************************************" @echo 'Paths:' @echo ' Base install:' $(BASE) @echo ' Configuration:' $(CONPATH) @echo ' Binaries:' $(BINPATH) @echo ' Modules:' $(MODPATH) @echo ' Data:' $(DATPATH) @echo 'To start the ircd, run:' $(SCRPATH)/inspircd start @echo 'Remember to create your config file:' $(CONPATH)/inspircd.conf @echo 'Examples are available at:' $(EXAPATH) GNUmakefile: make/template/main.mk src/version.sh configure @CONFIGURE_CACHE_FILE@ ./configure --update 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 @echo Completed. deinstall: -rm -f $(BINPATH)/inspircd -rm -rf $(EXAPATH) -rm -f $(MANPATH)/inspircd.1 -rm -f $(MANPATH)/inspircd-genssl.1 -rm -f $(MODPATH)/m_*.so -rm -f $(MODPATH)/core_*.so -rm -f $(SCRPATH)/inspircd.service -rm -f $(SCRPATH)/org.inspircd.plist configureclean: -rm -f Makefile rm -f GNUmakefile rm -f include/config.h rm -rf @CONFIGURE_DIRECTORY@ distclean: clean configureclean -rm -rf "$(SOURCEPATH)/run" find "$(SOURCEPATH)/src/modules" -type l | xargs rm -f help: @echo 'InspIRCd Makefile' @echo '' @echo 'Use: ${MAKE} [flags] [targets]' @echo '' @echo 'Flags:' @echo ' INSPIRCD_VERBOSE=1 Show the full command being executed instead of "BUILD: dns.cpp"' @echo ' INSPIRCD_DEBUG=1 Enable debug build, for module development or crash tracing' @echo ' INSPIRCD_DEBUG=2 Enable debug build with optimizations, for detailed backtraces' @echo ' INSPIRCD_DEBUG=3 Enable fast build with no optimisations or symbols, for Travis CI' @echo ' DESTDIR= Specify a destination root directory (for tarball creation)' @echo ' -j <N> Run a parallel build using N jobs' @echo '' @echo 'Targets:' @echo ' all Complete build of InspIRCd, without installing (default)' @echo ' install Build and install InspIRCd to the directory chosen in ./configure' @echo ' Currently installs to ${BASE}' @echo ' debug Compile a debug build. Equivalent to "make D=1 all"' @echo '' @echo ' INSPIRCD_TARGET=target Builds a user-specified target, such as "inspircd" or "core_dns"' @echo ' Multiple targets may be separated by a space' @echo '' @echo ' clean Cleans object files produced by the compile' @echo ' distclean Cleans all generated files (build, configure, run, etc)' @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 configureclean help ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/make/template/org.inspircd.plist�����������������������������������������������������0000664�0000000�0000000�00000001530�13554550454�0021550�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������%platform darwin <?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> <plist version="1.0"> <dict> <key>Iterations</key> <integer>3</integer> <key>KeepAlive</key> <true/> <key>Label</key> <string>org.inspircd</string> <key>LowPriorityIO</key> <true/> <key>Nice</key> <integer>1</integer> <key>Program</key> <string>@BINARY_DIR@/inspircd</string> <key>ProgramArguments</key> <array> <string>inspircd</string> <string>--nofork</string> </array> <key>ServiceIPC</key> <false/> <key>StandardOutPath</key> <string>@LOG_DIR@/launchd-stdout.log</string> <key>StandardErrorPath</key> <string>@LOG_DIR@/launchd-stderr.log</string> <key>UserName</key> <string>@USER@</string> <key>GroupName</key> <string>@GROUP@</string> </dict> </plist> ������������������������������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/make/test/���������������������������������������������������������������������������0000775�0000000�0000000�00000000000�13554550454�0015237�5����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/make/test/arc4random_buf.cpp���������������������������������������������������������0000664�0000000�0000000�00000001500�13554550454�0020625�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * InspIRCd -- Internet Relay Chat Daemon * * Copyright (C) 2018 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 <stdlib.h> int main() { char buffer[100]; arc4random_buf(buffer, sizeof(buffer)); return 0; } ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/make/test/clock_gettime.cpp����������������������������������������������������������0000664�0000000�0000000�00000001503�13554550454�0020553�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * InspIRCd -- Internet Relay Chat Daemon * * Copyright (C) 2013 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 <time.h> int main() { timespec time_spec; clock_gettime(CLOCK_REALTIME, &time_spec); return 0; } ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/make/test/compiler.cpp���������������������������������������������������������������0000664�0000000�0000000�00000002337�13554550454�0017562�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * InspIRCd -- Internet Relay Chat Daemon * * Copyright (C) 2016 Attila Molnar <attilamolnar@hush.com> * Copyright (C) 2014-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 <iostream> #if defined _LIBCPP_VERSION # include <array> # include <type_traits> # include <unordered_map> #else # include <tr1/array> # include <tr1/type_traits> # include <tr1/unordered_map> #endif #if defined __llvm__ && !defined __clang__ && __GNUC__ == 4 && __GNUC_MINOR__ == 2 && __GNUC_PATCHLEVEL__ == 1 # error "LLVM-GCC 4.2.1 has broken visibility support." #endif int main() { std::cout << "Hello, World!" << std::endl; return 0; } �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/make/test/compiler_info.cpp����������������������������������������������������������0000664�0000000�0000000�00000002732�13554550454�0020574�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * InspIRCd -- Internet Relay Chat Daemon * * Copyright (C) 2017 Peter Powell <petpow@saberuk.com> * * This file is part of InspIRCd. InspIRCd is free software: you can * redistribute it and/or modify it under the terms of the GNU General Public * License as published by the Free Software Foundation, version 2. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <iostream> #if defined __INTEL_COMPILER // Also defines __clang__ and __GNUC__ # define INSPIRCD_COMPILER_NAME "Intel" # define INSPIRCD_COMPILER_VERSION (__INTEL_COMPILER / 100) << '.' << (__INTEL_COMPILER % 100) #elif defined __clang__ // Also defines __GNUC__ # if defined __apple_build_version__ # define INSPIRCD_COMPILER_NAME "AppleClang" # else # define INSPIRCD_COMPILER_NAME "Clang" # endif # define INSPIRCD_COMPILER_VERSION __clang_major__ << '.' << __clang_minor__ #elif defined __GNUC__ # define INSPIRCD_COMPILER_NAME "GCC" # define INSPIRCD_COMPILER_VERSION __GNUC__ << '.' << __GNUC_MINOR__ #endif int main() { std::cout << "NAME " << INSPIRCD_COMPILER_NAME << std::endl << "VERSION " << INSPIRCD_COMPILER_VERSION << std::endl; return 0; } ��������������������������������������inspircd-3.4.0/make/test/eventfd.cpp����������������������������������������������������������������0000664�0000000�0000000�00000001674�13554550454�0017406�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * 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 * 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/eventfd.h> int main() { eventfd_t efd_data; int fd; fd = eventfd(0, EFD_NONBLOCK); eventfd_read(fd, &efd_data); return (fd < 0); } ��������������������������������������������������������������������inspircd-3.4.0/make/test/kqueue.cpp�����������������������������������������������������������������0000664�0000000�0000000�00000001477�13554550454�0017253�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * InspIRCd -- Internet Relay Chat Daemon * * Copyright (C) 2009 Daniel De Graaf <danieldg@inspircd.org> * * This file is part of InspIRCd. InspIRCd is free software: you can * redistribute it and/or modify it under the terms of the GNU General Public * License as published by the Free Software Foundation, version 2. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <sys/types.h> #include <sys/event.h> int main() { int fd = kqueue(); return (fd < 0); } �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/make/unit-cc.pl����������������������������������������������������������������������0000775�0000000�0000000�00000005157�13554550454�0016172�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������#!/usr/bin/env perl # # InspIRCd -- Internet Relay Chat Daemon # # 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 # 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/>. # BEGIN { push @INC, $ENV{SOURCEPATH}; require 5.10.0; } use strict; use warnings FATAL => qw(all); use File::Spec::Functions qw(abs2rel); use make::console; use make::directive; chdir $ENV{BUILDPATH}; my $type = shift; my $out = shift; if ($type eq 'core-ld') { do_core_link(@ARGV); } elsif ($type eq 'link-dir') { do_link_dir(@ARGV); } elsif ($type eq 'gen-o') { do_compile(1, 0, @ARGV); } elsif ($type eq 'gen-so') { do_compile(1, 1, @ARGV); } elsif ($type eq 'link-so') { do_compile(0, 1, @ARGV); } else { print STDERR "Unknown unit-cc subcommand $type!\n"; } exit 1; sub message($$$) { my ($type, $file, $command) = @_; if ($ENV{INSPIRCD_VERBOSE}) { print "$command\n"; } else { print_format "\t<|GREEN $type:|>\t\t$file\n"; } } sub rpath($) { my $message = shift; $message =~ s/-L(\S+)/-Wl,-rpath,$1 -L$1/g unless defined $ENV{INSPIRCD_DISABLE_RPATH}; return $message; } sub do_core_link { my $execstr = "$ENV{CXX} -o $out $ENV{CORELDFLAGS} @_ $ENV{LDLIBS}"; message 'LINK', $out, $execstr; exec $execstr; } sub do_link_dir { my ($dir, $link_flags) = (shift, ''); for my $file (<$dir/*.cpp>) { $link_flags .= rpath(get_directive($file, 'LinkerFlags', '')) . ' '; } my $execstr = "$ENV{CXX} -o $out $ENV{PICLDFLAGS} @_ $link_flags"; message 'LINK', $out, $execstr; exec $execstr; } sub do_compile { my ($do_compile, $do_link, $file) = @_; my $flags = ''; my $libs = ''; if ($do_compile) { $flags = $ENV{CORECXXFLAGS} . ' ' . get_directive($file, 'CompilerFlags', ''); if ($file =~ m#(?:^|/)((?:m|core)_[^/. ]+)(?:\.cpp|/.*\.cpp)$#) { $flags .= ' -DMODNAME=\\"'.$1.'\\"'; } } if ($do_link) { $flags = join ' ', $flags, $ENV{PICLDFLAGS}; $libs = rpath(get_directive($file, 'LinkerFlags', '')); } else { $flags .= ' -c'; } my $execstr = "$ENV{CXX} -o $out $flags $file $libs"; message 'BUILD', abs2rel($file, "$ENV{SOURCEPATH}/src"), $execstr; exec $execstr; } �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/modulemanager������������������������������������������������������������������������0000775�0000000�0000000�00000021513�13554550454�0016113�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������#!/usr/bin/env perl # # InspIRCd -- Internet Relay Chat Daemon # # Copyright (C) 2012-2017 Peter Powell <petpow@saberuk.com> # Copyright (C) 2008-2009 Robin Burchell <robin+git@viroteck.net> # # 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/>. # BEGIN { require 5.10.0; unless (eval "use LWP::Simple; 1") { die "Your system is missing the LWP::Simple Perl module!"; } unless (eval "use Crypt::SSLeay; 1" || eval "use IO::Socket::SSL; 1") { die "Your system is missing the Crypt::SSLeay or IO::Socket::SSL Perl modules!"; } } use feature ':5.10'; use strict; use warnings FATAL => qw(all); use File::Basename qw(basename); use FindBin qw($RealDir); use lib $RealDir; use make::common; use make::console; my %installed; # $installed{name} = $version my %modules; # $modules{$name}{$version} = { # url => URL of this version # depends => [ 'm_foo 1.2.0-1.3.0', ... ] # conflicts => [ ] # from => URL of source document # mask => Reason for not installing (INSECURE/DEPRECATED) # description => some string # } my %url_seen; sub parse_url; # retrieve and parse entries from sources.list sub parse_url { chomp(my $src = shift); return if $url_seen{$src}; $url_seen{$src}++; my $ua = LWP::UserAgent->new(ssl_opts => { verify_hostname => 0 }); my $response = $ua->get($src); unless ($response->is_success) { my $err = $response->message; die "Could not retrieve $src: $err"; } my $mod; for (split /\n+/, $response->content) { s/^\s+//; # ignore whitespace at start next if /^#/; if (/^module (\S+) (\S+) (\S+)/) { my($name, $ver, $url) = ($1,$2,$3); if ($modules{$name}{$ver}) { my $origsrc = $modules{$name}{$ver}{from}; warn "Overriding module $name $ver defined from $origsrc with one from $src"; } $mod = { from => $src, url => $url, depends => [], conflicts => [], }; $modules{$name}{$ver} = $mod; } elsif (/^depends (.*)/) { push @{$mod->{depends}}, $1; } elsif (/^conflicts (.*)/) { push @{$mod->{conflicts}}, $1; } elsif (/^description (.*)/) { $mod->{description} = $1; } elsif (/^mask (.*)/) { $mod->{mask} = $1; } elsif (/^source (\S+)/) { parse_url $1; } else { print "Unknown line in $src: $_\n"; } } } # hash of installed module versions from our mini-database, key (m_foobar) to version (00abacca..). my %mod_versions = read_config_file '.modulemanager'; # useless helper stub sub getmodversion { my ($file) = @_; return $mod_versions{$file}; } # read in external URL sources open SRC, 'sources.list' or die "Could not open sources.list: $!"; while (<SRC>) { next if /^\s*#/; parse_url($_); } close SRC; # determine core version my %version = get_version(); $installed{core} = "$version{MAJOR}.$version{MINOR}.$version{PATCH}"; for my $mod (keys %modules) { MODVER: for my $mver (keys %{$modules{$mod}}) { for my $dep (@{$modules{$mod}{$mver}{depends}}) { next unless $dep =~ /^core (.*)/; if (!ver_in_range($installed{core}, $1)) { delete $modules{$mod}{$mver}; next MODVER; } } } delete $modules{$mod} unless %{$modules{$mod}}; } $modules{core}{$installed{core}} = { url => 'NONE', depends => [], conflicts => [], from => 'local file', }; # set up core module list for my $modname (<src/modules/m_*.cpp>) { my $mod = basename($modname, '.cpp'); my $ver = getmodversion($mod) || '0.0'; $ver =~ s/\$Rev: (.*) \$/$1/; # for storing revision in SVN $installed{$mod} = $ver; next if $modules{$mod}{$ver}; $modules{$mod}{$ver} = { url => 'NONE', depends => [], conflicts => [], from => 'local file', }; } my %todo = %installed; sub ver_cmp { ($a,$b) = @_ if @_; if ($a !~ /^[0-9.]+$/ or $b !~ /^[0-9.]+$/) { # not a valid version number, don't try to sort return $a ne $b; } # else it's probably a numerical type version.. i.e. 1.0 my @a = split /\./, $a; my @b = split /\./, $b; push @a, 0 while $#a < $#b; push @b, ($_[2] || 0) while $#b < $#a; for my $i (0..$#a) { my $d = $a[$i] <=> $b[$i]; return $d if $d; } return 0; } sub ver_in_range { my($ver, $range) = @_; return 1 unless defined $range; my($l,$h) = ($range, $range); if ($range =~ /(.*)-(.*)/) { ($l,$h) = ($1,$2); } return 0 if $l && ver_cmp($ver, $l) < 0; return 0 if $h && ver_cmp($ver, $h, 9999) > 0; return 1; } sub find_mod_in_range { my($mod, $vers, $force) = @_; my @versions = keys %{$modules{$mod}}; @versions = sort { -ver_cmp() } @versions; for my $ver (@versions) { next if $modules{$mod}{$ver}{mask} && !$force; return $ver if ver_in_range($ver, $vers); } return undef; } sub resolve_deps { my($trial) = @_; my $tries = 100; my $changes = 'INIT'; my $fail = undef; while ($changes && $tries) { $tries--; $changes = ''; $fail = undef; my @modsnow = sort keys %todo; for my $mod (@modsnow) { my $ver = $todo{$mod}; my $info = $modules{$mod}{$ver} or die "no dependency information on $mod $ver"; for my $dep (@{$info->{depends}}) { $dep =~ /^(\S+)(?: (\S+))?/ or die "Bad dependency $dep from $info->{from}"; my($depmod, $depvers) = ($1,$2); next if $todo{$depmod} && ver_in_range($todo{$depmod}, $depvers); # need to install a dependency my $depver = find_mod_in_range($depmod, $depvers); if (defined $depver) { $todo{$depmod} = $depver; $changes .= " $mod-$ver->$depmod-$depver"; } else { $fail ||= "Could not find module $depmod $depvers required by $mod $ver"; } } for my $dep (@{$info->{conflicts}}) { $dep =~ /^(\S+)(?: (\S+))?/ or die "Bad dependency $dep from $info->{from}"; my($depmod, $depvers) = ($1,$2); next unless $todo{$depmod} && ver_in_range($todo{$depmod}, $depvers); # if there are changes this round, maybe the conflict won't come up after they are resolved. $fail ||= "Cannot install: module $mod ($ver) conflicts with $depmod version $todo{$depmod}"; } } } if ($trial) { return !($changes || $fail); } if ($changes) { print "Infinite dependency loop:$changes\n"; exit 1; } if ($fail) { print "$fail\n"; exit 1; } } command 'install', 'Install a third-party module', sub { for my $mod (@_) { my $vers = $mod =~ s/=([-0-9.]+)// ? $1 : undef; $mod = lc $mod; unless ($modules{$mod}) { print "Cannot find module $mod\n"; exit 1; } my $ver = find_mod_in_range($mod, $vers, $vers ? 1 : 0); unless ($ver) { print "Cannot find suitable version of $mod\n"; exit 1; } $todo{$mod} = $ver; } }; command 'upgrade', 'Upgrade a third-party module', sub { my @installed = sort keys %installed; for my $mod (@installed) { next unless $mod =~ /^m_/; my %saved = %todo; $todo{$mod} = find_mod_in_range($mod); if (!resolve_deps(1)) { %todo = %saved; } } }; command 'list', 'List available third-party modules', sub { my @all = sort keys %modules; for my $mod (@all) { my @vers = sort { ver_cmp() } keys %{$modules{$mod}}; my $desc = ''; for my $ver (@vers) { # latest defined description wins $desc = $modules{$mod}{$ver}{description} || $desc; } next if @vers == 1 && $modules{$mod}{$vers[0]}{url} eq 'NONE'; my $instver = $installed{$mod} || ''; my $vers = join ' ', map { $_ eq $instver ? "\e[1m$_\e[m" : $_ } @vers; print "$mod ($vers) - $desc\n"; } exit 0; }; execute_command @ARGV; resolve_deps(0); $| = 1; # immediate print of lines without \n print "Processing changes...\n"; for my $mod (keys %installed) { next if $todo{$mod}; print "Uninstalling $mod $installed{$mod}\n"; unlink "src/modules/$mod.cpp"; } my $count = scalar keys %todo; print "Checking $count items...\n"; for my $mod (sort keys %todo) { my $ver = $todo{$mod}; my $oldver = $installed{$mod}; if ($modules{$mod}{$ver}{mask}) { print "Module $mod $ver is masked: $modules{$mod}{$ver}{mask}\n"; } next if $oldver && $oldver eq $ver; my $url = $modules{$mod}{$ver}{url}; if ($oldver) { print "Upgrading $mod from $oldver to $ver using $url" } else { print "Installing $mod $ver from $url"; } $mod_versions{$mod} = $ver; my $ua = LWP::UserAgent->new(ssl_opts => { verify_hostname => 0 }); my $response = $ua->get($url); if ($response->is_success) { open(MF, ">src/modules/$mod.cpp") or die "\nFilesystem not writable: $!"; print MF $response->content; close(MF); print " - done\n"; } else { printf "\nHTTP %s: %s\n", $response->code, $response->message; } } # write database of installed versions write_config_file '.modulemanager', %mod_versions; print "Finished!\n"; �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/sources.list�������������������������������������������������������������������������0000664�0000000�0000000�00000000505�13554550454�0015723�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������###### # sources.list # # This file lists sources of third party modules that are available for installation with inspircd. # To manage these, you want the ./modulemanager binary. # # Feel free to add additional sources! :) # official repository https://raw.githubusercontent.com/inspircd/inspircd-contrib/master/modules.lst �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/src/���������������������������������������������������������������������������������0000775�0000000�0000000�00000000000�13554550454�0014132�5����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/src/bancache.cpp���������������������������������������������������������������������0000664�0000000�0000000�00000005750�13554550454�0016371�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * InspIRCd -- Internet Relay Chat Daemon * * Copyright (C) 2007-2008 Robin Burchell <robin+git@viroteck.net> * Copyright (C) 2007 Craig Edwards <craigedwards@brainbox.cc> * * This file is part of InspIRCd. InspIRCd is free software: you can * redistribute it and/or modify it under the terms of the GNU General Public * License as published by the Free Software Foundation, version 2. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include "inspircd.h" BanCacheHit::BanCacheHit(const std::string& type, const std::string& reason, time_t seconds) : Type(type) , Reason(reason) , Expiry(ServerInstance->Time() + seconds) { } BanCacheHit *BanCacheManager::AddHit(const std::string &ip, const std::string &type, const std::string &reason, time_t seconds) { BanCacheHit*& b = BanHash[ip]; if (b != NULL) // can't have two cache entries on the same IP, sorry.. return NULL; b = new BanCacheHit(type, reason, (seconds ? seconds : 86400)); return b; } BanCacheHit *BanCacheManager::GetHit(const std::string &ip) { BanCacheHash::iterator i = this->BanHash.find(ip); if (i == this->BanHash.end()) return NULL; // free and safe if (RemoveIfExpired(i)) return NULL; // expired return i->second; // hit. } bool BanCacheManager::RemoveIfExpired(BanCacheHash::iterator& it) { if (ServerInstance->Time() < it->second->Expiry) return false; ServerInstance->Logs->Log("BANCACHE", LOG_DEBUG, "Hit on " + it->first + " is out of date, removing!"); delete it->second; it = BanHash.erase(it); return true; } void BanCacheManager::RemoveEntries(const std::string& type, bool positive) { if (positive) ServerInstance->Logs->Log("BANCACHE", LOG_DEBUG, "BanCacheManager::RemoveEntries(): Removing positive hits for " + type); else ServerInstance->Logs->Log("BANCACHE", LOG_DEBUG, "BanCacheManager::RemoveEntries(): Removing all negative hits"); for (BanCacheHash::iterator i = BanHash.begin(); i != BanHash.end(); ) { if (RemoveIfExpired(i)) continue; // updates the iterator if expired BanCacheHit* b = i->second; bool remove = false; if (positive) { // when removing positive hits, remove only if the type matches remove = b->IsPositive() && (b->Type == type); } else { // when removing negative hits, remove all of them remove = !b->IsPositive(); } if (remove) { /* we need to remove this one. */ ServerInstance->Logs->Log("BANCACHE", LOG_DEBUG, "BanCacheManager::RemoveEntries(): Removing a hit on " + i->first); delete b; i = BanHash.erase(i); } else ++i; } } BanCacheManager::~BanCacheManager() { for (BanCacheHash::iterator n = BanHash.begin(); n != BanHash.end(); ++n) delete n->second; } ������������������������inspircd-3.4.0/src/base.cpp�������������������������������������������������������������������������0000664�0000000�0000000�00000022017�13554550454�0015552�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * InspIRCd -- Internet Relay Chat Daemon * * Copyright (C) 2009 Daniel De Graaf <danieldg@inspircd.org> * Copyright (C) 2007 Dennis Friis <peavey@inspircd.org> * Copyright (C) 2004-2006 Craig Edwards <craigedwards@brainbox.cc> * Copyright (C) 2006 Oliver Lupton <oliverlupton@gmail.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 "inspircd.h" #include "base.h" #include <time.h> #ifdef INSPIRCD_ENABLE_RTTI #include <typeinfo> #endif classbase::classbase() { if (ServerInstance) ServerInstance->Logs->Log("CULLLIST", LOG_DEBUG, "classbase::+ @%p", (void*)this); } CullResult classbase::cull() { if (ServerInstance) #ifdef INSPIRCD_ENABLE_RTTI ServerInstance->Logs->Log("CULLLIST", LOG_DEBUG, "classbase::-%s @%p", typeid(*this).name(), (void*)this); #else ServerInstance->Logs->Log("CULLLIST", LOG_DEBUG, "classbase::- @%p", (void*)this); #endif return CullResult(); } classbase::~classbase() { if (ServerInstance) ServerInstance->Logs->Log("CULLLIST", LOG_DEBUG, "classbase::~ @%p", (void*)this); } CullResult::CullResult() { } // This trick detects heap allocations of refcountbase objects static void* last_heap = NULL; void* refcountbase::operator new(size_t size) { last_heap = ::operator new(size); return last_heap; } void refcountbase::operator delete(void* obj) { if (last_heap == obj) last_heap = NULL; ::operator delete(obj); } refcountbase::refcountbase() : refcount(0) { if (this != last_heap) throw CoreException("Reference allocate on the stack!"); } refcountbase::~refcountbase() { if (refcount && ServerInstance) ServerInstance->Logs->Log("CULLLIST", LOG_DEBUG, "refcountbase::~ @%p with refcount %d", (void*)this, refcount); } usecountbase::~usecountbase() { if (usecount && ServerInstance) ServerInstance->Logs->Log("CULLLIST", LOG_DEBUG, "usecountbase::~ @%p with refcount %d", (void*)this, usecount); } ServiceProvider::~ServiceProvider() { } void ServiceProvider::RegisterService() { } ExtensionItem::ExtensionItem(const std::string& Key, ExtensibleType exttype, Module* mod) : ServiceProvider(mod, Key, SERVICE_METADATA) , type(exttype) { } ExtensionItem::~ExtensionItem() { } void* ExtensionItem::get_raw(const Extensible* container) const { Extensible::ExtensibleStore::const_iterator i = container->extensions.find(const_cast<ExtensionItem*>(this)); if (i == container->extensions.end()) return NULL; return i->second; } void* ExtensionItem::set_raw(Extensible* container, void* value) { std::pair<Extensible::ExtensibleStore::iterator,bool> rv = container->extensions.insert(std::make_pair(this, value)); if (rv.second) { return NULL; } else { void* old = rv.first->second; rv.first->second = value; return old; } } void* ExtensionItem::unset_raw(Extensible* container) { Extensible::ExtensibleStore::iterator i = container->extensions.find(this); if (i == container->extensions.end()) return NULL; void* rv = i->second; container->extensions.erase(i); return rv; } void ExtensionItem::RegisterService() { if (!ServerInstance->Extensions.Register(this)) throw ModuleException("Extension already exists: " + name); } bool ExtensionManager::Register(ExtensionItem* item) { return types.insert(std::make_pair(item->name, item)).second; } void ExtensionManager::BeginUnregister(Module* module, std::vector<reference<ExtensionItem> >& list) { ExtMap::iterator i = types.begin(); while (i != types.end()) { ExtMap::iterator me = i++; ExtensionItem* item = me->second; if (item->creator == module) { list.push_back(item); types.erase(me); } } } ExtensionItem* ExtensionManager::GetItem(const std::string& name) { ExtMap::iterator i = types.find(name); if (i == types.end()) return NULL; return i->second; } void Extensible::doUnhookExtensions(const std::vector<reference<ExtensionItem> >& toRemove) { for(std::vector<reference<ExtensionItem> >::const_iterator i = toRemove.begin(); i != toRemove.end(); ++i) { ExtensionItem* item = *i; ExtensibleStore::iterator e = extensions.find(item); if (e != extensions.end()) { item->free(this, e->second); extensions.erase(e); } } } Extensible::Extensible() : culled(false) { } CullResult Extensible::cull() { FreeAllExtItems(); culled = true; return classbase::cull(); } void Extensible::FreeAllExtItems() { for(ExtensibleStore::iterator i = extensions.begin(); i != extensions.end(); ++i) { i->first->free(this, i->second); } extensions.clear(); } Extensible::~Extensible() { if ((!extensions.empty() || !culled) && ServerInstance) ServerInstance->Logs->Log("CULLLIST", LOG_DEBUG, "Extensible destructor called without cull @%p", (void*)this); } void ExtensionItem::FromInternal(Extensible* container, const std::string& value) { FromNetwork(container, value); } void ExtensionItem::FromNetwork(Extensible* container, const std::string& value) { } std::string ExtensionItem::ToHuman(const Extensible* container, void* item) const { // Try to use the network form by default. std::string ret = ToNetwork(container, item); // If there's no network form then fall back to the internal form. if (ret.empty()) ret = ToInternal(container, item); return ret; } std::string ExtensionItem::ToInternal(const Extensible* container, void* item) const { return ToNetwork(container, item); } std::string ExtensionItem::ToNetwork(const Extensible* container, void* item) const { return std::string(); } std::string ExtensionItem::serialize(SerializeFormat format, const Extensible* container, void* item) const { // Wrap the deprecated API with the new API. switch (format) { case FORMAT_USER: return ToHuman(container, item); case FORMAT_INTERNAL: case FORMAT_PERSIST: return ToInternal(container, item); case FORMAT_NETWORK: return ToNetwork(container, item); } return ""; } void ExtensionItem::unserialize(SerializeFormat format, Extensible* container, const std::string& value) { // Wrap the deprecated API with the new API. switch (format) { case FORMAT_USER: break; case FORMAT_INTERNAL: case FORMAT_PERSIST: FromInternal(container, value); break; case FORMAT_NETWORK: FromNetwork(container, value); break; } } LocalStringExt::LocalStringExt(const std::string& Key, ExtensibleType exttype, Module* Owner) : SimpleExtItem<std::string>(Key, exttype, Owner) { } LocalStringExt::~LocalStringExt() { } std::string LocalStringExt::ToInternal(const Extensible* container, void* item) const { return item ? *static_cast<std::string*>(item) : std::string(); } void LocalStringExt::FromInternal(Extensible* container, const std::string& value) { set(container, value); } LocalIntExt::LocalIntExt(const std::string& Key, ExtensibleType exttype, Module* mod) : ExtensionItem(Key, exttype, mod) { } LocalIntExt::~LocalIntExt() { } std::string LocalIntExt::ToInternal(const Extensible* container, void* item) const { return ConvToStr(reinterpret_cast<intptr_t>(item)); } void LocalIntExt::FromInternal(Extensible* container, const std::string& value) { set(container, ConvToNum<intptr_t>(value)); } intptr_t LocalIntExt::get(const Extensible* container) const { return reinterpret_cast<intptr_t>(get_raw(container)); } intptr_t LocalIntExt::set(Extensible* container, intptr_t value) { if (value) return reinterpret_cast<intptr_t>(set_raw(container, reinterpret_cast<void*>(value))); else return reinterpret_cast<intptr_t>(unset_raw(container)); } void LocalIntExt::free(Extensible* container, void* item) { } StringExtItem::StringExtItem(const std::string& Key, ExtensibleType exttype, Module* mod) : ExtensionItem(Key, exttype, mod) { } StringExtItem::~StringExtItem() { } std::string* StringExtItem::get(const Extensible* container) const { return static_cast<std::string*>(get_raw(container)); } std::string StringExtItem::ToNetwork(const Extensible* container, void* item) const { return item ? *static_cast<std::string*>(item) : std::string(); } void StringExtItem::FromNetwork(Extensible* container, const std::string& value) { if (value.empty()) unset(container); else set(container, value); } void StringExtItem::set(Extensible* container, const std::string& value) { void* old = set_raw(container, new std::string(value)); free(container, old); } void StringExtItem::unset(Extensible* container) { void* old = unset_raw(container); free(container, old); } void StringExtItem::free(Extensible* container, void* item) { delete static_cast<std::string*>(item); } ModuleException::ModuleException(const std::string &message, Module* who) : CoreException(message, who ? who->ModuleSourceFile : "A Module") { } �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/src/channels.cpp���������������������������������������������������������������������0000664�0000000�0000000�00000037320�13554550454�0016436�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * InspIRCd -- Internet Relay Chat Daemon * * Copyright (C) 2009-2010 Daniel De Graaf <danieldg@inspircd.org> * Copyright (C) 2006-2008 Robin Burchell <robin+git@viroteck.net> * Copyright (C) 2006, 2008 Oliver Lupton <oliverlupton@gmail.com> * Copyright (C) 2008 Pippijn van Steenhoven <pip88nl@gmail.com> * Copyright (C) 2003-2008 Craig Edwards <craigedwards@brainbox.cc> * Copyright (C) 2008 Thomas Stagner <aquanight@inspircd.org> * Copyright (C) 2007 Dennis Friis <peavey@inspircd.org> * * This file is part of InspIRCd. InspIRCd is free software: you can * redistribute it and/or modify it under the terms of the GNU General Public * License as published by the Free Software Foundation, version 2. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include "inspircd.h" #include "listmode.h" namespace { ChanModeReference ban(NULL, "ban"); } Channel::Channel(const std::string &cname, time_t ts) : name(cname), age(ts), topicset(0) { if (!ServerInstance->chanlist.insert(std::make_pair(cname, this)).second) throw CoreException("Cannot create duplicate channel " + cname); } void Channel::SetMode(ModeHandler* mh, bool on) { if (mh && mh->GetId() != ModeParser::MODEID_MAX) modes[mh->GetId()] = on; } void Channel::SetTopic(User* u, const std::string& ntopic, time_t topicts, const std::string* setter) { // Send a TOPIC message to the channel only if the new topic text differs if (this->topic != ntopic) { this->topic = ntopic; ClientProtocol::Messages::Topic topicmsg(u, this, this->topic); Write(ServerInstance->GetRFCEvents().topic, topicmsg); } // Always update setter and set time if (!setter) setter = ServerInstance->Config->FullHostInTopic ? &u->GetFullHost() : &u->nick; this->setby.assign(*setter, 0, ServerInstance->Config->Limits.GetMaxMask()); this->topicset = topicts; FOREACH_MOD(OnPostTopicChange, (u, this, this->topic)); } Membership* Channel::AddUser(User* user) { std::pair<MemberMap::iterator, bool> ret = userlist.insert(std::make_pair(user, insp::aligned_storage<Membership>())); if (!ret.second) return NULL; Membership* memb = new(ret.first->second) Membership(user, this); return memb; } void Channel::DelUser(User* user) { MemberMap::iterator it = userlist.find(user); if (it != userlist.end()) DelUser(it); } void Channel::CheckDestroy() { if (!userlist.empty()) return; ModResult res; FIRST_MOD_RESULT(OnChannelPreDelete, res, (this)); if (res == MOD_RES_DENY) return; // If the channel isn't in chanlist then it is already in the cull list, don't add it again chan_hash::iterator iter = ServerInstance->chanlist.find(this->name); if ((iter == ServerInstance->chanlist.end()) || (iter->second != this)) return; FOREACH_MOD(OnChannelDelete, (this)); ServerInstance->chanlist.erase(iter); ServerInstance->GlobalCulls.AddItem(this); } void Channel::DelUser(const MemberMap::iterator& membiter) { Membership* memb = membiter->second; memb->cull(); memb->~Membership(); userlist.erase(membiter); // If this channel became empty then it should be removed CheckDestroy(); } Membership* Channel::GetUser(User* user) { MemberMap::iterator i = userlist.find(user); if (i == userlist.end()) return NULL; return i->second; } void Channel::SetDefaultModes() { ServerInstance->Logs->Log("CHANNELS", LOG_DEBUG, "SetDefaultModes %s", ServerInstance->Config->DefaultModes.c_str()); irc::spacesepstream list(ServerInstance->Config->DefaultModes); std::string modeseq; std::string parameter; list.GetToken(modeseq); for (std::string::iterator n = modeseq.begin(); n != modeseq.end(); ++n) { ModeHandler* mode = ServerInstance->Modes->FindMode(*n, MODETYPE_CHANNEL); if (mode) { if (mode->IsPrefixMode()) continue; if (mode->NeedsParam(true)) { list.GetToken(parameter); // If the parameter begins with a ':' then it's invalid if (parameter.c_str()[0] == ':') continue; } else parameter.clear(); if ((mode->NeedsParam(true)) && (parameter.empty())) continue; mode->OnModeChange(ServerInstance->FakeClient, ServerInstance->FakeClient, this, parameter, true); } } } /* * add a channel to a user, creating the record for it if needed and linking * it to the user record */ Channel* Channel::JoinUser(LocalUser* user, std::string cname, bool override, const std::string& key) { if (user->registered != REG_ALL) { ServerInstance->Logs->Log("CHANNELS", LOG_DEBUG, "Attempted to join unregistered user " + user->uuid + " to channel " + cname); return NULL; } /* * We don't restrict the number of channels that remote users or users that are override-joining may be in. * We restrict local users to <connect:maxchans> channels. * We restrict local operators to <oper:maxchans> channels. * This is a lot more logical than how it was formerly. -- w00t */ if (!override) { unsigned int maxchans = user->GetClass()->maxchans; if (!maxchans) maxchans = ServerInstance->Config->MaxChans; if (user->IsOper()) { unsigned int opermaxchans = ConvToNum<unsigned int>(user->oper->getConfig("maxchans")); // If not set, use 2.0's <channels:opers>, if that's not set either, use limit from CC if (!opermaxchans && user->HasPrivPermission("channels/high-join-limit")) opermaxchans = ServerInstance->Config->OperMaxChans; if (opermaxchans) maxchans = opermaxchans; } if (user->chans.size() >= maxchans) { user->WriteNumeric(ERR_TOOMANYCHANNELS, cname, "You are on too many channels"); return NULL; } } // Crop channel name if it's too long if (cname.length() > ServerInstance->Config->Limits.ChanMax) cname.resize(ServerInstance->Config->Limits.ChanMax); Channel* chan = ServerInstance->FindChan(cname); bool created_by_local = (chan == NULL); // Flag that will be passed to modules in the OnUserJoin() hook later std::string privs; // Prefix mode(letter)s to give to the joining user if (!chan) { privs = ServerInstance->Config->DefaultModes.substr(0, ServerInstance->Config->DefaultModes.find(' ')); if (override == false) { // Ask the modules whether they're ok with the join, pass NULL as Channel* as the channel is yet to be created ModResult MOD_RESULT; FIRST_MOD_RESULT(OnUserPreJoin, MOD_RESULT, (user, NULL, cname, privs, key)); if (MOD_RESULT == MOD_RES_DENY) return NULL; // A module wasn't happy with the join, abort } chan = new Channel(cname, ServerInstance->Time()); // Set the default modes on the channel (<options:defaultmodes>) chan->SetDefaultModes(); } else { /* Already on the channel */ if (chan->HasUser(user)) return NULL; if (override == false) { ModResult MOD_RESULT; FIRST_MOD_RESULT(OnUserPreJoin, MOD_RESULT, (user, chan, cname, privs, key)); // A module explicitly denied the join and (hopefully) generated a message // describing the situation, so we may stop here without sending anything if (MOD_RESULT == MOD_RES_DENY) return NULL; // If no module returned MOD_RES_DENY or MOD_RES_ALLOW (which is the case // most of the time) then proceed to check channel bans. // // If a module explicitly allowed the join (by returning MOD_RES_ALLOW), // then this entire section is skipped if (MOD_RESULT == MOD_RES_PASSTHRU) { if (chan->IsBanned(user)) { user->WriteNumeric(ERR_BANNEDFROMCHAN, chan->name, "Cannot join channel (you're banned)"); return NULL; } } } } // We figured that this join is allowed and also created the // channel if it didn't exist before, now do the actual join chan->ForceJoin(user, &privs, false, created_by_local); return chan; } Membership* Channel::ForceJoin(User* user, const std::string* privs, bool bursting, bool created_by_local) { if (IS_SERVER(user)) { ServerInstance->Logs->Log("CHANNELS", LOG_DEBUG, "Attempted to join server user " + user->uuid + " to channel " + this->name); return NULL; } Membership* memb = this->AddUser(user); if (!memb) return NULL; // Already on the channel user->chans.push_front(memb); if (privs) { // If the user was granted prefix modes (in the OnUserPreJoin hook, or they're a // remote user and their own server set the modes), then set them internally now for (std::string::const_iterator i = privs->begin(); i != privs->end(); ++i) { PrefixMode* mh = ServerInstance->Modes->FindPrefixMode(*i); if (mh) { std::string nick = user->nick; // Set the mode on the user mh->OnModeChange(ServerInstance->FakeClient, NULL, this, nick, true); } } } // Tell modules about this join, they have the chance now to populate except_list with users we won't send the JOIN (and possibly MODE) to CUList except_list; FOREACH_MOD(OnUserJoin, (memb, bursting, created_by_local, except_list)); ClientProtocol::Events::Join joinevent(memb); this->Write(joinevent, 0, except_list); FOREACH_MOD(OnPostJoin, (memb)); return memb; } bool Channel::IsBanned(User* user) { ModResult result; FIRST_MOD_RESULT(OnCheckChannelBan, result, (user, this)); if (result != MOD_RES_PASSTHRU) return (result == MOD_RES_DENY); ListModeBase* banlm = static_cast<ListModeBase*>(*ban); if (!banlm) return false; const ListModeBase::ModeList* bans = banlm->GetList(this); if (bans) { for (ListModeBase::ModeList::const_iterator it = bans->begin(); it != bans->end(); it++) { if (CheckBan(user, it->mask)) return true; } } return false; } bool Channel::CheckBan(User* user, const std::string& mask) { ModResult result; FIRST_MOD_RESULT(OnCheckBan, result, (user, this, mask)); if (result != MOD_RES_PASSTHRU) return (result == MOD_RES_DENY); // extbans were handled above, if this is one it obviously didn't match if ((mask.length() <= 2) || (mask[1] == ':')) return false; std::string::size_type at = mask.find('@'); if (at == std::string::npos) return false; const std::string nickIdent = user->nick + "!" + user->ident; std::string prefix(mask, 0, at); if (InspIRCd::Match(nickIdent, prefix, NULL)) { std::string suffix(mask, at + 1); if (InspIRCd::Match(user->GetRealHost(), suffix, NULL) || InspIRCd::Match(user->GetDisplayedHost(), suffix, NULL) || InspIRCd::MatchCIDR(user->GetIPString(), suffix, NULL)) return true; } return false; } ModResult Channel::GetExtBanStatus(User *user, char type) { ModResult rv; FIRST_MOD_RESULT(OnExtBanCheck, rv, (user, this, type)); if (rv != MOD_RES_PASSTHRU) return rv; ListModeBase* banlm = static_cast<ListModeBase*>(*ban); if (!banlm) return MOD_RES_PASSTHRU; const ListModeBase::ModeList* bans = banlm->GetList(this); if (bans) { for (ListModeBase::ModeList::const_iterator it = bans->begin(); it != bans->end(); ++it) { if (it->mask.length() <= 2 || it->mask[0] != type || it->mask[1] != ':') continue; if (CheckBan(user, it->mask.substr(2))) return MOD_RES_DENY; } } return MOD_RES_PASSTHRU; } /* Channel::PartUser * Remove a channel from a users record, remove the reference to the Membership object * from the channel and destroy it. */ bool Channel::PartUser(User* user, std::string& reason) { MemberMap::iterator membiter = userlist.find(user); if (membiter == userlist.end()) return false; Membership* memb = membiter->second; CUList except_list; FOREACH_MOD(OnUserPart, (memb, reason, except_list)); ClientProtocol::Messages::Part partmsg(memb, reason); Write(ServerInstance->GetRFCEvents().part, partmsg, 0, except_list); // Remove this channel from the user's chanlist user->chans.erase(memb); // Remove the Membership from this channel's userlist and destroy it this->DelUser(membiter); return true; } void Channel::KickUser(User* src, const MemberMap::iterator& victimiter, const std::string& reason) { Membership* memb = victimiter->second; CUList except_list; FOREACH_MOD(OnUserKick, (src, memb, reason, except_list)); ClientProtocol::Messages::Kick kickmsg(src, memb, reason); Write(ServerInstance->GetRFCEvents().kick, kickmsg, 0, except_list); memb->user->chans.erase(memb); this->DelUser(victimiter); } void Channel::Write(ClientProtocol::Event& protoev, char status, const CUList& except_list) { unsigned int minrank = 0; if (status) { PrefixMode* mh = ServerInstance->Modes->FindPrefix(status); if (mh) minrank = mh->GetPrefixRank(); } for (MemberMap::iterator i = userlist.begin(); i != userlist.end(); i++) { LocalUser* user = IS_LOCAL(i->first); if ((user) && (!except_list.count(user))) { /* User doesn't have the status we're after */ if (minrank && i->second->getRank() < minrank) continue; user->Send(protoev); } } } const char* Channel::ChanModes(bool showsecret) { static std::string scratch; std::string sparam; scratch.clear(); /* This was still iterating up to 190, Channel::modes is only 64 elements -- Om */ for(int n = 0; n < 64; n++) { ModeHandler* mh = ServerInstance->Modes->FindMode(n + 65, MODETYPE_CHANNEL); if (mh && IsModeSet(mh)) { scratch.push_back(n + 65); ParamModeBase* pm = mh->IsParameterMode(); if (!pm) continue; if (pm->IsParameterSecret() && !showsecret) { sparam += " <" + pm->name + ">"; } else { sparam += ' '; pm->GetParameter(this, sparam); } } } scratch += sparam; return scratch.c_str(); } void Channel::WriteNotice(const std::string& text) { ClientProtocol::Messages::Privmsg privmsg(ClientProtocol::Messages::Privmsg::nocopy, ServerInstance->FakeClient, this, text, MSG_NOTICE); Write(ServerInstance->GetRFCEvents().privmsg, privmsg); } /* returns the status character for a given user on a channel, e.g. @ for op, * % for halfop etc. If the user has several modes set, the highest mode * the user has must be returned. */ char Membership::GetPrefixChar() const { char pf = 0; unsigned int bestrank = 0; for (std::string::const_iterator i = modes.begin(); i != modes.end(); ++i) { PrefixMode* mh = ServerInstance->Modes->FindPrefixMode(*i); if (mh && mh->GetPrefixRank() > bestrank && mh->GetPrefix()) { bestrank = mh->GetPrefixRank(); pf = mh->GetPrefix(); } } return pf; } unsigned int Membership::getRank() { char mchar = modes.c_str()[0]; unsigned int rv = 0; if (mchar) { PrefixMode* mh = ServerInstance->Modes->FindPrefixMode(mchar); if (mh) rv = mh->GetPrefixRank(); } return rv; } std::string Membership::GetAllPrefixChars() const { std::string ret; for (std::string::const_iterator i = modes.begin(); i != modes.end(); ++i) { PrefixMode* mh = ServerInstance->Modes->FindPrefixMode(*i); if (mh && mh->GetPrefix()) ret.push_back(mh->GetPrefix()); } return ret; } unsigned int Channel::GetPrefixValue(User* user) { MemberMap::iterator m = userlist.find(user); if (m == userlist.end()) return 0; return m->second->getRank(); } bool Membership::SetPrefix(PrefixMode* delta_mh, bool adding) { char prefix = delta_mh->GetModeChar(); for (unsigned int i = 0; i < modes.length(); i++) { char mchar = modes[i]; PrefixMode* mh = ServerInstance->Modes->FindPrefixMode(mchar); if (mh && mh->GetPrefixRank() <= delta_mh->GetPrefixRank()) { modes = modes.substr(0,i) + (adding ? std::string(1, prefix) : "") + modes.substr(mchar == prefix ? i+1 : i); return adding != (mchar == prefix); } } if (adding) modes.push_back(prefix); return adding; } void Membership::WriteNotice(const std::string& text) const { LocalUser* const localuser = IS_LOCAL(user); if (!localuser) return; ClientProtocol::Messages::Privmsg privmsg(ClientProtocol::Messages::Privmsg::nocopy, ServerInstance->FakeClient, this->chan, text, MSG_NOTICE); localuser->Send(ServerInstance->GetRFCEvents().privmsg, privmsg); } ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/src/cidr.cpp�������������������������������������������������������������������������0000664�0000000�0000000�00000005732�13554550454�0015566�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * InspIRCd -- Internet Relay Chat Daemon * * Copyright (C) 2009 Daniel De Graaf <danieldg@inspircd.org> * Copyright (C) 2008 Craig Edwards <craigedwards@brainbox.cc> * Copyright (C) 2008 Robin Burchell <robin+git@viroteck.net> * * 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 "inspircd.h" /* Match CIDR strings, e.g. 127.0.0.1 to 127.0.0.0/8 or 3ffe:1:5:6::8 to 3ffe:1::0/32 * * This will also attempt to match any leading usernames or nicknames on the mask, using * match(), when match_with_username is true. */ bool irc::sockets::MatchCIDR(const std::string &address, const std::string &cidr_mask, bool match_with_username) { std::string address_copy; std::string cidr_copy; /* The caller is trying to match ident@<mask>/bits. * Chop off the ident@ portion, use match() on it * seperately. */ if (match_with_username) { /* Use strchr not strrchr, because its going to be nearer to the left */ std::string::size_type username_mask_pos = cidr_mask.rfind('@'); std::string::size_type username_addr_pos = address.rfind('@'); /* Both strings have an @ symbol in them */ if (username_mask_pos != std::string::npos && username_addr_pos != std::string::npos) { /* Try and match() the strings before the @ * symbols, and recursively call MatchCIDR without * username matching enabled to match the host part. */ return (InspIRCd::Match(address.substr(0, username_addr_pos), cidr_mask.substr(0, username_mask_pos), ascii_case_insensitive_map) && MatchCIDR(address.substr(username_addr_pos + 1), cidr_mask.substr(username_mask_pos + 1), false)); } else { address_copy.assign(address, username_addr_pos + 1, std::string::npos); cidr_copy.assign(cidr_mask, username_mask_pos + 1, std::string::npos); } } else { address_copy.assign(address); cidr_copy.assign(cidr_mask); } const std::string::size_type per_pos = cidr_copy.rfind('/'); if ((per_pos == std::string::npos) || (per_pos == cidr_copy.length()-1) || (cidr_copy.find_first_not_of("0123456789", per_pos+1) != std::string::npos) || (cidr_copy.find_first_not_of("0123456789abcdefABCDEF.:") < per_pos)) { // The CIDR mask is invalid return false; } irc::sockets::sockaddrs addr; if (!irc::sockets::aptosa(address_copy, 0, addr)) { // The address could not be parsed. return false; } irc::sockets::cidr_mask mask(cidr_copy); irc::sockets::cidr_mask mask2(addr, mask.length); return mask == mask2; } ��������������������������������������inspircd-3.4.0/src/clientprotocol.cpp���������������������������������������������������������������0000664�0000000�0000000�00000007017�13554550454�0017703�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * InspIRCd -- Internet Relay Chat Daemon * * Copyright (C) 2016 Attila Molnar <attilamolnar@hush.com> * * This file is part of InspIRCd. InspIRCd is free software: you can * redistribute it and/or modify it under the terms of the GNU General Public * License as published by the Free Software Foundation, version 2. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include "inspircd.h" ClientProtocol::Serializer::Serializer(Module* mod, const char* Name) : DataProvider(mod, std::string("serializer/") + Name) , evprov(mod, "event/messagetag") { } bool ClientProtocol::Serializer::HandleTag(LocalUser* user, const std::string& tagname, std::string& tagvalue, TagMap& tags) const { // Catch and block empty tags if (tagname.empty()) return false; const ::Events::ModuleEventProvider::SubscriberList& list = evprov.GetSubscribers(); for (::Events::ModuleEventProvider::SubscriberList::const_iterator i = list.begin(); i != list.end(); ++i) { MessageTagProvider* const tagprov = static_cast<MessageTagProvider*>(*i); const ModResult res = tagprov->OnProcessTag(user, tagname, tagvalue); if (res == MOD_RES_ALLOW) return tags.insert(std::make_pair(tagname, MessageTagData(tagprov, tagvalue))).second; else if (res == MOD_RES_DENY) break; } // No module handles the tag but that's not an error return true; } ClientProtocol::TagSelection ClientProtocol::Serializer::MakeTagWhitelist(LocalUser* user, const TagMap& tagmap) const { TagSelection tagwl; for (TagMap::const_iterator i = tagmap.begin(); i != tagmap.end(); ++i) { const MessageTagData& tagdata = i->second; if (tagdata.tagprov->ShouldSendTag(user, tagdata)) tagwl.Select(tagmap, i); } return tagwl; } const ClientProtocol::SerializedMessage& ClientProtocol::Serializer::SerializeForUser(LocalUser* user, Message& msg) { if (!msg.msginit_done) { msg.msginit_done = true; FOREACH_MOD_CUSTOM(evprov, MessageTagProvider, OnPopulateTags, (msg)); } return msg.GetSerialized(Message::SerializedInfo(this, MakeTagWhitelist(user, msg.GetTags()))); } const ClientProtocol::SerializedMessage& ClientProtocol::Message::GetSerialized(const SerializedInfo& serializeinfo) const { // First check if the serialized line they're asking for is in the cache for (SerializedList::const_iterator i = serlist.begin(); i != serlist.end(); ++i) { const SerializedInfo& curr = i->first; if (curr == serializeinfo) return i->second; } // Not cached, generate it and put it in the cache for later use serlist.push_back(std::make_pair(serializeinfo, serializeinfo.serializer->Serialize(*this, serializeinfo.tagwl))); return serlist.back().second; } void ClientProtocol::Event::GetMessagesForUser(LocalUser* user, MessageList& messagelist) { if (!eventinit_done) { eventinit_done = true; FOREACH_MOD_CUSTOM(*event, EventHook, OnEventInit, (*this)); } // Most of the time there's only a single message but in rare cases there are more if (initialmsg) messagelist.assign(1, initialmsg); else messagelist = *initialmsglist; // Let modules modify the message list ModResult res; FIRST_MOD_RESULT_CUSTOM(*event, EventHook, OnPreEventSend, res, (user, *this, messagelist)); if (res == MOD_RES_DENY) messagelist.clear(); } �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/src/command_parse.cpp����������������������������������������������������������������0000664�0000000�0000000�00000031335�13554550454�0017453�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * InspIRCd -- Internet Relay Chat Daemon * * Copyright (C) 2009-2010 Daniel De Graaf <danieldg@inspircd.org> * Copyright (C) 2006-2008 Robin Burchell <robin+git@viroteck.net> * Copyright (C) 2008 Thomas Stagner <aquanight@inspircd.org> * Copyright (C) 2005-2008 Craig Edwards <craigedwards@brainbox.cc> * Copyright (C) 2006-2007 Dennis Friis <peavey@inspircd.org> * * This file is part of InspIRCd. InspIRCd is free software: you can * redistribute it and/or modify it under the terms of the GNU General Public * License as published by the Free Software Foundation, version 2. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include "inspircd.h" bool InspIRCd::PassCompare(Extensible* ex, const std::string& data, const std::string& input, const std::string& hashtype) { ModResult res; FIRST_MOD_RESULT(OnPassCompare, res, (ex, data, input, hashtype)); /* Module matched */ if (res == MOD_RES_ALLOW) return true; /* Module explicitly didnt match */ if (res == MOD_RES_DENY) return false; /* We dont handle any hash types except for plaintext - Thanks tra26 */ if (!hashtype.empty() && hashtype != "plaintext") return false; return TimingSafeCompare(data, input); } bool CommandParser::LoopCall(User* user, Command* handler, const CommandBase::Params& parameters, unsigned int splithere, int extra, bool usemax) { if (splithere >= parameters.size()) return false; /* First check if we have more than one item in the list, if we don't we return false here and the handler * which called us just carries on as it was. */ if (parameters[splithere].find(',') == std::string::npos) return false; /** Some lame ircds will weed out dupes using some shitty O(n^2) algorithm. * By using std::set (thanks for the idea w00t) we can cut this down a ton. * ...VOOODOOOO! * * Only check for duplicates if there is one list (allow them in JOIN). */ insp::flat_set<std::string, irc::insensitive_swo> dupes; bool check_dupes = (extra < 0); /* Create two sepstreams, if we have only one list, then initialize the second sepstream with * an empty string. The second parameter of the constructor of the sepstream tells whether * or not to allow empty tokens. * We allow empty keys, so "JOIN #a,#b ,bkey" will be interpreted as "JOIN #a", "JOIN #b bkey" */ irc::commasepstream items1(parameters[splithere]); irc::commasepstream items2(extra >= 0 ? parameters[extra] : "", true); std::string item; unsigned int max = 0; LocalUser* localuser = IS_LOCAL(user); /* Attempt to iterate these lists and call the command handler * for every parameter or parameter pair until there are no more * left to parse. */ while (items1.GetToken(item) && (!usemax || max++ < ServerInstance->Config->MaxTargets)) { if ((!check_dupes) || (dupes.insert(item).second)) { CommandBase::Params new_parameters(parameters); new_parameters[splithere] = item; if (extra >= 0) { // If we have two lists then get the next item from the second list. // In case it runs out of elements then 'item' will be an empty string. items2.GetToken(item); new_parameters[extra] = item; } CommandBase::Params params(new_parameters, parameters.GetTags()); CmdResult result = handler->Handle(user, params); if (localuser) { // Run the OnPostCommand hook with the last parameter being true to indicate // that the event is being called in a loop. item.clear(); FOREACH_MOD(OnPostCommand, (handler, new_parameters, localuser, result, true)); } } } return true; } Command* CommandParser::GetHandler(const std::string &commandname) { CommandMap::iterator n = cmdlist.find(commandname); if (n != cmdlist.end()) return n->second; return NULL; } // calls a handler function for a command CmdResult CommandParser::CallHandler(const std::string& commandname, const CommandBase::Params& parameters, User* user, Command** cmd) { CommandMap::iterator n = cmdlist.find(commandname); if (n != cmdlist.end()) { if ((!parameters.empty()) && (parameters.back().empty()) && (!n->second->allow_empty_last_param)) return CMD_INVALID; if (parameters.size() >= n->second->min_params) { bool bOkay = false; if (IS_LOCAL(user) && n->second->flags_needed) { /* if user is local, and flags are needed .. */ if (user->IsModeSet(n->second->flags_needed)) { /* if user has the flags, and now has the permissions, go ahead */ if (user->HasCommandPermission(commandname)) bOkay = true; } } else { /* remote or no flags required anyway */ bOkay = true; } if (bOkay) { if (cmd) *cmd = n->second; ClientProtocol::TagMap tags; return n->second->Handle(user, CommandBase::Params(parameters, tags)); } } } return CMD_INVALID; } void CommandParser::ProcessCommand(LocalUser* user, std::string& command, CommandBase::Params& command_p) { /* find the command, check it exists */ Command* handler = GetHandler(command); // Penalty to give if the command fails before the handler is executed unsigned int failpenalty = 0; /* Modify the user's penalty regardless of whether or not the command exists */ if (!user->HasPrivPermission("users/flood/no-throttle")) { // If it *doesn't* exist, give it a slightly heftier penalty than normal to deter flooding us crap unsigned int penalty = (handler ? handler->Penalty * 1000 : 2000); user->CommandFloodPenalty += penalty; // Increase their penalty later if we fail and the command has 0 penalty by default (i.e. in Command::Penalty) to // throttle sending ERR_* from the command parser. If the command does have a non-zero penalty then this is not // needed because we've increased their penalty above. if (penalty == 0) failpenalty = 1000; } if (!handler) { ModResult MOD_RESULT; FIRST_MOD_RESULT(OnPreCommand, MOD_RESULT, (command, command_p, user, false)); if (MOD_RESULT == MOD_RES_DENY) return; /* * This double lookup is in case a module (abbreviation) wishes to change a command. * Sure, the double lookup is a bit painful, but bear in mind this only happens for unknowns anyway. * * Thanks dz for making me actually understand why this is necessary! * -- w00t */ handler = GetHandler(command); if (!handler) { if (user->registered == REG_ALL) user->WriteNumeric(ERR_UNKNOWNCOMMAND, command, "Unknown command"); ServerInstance->stats.Unknown++; return; } } // If we were given more parameters than max_params then append the excess parameter(s) // to command_p[maxparams-1], i.e. to the last param that is still allowed if (handler->max_params && command_p.size() > handler->max_params) { /* * command_p input (assuming max_params 1): * this * is * a * test */ // Iterator to the last parameter that will be kept const CommandBase::Params::iterator lastkeep = command_p.begin() + (handler->max_params - 1); // Iterator to the first excess parameter const CommandBase::Params::iterator firstexcess = lastkeep + 1; // Append all excess parameter(s) to the last parameter, seperated by spaces for (CommandBase::Params::const_iterator i = firstexcess; i != command_p.end(); ++i) { lastkeep->push_back(' '); lastkeep->append(*i); } // Erase the excess parameter(s) command_p.erase(firstexcess, command_p.end()); } /* * We call OnPreCommand here seperately if the command exists, so the magic above can * truncate to max_params if necessary. -- w00t */ ModResult MOD_RESULT; FIRST_MOD_RESULT(OnPreCommand, MOD_RESULT, (command, command_p, user, false)); if (MOD_RESULT == MOD_RES_DENY) return; /* activity resets the ping pending timer */ user->nextping = ServerInstance->Time() + user->MyClass->GetPingTime(); if (handler->flags_needed) { if (!user->IsModeSet(handler->flags_needed)) { user->CommandFloodPenalty += failpenalty; user->WriteNumeric(ERR_NOPRIVILEGES, "Permission Denied - You do not have the required operator privileges"); return; } if (!user->HasCommandPermission(command)) { user->CommandFloodPenalty += failpenalty; user->WriteNumeric(ERR_NOPRIVILEGES, InspIRCd::Format("Permission Denied - Oper type %s does not have access to command %s", user->oper->name.c_str(), command.c_str())); return; } } if ((!command_p.empty()) && (command_p.back().empty()) && (!handler->allow_empty_last_param)) command_p.pop_back(); if (command_p.size() < handler->min_params) { user->CommandFloodPenalty += failpenalty; user->WriteNumeric(ERR_NEEDMOREPARAMS, command, "Not enough parameters."); if ((ServerInstance->Config->SyntaxHints) && (user->registered == REG_ALL) && (handler->syntax.length())) user->WriteNumeric(RPL_SYNTAX, handler->name, handler->syntax); return; } if ((user->registered != REG_ALL) && (!handler->WorksBeforeReg())) { user->CommandFloodPenalty += failpenalty; user->WriteNumeric(ERR_NOTREGISTERED, command, "You have not registered"); } else { /* passed all checks.. first, do the (ugly) stats counters. */ handler->use_count++; /* module calls too */ FIRST_MOD_RESULT(OnPreCommand, MOD_RESULT, (command, command_p, user, true)); if (MOD_RESULT == MOD_RES_DENY) return; /* * WARNING: be careful, the user may be deleted soon */ CmdResult result = handler->Handle(user, command_p); FOREACH_MOD(OnPostCommand, (handler, command_p, user, result, false)); } } void CommandParser::RemoveCommand(Command* x) { CommandMap::iterator n = cmdlist.find(x->name); if (n != cmdlist.end() && n->second == x) cmdlist.erase(n); } CommandBase::CommandBase(Module* mod, const std::string& cmd, unsigned int minpara, unsigned int maxpara) : ServiceProvider(mod, cmd, SERVICE_COMMAND) , flags_needed(0) , min_params(minpara) , max_params(maxpara) , use_count(0) , works_before_reg(false) , allow_empty_last_param(true) , Penalty(1) { } CommandBase::~CommandBase() { } void CommandBase::EncodeParameter(std::string& parameter, unsigned int index) { } RouteDescriptor CommandBase::GetRouting(User* user, const Params& parameters) { return ROUTE_LOCALONLY; } Command::Command(Module* mod, const std::string& cmd, unsigned int minpara, unsigned int maxpara) : CommandBase(mod, cmd, minpara, maxpara) , force_manual_route(false) { } Command::~Command() { ServerInstance->Parser.RemoveCommand(this); } void Command::RegisterService() { if (!ServerInstance->Parser.AddCommand(this)) throw ModuleException("Command already exists: " + name); } void CommandParser::ProcessBuffer(LocalUser* user, const std::string& buffer) { ClientProtocol::ParseOutput parseoutput; if (!user->serializer->Parse(user, buffer, parseoutput)) return; std::string& command = parseoutput.cmd; std::transform(command.begin(), command.end(), command.begin(), ::toupper); CommandBase::Params parameters(parseoutput.params, parseoutput.tags); ProcessCommand(user, command, parameters); } bool CommandParser::AddCommand(Command *f) { /* create the command and push it onto the table */ if (cmdlist.find(f->name) == cmdlist.end()) { cmdlist[f->name] = f; return true; } return false; } CommandParser::CommandParser() { } std::string CommandParser::TranslateUIDs(const std::vector<TranslateType>& to, const CommandBase::Params& source, bool prefix_final, CommandBase* custom_translator) { std::vector<TranslateType>::const_iterator types = to.begin(); std::string dest; for (unsigned int i = 0; i < source.size(); i++) { TranslateType t = TR_TEXT; // They might supply less translation types than parameters, // in that case pretend that all remaining types are TR_TEXT if (types != to.end()) { t = *types; types++; } bool last = (i == (source.size() - 1)); if (prefix_final && last) dest.push_back(':'); TranslateSingleParam(t, source[i], dest, custom_translator, i); if (!last) dest.push_back(' '); } return dest; } void CommandParser::TranslateSingleParam(TranslateType to, const std::string& item, std::string& dest, CommandBase* custom_translator, unsigned int paramnumber) { switch (to) { case TR_NICK: { /* Translate single nickname */ User* user = ServerInstance->FindNick(item); if (user) dest.append(user->uuid); else dest.append(item); break; } case TR_CUSTOM: { if (custom_translator) { std::string translated = item; custom_translator->EncodeParameter(translated, paramnumber); dest.append(translated); break; } // If no custom translator was given, fall through } /*@fallthrough@*/ default: /* Do nothing */ dest.append(item); break; } } ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/src/commands.cpp���������������������������������������������������������������������0000664�0000000�0000000�00000003501�13554550454�0016436�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * InspIRCd -- Internet Relay Chat Daemon * * Copyright (C) 2009 Daniel De Graaf <danieldg@inspircd.org> * Copyright (C) 2007 Dennis Friis <peavey@inspircd.org> * Copyright (C) 2004-2007 Craig Edwards <craigedwards@brainbox.cc> * Copyright (C) 2006 Oliver Lupton <oliverlupton@gmail.com> * Copyright (C) 2005 Craig McLure <craig@chatspike.net> * * 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 "inspircd.h" CmdResult SplitCommand::Handle(User* user, const Params& parameters) { switch (user->usertype) { case USERTYPE_LOCAL: return HandleLocal(static_cast<LocalUser*>(user), parameters); case USERTYPE_REMOTE: return HandleRemote(static_cast<RemoteUser*>(user), parameters); case USERTYPE_SERVER: return HandleServer(static_cast<FakeUser*>(user), parameters); } ServerInstance->Logs->Log("COMMAND", LOG_DEFAULT, "Unknown user type %d in command (uuid=%s)!", user->usertype, user->uuid.c_str()); return CMD_INVALID; } CmdResult SplitCommand::HandleLocal(LocalUser* user, const Params& parameters) { return CMD_INVALID; } CmdResult SplitCommand::HandleRemote(RemoteUser* user, const Params& parameters) { return CMD_INVALID; } CmdResult SplitCommand::HandleServer(FakeUser* user, const Params& parameters) { return CMD_INVALID; } �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/src/configparser.cpp�����������������������������������������������������������������0000664�0000000�0000000�00000044510�13554550454�0017324�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * InspIRCd -- Internet Relay Chat Daemon * * 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 * 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 "inspircd.h" #include <fstream> #include "configparser.h" enum ParseFlags { // Legacy config parsing should be used. FLAG_USE_COMPAT = 1, // Executable includes are disabled. FLAG_NO_EXEC = 2, // All includes are disabled. FLAG_NO_INC = 4 }; // Represents the position within a config file. struct FilePosition { // The name of the file which is being read. std::string name; // The line of the file that this position points to. unsigned int line; // The column of the file that this position points to. unsigned int column; FilePosition(const std::string& Name) : name(Name) , line(1) , column(1) { } /** Returns a string that represents this file position. */ std::string str() { return name + ":" + ConvToStr(line) + ":" + ConvToStr(column); } }; // RAII wrapper for FILE* which closes the file when it goes out of scope. class FileWrapper { private: // Whether this file handle should be closed with pclose. bool close_with_pclose; // The file handle which is being wrapped. FILE* const file; public: FileWrapper(FILE* File, bool CloseWithPClose = false) : close_with_pclose(CloseWithPClose) , file(File) { } // Operator which determines whether the file is open. operator bool() { return (file != NULL); } // Operator which retrieves the underlying FILE pointer. operator FILE*() { return file; } ~FileWrapper() { if (!file) return; if (close_with_pclose) pclose(file); else fclose(file); } }; struct Parser { ParseStack& stack; int flags; FILE* const file; FilePosition current; FilePosition last_tag; reference<ConfigTag> tag; int ungot; std::string mandatory_tag; Parser(ParseStack& me, int myflags, FILE* conf, const std::string& name, const std::string& mandatorytag) : stack(me), flags(myflags), file(conf), current(name), last_tag(name), ungot(-1), mandatory_tag(mandatorytag) { } int next(bool eof_ok = false) { if (ungot != -1) { int ch = ungot; ungot = -1; return ch; } int ch = fgetc(file); if (ch == EOF && !eof_ok) { throw CoreException("Unexpected end-of-file"); } else if (ch == '\n') { current.line++; current.column = 0; } else { current.column++; } return ch; } void unget(int ch) { if (ungot != -1) throw CoreException("INTERNAL ERROR: cannot unget twice"); ungot = ch; } void comment() { while (1) { int ch = next(); if (ch == '\n') return; } } void nextword(std::string& rv) { int ch = next(); while (isspace(ch)) ch = next(); while (isalnum(ch) || ch == '_'|| ch == '-') { rv.push_back(ch); ch = next(); } unget(ch); } bool kv(ConfigItems* items) { std::string key; nextword(key); int ch = next(); if (ch == '>' && key.empty()) { return false; } else if (ch == '#' && key.empty()) { comment(); return true; } else if (ch != '=') { throw CoreException("Invalid character " + std::string(1, ch) + " in key (" + key + ")"); } std::string value; ch = next(); if (ch != '"') { throw CoreException("Invalid character in value of <" + tag->tag + ":" + key + ">"); } while (1) { ch = next(); if (ch == '&' && !(flags & FLAG_USE_COMPAT)) { std::string varname; while (1) { ch = next(); if (isalnum(ch) || (varname.empty() && ch == '#')) varname.push_back(ch); else if (ch == ';') break; else { stack.errstr << "Invalid XML entity name in value of <" + tag->tag + ":" + key + ">\n" << "To include an ampersand or quote, use &amp; or &quot;\n"; throw CoreException("Parse error"); } } if (varname.empty()) throw CoreException("Empty XML entity reference"); else if (varname[0] == '#' && (varname.size() == 1 || (varname.size() == 2 && varname[1] == 'x'))) throw CoreException("Empty numeric character reference"); else if (varname[0] == '#') { const char* cvarname = varname.c_str(); char* endptr; unsigned long lvalue; if (cvarname[1] == 'x') lvalue = strtoul(cvarname + 2, &endptr, 16); else lvalue = strtoul(cvarname + 1, &endptr, 10); if (*endptr != '\0' || lvalue > 255) throw CoreException("Invalid numeric character reference '&" + varname + ";'"); value.push_back(static_cast<char>(lvalue)); } else { insp::flat_map<std::string, std::string>::iterator var = stack.vars.find(varname); if (var == stack.vars.end()) throw CoreException("Undefined XML entity reference '&" + varname + ";'"); value.append(var->second); } } else if (ch == '\\' && (flags & FLAG_USE_COMPAT)) { int esc = next(); if (esc == 'n') value.push_back('\n'); else if (isalpha(esc)) throw CoreException("Unknown escape character \\" + std::string(1, esc)); else value.push_back(esc); } else if (ch == '"') break; else if (ch != '\r') value.push_back(ch); } if (items->find(key) != items->end()) throw CoreException("Duplicate key '" + key + "' found"); (*items)[key] = value; return true; } void dotag() { last_tag = current; std::string name; nextword(name); int spc = next(); if (spc == '>') unget(spc); else if (!isspace(spc)) throw CoreException("Invalid character in tag name"); if (name.empty()) throw CoreException("Empty tag name"); ConfigItems* items; tag = ConfigTag::create(name, current.name, current.line, items); while (kv(items)) { // Do nothing here (silences a GCC warning). } if (name == mandatory_tag) { // Found the mandatory tag mandatory_tag.clear(); } if (stdalgo::string::equalsci(name, "include")) { stack.DoInclude(tag, flags); } else if (stdalgo::string::equalsci(name, "files")) { for(ConfigItems::iterator i = items->begin(); i != items->end(); i++) { stack.DoReadFile(i->first, i->second, flags, false); } } else if (stdalgo::string::equalsci(name, "execfiles")) { for(ConfigItems::iterator i = items->begin(); i != items->end(); i++) { stack.DoReadFile(i->first, i->second, flags, true); } } else if (stdalgo::string::equalsci(name, "define")) { if (flags & FLAG_USE_COMPAT) throw CoreException("<define> tags may only be used in XML-style config (add <config format=\"xml\">)"); std::string varname = tag->getString("name"); std::string value = tag->getString("value"); if (varname.empty()) throw CoreException("Variable definition must include variable name"); stack.vars[varname] = value; } else if (stdalgo::string::equalsci(name, "config")) { std::string format = tag->getString("format"); if (stdalgo::string::equalsci(format, "xml")) flags &= ~FLAG_USE_COMPAT; else if (stdalgo::string::equalsci(format, "compat")) flags |= FLAG_USE_COMPAT; else if (!format.empty()) throw CoreException("Unknown configuration format " + format); } else { stack.output.insert(std::make_pair(name, tag)); } // this is not a leak; reference<> takes care of the delete tag = NULL; } bool outer_parse() { try { while (1) { int ch = next(true); switch (ch) { case EOF: // this is the one place where an EOF is not an error if (!mandatory_tag.empty()) throw CoreException("Mandatory tag \"" + mandatory_tag + "\" not found"); return true; case '#': comment(); break; case '<': dotag(); break; case ' ': case '\r': case '\t': case '\n': break; case 0xFE: case 0xFF: stack.errstr << "Do not save your files as UTF-16 or UTF-32, use UTF-8!\n"; /*@fallthrough@*/ default: throw CoreException("Syntax error - start of tag expected"); } } } catch (CoreException& err) { stack.errstr << err.GetReason() << " at " << current.str(); if (tag) stack.errstr << " (inside tag " << tag->tag << " at line " << tag->src_line << ")\n"; else stack.errstr << " (last tag was on line " << last_tag.line << ")\n"; } return false; } }; void ParseStack::DoInclude(ConfigTag* tag, int flags) { if (flags & FLAG_NO_INC) throw CoreException("Invalid <include> tag in file included with noinclude=\"yes\""); std::string mandatorytag; tag->readString("mandatorytag", mandatorytag); std::string name; if (tag->readString("file", name)) { if (tag->getBool("noinclude", false)) flags |= FLAG_NO_INC; if (tag->getBool("noexec", false)) flags |= FLAG_NO_EXEC; if (!ParseFile(ServerInstance->Config->Paths.PrependConfig(name), flags, mandatorytag)) throw CoreException("Included"); } else if (tag->readString("directory", name)) { if (tag->getBool("noinclude", false)) flags |= FLAG_NO_INC; if (tag->getBool("noexec", false)) flags |= FLAG_NO_EXEC; const std::string includedir = ServerInstance->Config->Paths.PrependConfig(name); std::vector<std::string> files; if (!FileSystem::GetFileList(includedir, files, "*.conf")) throw CoreException("Unable to read directory for include: " + includedir); std::sort(files.begin(), files.end()); for (std::vector<std::string>::const_iterator iter = files.begin(); iter != files.end(); ++iter) { const std::string path = includedir + '/' + *iter; if (!ParseFile(path, flags, mandatorytag)) throw CoreException("Included"); } } else if (tag->readString("executable", name)) { if (flags & FLAG_NO_EXEC) throw CoreException("Invalid <include:executable> tag in file included with noexec=\"yes\""); if (tag->getBool("noinclude", false)) flags |= FLAG_NO_INC; if (tag->getBool("noexec", true)) flags |= FLAG_NO_EXEC; if (!ParseFile(name, flags, mandatorytag, true)) throw CoreException("Included"); } } void ParseStack::DoReadFile(const std::string& key, const std::string& name, int flags, bool exec) { if (flags & FLAG_NO_INC) throw CoreException("Invalid <files> tag in file included with noinclude=\"yes\""); if (exec && (flags & FLAG_NO_EXEC)) throw CoreException("Invalid <execfiles> tag in file included with noexec=\"yes\""); std::string path = ServerInstance->Config->Paths.PrependConfig(name); FileWrapper file(exec ? popen(name.c_str(), "r") : fopen(path.c_str(), "r"), exec); if (!file) throw CoreException("Could not read \"" + path + "\" for \"" + key + "\" file"); file_cache& cache = FilesOutput[key]; cache.clear(); char linebuf[5120]; while (fgets(linebuf, sizeof(linebuf), file)) { size_t len = strlen(linebuf); if (len) { if (linebuf[len-1] == '\n') len--; cache.push_back(std::string(linebuf, len)); } } } bool ParseStack::ParseFile(const std::string& path, int flags, const std::string& mandatory_tag, bool isexec) { ServerInstance->Logs->Log("CONFIG", LOG_DEBUG, "Reading (isexec=%d) %s", isexec, path.c_str()); if (stdalgo::isin(reading, path)) throw CoreException((isexec ? "Executable " : "File ") + path + " is included recursively (looped inclusion)"); /* It's not already included, add it to the list of files we've loaded */ FileWrapper file((isexec ? popen(path.c_str(), "r") : fopen(path.c_str(), "r")), isexec); if (!file) throw CoreException("Could not read \"" + path + "\" for include"); reading.push_back(path); Parser p(*this, flags, file, path, mandatory_tag); bool ok = p.outer_parse(); reading.pop_back(); return ok; } bool ConfigTag::readString(const std::string& key, std::string& value, bool allow_lf) { for(ConfigItems::iterator j = items.begin(); j != items.end(); ++j) { if(j->first != key) continue; value = j->second; if (!allow_lf && (value.find('\n') != std::string::npos)) { ServerInstance->Logs->Log("CONFIG", LOG_DEFAULT, "Value of <" + tag + ":" + key + "> at " + getTagLocation() + " contains a linefeed, and linefeeds in this value are not permitted -- stripped to spaces."); for (std::string::iterator n = value.begin(); n != value.end(); n++) if (*n == '\n') *n = ' '; } return true; } return false; } std::string ConfigTag::getString(const std::string& key, const std::string& def, const TR1NS::function<bool(const std::string&)>& validator) { std::string res; if (!readString(key, res)) return def; if (!validator(res)) { ServerInstance->Logs->Log("CONFIG", LOG_DEFAULT, "WARNING: The value of <%s:%s> is not valid; value set to %s.", tag.c_str(), key.c_str(), def.c_str()); return def; } return res; } std::string ConfigTag::getString(const std::string& key, const std::string& def, size_t minlen, size_t maxlen) { std::string res; if (!readString(key, res)) return def; if (res.length() < minlen || res.length() > maxlen) { ServerInstance->Logs->Log("CONFIG", LOG_DEFAULT, "WARNING: The length of <%s:%s> is not between %ld and %ld; value set to %s.", tag.c_str(), key.c_str(), minlen, maxlen, def.c_str()); return def; } return res; } namespace { /** Check for an invalid magnitude specifier. If one is found a warning is logged and the * value is corrected (set to \p def). * @param tag The tag name; used in the warning message. * @param key The key name; used in the warning message. * @param val The full value set in the config as a string. * @param num The value to verify and modify if needed. * @param def The default value, \p res will be set to this if \p tail does not contain a. * valid magnitude specifier. * @param tail The location in the config value at which the magnifier is located. */ template <typename Numeric> void CheckMagnitude(const std::string& tag, const std::string& key, const std::string& val, Numeric& num, Numeric def, const char* tail) { // If this is NULL then no magnitude specifier was given. if (!*tail) return; switch (toupper(*tail)) { case 'K': num *= 1024; return; case 'M': num *= 1024 * 1024; return; case 'G': num *= 1024 * 1024 * 1024; return; } const std::string message = "WARNING: <" + tag + ":" + key + "> value of " + val + " contains an invalid magnitude specifier '" + tail + "'; value set to " + ConvToStr(def) + "."; ServerInstance->Logs->Log("CONFIG", LOG_DEFAULT, message); num = def; } /** Check for an out of range value. If the value falls outside the boundaries a warning is * logged and the value is corrected (set to \p def). * @param tag The tag name; used in the warning message. * @param key The key name; used in the warning message. * @param num The value to verify and modify if needed. * @param def The default value, \p res will be set to this if (min <= res <= max) doesn't hold true. * @param min Minimum accepted value for \p res. * @param max Maximum accepted value for \p res. */ template <typename Numeric> void CheckRange(const std::string& tag, const std::string& key, Numeric& num, Numeric def, Numeric min, Numeric max) { if (num >= min && num <= max) return; const std::string message = "WARNING: <" + tag + ":" + key + "> value of " + ConvToStr(num) + " is not between " + ConvToStr(min) + " and " + ConvToStr(max) + "; value set to " + ConvToStr(def) + "."; ServerInstance->Logs->Log("CONFIG", LOG_DEFAULT, message); num = def; } } long ConfigTag::getInt(const std::string &key, long def, long min, long max) { std::string result; if(!readString(key, result)) return def; const char* res_cstr = result.c_str(); char* res_tail = NULL; long res = strtol(res_cstr, &res_tail, 0); if (res_tail == res_cstr) return def; CheckMagnitude(tag, key, result, res, def, res_tail); CheckRange(tag, key, res, def, min, max); return res; } unsigned long ConfigTag::getUInt(const std::string& key, unsigned long def, unsigned long min, unsigned long max) { std::string result; if (!readString(key, result)) return def; const char* res_cstr = result.c_str(); char* res_tail = NULL; unsigned long res = strtoul(res_cstr, &res_tail, 0); if (res_tail == res_cstr) return def; CheckMagnitude(tag, key, result, res, def, res_tail); CheckRange(tag, key, res, def, min, max); return res; } unsigned long ConfigTag::getDuration(const std::string& key, unsigned long def, unsigned long min, unsigned long max) { std::string duration; if (!readString(key, duration)) return def; unsigned long ret; if (!InspIRCd::Duration(duration, ret)) { ServerInstance->Logs->Log("CONFIG", LOG_DEFAULT, "Value of <" + tag + ":" + key + "> at " + getTagLocation() + " is not a duration; value set to " + ConvToStr(def) + "."); return def; } CheckRange(tag, key, ret, def, min, max); return ret; } double ConfigTag::getFloat(const std::string& key, double def, double min, double max) { std::string result; if (!readString(key, result)) return def; double res = strtod(result.c_str(), NULL); CheckRange(tag, key, res, def, min, max); return res; } bool ConfigTag::getBool(const std::string &key, bool def) { std::string result; if(!readString(key, result)) return def; if (result == "yes" || result == "true" || result == "1" || result == "on") return true; if (result == "no" || result == "false" || result == "0" || result == "off") return false; ServerInstance->Logs->Log("CONFIG", LOG_DEFAULT, "Value of <" + tag + ":" + key + "> at " + getTagLocation() + " is not valid, ignoring"); return def; } std::string ConfigTag::getTagLocation() { return src_name + ":" + ConvToStr(src_line); } ConfigTag* ConfigTag::create(const std::string& Tag, const std::string& file, int line, ConfigItems*& Items) { ConfigTag* rv = new ConfigTag(Tag, file, line); Items = &rv->items; return rv; } ConfigTag::ConfigTag(const std::string& Tag, const std::string& file, int line) : tag(Tag), src_name(file), src_line(line) { } OperInfo::OperInfo(const std::string& Name) : name(Name) { } std::string OperInfo::getConfig(const std::string& key) { std::string rv; if (type_block) type_block->readString(key, rv); if (oper_block) oper_block->readString(key, rv); return rv; } ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/src/configreader.cpp�����������������������������������������������������������������0000664�0000000�0000000�00000056134�13554550454�0017277�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * InspIRCd -- Internet Relay Chat Daemon * * Copyright (C) 2009-2010 Daniel De Graaf <danieldg@inspircd.org> * Copyright (C) 2007-2009 Robin Burchell <robin+git@viroteck.net> * Copyright (C) 2006-2009 Dennis Friis <peavey@inspircd.org> * Copyright (C) 2006-2008 Craig Edwards <craigedwards@brainbox.cc> * Copyright (C) 2008 Thomas Stagner <aquanight@inspircd.org> * Copyright (C) 2006 Oliver Lupton <oliverlupton@gmail.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 "inspircd.h" #include "xline.h" #include "listmode.h" #include "exitcodes.h" #include "configparser.h" #include <iostream> ServerLimits::ServerLimits(ConfigTag* tag) : NickMax(tag->getUInt("maxnick", 30)) , ChanMax(tag->getUInt("maxchan", 64)) , MaxModes(tag->getUInt("maxmodes", 20)) , IdentMax(tag->getUInt("maxident", 10)) , MaxQuit(tag->getUInt("maxquit", 255)) , MaxTopic(tag->getUInt("maxtopic", 307)) , MaxKick(tag->getUInt("maxkick", 255)) , MaxReal(tag->getUInt("maxreal", tag->getUInt("maxgecos", 128))) , MaxAway(tag->getUInt("maxaway", 200)) , MaxLine(tag->getUInt("maxline", 512)) , MaxHost(tag->getUInt("maxhost", 64)) { } ServerConfig::ServerPaths::ServerPaths(ConfigTag* tag) : Config(tag->getString("configdir", INSPIRCD_CONFIG_PATH)) , Data(tag->getString("datadir", INSPIRCD_DATA_PATH)) , Log(tag->getString("logdir", INSPIRCD_LOG_PATH)) , Module(tag->getString("moduledir", INSPIRCD_MODULE_PATH)) { } static ConfigTag* CreateEmptyTag() { ConfigItems* items; return ConfigTag::create("empty", "<auto>", 0, items); } ServerConfig::ServerConfig() : EmptyTag(CreateEmptyTag()) , Limits(EmptyTag) , Paths(EmptyTag) , RawLog(false) , NoSnoticeStack(false) { } ServerConfig::~ServerConfig() { delete EmptyTag; } static void ReadXLine(ServerConfig* conf, const std::string& tag, const std::string& key, XLineFactory* make) { insp::flat_set<std::string> configlines; ConfigTagList tags = conf->ConfTags(tag); for(ConfigIter i = tags.first; i != tags.second; ++i) { ConfigTag* ctag = i->second; std::string mask; if (!ctag->readString(key, mask)) throw CoreException("<"+tag+":"+key+"> missing at " + ctag->getTagLocation()); std::string reason = ctag->getString("reason", "<Config>"); XLine* xl = make->Generate(ServerInstance->Time(), 0, "<Config>", reason, mask); xl->from_config = true; configlines.insert(xl->Displayable()); if (!ServerInstance->XLines->AddLine(xl, NULL)) delete xl; } ServerInstance->XLines->ExpireRemovedConfigLines(make->GetType(), configlines); } typedef std::map<std::string, ConfigTag*> LocalIndex; void ServerConfig::CrossCheckOperClassType() { LocalIndex operclass; ConfigTagList tags = ConfTags("class"); for(ConfigIter i = tags.first; i != tags.second; ++i) { ConfigTag* tag = i->second; std::string name = tag->getString("name"); if (name.empty()) throw CoreException("<class:name> missing from tag at " + tag->getTagLocation()); if (operclass.find(name) != operclass.end()) throw CoreException("Duplicate class block with name " + name + " at " + tag->getTagLocation()); operclass[name] = tag; } tags = ConfTags("type"); for(ConfigIter i = tags.first; i != tags.second; ++i) { ConfigTag* tag = i->second; std::string name = tag->getString("name"); if (name.empty()) throw CoreException("<type:name> is missing from tag at " + tag->getTagLocation()); if (OperTypes.find(name) != OperTypes.end()) throw CoreException("Duplicate type block with name " + name + " at " + tag->getTagLocation()); OperInfo* ifo = new OperInfo(name); OperTypes[name] = ifo; ifo->type_block = tag; std::string classname; irc::spacesepstream str(tag->getString("classes")); while (str.GetToken(classname)) { LocalIndex::iterator cls = operclass.find(classname); if (cls == operclass.end()) throw CoreException("Oper type " + name + " has missing class " + classname); ifo->class_blocks.push_back(cls->second); } } tags = ConfTags("oper"); for(ConfigIter i = tags.first; i != tags.second; ++i) { ConfigTag* tag = i->second; std::string name = tag->getString("name"); if (name.empty()) throw CoreException("<oper:name> missing from tag at " + tag->getTagLocation()); std::string type = tag->getString("type"); OperIndex::iterator tblk = OperTypes.find(type); if (tblk == OperTypes.end()) throw CoreException("Oper block " + name + " has missing type " + type); if (oper_blocks.find(name) != oper_blocks.end()) throw CoreException("Duplicate oper block with name " + name + " at " + tag->getTagLocation()); OperInfo* ifo = new OperInfo(type); ifo->oper_block = tag; ifo->type_block = tblk->second->type_block; ifo->class_blocks.assign(tblk->second->class_blocks.begin(), tblk->second->class_blocks.end()); oper_blocks[name] = ifo; } } void ServerConfig::CrossCheckConnectBlocks(ServerConfig* current) { typedef std::map<std::string, ConnectClass*> ClassMap; ClassMap oldBlocksByMask; if (current) { for(ClassVector::iterator i = current->Classes.begin(); i != current->Classes.end(); ++i) { ConnectClass* c = *i; if (c->name.compare(0, 8, "unnamed-", 8)) { oldBlocksByMask["n" + c->name] = c; } else if (c->type == CC_ALLOW || c->type == CC_DENY) { std::string typeMask = (c->type == CC_ALLOW) ? "a" : "d"; typeMask += c->host; oldBlocksByMask[typeMask] = c; } } } size_t blk_count = config_data.count("connect"); if (blk_count == 0) { // No connect blocks found; make a trivial default block ConfigItems* items; ConfigTag* tag = ConfigTag::create("connect", "<auto>", 0, items); (*items)["allow"] = "*"; config_data.insert(std::make_pair("connect", tag)); blk_count = 1; } Classes.resize(blk_count); std::map<std::string, size_t> names; bool try_again = true; for(size_t tries = 0; try_again; tries++) { try_again = false; ConfigTagList tags = ConfTags("connect"); size_t i = 0; for(ConfigIter it = tags.first; it != tags.second; ++it, ++i) { ConfigTag* tag = it->second; if (Classes[i]) continue; ConnectClass* parent = NULL; std::string parentName = tag->getString("parent"); if (!parentName.empty()) { std::map<std::string, size_t>::const_iterator parentIter = names.find(parentName); if (parentIter == names.end()) { try_again = true; // couldn't find parent this time. If it's the last time, we'll never find it. if (tries >= blk_count) throw CoreException("Could not find parent connect class \"" + parentName + "\" for connect block at " + tag->getTagLocation()); continue; } parent = Classes[parentIter->second]; } std::string name = tag->getString("name"); std::string mask, typeMask; char type; if (tag->readString("allow", mask, false)) { type = CC_ALLOW; typeMask = 'a' + mask; } else if (tag->readString("deny", mask, false)) { type = CC_DENY; typeMask = 'd' + mask; } else if (!name.empty()) { type = CC_NAMED; mask = name; typeMask = 'n' + mask; } else { throw CoreException("Connect class must have allow, deny, or name specified at " + tag->getTagLocation()); } if (name.empty()) { name = "unnamed-" + ConvToStr(i); } else { typeMask = 'n' + name; } if (names.find(name) != names.end()) throw CoreException("Two connect classes with name \"" + name + "\" defined!"); names[name] = i; ConnectClass* me = parent ? new ConnectClass(tag, type, mask, *parent) : new ConnectClass(tag, type, mask); me->name = name; me->registration_timeout = tag->getDuration("timeout", me->registration_timeout); me->pingtime = tag->getDuration("pingfreq", me->pingtime); std::string sendq; if (tag->readString("sendq", sendq)) { // attempt to guess a good hard/soft sendq from a single value unsigned long value = strtoul(sendq.c_str(), NULL, 10); if (value > 16384) me->softsendqmax = value / 16; else me->softsendqmax = value; me->hardsendqmax = value * 8; } me->softsendqmax = tag->getUInt("softsendq", me->softsendqmax); me->hardsendqmax = tag->getUInt("hardsendq", me->hardsendqmax); me->recvqmax = tag->getUInt("recvq", me->recvqmax); me->penaltythreshold = tag->getUInt("threshold", me->penaltythreshold); me->commandrate = tag->getUInt("commandrate", me->commandrate); me->fakelag = tag->getBool("fakelag", me->fakelag); me->maxlocal = tag->getUInt("localmax", me->maxlocal); me->maxglobal = tag->getUInt("globalmax", me->maxglobal); me->maxchans = tag->getUInt("maxchans", me->maxchans); me->maxconnwarn = tag->getBool("maxconnwarn", me->maxconnwarn); me->limit = tag->getUInt("limit", me->limit); me->resolvehostnames = tag->getBool("resolvehostnames", me->resolvehostnames); std::string ports = tag->getString("port"); if (!ports.empty()) { irc::portparser portrange(ports, false); while (int port = portrange.GetToken()) me->ports.insert(port); } ClassMap::iterator oldMask = oldBlocksByMask.find(typeMask); if (oldMask != oldBlocksByMask.end()) { ConnectClass* old = oldMask->second; oldBlocksByMask.erase(oldMask); old->Update(me); delete me; me = old; } Classes[i] = me; } } } static std::string GetServerName() { #ifndef _WIN32 char hostname[256]; if (gethostname(hostname, sizeof(hostname)) == 0) { std::string name(hostname); if (name.find('.') == std::string::npos) name.push_back('.'); if (name.length() <= ServerInstance->Config->Limits.MaxHost && InspIRCd::IsHost(name)) return name; } #endif return "irc.example.com"; } void ServerConfig::Fill() { ConfigTag* options = ConfValue("options"); ConfigTag* security = ConfValue("security"); ConfigTag* server = ConfValue("server"); if (sid.empty()) { ServerName = server->getString("name", GetServerName(), InspIRCd::IsHost); sid = server->getString("id"); if (!sid.empty() && !InspIRCd::IsSID(sid)) throw CoreException(sid + " is not a valid server ID. A server ID must be 3 characters long, with the first character a digit and the next two characters a digit or letter."); CaseMapping = options->getString("casemapping", "rfc1459"); if (CaseMapping == "ascii") national_case_insensitive_map = ascii_case_insensitive_map; else if (CaseMapping == "rfc1459") national_case_insensitive_map = rfc_case_insensitive_map; else throw CoreException("<options:casemapping> must be set to 'ascii', or 'rfc1459'"); } else { std::string name = server->getString("name"); if (!name.empty() && name != ServerName) throw CoreException("You must restart to change the server name"); std::string nsid = server->getString("id"); if (!nsid.empty() && nsid != sid) throw CoreException("You must restart to change the server id"); std::string casemapping = options->getString("casemapping"); if (!casemapping.empty() && casemapping != CaseMapping) throw CoreException("You must restart to change the server casemapping"); } SoftLimit = ConfValue("performance")->getUInt("softlimit", (SocketEngine::GetMaxFds() > 0 ? SocketEngine::GetMaxFds() : LONG_MAX), 10); CCOnConnect = ConfValue("performance")->getBool("clonesonconnect", true); MaxConn = ConfValue("performance")->getUInt("somaxconn", SOMAXCONN); TimeSkipWarn = ConfValue("performance")->getDuration("timeskipwarn", 2, 0, 30); XLineMessage = options->getString("xlinemessage", options->getString("moronbanner", "You're banned!")); ServerDesc = server->getString("description", "Configure Me"); Network = server->getString("network", "Network"); NetBufferSize = ConfValue("performance")->getInt("netbuffersize", 10240, 1024, 65534); CustomVersion = security->getString("customversion"); HideBans = security->getBool("hidebans"); HideServer = security->getString("hideserver", security->getString("hidewhois")); SyntaxHints = options->getBool("syntaxhints"); FullHostInTopic = options->getBool("hostintopic"); MaxTargets = security->getUInt("maxtargets", 20, 1, 31); DefaultModes = options->getString("defaultmodes", "not"); PID = ConfValue("pid")->getString("file"); MaxChans = ConfValue("channels")->getUInt("users", 20); OperMaxChans = ConfValue("channels")->getUInt("opers", 0); c_ipv4_range = ConfValue("cidr")->getUInt("ipv4clone", 32, 1, 32); c_ipv6_range = ConfValue("cidr")->getUInt("ipv6clone", 128, 1, 128); Limits = ServerLimits(ConfValue("limits")); Paths = ServerPaths(ConfValue("path")); NoSnoticeStack = options->getBool("nosnoticestack", false); std::string defbind = options->getString("defaultbind"); if (stdalgo::string::equalsci(defbind, "ipv4")) { WildcardIPv6 = false; } else if (stdalgo::string::equalsci(defbind, "ipv6")) { WildcardIPv6 = true; } else { WildcardIPv6 = true; int socktest = socket(AF_INET6, SOCK_STREAM, 0); if (socktest < 0) WildcardIPv6 = false; else SocketEngine::Close(socktest); } ReadXLine(this, "badip", "ipmask", ServerInstance->XLines->GetFactory("Z")); ReadXLine(this, "badnick", "nick", ServerInstance->XLines->GetFactory("Q")); ReadXLine(this, "badhost", "host", ServerInstance->XLines->GetFactory("K")); ReadXLine(this, "exception", "host", ServerInstance->XLines->GetFactory("E")); const std::string restrictbannedusers = options->getString("restrictbannedusers", "yes"); if (stdalgo::string::equalsci(restrictbannedusers, "no")) RestrictBannedUsers = ServerConfig::BUT_NORMAL; else if (stdalgo::string::equalsci(restrictbannedusers, "silent")) RestrictBannedUsers = ServerConfig::BUT_RESTRICT_SILENT; else if (stdalgo::string::equalsci(restrictbannedusers, "yes")) RestrictBannedUsers = ServerConfig::BUT_RESTRICT_NOTIFY; else throw CoreException(restrictbannedusers + " is an invalid <options:restrictbannedusers> value, at " + options->getTagLocation()); } // WARNING: it is not safe to use most of the codebase in this function, as it // will run in the config reader thread void ServerConfig::Read() { /* Load and parse the config file, if there are any errors then explode */ ParseStack stack(this); try { valid = stack.ParseFile(ServerInstance->ConfigFileName, 0); } catch (CoreException& err) { valid = false; errstr << err.GetReason() << std::endl; } } void ServerConfig::Apply(ServerConfig* old, const std::string &useruid) { valid = true; if (old) { /* * These values can only be set on boot. Keep their old values. Do it before we send messages so we actually have a servername. */ this->CaseMapping = old->CaseMapping; this->ServerName = old->ServerName; this->sid = old->sid; this->cmdline = old->cmdline; } /* The stuff in here may throw CoreException, be sure we're in a position to catch it. */ try { // Ensure the user has actually edited ther config. ConfigTagList dietags = ConfTags("die"); if (dietags.first != dietags.second) { errstr << "Your configuration has not been edited correctly!" << std::endl; for (ConfigIter iter = dietags.first; iter != dietags.second; ++iter) { ConfigTag* tag = iter->second; const std::string reason = tag->getString("reason", "You left a <die> tag in your config", 1); errstr << reason << " (at " << tag->getTagLocation() << ")" << std::endl; } } Fill(); // Handle special items CrossCheckOperClassType(); CrossCheckConnectBlocks(old); } catch (CoreException &ce) { errstr << ce.GetReason() << std::endl; } // Check errors before dealing with failed binds, since continuing on failed bind is wanted in some circumstances. valid = errstr.str().empty(); // write once here, to try it out and make sure its ok if (valid) ServerInstance->WritePID(this->PID, !old); ConfigTagList binds = ConfTags("bind"); if (binds.first == binds.second) errstr << "Possible configuration error: you have not defined any <bind> blocks." << std::endl << "You will need to do this if you want clients to be able to connect!" << std::endl; if (old && valid) { // On first run, ports are bound later on FailedPortList pl; ServerInstance->BindPorts(pl); if (pl.size()) { errstr << "Not all your client ports could be bound." << std::endl << "The following port(s) failed to bind:" << std::endl; int j = 1; for (FailedPortList::iterator i = pl.begin(); i != pl.end(); i++, j++) { errstr << j << ".\tAddress: " << i->first.str() << "\tReason: " << strerror(i->second) << std::endl; } } } User* user = useruid.empty() ? NULL : ServerInstance->FindNick(useruid); if (!valid) { ServerInstance->Logs->Log("CONFIG", LOG_DEFAULT, "There were errors in your configuration file:"); Classes.clear(); } while (errstr.good()) { std::string line; getline(errstr, line, '\n'); if (line.empty()) continue; // On startup, print out to console (still attached at this point) if (!old) std::cout << line << std::endl; // If a user is rehashing, tell them directly if (user) user->WriteRemoteNotice(InspIRCd::Format("*** %s", line.c_str())); // Also tell opers ServerInstance->SNO->WriteGlobalSno('a', line); } errstr.clear(); errstr.str(std::string()); /* No old configuration -> initial boot, nothing more to do here */ if (!old) { if (!valid) { ServerInstance->Exit(EXIT_STATUS_CONFIG); } return; } // If there were errors processing configuration, don't touch modules. if (!valid) return; ApplyModules(user); if (user) user->WriteRemoteNotice("*** Successfully rehashed server."); ServerInstance->SNO->WriteGlobalSno('a', "*** Successfully rehashed server."); } void ServerConfig::ApplyModules(User* user) { std::vector<std::string> added_modules; ModuleManager::ModuleMap removed_modules = ServerInstance->Modules->GetModules(); ConfigTagList tags = ConfTags("module"); for(ConfigIter i = tags.first; i != tags.second; ++i) { ConfigTag* tag = i->second; std::string name; if (tag->readString("name", name)) { name = ModuleManager::ExpandModName(name); // if this module is already loaded, the erase will succeed, so we need do nothing // otherwise, we need to add the module (which will be done later) if (removed_modules.erase(name) == 0) added_modules.push_back(name); } } for (ModuleManager::ModuleMap::iterator i = removed_modules.begin(); i != removed_modules.end(); ++i) { const std::string& modname = i->first; // Don't remove core_*.so, just remove m_*.so if (InspIRCd::Match(modname, "core_*.so", ascii_case_insensitive_map)) continue; if (ServerInstance->Modules->Unload(i->second)) { ServerInstance->SNO->WriteGlobalSno('a', "*** REHASH UNLOADED MODULE: %s", modname.c_str()); if (user) user->WriteNumeric(RPL_UNLOADEDMODULE, modname, InspIRCd::Format("Module %s successfully unloaded.", modname.c_str())); else ServerInstance->SNO->WriteGlobalSno('a', "Module %s successfully unloaded.", modname.c_str()); } else { if (user) user->WriteNumeric(ERR_CANTUNLOADMODULE, modname, InspIRCd::Format("Failed to unload module %s: %s", modname.c_str(), ServerInstance->Modules->LastError().c_str())); else ServerInstance->SNO->WriteGlobalSno('a', "Failed to unload module %s: %s", modname.c_str(), ServerInstance->Modules->LastError().c_str()); } } for (std::vector<std::string>::iterator adding = added_modules.begin(); adding != added_modules.end(); adding++) { // Skip modules which are already loaded. if (ServerInstance->Modules->Find(*adding)) continue; if (ServerInstance->Modules->Load(*adding)) { ServerInstance->SNO->WriteGlobalSno('a', "*** REHASH LOADED MODULE: %s",adding->c_str()); if (user) user->WriteNumeric(RPL_LOADEDMODULE, *adding, InspIRCd::Format("Module %s successfully loaded.", adding->c_str())); else ServerInstance->SNO->WriteGlobalSno('a', "Module %s successfully loaded.", adding->c_str()); } else { if (user) user->WriteNumeric(ERR_CANTLOADMODULE, *adding, InspIRCd::Format("Failed to load module %s: %s", adding->c_str(), ServerInstance->Modules->LastError().c_str())); else ServerInstance->SNO->WriteGlobalSno('a', "Failed to load module %s: %s", adding->c_str(), ServerInstance->Modules->LastError().c_str()); } } } ConfigTag* ServerConfig::ConfValue(const std::string &tag) { ConfigTagList found = config_data.equal_range(tag); if (found.first == found.second) return EmptyTag; ConfigTag* rv = found.first->second; found.first++; if (found.first != found.second) ServerInstance->Logs->Log("CONFIG", LOG_DEFAULT, "Multiple <" + tag + "> tags found; only first will be used " "(first at " + rv->getTagLocation() + "; second at " + found.first->second->getTagLocation() + ")"); return rv; } ConfigTagList ServerConfig::ConfTags(const std::string& tag) { return config_data.equal_range(tag); } std::string ServerConfig::Escape(const std::string& str, bool xml) { std::string escaped; for (std::string::const_iterator it = str.begin(); it != str.end(); ++it) { switch (*it) { case '"': escaped += xml ? "&quot;" : "\""; break; case '&': escaped += xml ? "&amp;" : "&"; break; case '\\': escaped += xml ? "\\" : "\\\\"; break; default: escaped += *it; break; } } return escaped; } void ConfigReaderThread::Run() { Config->Read(); done = true; } void ConfigReaderThread::Finish() { ServerConfig* old = ServerInstance->Config; ServerInstance->Logs->Log("CONFIG", LOG_DEBUG, "Switching to new configuration..."); ServerInstance->Config = this->Config; Config->Apply(old, TheUserUID); if (Config->valid) { /* * Apply the changed configuration from the rehash. * * XXX: The order of these is IMPORTANT, do not reorder them without testing * thoroughly!!! */ ServerInstance->Users.RehashCloneCounts(); ServerInstance->XLines->CheckELines(); ServerInstance->XLines->ApplyLines(); User* user = ServerInstance->FindNick(TheUserUID); ConfigStatus status(user); const ModuleManager::ModuleMap& mods = ServerInstance->Modules->GetModules(); for (ModuleManager::ModuleMap::const_iterator i = mods.begin(); i != mods.end(); ++i) { try { ServerInstance->Logs->Log("MODULE", LOG_DEBUG, "Rehashing " + i->first); i->second->ReadConfig(status); } catch (CoreException& modex) { ServerInstance->Logs->Log("MODULE", LOG_DEFAULT, "Exception caught: " + modex.GetReason()); if (user) user->WriteNotice(i->first + ": " + modex.GetReason()); } } // The description of this server may have changed - update it for WHOIS etc. ServerInstance->FakeClient->server->description = Config->ServerDesc; ServerInstance->ISupport.Build(); ServerInstance->Logs->CloseLogs(); ServerInstance->Logs->OpenFileLogs(); if (Config->RawLog && !old->RawLog) ServerInstance->Users->ServerNoticeAll("*** Raw I/O logging is enabled on this server. All messages, passwords, and commands are being recorded."); Config = old; } else { // whoops, abort! ServerInstance->Config = old; } } ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/src/coremods/������������������������������������������������������������������������0000775�0000000�0000000�00000000000�13554550454�0015745�5����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/src/coremods/core_channel/�����������������������������������������������������������0000775�0000000�0000000�00000000000�13554550454�0020365�5����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/src/coremods/core_channel/cmd_invite.cpp���������������������������������������������0000664�0000000�0000000�00000012470�13554550454�0023216�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * InspIRCd -- Internet Relay Chat Daemon * * Copyright (C) 2009 Daniel De Graaf <danieldg@inspircd.org> * Copyright (C) 2007-2008 Robin Burchell <robin+git@viroteck.net> * Copyright (C) 2008 Craig Edwards <craigedwards@brainbox.cc> * Copyright (C) 2008 Thomas Stagner <aquanight@inspircd.org> * * This file is part of InspIRCd. InspIRCd is free software: you can * redistribute it and/or modify it under the terms of the GNU General Public * License as published by the Free Software Foundation, version 2. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include "inspircd.h" #include "core_channel.h" #include "invite.h" CommandInvite::CommandInvite(Module* parent, Invite::APIImpl& invapiimpl) : Command(parent, "INVITE", 0, 0) , invapi(invapiimpl) { Penalty = 4; syntax = "[<nick> <channel> [<time>]]"; } /** Handle /INVITE */ CmdResult CommandInvite::Handle(User* user, const Params& parameters) { ModResult MOD_RESULT; if (parameters.size() >= 2) { User* u; if (IS_LOCAL(user)) u = ServerInstance->FindNickOnly(parameters[0]); else u = ServerInstance->FindNick(parameters[0]); Channel* c = ServerInstance->FindChan(parameters[1]); time_t timeout = 0; if (parameters.size() >= 3) { if (IS_LOCAL(user)) { unsigned long duration; if (!InspIRCd::Duration(parameters[2], duration)) { user->WriteNotice("*** Invalid duration for invite"); return CMD_FAILURE; } timeout = ServerInstance->Time() + duration; } else if (parameters.size() > 3) timeout = ConvToNum<time_t>(parameters[3]); } if (!c) { user->WriteNumeric(Numerics::NoSuchChannel(parameters[1])); return CMD_FAILURE; } if ((!u) || (u->registered != REG_ALL)) { user->WriteNumeric(Numerics::NoSuchNick(parameters[0])); return CMD_FAILURE; } // Verify channel timestamp if the INVITE is coming from a remote server if (!IS_LOCAL(user)) { // Remote INVITE commands must carry a channel timestamp if (parameters.size() < 3) return CMD_INVALID; // Drop the invite if our channel TS is lower time_t RemoteTS = ConvToNum<time_t>(parameters[2]); if (c->age < RemoteTS) return CMD_FAILURE; } if ((IS_LOCAL(user)) && (!c->HasUser(user))) { user->WriteNumeric(ERR_NOTONCHANNEL, c->name, "You're not on that channel!"); return CMD_FAILURE; } if (c->HasUser(u)) { user->WriteNumeric(ERR_USERONCHANNEL, u->nick, c->name, "is already on channel"); return CMD_FAILURE; } FIRST_MOD_RESULT(OnUserPreInvite, MOD_RESULT, (user,u,c,timeout)); if (MOD_RESULT == MOD_RES_DENY) { return CMD_FAILURE; } else if (MOD_RESULT == MOD_RES_PASSTHRU) { if (IS_LOCAL(user)) { unsigned int rank = c->GetPrefixValue(user); if (rank < HALFOP_VALUE) { // Check whether halfop mode is available and phrase error message accordingly ModeHandler* mh = ServerInstance->Modes->FindMode('h', MODETYPE_CHANNEL); user->WriteNumeric(ERR_CHANOPRIVSNEEDED, c->name, InspIRCd::Format("You must be a channel %soperator", (mh && mh->name == "halfop" ? "half-" : ""))); return CMD_FAILURE; } } } LocalUser* const localtargetuser = IS_LOCAL(u); if (localtargetuser) { invapi.Create(localtargetuser, c, timeout); ClientProtocol::Messages::Invite invitemsg(user, localtargetuser, c); localtargetuser->Send(ServerInstance->GetRFCEvents().invite, invitemsg); } if (IS_LOCAL(user)) { user->WriteNumeric(RPL_INVITING, u->nick, c->name); if (u->IsAway()) user->WriteNumeric(RPL_AWAY, u->nick, u->awaymsg); } char prefix = 0; unsigned int minrank = 0; switch (announceinvites) { case Invite::ANNOUNCE_OPS: { prefix = '@'; minrank = OP_VALUE; break; } case Invite::ANNOUNCE_DYNAMIC: { PrefixMode* mh = ServerInstance->Modes->FindPrefixMode('h'); if ((mh) && (mh->name == "halfop")) { prefix = mh->GetPrefix(); minrank = mh->GetPrefixRank(); } break; } default: { } } CUList excepts; FOREACH_MOD(OnUserInvite, (user, u, c, timeout, minrank, excepts)); if (announceinvites != Invite::ANNOUNCE_NONE) { excepts.insert(user); ClientProtocol::Messages::Privmsg privmsg(ServerInstance->FakeClient, c, InspIRCd::Format("*** %s invited %s into the channel", user->nick.c_str(), u->nick.c_str()), MSG_NOTICE); c->Write(ServerInstance->GetRFCEvents().privmsg, privmsg, prefix, excepts); } } else if (IS_LOCAL(user)) { // pinched from ircu - invite with not enough parameters shows channels // youve been invited to but haven't joined yet. const Invite::List* list = invapi.GetList(IS_LOCAL(user)); if (list) { for (Invite::List::const_iterator i = list->begin(); i != list->end(); ++i) user->WriteNumeric(RPL_INVITELIST, (*i)->chan->name); } user->WriteNumeric(RPL_ENDOFINVITELIST, "End of INVITE list"); } return CMD_SUCCESS; } RouteDescriptor CommandInvite::GetRouting(User* user, const Params& parameters) { return (IS_LOCAL(user) ? ROUTE_LOCALONLY : ROUTE_BROADCAST); } ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/src/coremods/core_channel/cmd_join.cpp�����������������������������������������������0000664�0000000�0000000�00000003236�13554550454�0022657�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * InspIRCd -- Internet Relay Chat Daemon * * Copyright (C) 2009 Daniel De Graaf <danieldg@inspircd.org> * Copyright (C) 2007 Robin Burchell <robin+git@viroteck.net> * * 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 "inspircd.h" #include "core_channel.h" CommandJoin::CommandJoin(Module* parent) : SplitCommand(parent, "JOIN", 1, 2) { syntax = "<channel>[,<channel>]+ [<key>[,<key>]+]"; Penalty = 2; } /** Handle /JOIN */ CmdResult CommandJoin::HandleLocal(LocalUser* user, const Params& parameters) { if (parameters.size() > 1) { if (CommandParser::LoopCall(user, this, parameters, 0, 1, false)) return CMD_SUCCESS; if (ServerInstance->IsChannel(parameters[0])) { Channel::JoinUser(user, parameters[0], false, parameters[1]); return CMD_SUCCESS; } } else { if (CommandParser::LoopCall(user, this, parameters, 0, -1, false)) return CMD_SUCCESS; if (ServerInstance->IsChannel(parameters[0])) { Channel::JoinUser(user, parameters[0]); return CMD_SUCCESS; } } user->WriteNumeric(ERR_BADCHANMASK, parameters[0], "Invalid channel name"); return CMD_FAILURE; } ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/src/coremods/core_channel/cmd_kick.cpp�����������������������������������������������0000664�0000000�0000000�00000007561�13554550454�0022646�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * InspIRCd -- Internet Relay Chat Daemon * * Copyright (C) 2009 Daniel De Graaf <danieldg@inspircd.org> * Copyright (C) 2007 Robin Burchell <robin+git@viroteck.net> * * 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 "inspircd.h" #include "core_channel.h" CommandKick::CommandKick(Module* parent) : Command(parent, "KICK", 2, 3) { syntax = "<channel> <nick>[,<nick>]+ [:<reason>]"; } /** Handle /KICK */ CmdResult CommandKick::Handle(User* user, const Params& parameters) { Channel* c = ServerInstance->FindChan(parameters[0]); User* u; if (CommandParser::LoopCall(user, this, parameters, 1)) return CMD_SUCCESS; if (IS_LOCAL(user)) u = ServerInstance->FindNickOnly(parameters[1]); else u = ServerInstance->FindNick(parameters[1]); if (!c) { user->WriteNumeric(Numerics::NoSuchChannel(parameters[0])); return CMD_FAILURE; } if ((!u) || (u->registered != REG_ALL)) { user->WriteNumeric(Numerics::NoSuchNick(parameters[1])); return CMD_FAILURE; } Membership* srcmemb = NULL; if (IS_LOCAL(user)) { srcmemb = c->GetUser(user); if (!srcmemb) { user->WriteNumeric(ERR_NOTONCHANNEL, parameters[0], "You're not on that channel!"); return CMD_FAILURE; } if (u->server->IsULine()) { user->WriteNumeric(ERR_CHANOPRIVSNEEDED, c->name, "You may not kick a U-lined client"); return CMD_FAILURE; } } const Channel::MemberMap::iterator victimiter = c->userlist.find(u); if (victimiter == c->userlist.end()) { user->WriteNumeric(ERR_USERNOTINCHANNEL, u->nick, c->name, "They are not on that channel"); return CMD_FAILURE; } Membership* const memb = victimiter->second; // KICKs coming from servers can carry a membership id if ((!IS_LOCAL(user)) && (parameters.size() > 3)) { // If the current membership id is not equal to the one in the message then the user rejoined if (memb->id != Membership::IdFromString(parameters[2])) { ServerInstance->Logs->Log(MODNAME, LOG_DEBUG, "Dropped KICK due to membership id mismatch: " + ConvToStr(memb->id) + " != " + parameters[2]); return CMD_FAILURE; } } const bool has_reason = (parameters.size() > 2); const std::string reason((has_reason ? parameters.back() : user->nick), 0, ServerInstance->Config->Limits.MaxKick); // Do the following checks only if the KICK is done by a local user; // each server enforces its own rules. if (srcmemb) { // Modules are allowed to explicitly allow or deny kicks done by local users ModResult res; FIRST_MOD_RESULT(OnUserPreKick, res, (user, memb, reason)); if (res == MOD_RES_DENY) return CMD_FAILURE; if (res == MOD_RES_PASSTHRU) { unsigned int them = srcmemb->getRank(); unsigned int req = HALFOP_VALUE; for (std::string::size_type i = 0; i < memb->modes.length(); i++) { ModeHandler* mh = ServerInstance->Modes->FindMode(memb->modes[i], MODETYPE_CHANNEL); if (mh && mh->GetLevelRequired(true) > req) req = mh->GetLevelRequired(true); } if (them < req) { user->WriteNumeric(ERR_CHANOPRIVSNEEDED, c->name, InspIRCd::Format("You must be a channel %soperator", req > HALFOP_VALUE ? "" : "half-")); return CMD_FAILURE; } } } c->KickUser(user, victimiter, reason); return CMD_SUCCESS; } RouteDescriptor CommandKick::GetRouting(User* user, const Params& parameters) { return (IS_LOCAL(user) ? ROUTE_LOCALONLY : ROUTE_BROADCAST); } �����������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/src/coremods/core_channel/cmd_names.cpp����������������������������������������������0000664�0000000�0000000�00000006510�13554550454�0023021�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * InspIRCd -- Internet Relay Chat Daemon * * Copyright (C) 2009 Daniel De Graaf <danieldg@inspircd.org> * Copyright (C) 2007 Robin Burchell <robin+git@viroteck.net> * * 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 "inspircd.h" #include "core_channel.h" #include "modules/names.h" CommandNames::CommandNames(Module* parent) : SplitCommand(parent, "NAMES", 0, 0) , secretmode(parent, "secret") , privatemode(parent, "private") , invisiblemode(parent, "invisible") , namesevprov(parent, "event/names") { syntax = "[<channel>[,<channel>]+]"; } /** Handle /NAMES */ CmdResult CommandNames::HandleLocal(LocalUser* user, const Params& parameters) { Channel* c; if (parameters.empty()) { user->WriteNumeric(RPL_ENDOFNAMES, '*', "End of /NAMES list."); return CMD_SUCCESS; } if (CommandParser::LoopCall(user, this, parameters, 0)) return CMD_SUCCESS; c = ServerInstance->FindChan(parameters[0]); if (c) { // Show the NAMES list if one of the following is true: // - the channel is not secret // - the user doing the /NAMES is inside the channel // - the user doing the /NAMES has the channels/auspex privilege // If the user is inside the channel or has privs, instruct SendNames() to show invisible (+i) members bool show_invisible = ((c->HasUser(user)) || (user->HasPrivPermission("channels/auspex"))); if ((show_invisible) || (!c->IsModeSet(secretmode))) { SendNames(user, c, show_invisible); return CMD_SUCCESS; } } user->WriteNumeric(Numerics::NoSuchChannel(parameters[0])); return CMD_FAILURE; } void CommandNames::SendNames(LocalUser* user, Channel* chan, bool show_invisible) { Numeric::Builder<' '> reply(user, RPL_NAMREPLY, false, chan->name.size() + 3); Numeric::Numeric& numeric = reply.GetNumeric(); if (chan->IsModeSet(secretmode)) numeric.push(std::string(1, '@')); else if (chan->IsModeSet(privatemode)) numeric.push(std::string(1, '*')); else numeric.push(std::string(1, '=')); numeric.push(chan->name); numeric.push(std::string()); std::string prefixlist; std::string nick; const Channel::MemberMap& members = chan->GetUsers(); for (Channel::MemberMap::const_iterator i = members.begin(); i != members.end(); ++i) { if ((!show_invisible) && (i->first->IsModeSet(invisiblemode))) { // Member is invisible and we are not supposed to show them continue; } Membership* const memb = i->second; prefixlist.clear(); char prefix = memb->GetPrefixChar(); if (prefix) prefixlist.push_back(prefix); nick = i->first->nick; ModResult res; FIRST_MOD_RESULT_CUSTOM(namesevprov, Names::EventListener, OnNamesListItem, res, (user, memb, prefixlist, nick)); if (res != MOD_RES_DENY) reply.Add(prefixlist, nick); } reply.Flush(); user->WriteNumeric(RPL_ENDOFNAMES, chan->name, "End of /NAMES list."); } ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/src/coremods/core_channel/cmd_topic.cpp����������������������������������������������0000664�0000000�0000000�00000006035�13554550454�0023036�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * InspIRCd -- Internet Relay Chat Daemon * * Copyright (C) 2009 Daniel De Graaf <danieldg@inspircd.org> * Copyright (C) 2007-2008 Robin Burchell <robin+git@viroteck.net> * Copyright (C) 2008 Craig Edwards <craigedwards@brainbox.cc> * Copyright (C) 2008 Thomas Stagner <aquanight@inspircd.org> * * This file is part of InspIRCd. InspIRCd is free software: you can * redistribute it and/or modify it under the terms of the GNU General Public * License as published by the Free Software Foundation, version 2. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include "inspircd.h" #include "core_channel.h" CommandTopic::CommandTopic(Module* parent) : SplitCommand(parent, "TOPIC", 1, 2) , exemptionprov(parent) , secretmode(parent, "secret") , topiclockmode(parent, "topiclock") { syntax = "<channel> [:<topic>]"; Penalty = 2; } CmdResult CommandTopic::HandleLocal(LocalUser* user, const Params& parameters) { Channel* c = ServerInstance->FindChan(parameters[0]); if (!c) { user->WriteNumeric(Numerics::NoSuchChannel(parameters[0])); return CMD_FAILURE; } if (parameters.size() == 1) { if ((c->IsModeSet(secretmode)) && (!c->HasUser(user) && !user->HasPrivPermission("channels/auspex"))) { user->WriteNumeric(Numerics::NoSuchChannel(c->name)); return CMD_FAILURE; } if (c->topic.length()) { Topic::ShowTopic(user, c); } else { user->WriteNumeric(RPL_NOTOPICSET, c->name, "No topic is set."); } return CMD_SUCCESS; } std::string t = parameters[1]; // needed, in case a module wants to change it ModResult res; FIRST_MOD_RESULT(OnPreTopicChange, res, (user,c,t)); if (res == MOD_RES_DENY) return CMD_FAILURE; if (res != MOD_RES_ALLOW) { if (!c->HasUser(user)) { user->WriteNumeric(ERR_NOTONCHANNEL, c->name, "You're not on that channel!"); return CMD_FAILURE; } if (c->IsModeSet(topiclockmode)) { ModResult MOD_RESULT = CheckExemption::Call(exemptionprov, user, c, "topiclock"); if (!MOD_RESULT.check(c->GetPrefixValue(user) >= HALFOP_VALUE)) { user->WriteNumeric(ERR_CHANOPRIVSNEEDED, c->name, "You do not have access to change the topic on this channel"); return CMD_FAILURE; } } } // Make sure the topic is not longer than the limit in the config if (t.length() > ServerInstance->Config->Limits.MaxTopic) t.erase(ServerInstance->Config->Limits.MaxTopic); // Only change if the new topic is different than the current one if (c->topic != t) c->SetTopic(user, t, ServerInstance->Time()); return CMD_SUCCESS; } void Topic::ShowTopic(LocalUser* user, Channel* chan) { user->WriteNumeric(RPL_TOPIC, chan->name, chan->topic); user->WriteNumeric(RPL_TOPICTIME, chan->name, chan->setby, (unsigned long)chan->topicset); } ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/src/coremods/core_channel/cmode_k.cpp������������������������������������������������0000664�0000000�0000000�00000005255�13554550454�0022501�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * InspIRCd -- Internet Relay Chat Daemon * * Copyright (C) 2009 Daniel De Graaf <danieldg@inspircd.org> * Copyright (C) 2008 Robin Burchell <robin+git@viroteck.net> * Copyright (C) 2007 Dennis Friis <peavey@inspircd.org> * Copyright (C) 2006 Craig Edwards <craigedwards@brainbox.cc> * * This file is part of InspIRCd. InspIRCd is free software: you can * redistribute it and/or modify it under the terms of the GNU General Public * License as published by the Free Software Foundation, version 2. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include "inspircd.h" #include "core_channel.h" const std::string::size_type ModeChannelKey::maxkeylen = 32; ModeChannelKey::ModeChannelKey(Module* Creator) : ParamMode<ModeChannelKey, LocalStringExt>(Creator, "key", 'k', PARAM_ALWAYS) { syntax = "<key>"; } ModeAction ModeChannelKey::OnModeChange(User* source, User*, Channel* channel, std::string &parameter, bool adding) { const std::string* key = ext.get(channel); bool exists = (key != NULL); if (IS_LOCAL(source)) { if (exists == adding) return MODEACTION_DENY; if (exists && (parameter != *key)) { /* Key is currently set and the correct key wasnt given */ return MODEACTION_DENY; } } else { if (exists && adding && parameter == *key) { /* no-op, don't show */ return MODEACTION_DENY; } } if (adding) { // When joining a channel multiple keys are delimited with a comma so we strip // them out here to avoid creating channels that are unjoinable. size_t commapos; while ((commapos = parameter.find(',')) != std::string::npos) parameter.erase(commapos, 1); // Truncate the parameter to the maximum key length. if (parameter.length() > maxkeylen) parameter.erase(maxkeylen); // If the password is empty here then it only consisted of commas. This is not // acceptable so we reject the mode change. if (parameter.empty()) return MODEACTION_DENY; ext.set(channel, parameter); } else ext.unset(channel); channel->SetMode(this, adding); return MODEACTION_ALLOW; } void ModeChannelKey::SerializeParam(Channel* chan, const std::string* key, std::string& out) { out += *key; } ModeAction ModeChannelKey::OnSet(User* source, Channel* chan, std::string& param) { // Dummy function, never called return MODEACTION_DENY; } bool ModeChannelKey::IsParameterSecret() { return true; } ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/src/coremods/core_channel/cmode_l.cpp������������������������������������������������0000664�0000000�0000000�00000003165�13554550454�0022500�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * InspIRCd -- Internet Relay Chat Daemon * * Copyright (C) 2009 Daniel De Graaf <danieldg@inspircd.org> * Copyright (C) 2007 Dennis Friis <peavey@inspircd.org> * Copyright (C) 2006 Craig Edwards <craigedwards@brainbox.cc> * * This file is part of InspIRCd. InspIRCd is free software: you can * redistribute it and/or modify it under the terms of the GNU General Public * License as published by the Free Software Foundation, version 2. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include "inspircd.h" #include "core_channel.h" ModeChannelLimit::ModeChannelLimit(Module* Creator) : ParamMode<ModeChannelLimit, LocalIntExt>(Creator, "limit", 'l') , minlimit(0) { syntax = "<limit>"; } bool ModeChannelLimit::ResolveModeConflict(std::string &their_param, const std::string &our_param, Channel*) { /* When TS is equal, the higher channel limit wins */ return ConvToNum<intptr_t>(their_param) < ConvToNum<intptr_t>(our_param); } ModeAction ModeChannelLimit::OnSet(User* user, Channel* chan, std::string& parameter) { size_t limit = ConvToNum<size_t>(parameter); if (limit < minlimit) return MODEACTION_DENY; ext.set(chan, limit); return MODEACTION_ALLOW; } void ModeChannelLimit::SerializeParam(Channel* chan, intptr_t n, std::string& out) { out += ConvToStr(n); } �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/src/coremods/core_channel/core_channel.cpp�������������������������������������������0000664�0000000�0000000�00000026376�13554550454�0023527�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * InspIRCd -- Internet Relay Chat Daemon * * Copyright (C) 2014-2015 Attila Molnar <attilamolnar@hush.com> * * This file is part of InspIRCd. InspIRCd is free software: you can * redistribute it and/or modify it under the terms of the GNU General Public * License as published by the Free Software Foundation, version 2. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include "inspircd.h" #include "core_channel.h" #include "invite.h" #include "listmode.h" namespace { /** Hook that sends a MODE after a JOIN if the user in the JOIN has some modes prefix set. * This happens e.g. when modules such as operprefix explicitly set prefix modes on the joining * user, or when a member with prefix modes does a host cycle. */ class JoinHook : public ClientProtocol::EventHook { ClientProtocol::Messages::Mode modemsg; Modes::ChangeList modechangelist; const User* joininguser; public: /** If true, MODE changes after JOIN will be sourced from the user, rather than the server */ bool modefromuser; JoinHook(Module* mod) : ClientProtocol::EventHook(mod, "JOIN") { } void OnEventInit(const ClientProtocol::Event& ev) CXX11_OVERRIDE { const ClientProtocol::Events::Join& join = static_cast<const ClientProtocol::Events::Join&>(ev); const Membership& memb = *join.GetMember(); modechangelist.clear(); for (std::string::const_iterator i = memb.modes.begin(); i != memb.modes.end(); ++i) { PrefixMode* const pm = ServerInstance->Modes.FindPrefixMode(*i); if (!pm) continue; // Shouldn't happen modechangelist.push_add(pm, memb.user->nick); } if (modechangelist.empty()) { // Member got no modes on join joininguser = NULL; return; } joininguser = memb.user; // Prepare a mode protocol event that we can append to the message list in OnPreEventSend() modemsg.SetParams(memb.chan, NULL, modechangelist); if (modefromuser) modemsg.SetSource(join); else modemsg.SetSourceUser(ServerInstance->FakeClient); } ModResult OnPreEventSend(LocalUser* user, const ClientProtocol::Event& ev, ClientProtocol::MessageList& messagelist) CXX11_OVERRIDE { // If joininguser is NULL then they didn't get any modes on join, skip. // Also don't show their own modes to them, they get that in the NAMES list not via MODE. if ((joininguser) && (user != joininguser)) messagelist.push_back(&modemsg); return MOD_RES_PASSTHRU; } }; } class CoreModChannel : public Module, public CheckExemption::EventListener { Invite::APIImpl invapi; CommandInvite cmdinvite; CommandJoin cmdjoin; CommandKick cmdkick; CommandNames cmdnames; CommandTopic cmdtopic; Events::ModuleEventProvider evprov; JoinHook joinhook; ModeChannelBan banmode; SimpleChannelModeHandler inviteonlymode; ModeChannelKey keymode; ModeChannelLimit limitmode; SimpleChannelModeHandler moderatedmode; SimpleChannelModeHandler noextmsgmode; ModeChannelOp opmode; SimpleChannelModeHandler privatemode; SimpleChannelModeHandler secretmode; SimpleChannelModeHandler topiclockmode; ModeChannelVoice voicemode; insp::flat_map<std::string, char> exemptions; ModResult IsInvited(User* user, Channel* chan) { LocalUser* localuser = IS_LOCAL(user); if ((localuser) && (invapi.IsInvited(localuser, chan))) return MOD_RES_ALLOW; return MOD_RES_PASSTHRU; } public: CoreModChannel() : CheckExemption::EventListener(this, UINT_MAX) , invapi(this) , cmdinvite(this, invapi) , cmdjoin(this) , cmdkick(this) , cmdnames(this) , cmdtopic(this) , evprov(this, "event/channel") , joinhook(this) , banmode(this) , inviteonlymode(this, "inviteonly", 'i') , keymode(this) , limitmode(this) , moderatedmode(this, "moderated", 'm') , noextmsgmode(this, "noextmsg", 'n') , opmode(this) , privatemode(this, "private", 'p') , secretmode(this, "secret", 's') , topiclockmode(this, "topiclock", 't') , voicemode(this) { } void ReadConfig(ConfigStatus& status) CXX11_OVERRIDE { ConfigTag* optionstag = ServerInstance->Config->ConfValue("options"); std::string current; irc::spacesepstream defaultstream(optionstag->getString("exemptchanops")); insp::flat_map<std::string, char> exempts; while (defaultstream.GetToken(current)) { std::string::size_type pos = current.find(':'); if (pos == std::string::npos || (pos + 2) > current.size()) throw ModuleException("Invalid exemptchanops value '" + current + "' at " + optionstag->getTagLocation()); const std::string restriction = current.substr(0, pos); const char prefix = current[pos + 1]; ServerInstance->Logs->Log(MODNAME, LOG_DEBUG, "Exempting prefix %c from %s", prefix, restriction.c_str()); exempts[restriction] = prefix; } ConfigTag* securitytag = ServerInstance->Config->ConfValue("security"); const std::string announceinvites = securitytag->getString("announceinvites", "dynamic"); Invite::AnnounceState newannouncestate; if (stdalgo::string::equalsci(announceinvites, "none")) newannouncestate = Invite::ANNOUNCE_NONE; else if (stdalgo::string::equalsci(announceinvites, "all")) newannouncestate = Invite::ANNOUNCE_ALL; else if (stdalgo::string::equalsci(announceinvites, "ops")) newannouncestate = Invite::ANNOUNCE_OPS; else if (stdalgo::string::equalsci(announceinvites, "dynamic")) newannouncestate = Invite::ANNOUNCE_DYNAMIC; else throw ModuleException(announceinvites + " is an invalid <security:announceinvites> value, at " + securitytag->getTagLocation()); // Config is valid, apply it // Validates and applies <maxlist> tags, so do it first banmode.DoRehash(); exemptions.swap(exempts); // In 2.0 we allowed limits of 0 to be set. This is non-standard behaviour // and will be removed in the next major release. limitmode.minlimit = optionstag->getBool("allowzerolimit", true) ? 0 : 1;; cmdinvite.announceinvites = newannouncestate; joinhook.modefromuser = optionstag->getBool("cyclehostsfromuser"); Implementation events[] = { I_OnCheckKey, I_OnCheckLimit, I_OnCheckChannelBan }; if (optionstag->getBool("invitebypassmodes", true)) ServerInstance->Modules.Attach(events, this, sizeof(events)/sizeof(Implementation)); else { for (unsigned int i = 0; i < sizeof(events)/sizeof(Implementation); i++) ServerInstance->Modules.Detach(events[i], this); } } void On005Numeric(std::map<std::string, std::string>& tokens) CXX11_OVERRIDE { tokens["KEYLEN"] = ConvToStr(ModeChannelKey::maxkeylen); insp::flat_map<int, std::string> limits; std::string vlist; const ModeParser::ListModeList& listmodes = ServerInstance->Modes->GetListModes(); for (ModeParser::ListModeList::const_iterator iter = listmodes.begin(); iter != listmodes.end(); ++iter) { ListModeBase* lm = *iter; const unsigned int limit = lm->GetLowerLimit(); limits[limit].push_back(lm->GetModeChar()); if (lm->HasVariableLength()) vlist.push_back(lm->GetModeChar()); } std::string& buffer = tokens["MAXLIST"]; for (insp::flat_map<int, std::string>::const_iterator iter = limits.begin(); iter != limits.end(); ++iter) { if (!buffer.empty()) buffer.push_back(','); std::string modes(iter->second); std::sort(modes.begin(), modes.end()); buffer.append(modes); buffer.push_back(':'); buffer.append(ConvToStr(iter->first)); } if (!vlist.empty()) { tokens["VBANLIST"]; // deprecated tokens["VLIST"] = vlist; } } ModResult OnUserPreJoin(LocalUser* user, Channel* chan, const std::string&, std::string&, const std::string& keygiven) CXX11_OVERRIDE { if (!chan) return MOD_RES_PASSTHRU; // Check whether the channel key is correct. const std::string ckey = chan->GetModeParameter(&keymode); if (!ckey.empty()) { ModResult MOD_RESULT; FIRST_MOD_RESULT(OnCheckKey, MOD_RESULT, (user, chan, keygiven)); if (!MOD_RESULT.check(InspIRCd::TimingSafeCompare(ckey, keygiven))) { // If no key provided, or key is not the right one, and can't bypass +k (not invited or option not enabled) user->WriteNumeric(ERR_BADCHANNELKEY, chan->name, "Cannot join channel (incorrect channel key)"); return MOD_RES_DENY; } } // Check whether the invite only mode is set. if (chan->IsModeSet(inviteonlymode)) { ModResult MOD_RESULT; FIRST_MOD_RESULT(OnCheckInvite, MOD_RESULT, (user, chan)); if (MOD_RESULT != MOD_RES_ALLOW) { user->WriteNumeric(ERR_INVITEONLYCHAN, chan->name, "Cannot join channel (invite only)"); return MOD_RES_DENY; } } // Check whether the limit would be exceeded by this user joining. if (chan->IsModeSet(limitmode)) { ModResult MOD_RESULT; FIRST_MOD_RESULT(OnCheckLimit, MOD_RESULT, (user, chan)); if (!MOD_RESULT.check(chan->GetUserCounter() < static_cast<size_t>(limitmode.ext.get(chan)))) { user->WriteNumeric(ERR_CHANNELISFULL, chan->name, "Cannot join channel (channel is full)"); return MOD_RES_DENY; } } // Everything looks okay. return MOD_RES_PASSTHRU; } void OnPostJoin(Membership* memb) CXX11_OVERRIDE { Channel* const chan = memb->chan; LocalUser* const localuser = IS_LOCAL(memb->user); if (localuser) { // Remove existing invite, if any invapi.Remove(localuser, chan); if (chan->topic.length()) Topic::ShowTopic(localuser, chan); // Show all members of the channel, including invisible (+i) users cmdnames.SendNames(localuser, chan, true); } } ModResult OnCheckKey(User* user, Channel* chan, const std::string& keygiven) CXX11_OVERRIDE { // Hook only runs when being invited bypasses +bkl return IsInvited(user, chan); } ModResult OnCheckChannelBan(User* user, Channel* chan) CXX11_OVERRIDE { // Hook only runs when being invited bypasses +bkl return IsInvited(user, chan); } ModResult OnCheckLimit(User* user, Channel* chan) CXX11_OVERRIDE { // Hook only runs when being invited bypasses +bkl return IsInvited(user, chan); } ModResult OnCheckInvite(User* user, Channel* chan) CXX11_OVERRIDE { // Hook always runs return IsInvited(user, chan); } void OnUserDisconnect(LocalUser* user) CXX11_OVERRIDE { invapi.RemoveAll(user); } void OnChannelDelete(Channel* chan) CXX11_OVERRIDE { // Make sure the channel won't appear in invite lists from now on, don't wait for cull to unset the ext invapi.RemoveAll(chan); } ModResult OnCheckExemption(User* user, Channel* chan, const std::string& restriction) CXX11_OVERRIDE { if (!exemptions.count(restriction)) return MOD_RES_PASSTHRU; unsigned int mypfx = chan->GetPrefixValue(user); char minmode = exemptions[restriction]; PrefixMode* mh = ServerInstance->Modes->FindPrefixMode(minmode); if (mh && mypfx >= mh->GetPrefixRank()) return MOD_RES_ALLOW; if (mh || minmode == '*') return MOD_RES_DENY; return MOD_RES_PASSTHRU; } void Prioritize() CXX11_OVERRIDE { ServerInstance->Modules.SetPriority(this, I_OnPostJoin, PRIORITY_FIRST); ServerInstance->Modules.SetPriority(this, I_OnUserPreJoin, PRIORITY_LAST); } Version GetVersion() CXX11_OVERRIDE { return Version("Provides the INVITE, JOIN, KICK, NAMES, and TOPIC commands", VF_VENDOR|VF_CORE); } }; MODULE_INIT(CoreModChannel) ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/src/coremods/core_channel/core_channel.h���������������������������������������������0000664�0000000�0000000�00000013734�13554550454�0023166�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * InspIRCd -- Internet Relay Chat Daemon * * Copyright (C) 2014 Attila Molnar <attilamolnar@hush.com> * Copyright (C) 2008 Robin Burchell <robin+git@viroteck.net> * Copyright (C) 2007 Dennis Friis <peavey@inspircd.org> * Copyright (C) 2006 Craig Edwards <craigedwards@brainbox.cc> * * This file is part of InspIRCd. InspIRCd is free software: you can * redistribute it and/or modify it under the terms of the GNU General Public * License as published by the Free Software Foundation, version 2. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include "inspircd.h" #include "listmode.h" #include "modules/exemption.h" namespace Topic { void ShowTopic(LocalUser* user, Channel* chan); } namespace Invite { class APIImpl; /** Used to indicate who we announce invites to on a channel. */ enum AnnounceState { /** Don't send invite announcements. */ ANNOUNCE_NONE, /** Send invite announcements to all users. */ ANNOUNCE_ALL, /** Send invite announcements to channel operators and higher. */ ANNOUNCE_OPS, /** Send invite announcements to channel half-operators (if available) and higher. */ ANNOUNCE_DYNAMIC }; } /** Handle /INVITE. */ class CommandInvite : public Command { Invite::APIImpl& invapi; public: Invite::AnnounceState announceinvites; /** Constructor for invite. */ CommandInvite(Module* parent, Invite::APIImpl& invapiimpl); /** Handle command. * @param parameters The parameters to the command * @param user The user issuing the command * @return A value from CmdResult to indicate command success or failure. */ CmdResult Handle(User* user, const Params& parameters) CXX11_OVERRIDE; RouteDescriptor GetRouting(User* user, const Params& parameters) CXX11_OVERRIDE; }; /** Handle /JOIN. */ class CommandJoin : public SplitCommand { public: /** Constructor for join. */ CommandJoin(Module* parent); /** Handle command. * @param parameters The parameters to the command * @param user The user issuing the command * @return A value from CmdResult to indicate command success or failure. */ CmdResult HandleLocal(LocalUser* user, const Params& parameters) CXX11_OVERRIDE; }; /** Handle /TOPIC. */ class CommandTopic : public SplitCommand { CheckExemption::EventProvider exemptionprov; ChanModeReference secretmode; ChanModeReference topiclockmode; public: /** Constructor for topic. */ CommandTopic(Module* parent); /** Handle command. * @param parameters The parameters to the command * @param user The user issuing the command * @return A value from CmdResult to indicate command success or failure. */ CmdResult HandleLocal(LocalUser* user, const Params& parameters) CXX11_OVERRIDE; }; /** Handle /NAMES. */ class CommandNames : public SplitCommand { private: ChanModeReference secretmode; ChanModeReference privatemode; UserModeReference invisiblemode; Events::ModuleEventProvider namesevprov; public: /** Constructor for names. */ CommandNames(Module* parent); /** Handle command. * @param parameters The parameters to the command * @param user The user issuing the command * @return A value from CmdResult to indicate command success or failure. */ CmdResult HandleLocal(LocalUser* user, const Params& parameters) CXX11_OVERRIDE; /** Spool the NAMES list for a given channel to the given user * @param user User to spool the NAMES list to * @param chan Channel whose nicklist to send * @param show_invisible True to show invisible (+i) members to the user, false to omit them from the list */ void SendNames(LocalUser* user, Channel* chan, bool show_invisible); }; /** Handle /KICK. */ class CommandKick : public Command { public: /** Constructor for kick. */ CommandKick(Module* parent); /** Handle command. * @param parameters The parameters to the command * @param user The user issuing the command * @return A value from CmdResult to indicate command success or failure. */ CmdResult Handle(User* user, const Params& parameters) CXX11_OVERRIDE; RouteDescriptor GetRouting(User* user, const Params& parameters) CXX11_OVERRIDE; }; /** Channel mode +b */ class ModeChannelBan : public ListModeBase { public: ModeChannelBan(Module* Creator) : ListModeBase(Creator, "ban", 'b', "End of channel ban list", 367, 368, true) { syntax = "<mask>"; } }; /** Channel mode +k */ class ModeChannelKey : public ParamMode<ModeChannelKey, LocalStringExt> { public: static const std::string::size_type maxkeylen; ModeChannelKey(Module* Creator); ModeAction OnModeChange(User* source, User* dest, Channel* channel, std::string& parameter, bool adding) CXX11_OVERRIDE; void SerializeParam(Channel* chan, const std::string* key, std::string& out) ; ModeAction OnSet(User* source, Channel* chan, std::string& param) CXX11_OVERRIDE; bool IsParameterSecret() CXX11_OVERRIDE; }; /** Channel mode +l */ class ModeChannelLimit : public ParamMode<ModeChannelLimit, LocalIntExt> { public: size_t minlimit; ModeChannelLimit(Module* Creator); bool ResolveModeConflict(std::string& their_param, const std::string& our_param, Channel* channel) CXX11_OVERRIDE; void SerializeParam(Channel* chan, intptr_t n, std::string& out); ModeAction OnSet(User* source, Channel* channel, std::string& parameter) CXX11_OVERRIDE; }; /** Channel mode +o */ class ModeChannelOp : public PrefixMode { public: ModeChannelOp(Module* Creator) : PrefixMode(Creator, "op", 'o', OP_VALUE, '@') { ranktoset = ranktounset = OP_VALUE; } }; /** Channel mode +v */ class ModeChannelVoice : public PrefixMode { public: ModeChannelVoice(Module* Creator) : PrefixMode(Creator, "voice", 'v', VOICE_VALUE, '+') { selfremove = false; ranktoset = ranktounset = HALFOP_VALUE; } }; ������������������������������������inspircd-3.4.0/src/coremods/core_channel/invite.cpp�������������������������������������������������0000664�0000000�0000000�00000012044�13554550454�0022370�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * InspIRCd -- Internet Relay Chat Daemon * * Copyright (C) 2012, 2015 Attila Molnar <attilamolnar@hush.com> * * This file is part of InspIRCd. InspIRCd is free software: you can * redistribute it and/or modify it under the terms of the GNU General Public * License as published by the Free Software Foundation, version 2. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include "inspircd.h" #include "invite.h" class InviteExpireTimer : public Timer { Invite::Invite* const inv; bool Tick(time_t currtime) CXX11_OVERRIDE; public: InviteExpireTimer(Invite::Invite* invite, time_t timeout); }; static Invite::APIImpl* apiimpl; void RemoveInvite(Invite::Invite* inv, bool remove_user, bool remove_chan) { apiimpl->Destruct(inv, remove_user, remove_chan); } void UnserializeInvite(LocalUser* user, const std::string& str) { apiimpl->Unserialize(user, str); } Invite::APIBase::APIBase(Module* parent) : DataProvider(parent, "core_channel_invite") { } Invite::APIImpl::APIImpl(Module* parent) : APIBase(parent) , userext(parent, "invite_user") , chanext(parent, "invite_chan") { apiimpl = this; } void Invite::APIImpl::Destruct(Invite* inv, bool remove_user, bool remove_chan) { Store<LocalUser>* ustore = userext.get(inv->user); if (ustore) { ustore->invites.erase(inv); if ((remove_user) && (ustore->invites.empty())) userext.unset(inv->user); } Store<Channel>* cstore = chanext.get(inv->chan); if (cstore) { cstore->invites.erase(inv); if ((remove_chan) && (cstore->invites.empty())) chanext.unset(inv->chan); } delete inv; } bool Invite::APIImpl::Remove(LocalUser* user, Channel* chan) { Invite* inv = Find(user, chan); if (inv) { Destruct(inv); return true; } return false; } void Invite::APIImpl::Create(LocalUser* user, Channel* chan, time_t timeout) { if ((timeout != 0) && (ServerInstance->Time() >= timeout)) // Expired, don't bother return; ServerInstance->Logs->Log(MODNAME, LOG_DEBUG, "Invite::APIImpl::Create(): user=%s chan=%s timeout=%lu", user->uuid.c_str(), chan->name.c_str(), (unsigned long)timeout); Invite* inv = Find(user, chan); if (inv) { // We only ever extend invites, so nothing to do if the existing one is not timed if (!inv->IsTimed()) return; ServerInstance->Logs->Log(MODNAME, LOG_DEBUG, "Invite::APIImpl::Create(): changing expiration in %p", (void*) inv); if (timeout == 0) { // Convert timed invite to non-expiring delete inv->expiretimer; inv->expiretimer = NULL; } else if (inv->expiretimer->GetTrigger() >= ServerInstance->Time() + timeout) { // New expiration time is further than the current, extend the expiration inv->expiretimer->SetInterval(timeout - ServerInstance->Time()); } } else { inv = new Invite(user, chan); if (timeout) { inv->expiretimer = new InviteExpireTimer(inv, timeout - ServerInstance->Time()); ServerInstance->Timers.AddTimer(inv->expiretimer); } userext.get(user, true)->invites.push_front(inv); chanext.get(chan, true)->invites.push_front(inv); ServerInstance->Logs->Log(MODNAME, LOG_DEBUG, "Invite::APIImpl::Create(): created new Invite %p", (void*) inv); } } Invite::Invite* Invite::APIImpl::Find(LocalUser* user, Channel* chan) { const List* list = APIImpl::GetList(user); if (!list) return NULL; for (List::iterator i = list->begin(); i != list->end(); ++i) { Invite* inv = *i; if (inv->chan == chan) return inv; } return NULL; } const Invite::List* Invite::APIImpl::GetList(LocalUser* user) { Store<LocalUser>* list = userext.get(user); if (list) return &list->invites; return NULL; } void Invite::APIImpl::Unserialize(LocalUser* user, const std::string& value) { irc::spacesepstream ss(value); for (std::string channame, exptime; (ss.GetToken(channame) && ss.GetToken(exptime)); ) { Channel* chan = ServerInstance->FindChan(channame); if (chan) Create(user, chan, ConvToNum<time_t>(exptime)); } } Invite::Invite::Invite(LocalUser* u, Channel* c) : user(u) , chan(c) , expiretimer(NULL) { } Invite::Invite::~Invite() { delete expiretimer; ServerInstance->Logs->Log(MODNAME, LOG_DEBUG, "Invite::~ %p", (void*) this); } void Invite::Invite::Serialize(bool human, bool show_chans, std::string& out) { if (show_chans) out.append(this->chan->name); else out.append(human ? user->nick : user->uuid); out.push_back(' '); if (expiretimer) out.append(ConvToStr(expiretimer->GetTrigger())); else out.push_back('0'); out.push_back(' '); } InviteExpireTimer::InviteExpireTimer(Invite::Invite* invite, time_t timeout) : Timer(timeout) , inv(invite) { } bool InviteExpireTimer::Tick(time_t currtime) { ServerInstance->Logs->Log(MODNAME, LOG_DEBUG, "InviteExpireTimer::Tick(): expired %p", (void*) inv); apiimpl->Destruct(inv); return false; } ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/src/coremods/core_channel/invite.h���������������������������������������������������0000664�0000000�0000000�00000007220�13554550454�0022035�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * InspIRCd -- Internet Relay Chat Daemon * * Copyright (C) 2015 Attila Molnar <attilamolnar@hush.com> * * This file is part of InspIRCd. InspIRCd is free software: you can * redistribute it and/or modify it under the terms of the GNU General Public * License as published by the Free Software Foundation, version 2. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include "modules/invite.h" namespace Invite { template<typename T> struct Store { typedef insp::intrusive_list<Invite, T> List; /** List of pending Invites */ List invites; }; template<typename T, ExtensionItem::ExtensibleType ExtType> class ExtItem; class APIImpl; } extern void RemoveInvite(Invite::Invite* inv, bool remove_user, bool remove_chan); extern void UnserializeInvite(LocalUser* user, const std::string& value); template<typename T, ExtensionItem::ExtensibleType ExtType> class Invite::ExtItem : public ExtensionItem { private: static std::string ToString(void* item, bool human) { std::string ret; Store<T>* store = static_cast<Store<T>*>(item); for (typename insp::intrusive_list<Invite, T>::iterator i = store->invites.begin(); i != store->invites.end(); ++i) { Invite* inv = *i; inv->Serialize(human, (ExtType == ExtensionItem::EXT_USER), ret); } if (!ret.empty()) ret.erase(ret.length()-1); return ret; } public: ExtItem(Module* owner, const char* extname) : ExtensionItem(extname, ExtType, owner) { } Store<T>* get(Extensible* ext, bool create = false) { Store<T>* store = static_cast<Store<T>*>(get_raw(ext)); if ((create) && (!store)) { store = new Store<T>; set_raw(ext, store); } return store; } void unset(Extensible* ext) { void* store = unset_raw(ext); if (store) free(ext, store); } void free(Extensible* container, void* item) CXX11_OVERRIDE { Store<T>* store = static_cast<Store<T>*>(item); for (typename Store<T>::List::iterator i = store->invites.begin(); i != store->invites.end(); ) { Invite* inv = *i; // Destructing the Invite invalidates the iterator, so move it now ++i; RemoveInvite(inv, (ExtType != ExtensionItem::EXT_USER), (ExtType == ExtensionItem::EXT_USER)); } delete store; } std::string ToHuman(const Extensible* container, void* item) const CXX11_OVERRIDE { return ToString(item, true); } std::string ToInternal(const Extensible* container, void* item) const CXX11_OVERRIDE { return ToString(item, false); } void FromInternal(Extensible* container, const std::string& value) CXX11_OVERRIDE { if (ExtType != ExtensionItem::EXT_CHANNEL) UnserializeInvite(static_cast<LocalUser*>(container), value); } }; class Invite::APIImpl : public APIBase { ExtItem<LocalUser, ExtensionItem::EXT_USER> userext; ExtItem<Channel, ExtensionItem::EXT_CHANNEL> chanext; public: APIImpl(Module* owner); void Create(LocalUser* user, Channel* chan, time_t timeout) CXX11_OVERRIDE; Invite* Find(LocalUser* user, Channel* chan) CXX11_OVERRIDE; bool Remove(LocalUser* user, Channel* chan) CXX11_OVERRIDE; const List* GetList(LocalUser* user) CXX11_OVERRIDE; void RemoveAll(LocalUser* user) { userext.unset(user); } void RemoveAll(Channel* chan) { chanext.unset(chan); } void Destruct(Invite* inv, bool remove_chan = true, bool remove_user = true); void Unserialize(LocalUser* user, const std::string& value); }; ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/src/coremods/core_dns.cpp������������������������������������������������������������0000664�0000000�0000000�00000055513�13554550454�0020256�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * InspIRCd -- Internet Relay Chat Daemon * * Copyright (C) 2013 Adam <Adam@anope.org> * Copyright (C) 2003-2013 Anope Team <team@anope.org> * * This file is part of InspIRCd. InspIRCd is free software: you can * redistribute it and/or modify it under the terms of the GNU General Public * License as published by the Free Software Foundation, version 2. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include "inspircd.h" #include "modules/dns.h" #include <iostream> #include <fstream> #ifdef _WIN32 #include <Iphlpapi.h> #pragma comment(lib, "Iphlpapi.lib") #endif namespace DNS { /** Maximum value of a dns request id, 16 bits wide, 0xFFFF. */ const unsigned int MAX_REQUEST_ID = 0xFFFF; } using namespace DNS; /** A full packet sent or received to/from the nameserver */ class Packet : public Query { void PackName(unsigned char* output, unsigned short output_size, unsigned short& pos, const std::string& name) { if (pos + name.length() + 2 > output_size) throw Exception("Unable to pack name"); ServerInstance->Logs->Log(MODNAME, LOG_DEBUG, "Packing name " + name); irc::sepstream sep(name, '.'); std::string token; while (sep.GetToken(token)) { output[pos++] = token.length(); memcpy(&output[pos], token.data(), token.length()); pos += token.length(); } output[pos++] = 0; } std::string UnpackName(const unsigned char* input, unsigned short input_size, unsigned short& pos) { std::string name; unsigned short pos_ptr = pos, lowest_ptr = input_size; bool compressed = false; if (pos_ptr >= input_size) throw Exception("Unable to unpack name - no input"); while (input[pos_ptr] > 0) { unsigned short offset = input[pos_ptr]; if (offset & POINTER) { if ((offset & POINTER) != POINTER) throw Exception("Unable to unpack name - bogus compression header"); if (pos_ptr + 1 >= input_size) throw Exception("Unable to unpack name - bogus compression header"); /* Place pos at the second byte of the first (farthest) compression pointer */ if (compressed == false) { ++pos; compressed = true; } pos_ptr = (offset & LABEL) << 8 | input[pos_ptr + 1]; /* Pointers can only go back */ if (pos_ptr >= lowest_ptr) throw Exception("Unable to unpack name - bogus compression pointer"); lowest_ptr = pos_ptr; } else { if (pos_ptr + offset + 1 >= input_size) throw Exception("Unable to unpack name - offset too large"); if (!name.empty()) name += "."; for (unsigned i = 1; i <= offset; ++i) name += input[pos_ptr + i]; pos_ptr += offset + 1; if (compressed == false) /* Move up pos */ pos = pos_ptr; } } /* +1 pos either to one byte after the compression pointer or one byte after the ending \0 */ ++pos; if (name.empty()) throw Exception("Unable to unpack name - no name"); ServerInstance->Logs->Log(MODNAME, LOG_DEBUG, "Unpack name " + name); return name; } Question UnpackQuestion(const unsigned char* input, unsigned short input_size, unsigned short& pos) { Question q; q.name = this->UnpackName(input, input_size, pos); if (pos + 4 > input_size) throw Exception("Unable to unpack question"); q.type = static_cast<QueryType>(input[pos] << 8 | input[pos + 1]); pos += 2; // Skip over query class code pos += 2; return q; } ResourceRecord UnpackResourceRecord(const unsigned char* input, unsigned short input_size, unsigned short& pos) { ResourceRecord record = static_cast<ResourceRecord>(this->UnpackQuestion(input, input_size, pos)); if (pos + 6 > input_size) throw Exception("Unable to unpack resource record"); record.ttl = (input[pos] << 24) | (input[pos + 1] << 16) | (input[pos + 2] << 8) | input[pos + 3]; pos += 4; uint16_t rdlength = input[pos] << 8 | input[pos + 1]; pos += 2; switch (record.type) { case QUERY_A: { if (pos + 4 > input_size) throw Exception("Unable to unpack resource record"); irc::sockets::sockaddrs addrs; memset(&addrs, 0, sizeof(addrs)); addrs.in4.sin_family = AF_INET; addrs.in4.sin_addr.s_addr = input[pos] | (input[pos + 1] << 8) | (input[pos + 2] << 16) | (input[pos + 3] << 24); pos += 4; record.rdata = addrs.addr(); break; } case QUERY_AAAA: { if (pos + 16 > input_size) throw Exception("Unable to unpack resource record"); irc::sockets::sockaddrs addrs; memset(&addrs, 0, sizeof(addrs)); addrs.in6.sin6_family = AF_INET6; for (int j = 0; j < 16; ++j) addrs.in6.sin6_addr.s6_addr[j] = input[pos + j]; pos += 16; record.rdata = addrs.addr(); break; } case QUERY_CNAME: case QUERY_PTR: { record.rdata = this->UnpackName(input, input_size, pos); if (!InspIRCd::IsHost(record.rdata)) throw Exception("Invalid name"); // XXX: Causes the request to time out break; } case QUERY_TXT: { if (pos + rdlength > input_size) throw Exception("Unable to unpack txt resource record"); record.rdata = std::string(reinterpret_cast<const char *>(input + pos), rdlength); pos += rdlength; if (record.rdata.find_first_of("\r\n\0", 0, 3) != std::string::npos) throw Exception("Invalid character in txt record"); break; } default: break; } if (!record.name.empty() && !record.rdata.empty()) ServerInstance->Logs->Log(MODNAME, LOG_DEBUG, record.name + " -> " + record.rdata); return record; } public: static const int POINTER = 0xC0; static const int LABEL = 0x3F; static const int HEADER_LENGTH = 12; /* ID for this packet */ RequestId id; /* Flags on the packet */ unsigned short flags; Packet() : id(0), flags(0) { } void Fill(const unsigned char* input, const unsigned short len) { if (len < HEADER_LENGTH) throw Exception("Unable to fill packet"); unsigned short packet_pos = 0; this->id = (input[packet_pos] << 8) | input[packet_pos + 1]; packet_pos += 2; this->flags = (input[packet_pos] << 8) | input[packet_pos + 1]; packet_pos += 2; unsigned short qdcount = (input[packet_pos] << 8) | input[packet_pos + 1]; packet_pos += 2; unsigned short ancount = (input[packet_pos] << 8) | input[packet_pos + 1]; packet_pos += 2; unsigned short nscount = (input[packet_pos] << 8) | input[packet_pos + 1]; packet_pos += 2; unsigned short arcount = (input[packet_pos] << 8) | input[packet_pos + 1]; packet_pos += 2; ServerInstance->Logs->Log(MODNAME, LOG_DEBUG, "qdcount: " + ConvToStr(qdcount) + " ancount: " + ConvToStr(ancount) + " nscount: " + ConvToStr(nscount) + " arcount: " + ConvToStr(arcount)); if (qdcount != 1) throw Exception("Question count != 1 in incoming packet"); this->question = this->UnpackQuestion(input, len, packet_pos); for (unsigned i = 0; i < ancount; ++i) this->answers.push_back(this->UnpackResourceRecord(input, len, packet_pos)); } unsigned short Pack(unsigned char* output, unsigned short output_size) { if (output_size < HEADER_LENGTH) throw Exception("Unable to pack packet"); unsigned short pos = 0; output[pos++] = this->id >> 8; output[pos++] = this->id & 0xFF; output[pos++] = this->flags >> 8; output[pos++] = this->flags & 0xFF; output[pos++] = 0; // Question count, high byte output[pos++] = 1; // Question count, low byte output[pos++] = 0; // Answer count, high byte output[pos++] = 0; // Answer count, low byte output[pos++] = 0; output[pos++] = 0; output[pos++] = 0; output[pos++] = 0; { Question& q = this->question; if (q.type == QUERY_PTR) { irc::sockets::sockaddrs ip; irc::sockets::aptosa(q.name, 0, ip); if (q.name.find(':') != std::string::npos) { static const char* const hex = "0123456789abcdef"; char reverse_ip[128]; unsigned reverse_ip_count = 0; for (int j = 15; j >= 0; --j) { reverse_ip[reverse_ip_count++] = hex[ip.in6.sin6_addr.s6_addr[j] & 0xF]; reverse_ip[reverse_ip_count++] = '.'; reverse_ip[reverse_ip_count++] = hex[ip.in6.sin6_addr.s6_addr[j] >> 4]; reverse_ip[reverse_ip_count++] = '.'; } reverse_ip[reverse_ip_count++] = 0; q.name = reverse_ip; q.name += "ip6.arpa"; } else { unsigned long forward = ip.in4.sin_addr.s_addr; ip.in4.sin_addr.s_addr = forward << 24 | (forward & 0xFF00) << 8 | (forward & 0xFF0000) >> 8 | forward >> 24; q.name = ip.addr() + ".in-addr.arpa"; } } this->PackName(output, output_size, pos, q.name); if (pos + 4 >= output_size) throw Exception("Unable to pack packet"); short s = htons(q.type); memcpy(&output[pos], &s, 2); pos += 2; // Query class, always IN output[pos++] = 0; output[pos++] = 1; } return pos; } }; class MyManager : public Manager, public Timer, public EventHandler { typedef TR1NS::unordered_map<Question, Query, Question::hash> cache_map; cache_map cache; irc::sockets::sockaddrs myserver; bool unloading; /** Maximum number of entries in cache */ static const unsigned int MAX_CACHE_SIZE = 1000; static bool IsExpired(const Query& record, time_t now = ServerInstance->Time()) { const ResourceRecord& req = record.answers[0]; return (req.created + static_cast<time_t>(req.ttl) < now); } /** Check the DNS cache to see if request can be handled by a cached result * @return true if a cached result was found. */ bool CheckCache(DNS::Request* req, const DNS::Question& question) { ServerInstance->Logs->Log(MODNAME, LOG_SPARSE, "cache: Checking cache for " + question.name); cache_map::iterator it = this->cache.find(question); if (it == this->cache.end()) return false; Query& record = it->second; if (IsExpired(record)) { this->cache.erase(it); return false; } ServerInstance->Logs->Log(MODNAME, LOG_DEBUG, "cache: Using cached result for " + question.name); record.cached = true; req->OnLookupComplete(&record); return true; } /** Add a record to the dns cache * @param r The record */ void AddCache(Query& r) { if (cache.size() >= MAX_CACHE_SIZE) cache.clear(); // Determine the lowest TTL value and use that as the TTL of the cache entry unsigned int cachettl = UINT_MAX; for (std::vector<ResourceRecord>::const_iterator i = r.answers.begin(); i != r.answers.end(); ++i) { const ResourceRecord& rr = *i; if (rr.ttl < cachettl) cachettl = rr.ttl; } cachettl = std::min(cachettl, (unsigned int)5*60); ResourceRecord& rr = r.answers.front(); // Set TTL to what we've determined to be the lowest rr.ttl = cachettl; ServerInstance->Logs->Log(MODNAME, LOG_DEBUG, "cache: added cache for " + rr.name + " -> " + rr.rdata + " ttl: " + ConvToStr(rr.ttl)); this->cache[r.question] = r; } public: DNS::Request* requests[MAX_REQUEST_ID+1]; MyManager(Module* c) : Manager(c), Timer(5*60, true) , unloading(false) { for (unsigned int i = 0; i <= MAX_REQUEST_ID; ++i) requests[i] = NULL; ServerInstance->Timers.AddTimer(this); } ~MyManager() { // Ensure Process() will fail for new requests unloading = true; for (unsigned int i = 0; i <= MAX_REQUEST_ID; ++i) { DNS::Request* request = requests[i]; if (!request) continue; Query rr(request->question); rr.error = ERROR_UNKNOWN; request->OnError(&rr); delete request; } } void Process(DNS::Request* req) CXX11_OVERRIDE { if ((unloading) || (req->creator->dying)) throw Exception("Module is being unloaded"); ServerInstance->Logs->Log(MODNAME, LOG_DEBUG, "Processing request to lookup " + req->question.name + " of type " + ConvToStr(req->question.type) + " to " + this->myserver.addr()); /* Create an id */ unsigned int tries = 0; int id; do { id = ServerInstance->GenRandomInt(DNS::MAX_REQUEST_ID+1); if (++tries == DNS::MAX_REQUEST_ID*5) { // If we couldn't find an empty slot this many times, do a sequential scan as a last // resort. If an empty slot is found that way, go on, otherwise throw an exception id = -1; for (unsigned int i = 0; i <= DNS::MAX_REQUEST_ID; i++) { if (!this->requests[i]) { id = i; break; } } if (id == -1) throw Exception("DNS: All ids are in use"); break; } } while (this->requests[id]); req->id = id; this->requests[req->id] = req; Packet p; p.flags = QUERYFLAGS_RD; p.id = req->id; p.question = req->question; unsigned char buffer[524]; unsigned short len = p.Pack(buffer, sizeof(buffer)); /* Note that calling Pack() above can actually change the contents of p.question.name, if the query is a PTR, * to contain the value that would be in the DNS cache, which is why this is here. */ if (req->use_cache && this->CheckCache(req, p.question)) { ServerInstance->Logs->Log(MODNAME, LOG_DEBUG, "Using cached result"); delete req; return; } // Update name in the original request so question checking works for PTR queries req->question.name = p.question.name; if (SocketEngine::SendTo(this, buffer, len, 0, this->myserver) != len) throw Exception("DNS: Unable to send query"); // Add timer for timeout ServerInstance->Timers.AddTimer(req); } void RemoveRequest(DNS::Request* req) CXX11_OVERRIDE { if (requests[req->id] == req) requests[req->id] = NULL; } std::string GetErrorStr(Error e) CXX11_OVERRIDE { switch (e) { case ERROR_UNLOADED: return "Module is unloading"; case ERROR_TIMEDOUT: return "Request timed out"; case ERROR_NOT_AN_ANSWER: case ERROR_NONSTANDARD_QUERY: case ERROR_FORMAT_ERROR: case ERROR_MALFORMED: return "Malformed answer"; case ERROR_SERVER_FAILURE: case ERROR_NOT_IMPLEMENTED: case ERROR_REFUSED: case ERROR_INVALIDTYPE: return "Nameserver failure"; case ERROR_DOMAIN_NOT_FOUND: case ERROR_NO_RECORDS: return "Domain not found"; case ERROR_NONE: case ERROR_UNKNOWN: default: return "Unknown error"; } } std::string GetTypeStr(QueryType qt) CXX11_OVERRIDE { switch (qt) { case QUERY_A: return "A"; case QUERY_AAAA: return "AAAA"; case QUERY_CNAME: return "CNAME"; case QUERY_PTR: return "PTR"; case QUERY_TXT: return "TXT"; default: return "UNKNOWN"; } } void OnEventHandlerError(int errcode) CXX11_OVERRIDE { ServerInstance->Logs->Log(MODNAME, LOG_DEBUG, "UDP socket got an error event"); } void OnEventHandlerRead() CXX11_OVERRIDE { unsigned char buffer[524]; irc::sockets::sockaddrs from; socklen_t x = sizeof(from); int length = SocketEngine::RecvFrom(this, buffer, sizeof(buffer), 0, &from.sa, &x); if (length < Packet::HEADER_LENGTH) return; if (myserver != from) { std::string server1 = from.str(); std::string server2 = myserver.str(); ServerInstance->Logs->Log(MODNAME, LOG_DEBUG, "Got a result from the wrong server! Bad NAT or DNS forging attempt? '%s' != '%s'", server1.c_str(), server2.c_str()); return; } Packet recv_packet; bool valid = false; try { recv_packet.Fill(buffer, length); valid = true; } catch (Exception& ex) { ServerInstance->Logs->Log(MODNAME, LOG_DEBUG, ex.GetReason()); } // recv_packet.id must be filled in here DNS::Request* request = this->requests[recv_packet.id]; if (request == NULL) { ServerInstance->Logs->Log(MODNAME, LOG_DEBUG, "Received an answer for something we didn't request"); return; } if (request->question != recv_packet.question) { // This can happen under high latency, drop it silently, do not fail the request ServerInstance->Logs->Log(MODNAME, LOG_DEBUG, "Received an answer that isn't for a question we asked"); return; } if (!valid) { ServerInstance->stats.DnsBad++; recv_packet.error = ERROR_MALFORMED; request->OnError(&recv_packet); } else if (recv_packet.flags & QUERYFLAGS_OPCODE) { ServerInstance->Logs->Log(MODNAME, LOG_DEBUG, "Received a nonstandard query"); ServerInstance->stats.DnsBad++; recv_packet.error = ERROR_NONSTANDARD_QUERY; request->OnError(&recv_packet); } else if (!(recv_packet.flags & QUERYFLAGS_QR) || (recv_packet.flags & QUERYFLAGS_RCODE)) { Error error = ERROR_UNKNOWN; switch (recv_packet.flags & QUERYFLAGS_RCODE) { case 1: ServerInstance->Logs->Log(MODNAME, LOG_DEBUG, "format error"); error = ERROR_FORMAT_ERROR; break; case 2: ServerInstance->Logs->Log(MODNAME, LOG_DEBUG, "server error"); error = ERROR_SERVER_FAILURE; break; case 3: ServerInstance->Logs->Log(MODNAME, LOG_DEBUG, "domain not found"); error = ERROR_DOMAIN_NOT_FOUND; break; case 4: ServerInstance->Logs->Log(MODNAME, LOG_DEBUG, "not implemented"); error = ERROR_NOT_IMPLEMENTED; break; case 5: ServerInstance->Logs->Log(MODNAME, LOG_DEBUG, "refused"); error = ERROR_REFUSED; break; default: break; } ServerInstance->stats.DnsBad++; recv_packet.error = error; request->OnError(&recv_packet); } else if (recv_packet.answers.empty()) { ServerInstance->Logs->Log(MODNAME, LOG_DEBUG, "No resource records returned"); ServerInstance->stats.DnsBad++; recv_packet.error = ERROR_NO_RECORDS; request->OnError(&recv_packet); } else { ServerInstance->Logs->Log(MODNAME, LOG_DEBUG, "Lookup complete for " + request->question.name); ServerInstance->stats.DnsGood++; request->OnLookupComplete(&recv_packet); this->AddCache(recv_packet); } ServerInstance->stats.Dns++; /* Request's destructor removes it from the request map */ delete request; } bool Tick(time_t now) CXX11_OVERRIDE { ServerInstance->Logs->Log(MODNAME, LOG_DEBUG, "cache: purging DNS cache"); for (cache_map::iterator it = this->cache.begin(); it != this->cache.end(); ) { const Query& query = it->second; if (IsExpired(query, now)) this->cache.erase(it++); else ++it; } return true; } void Rehash(const std::string& dnsserver, std::string sourceaddr, unsigned int sourceport) { if (this->GetFd() > -1) { SocketEngine::Shutdown(this, 2); SocketEngine::Close(this); /* Remove expired entries from the cache */ this->Tick(ServerInstance->Time()); } irc::sockets::aptosa(dnsserver, DNS::PORT, myserver); /* Initialize mastersocket */ int s = socket(myserver.family(), SOCK_DGRAM, 0); this->SetFd(s); /* Have we got a socket? */ if (this->GetFd() != -1) { SocketEngine::SetReuse(s); SocketEngine::NonBlocking(s); irc::sockets::sockaddrs bindto; if (sourceaddr.empty()) { // set a sourceaddr for irc::sockets::aptosa() based on the servers af type if (myserver.family() == AF_INET) sourceaddr = "0.0.0.0"; else if (myserver.family() == AF_INET6) sourceaddr = "::"; } irc::sockets::aptosa(sourceaddr, sourceport, bindto); if (SocketEngine::Bind(this->GetFd(), bindto) < 0) { /* Failed to bind */ ServerInstance->Logs->Log(MODNAME, LOG_SPARSE, "Error binding dns socket - hostnames will NOT resolve"); SocketEngine::Close(this->GetFd()); this->SetFd(-1); } else if (!SocketEngine::AddFd(this, FD_WANT_POLL_READ | FD_WANT_NO_WRITE)) { ServerInstance->Logs->Log(MODNAME, LOG_SPARSE, "Internal error starting DNS - hostnames will NOT resolve."); SocketEngine::Close(this->GetFd()); this->SetFd(-1); } if (bindto.family() != myserver.family()) ServerInstance->Logs->Log(MODNAME, LOG_SPARSE, "Nameserver address family differs from source address family - hostnames might not resolve"); } else { ServerInstance->Logs->Log(MODNAME, LOG_SPARSE, "Error creating DNS socket - hostnames will NOT resolve"); } } }; class ModuleDNS : public Module { MyManager manager; std::string DNSServer; std::string SourceIP; unsigned int SourcePort; void FindDNSServer() { #ifdef _WIN32 // attempt to look up their nameserver from the system ServerInstance->Logs->Log(MODNAME, LOG_DEFAULT, "WARNING: <dns:server> not defined, attempting to find a working server in the system settings..."); PFIXED_INFO pFixedInfo; DWORD dwBufferSize = sizeof(FIXED_INFO); pFixedInfo = (PFIXED_INFO) HeapAlloc(GetProcessHeap(), 0, sizeof(FIXED_INFO)); if (pFixedInfo) { if (GetNetworkParams(pFixedInfo, &dwBufferSize) == ERROR_BUFFER_OVERFLOW) { HeapFree(GetProcessHeap(), 0, pFixedInfo); pFixedInfo = (PFIXED_INFO) HeapAlloc(GetProcessHeap(), 0, dwBufferSize); } if (pFixedInfo) { if (GetNetworkParams(pFixedInfo, &dwBufferSize) == NO_ERROR) DNSServer = pFixedInfo->DnsServerList.IpAddress.String; HeapFree(GetProcessHeap(), 0, pFixedInfo); } if (!DNSServer.empty()) { ServerInstance->Logs->Log(MODNAME, LOG_DEFAULT, "<dns:server> set to '%s' as first active resolver in the system settings.", DNSServer.c_str()); return; } } ServerInstance->Logs->Log(MODNAME, LOG_DEFAULT, "No viable nameserver found! Defaulting to nameserver '127.0.0.1'!"); #else // attempt to look up their nameserver from /etc/resolv.conf ServerInstance->Logs->Log(MODNAME, LOG_DEFAULT, "WARNING: <dns:server> not defined, attempting to find working server in /etc/resolv.conf..."); std::ifstream resolv("/etc/resolv.conf"); while (resolv >> DNSServer) { if (DNSServer == "nameserver") { resolv >> DNSServer; if (DNSServer.find_first_not_of("0123456789.") == std::string::npos || DNSServer.find_first_not_of("0123456789ABCDEFabcdef:") == std::string::npos) { ServerInstance->Logs->Log(MODNAME, LOG_DEFAULT, "<dns:server> set to '%s' as first resolver in /etc/resolv.conf.",DNSServer.c_str()); return; } } } ServerInstance->Logs->Log(MODNAME, LOG_DEFAULT, "/etc/resolv.conf contains no viable nameserver entries! Defaulting to nameserver '127.0.0.1'!"); #endif DNSServer = "127.0.0.1"; } public: ModuleDNS() : manager(this) , SourcePort(0) { } void ReadConfig(ConfigStatus& status) CXX11_OVERRIDE { std::string oldserver = DNSServer; const std::string oldip = SourceIP; const unsigned int oldport = SourcePort; ConfigTag* tag = ServerInstance->Config->ConfValue("dns"); DNSServer = tag->getString("server"); SourceIP = tag->getString("sourceip"); SourcePort = tag->getUInt("sourceport", 0, 0, UINT16_MAX); if (DNSServer.empty()) FindDNSServer(); if (oldserver != DNSServer || oldip != SourceIP || oldport != SourcePort) this->manager.Rehash(DNSServer, SourceIP, SourcePort); } void OnUnloadModule(Module* mod) CXX11_OVERRIDE { for (unsigned int i = 0; i <= MAX_REQUEST_ID; ++i) { DNS::Request* req = this->manager.requests[i]; if (!req) continue; if (req->creator == mod) { Query rr(req->question); rr.error = ERROR_UNLOADED; req->OnError(&rr); delete req; } } } Version GetVersion() CXX11_OVERRIDE { return Version("Provides support for DNS lookups", VF_CORE|VF_VENDOR); } }; MODULE_INIT(ModuleDNS) �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/src/coremods/core_hostname_lookup.cpp������������������������������������������������0000664�0000000�0000000�00000014345�13554550454�0022677�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * InspIRCd -- Internet Relay Chat Daemon * * Copyright (C) 2013-2016 Adam <Adam@anope.org> * * This file is part of InspIRCd. InspIRCd is free software: you can * redistribute it and/or modify it under the terms of the GNU General Public * License as published by the Free Software Foundation, version 2. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include "inspircd.h" #include "modules/dns.h" namespace { LocalIntExt* dl; } /** Derived from Resolver, and performs user forward/reverse lookups. */ class UserResolver : public DNS::Request { private: /** UUID we are looking up */ const std::string uuid; /** Handles errors which happen during DNS resolution. */ static void HandleError(LocalUser* user, const std::string& message) { user->WriteNotice("*** " + message + "; using your IP address (" + user->GetIPString() + ") instead."); bool display_is_real = user->GetDisplayedHost() == user->GetRealHost(); user->ChangeRealHost(user->GetIPString(), display_is_real); dl->unset(user); } public: /** Create a resolver. * @param mgr DNS Manager * @param me this module * @param user The user to begin lookup on * @param to_resolve The IP or host to resolve * @param qt The query type */ UserResolver(DNS::Manager* mgr, Module* me, LocalUser* user, const std::string& to_resolve, DNS::QueryType qt) : DNS::Request(mgr, me, to_resolve, qt) , uuid(user->uuid) { } /** Called on successful lookup * if a previous result has already come back. * @param r The finished query */ void OnLookupComplete(const DNS::Query* r) CXX11_OVERRIDE { LocalUser* bound_user = IS_LOCAL(ServerInstance->FindUUID(uuid)); if (!bound_user) { ServerInstance->Logs->Log(MODNAME, LOG_DEBUG, "Resolution finished for user '%s' who is gone", uuid.c_str()); return; } const DNS::ResourceRecord* ans_record = r->FindAnswerOfType(this->question.type); if (ans_record == NULL) { HandleError(bound_user, "Could not resolve your hostname: No " + this->manager->GetTypeStr(this->question.type) + " records found"); return; } ServerInstance->Logs->Log(MODNAME, LOG_DEBUG, "DNS %s result for %s: '%s' -> '%s'%s", this->manager->GetTypeStr(question.type).c_str(), uuid.c_str(), ans_record->name.c_str(), ans_record->rdata.c_str(), r->cached ? " (cached)" : ""); if (this->question.type == DNS::QUERY_PTR) { UserResolver* res_forward; if (bound_user->client_sa.family() == AF_INET6) { /* IPV6 forward lookup */ res_forward = new UserResolver(this->manager, this->creator, bound_user, ans_record->rdata, DNS::QUERY_AAAA); } else { /* IPV4 lookup */ res_forward = new UserResolver(this->manager, this->creator, bound_user, ans_record->rdata, DNS::QUERY_A); } try { this->manager->Process(res_forward); } catch (DNS::Exception& e) { delete res_forward; ServerInstance->Logs->Log(MODNAME, LOG_DEBUG, "Error in resolver: " + e.GetReason()); HandleError(bound_user, "There was an internal error resolving your host"); } } else if (this->question.type == DNS::QUERY_A || this->question.type == DNS::QUERY_AAAA) { /* Both lookups completed */ irc::sockets::sockaddrs* user_ip = &bound_user->client_sa; bool rev_match = false; if (user_ip->family() == AF_INET6) { struct in6_addr res_bin; if (inet_pton(AF_INET6, ans_record->rdata.c_str(), &res_bin)) { rev_match = !memcmp(&user_ip->in6.sin6_addr, &res_bin, sizeof(res_bin)); } } else { struct in_addr res_bin; if (inet_pton(AF_INET, ans_record->rdata.c_str(), &res_bin)) { rev_match = !memcmp(&user_ip->in4.sin_addr, &res_bin, sizeof(res_bin)); } } if (rev_match) { bound_user->WriteNotice("*** Found your hostname (" + this->question.name + (r->cached ? ") -- cached" : ")")); bound_user->ChangeRealHost(this->question.name, true); dl->unset(bound_user); } else { HandleError(bound_user, "Your hostname does not match up with your IP address"); } } } /** Called on failed lookup * @param query The errored query */ void OnError(const DNS::Query* query) CXX11_OVERRIDE { LocalUser* bound_user = IS_LOCAL(ServerInstance->FindUUID(uuid)); if (bound_user) HandleError(bound_user, "Could not resolve your hostname: " + this->manager->GetErrorStr(query->error)); } }; class ModuleHostnameLookup : public Module { private: LocalIntExt dnsLookup; dynamic_reference<DNS::Manager> DNS; public: ModuleHostnameLookup() : dnsLookup("dnsLookup", ExtensionItem::EXT_USER, this) , DNS(this, "DNS") { dl = &dnsLookup; } void OnSetUserIP(LocalUser* user) CXX11_OVERRIDE { // If core_dns is not loaded or hostname resolution is disabled for the user's // connect class then the logic in this function does not apply. if (!DNS || !user->MyClass->resolvehostnames) return; // Clients can't have a DNS hostname if they aren't connected via IPv4 or IPv6. if (user->client_sa.family() != AF_INET && user->client_sa.family() != AF_INET6) return; user->WriteNotice("*** Looking up your hostname..."); UserResolver* res_reverse = new UserResolver(*this->DNS, this, user, user->GetIPString(), DNS::QUERY_PTR); try { /* If both the reverse and forward queries are cached, the user will be able to pass DNS completely * before Process() completes, which is why dnsLookup.set() is here, before Process() */ this->dnsLookup.set(user, 1); this->DNS->Process(res_reverse); } catch (DNS::Exception& e) { this->dnsLookup.set(user, 0); delete res_reverse; ServerInstance->Logs->Log(MODNAME, LOG_DEBUG, "Error in resolver: " + e.GetReason()); } } ModResult OnCheckReady(LocalUser* user) CXX11_OVERRIDE { return this->dnsLookup.get(user) ? MOD_RES_DENY : MOD_RES_PASSTHRU; } Version GetVersion() CXX11_OVERRIDE { return Version("Provides support for DNS lookups on connecting clients", VF_CORE|VF_VENDOR); } }; MODULE_INIT(ModuleHostnameLookup) �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/src/coremods/core_info/��������������������������������������������������������������0000775�0000000�0000000�00000000000�13554550454�0017710�5����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/src/coremods/core_info/cmd_admin.cpp�������������������������������������������������0000664�0000000�0000000�00000003116�13554550454�0022330�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * InspIRCd -- Internet Relay Chat Daemon * * Copyright (C) 2009-2010 Daniel De Graaf <danieldg@inspircd.org> * Copyright (C) 2007 Robin Burchell <robin+git@viroteck.net> * * 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 "inspircd.h" #include "core_info.h" CommandAdmin::CommandAdmin(Module* parent) : ServerTargetCommand(parent, "ADMIN") { Penalty = 2; syntax = "[<servername>]"; } /** Handle /ADMIN */ CmdResult CommandAdmin::Handle(User* user, const Params& parameters) { if (parameters.size() > 0 && !irc::equals(parameters[0], ServerInstance->Config->ServerName)) return CMD_SUCCESS; user->WriteRemoteNumeric(RPL_ADMINME, ServerInstance->Config->ServerName, "Administrative info"); if (!AdminName.empty()) user->WriteRemoteNumeric(RPL_ADMINLOC1, InspIRCd::Format("Name: %s", AdminName.c_str())); user->WriteRemoteNumeric(RPL_ADMINLOC2, InspIRCd::Format("Nickname: %s", AdminNick.c_str())); user->WriteRemoteNumeric(RPL_ADMINEMAIL, InspIRCd::Format("Email: %s", AdminEmail.c_str())); return CMD_SUCCESS; } ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/src/coremods/core_info/cmd_commands.cpp����������������������������������������������0000664�0000000�0000000�00000003524�13554550454�0023044�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * InspIRCd -- Internet Relay Chat Daemon * * Copyright (C) 2009 Daniel De Graaf <danieldg@inspircd.org> * Copyright (C) 2007 Robin Burchell <robin+git@viroteck.net> * * 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 "inspircd.h" #include "core_info.h" enum { // InspIRCd-specific. RPL_COMMANDS = 700, RPL_COMMANDSEND = 701 }; CommandCommands::CommandCommands(Module* parent) : Command(parent, "COMMANDS", 0, 0) { Penalty = 3; } /** Handle /COMMANDS */ CmdResult CommandCommands::Handle(User* user, const Params& parameters) { const CommandParser::CommandMap& commands = ServerInstance->Parser.GetCommands(); std::vector<std::string> list; list.reserve(commands.size()); for (CommandParser::CommandMap::const_iterator i = commands.begin(); i != commands.end(); ++i) { // Don't show S2S commands to users if (i->second->flags_needed == FLAG_SERVERONLY) continue; Module* src = i->second->creator; list.push_back(InspIRCd::Format("%s %s %d %d", i->second->name.c_str(), src->ModuleSourceFile.c_str(), i->second->min_params, i->second->Penalty)); } std::sort(list.begin(), list.end()); for(unsigned int i=0; i < list.size(); i++) user->WriteNumeric(RPL_COMMANDS, list[i]); user->WriteNumeric(RPL_COMMANDSEND, "End of COMMANDS list"); return CMD_SUCCESS; } ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/src/coremods/core_info/cmd_info.cpp��������������������������������������������������0000664�0000000�0000000�00000006545�13554550454�0022204�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * InspIRCd -- Internet Relay Chat Daemon * * Copyright (C) 2011 Jackmcbarn <jackmcbarn@jackmcbarn.no-ip.org> * Copyright (C) 2009-2010 Daniel De Graaf <danieldg@inspircd.org> * Copyright (C) 2007-2015 Robin Burchell <robin+git@viroteck.net> * Copyright (C) 2008 Thomas Stagner <aquanight@inspircd.org> * * This file is part of InspIRCd. InspIRCd is free software: you can * redistribute it and/or modify it under the terms of the GNU General Public * License as published by the Free Software Foundation, version 2. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include "inspircd.h" #include "core_info.h" CommandInfo::CommandInfo(Module* parent) : ServerTargetCommand(parent, "INFO") { Penalty = 4; syntax = "[<servername>]"; } static const char* const lines[] = { " -/\\- \002InspIRCd\002 -\\/-", " November 2002 - Present", " ", "\002Core Developers\002:", " Attila Molnar, Attila, <attilamolnar@hush.com>", " Peter Powell, SaberUK, <petpow@saberuk.com>", " ", "\002Former Developers\002:", " Oliver Lupton, Om, <om@inspircd.org>", " John Brooks, Special, <special@inspircd.org>", " Dennis Friis, peavey, <peavey@inspircd.org>", " Thomas Stagner, aquanight, <aquanight@inspircd.org>", " Uli Schlachter, psychon, <psychon@inspircd.org>", " Matt Smith, dz, <dz@inspircd.org>", " Daniel De Graaf, danieldg, <danieldg@inspircd.org>", " ", "\002Founding Developers\002:", " Craig Edwards, Brain, <brain@inspircd.org>", " Craig McLure, Craig, <craig@inspircd.org>", " Robin Burchell, w00t, <w00t@inspircd.org>", " ", "\002Active Contributors\002:", " Adam linuxdaemon Sheogorath", " ", "\002Former Contributors\002:", " dmb Zaba skenmy GreenReaper", " Dan Jason satmd owine", " Adremelech John2 jilles HiroP", " eggy Bricker AnMaster djGrrr", " nenolod Quension praetorian pippijn", " CC jamie typobox43 Burlex", " Stskeeps ThaPrince BuildSmart Thunderhacker", " Skip LeaChim Majic MacGyver", " Namegduf Ankit Phoenix Taros", " jackmcbarn ChrisTX Shawn Shutter", " ", "\002Thanks To\002:", " Asmo Brik fraggeln genius3000", " ", " Best experienced with: \002An IRC client\002", NULL }; /** Handle /INFO */ CmdResult CommandInfo::Handle(User* user, const Params& parameters) { if (parameters.size() > 0 && !irc::equals(parameters[0], ServerInstance->Config->ServerName)) return CMD_SUCCESS; int i=0; while (lines[i]) user->WriteRemoteNumeric(RPL_INFO, lines[i++]); user->WriteRemoteNumeric(RPL_ENDOFINFO, "End of /INFO list"); return CMD_SUCCESS; } �����������������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/src/coremods/core_info/cmd_modules.cpp�����������������������������������������������0000664�0000000�0000000�00000005047�13554550454�0022715�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * InspIRCd -- Internet Relay Chat Daemon * * Copyright (C) 2009 Daniel De Graaf <danieldg@inspircd.org> * Copyright (C) 2008 Craig Edwards <craigedwards@brainbox.cc> * Copyright (C) 2007 Robin Burchell <robin+git@viroteck.net> * * 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 "inspircd.h" #include "core_info.h" enum { // From ircd-ratbox with an InspIRCd-specific format. RPL_MODLIST = 702, RPL_ENDOFMODLIST = 703 }; CommandModules::CommandModules(Module* parent) : ServerTargetCommand(parent, "MODULES") { Penalty = 4; syntax = "[<servername>]"; } /** Handle /MODULES */ CmdResult CommandModules::Handle(User* user, const Params& parameters) { // Don't ask remote servers about their modules unless the local user asking is an oper // 2.0 asks anyway, so let's handle that the same way bool for_us = (parameters.empty() || irc::equals(parameters[0], ServerInstance->Config->ServerName)); if ((!for_us) || (!IS_LOCAL(user))) { if (!user->IsOper()) { user->WriteNotice("*** You cannot check what modules other servers have loaded."); return CMD_FAILURE; } // From an oper and not for us, forward if (!for_us) return CMD_SUCCESS; } const ModuleManager::ModuleMap& mods = ServerInstance->Modules->GetModules(); for (ModuleManager::ModuleMap::const_iterator i = mods.begin(); i != mods.end(); ++i) { Module* m = i->second; Version V = m->GetVersion(); if (IS_LOCAL(user) && user->HasPrivPermission("servers/auspex")) { std::string flags("VCO"); size_t pos = 0; for (int mult = 2; mult <= VF_OPTCOMMON; mult *= 2, ++pos) if (!(V.Flags & mult)) flags[pos] = '-'; std::string srcrev = m->ModuleDLLManager->GetVersion(); user->WriteRemoteNumeric(RPL_MODLIST, m->ModuleSourceFile, srcrev.empty() ? "*" : srcrev, flags, V.description); } else { user->WriteRemoteNumeric(RPL_MODLIST, m->ModuleSourceFile, '*', '*', V.description); } } user->WriteRemoteNumeric(RPL_ENDOFMODLIST, "End of MODULES list"); return CMD_SUCCESS; } �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/src/coremods/core_info/cmd_motd.cpp��������������������������������������������������0000664�0000000�0000000�00000004152�13554550454�0022204�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * InspIRCd -- Internet Relay Chat Daemon * * Copyright (C) 2009-2010 Daniel De Graaf <danieldg@inspircd.org> * Copyright (C) 2007 Robin Burchell <robin+git@viroteck.net> * * 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 "inspircd.h" #include "core_info.h" CommandMotd::CommandMotd(Module* parent) : ServerTargetCommand(parent, "MOTD") { syntax = "[<servername>]"; } /** Handle /MOTD */ CmdResult CommandMotd::Handle(User* user, const Params& parameters) { if (parameters.size() > 0 && !irc::equals(parameters[0], ServerInstance->Config->ServerName)) { // Give extra penalty if a non-oper queries the /MOTD of a remote server LocalUser* localuser = IS_LOCAL(user); if ((localuser) && (!user->IsOper())) localuser->CommandFloodPenalty += 2000; return CMD_SUCCESS; } ConfigTag* tag = ServerInstance->Config->EmptyTag; LocalUser* localuser = IS_LOCAL(user); if (localuser) tag = localuser->GetClass()->config; std::string motd_name = tag->getString("motd", "motd"); ConfigFileCache::iterator motd = motds.find(motd_name); if (motd == motds.end()) { user->WriteRemoteNumeric(ERR_NOMOTD, "Message of the day file is missing."); return CMD_SUCCESS; } user->WriteRemoteNumeric(RPL_MOTDSTART, InspIRCd::Format("%s message of the day", ServerInstance->Config->ServerName.c_str())); for (file_cache::iterator i = motd->second.begin(); i != motd->second.end(); i++) user->WriteRemoteNumeric(RPL_MOTD, InspIRCd::Format("- %s", i->c_str())); user->WriteRemoteNumeric(RPL_ENDOFMOTD, "End of message of the day."); return CMD_SUCCESS; } ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/src/coremods/core_info/cmd_time.cpp��������������������������������������������������0000664�0000000�0000000�00000002412�13554550454�0022174�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * InspIRCd -- Internet Relay Chat Daemon * * Copyright (C) 2009-2010 Daniel De Graaf <danieldg@inspircd.org> * Copyright (C) 2007 Robin Burchell <robin+git@viroteck.net> * * 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 "inspircd.h" #include "core_info.h" CommandTime::CommandTime(Module* parent) : ServerTargetCommand(parent, "TIME") { syntax = "[<servername>]"; } CmdResult CommandTime::Handle(User* user, const Params& parameters) { if (parameters.size() > 0 && !irc::equals(parameters[0], ServerInstance->Config->ServerName)) return CMD_SUCCESS; user->WriteRemoteNumeric(RPL_TIME, ServerInstance->Config->ServerName, InspIRCd::TimeString(ServerInstance->Time())); return CMD_SUCCESS; } ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/src/coremods/core_info/cmd_version.cpp�����������������������������������������������0000664�0000000�0000000�00000002534�13554550454�0022730�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * InspIRCd -- Internet Relay Chat Daemon * * Copyright (C) 2009 Daniel De Graaf <danieldg@inspircd.org> * Copyright (C) 2007 Robin Burchell <robin+git@viroteck.net> * * 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 "inspircd.h" #include "core_info.h" CommandVersion::CommandVersion(Module* parent) : Command(parent, "VERSION", 0, 0) { syntax = "[<servername>]"; } CmdResult CommandVersion::Handle(User* user, const Params& parameters) { Numeric::Numeric numeric(RPL_VERSION); irc::tokenstream tokens(ServerInstance->GetVersionString(user->IsOper())); for (std::string token; tokens.GetTrailing(token); ) numeric.push(token); user->WriteNumeric(numeric); LocalUser *lu = IS_LOCAL(user); if (lu != NULL) { ServerInstance->ISupport.SendTo(lu); } return CMD_SUCCESS; } ��������������������������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/src/coremods/core_info/core_info.cpp�������������������������������������������������0000664�0000000�0000000�00000013427�13554550454�0022366�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * InspIRCd -- Internet Relay Chat Daemon * * Copyright (C) 2014 Attila Molnar <attilamolnar@hush.com> * * This file is part of InspIRCd. InspIRCd is free software: you can * redistribute it and/or modify it under the terms of the GNU General Public * License as published by the Free Software Foundation, version 2. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include "inspircd.h" #include "core_info.h" enum { // From RFC 2812. RPL_WELCOME = 1, RPL_YOURHOST = 2, RPL_CREATED = 3, RPL_MYINFO = 4 }; RouteDescriptor ServerTargetCommand::GetRouting(User* user, const Params& parameters) { // Parameter must be a server name, not a nickname or uuid if ((!parameters.empty()) && (parameters[0].find('.') != std::string::npos)) return ROUTE_UNICAST(parameters[0]); return ROUTE_LOCALONLY; } class CoreModInfo : public Module { CommandAdmin cmdadmin; CommandCommands cmdcommands; CommandInfo cmdinfo; CommandModules cmdmodules; CommandMotd cmdmotd; CommandTime cmdtime; CommandVersion cmdversion; Numeric::Numeric numeric004; /** Returns a list of user or channel mode characters. * Used for constructing the parts of the mode list in the 004 numeric. * @param mt Controls whether to list user modes or channel modes * @param needparam Return modes only if they require a parameter to be set * @return The available mode letters that satisfy the given conditions */ static std::string CreateModeList(ModeType mt, bool needparam = false) { std::string modestr; for (unsigned char mode = 'A'; mode <= 'z'; mode++) { ModeHandler* mh = ServerInstance->Modes.FindMode(mode, mt); if ((mh) && ((!needparam) || (mh->NeedsParam(true)))) modestr.push_back(mode); } return modestr; } void OnServiceChange(const ServiceProvider& prov) { if (prov.service != SERVICE_MODE) return; std::vector<std::string>& params = numeric004.GetParams(); params.erase(params.begin()+2, params.end()); // Create lists of modes // 1. User modes // 2. Channel modes // 3. Channel modes that require a parameter when set numeric004.push(CreateModeList(MODETYPE_USER)); numeric004.push(CreateModeList(MODETYPE_CHANNEL)); numeric004.push(CreateModeList(MODETYPE_CHANNEL, true)); } public: CoreModInfo() : cmdadmin(this) , cmdcommands(this) , cmdinfo(this) , cmdmodules(this) , cmdmotd(this) , cmdtime(this) , cmdversion(this) , numeric004(RPL_MYINFO) { numeric004.push(ServerInstance->Config->ServerName); numeric004.push(INSPIRCD_BRANCH); } void ReadConfig(ConfigStatus& status) CXX11_OVERRIDE { // Process the escape codes in the MOTDs. ConfigFileCache newmotds; for (ServerConfig::ClassVector::const_iterator iter = ServerInstance->Config->Classes.begin(); iter != ServerInstance->Config->Classes.end(); ++iter) { ConfigTag* tag = (*iter)->config; // Don't process the file if it has already been processed. const std::string motd = tag->getString("motd", "motd"); if (newmotds.find(motd) != newmotds.end()) continue; // We can't process the file if it doesn't exist. ConfigFileCache::iterator file = ServerInstance->Config->Files.find(motd); if (file == ServerInstance->Config->Files.end()) continue; // Process escape codes. newmotds[file->first] = file->second; InspIRCd::ProcessColors(newmotds[file->first]); } cmdmotd.motds.swap(newmotds); ConfigTag* tag = ServerInstance->Config->ConfValue("admin"); cmdadmin.AdminName = tag->getString("name"); cmdadmin.AdminEmail = tag->getString("email", "null@example.com"); cmdadmin.AdminNick = tag->getString("nick", "admin"); } void OnUserConnect(LocalUser* user) CXX11_OVERRIDE { user->WriteNumeric(RPL_WELCOME, InspIRCd::Format("Welcome to the %s IRC Network %s", ServerInstance->Config->Network.c_str(), user->GetFullRealHost().c_str())); user->WriteNumeric(RPL_YOURHOST, InspIRCd::Format("Your host is %s, running version %s", ServerInstance->Config->ServerName.c_str(), INSPIRCD_BRANCH)); user->WriteNumeric(RPL_CREATED, InspIRCd::TimeString(ServerInstance->startup_time, "This server was created %H:%M:%S %b %d %Y")); user->WriteNumeric(numeric004); ServerInstance->ISupport.SendTo(user); /* Trigger MOTD and LUSERS output, give modules a chance too */ ModResult MOD_RESULT; std::string command("LUSERS"); CommandBase::Params parameters; FIRST_MOD_RESULT(OnPreCommand, MOD_RESULT, (command, parameters, user, true)); if (!MOD_RESULT) ServerInstance->Parser.CallHandler(command, parameters, user); MOD_RESULT = MOD_RES_PASSTHRU; command = "MOTD"; FIRST_MOD_RESULT(OnPreCommand, MOD_RESULT, (command, parameters, user, true)); if (!MOD_RESULT) ServerInstance->Parser.CallHandler(command, parameters, user); if (ServerInstance->Config->RawLog) { ClientProtocol::Messages::Privmsg rawlogmsg(ServerInstance->FakeClient, user, "*** Raw I/O logging is enabled on this server. All messages, passwords, and commands are being recorded."); user->Send(ServerInstance->GetRFCEvents().privmsg, rawlogmsg); } } void OnServiceAdd(ServiceProvider& service) CXX11_OVERRIDE { OnServiceChange(service); } void OnServiceDel(ServiceProvider& service) CXX11_OVERRIDE { OnServiceChange(service); } void Prioritize() CXX11_OVERRIDE { ServerInstance->Modules.SetPriority(this, I_OnUserConnect, PRIORITY_FIRST); } Version GetVersion() CXX11_OVERRIDE { return Version("Provides the ADMIN, COMMANDS, INFO, MODULES, MOTD, TIME, and VERSION commands", VF_VENDOR|VF_CORE); } }; MODULE_INIT(CoreModInfo) �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/src/coremods/core_info/core_info.h���������������������������������������������������0000664�0000000�0000000�00000010456�13554550454�0022032�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * InspIRCd -- Internet Relay Chat Daemon * * Copyright (C) 2014 Attila Molnar <attilamolnar@hush.com> * * This file is part of InspIRCd. InspIRCd is free software: you can * redistribute it and/or modify it under the terms of the GNU General Public * License as published by the Free Software Foundation, version 2. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include "inspircd.h" /** These commands require no parameters, but if there is a parameter it is a server name where the command will be routed to. */ class ServerTargetCommand : public Command { public: ServerTargetCommand(Module* mod, const std::string& Name) : Command(mod, Name) { } RouteDescriptor GetRouting(User* user, const Params& parameters) CXX11_OVERRIDE; }; /** Handle /ADMIN. */ class CommandAdmin : public ServerTargetCommand { public: /** Holds the admin's name, for output in * the /ADMIN command. */ std::string AdminName; /** Holds the email address of the admin, * for output in the /ADMIN command. */ std::string AdminEmail; /** Holds the admin's nickname, for output * in the /ADMIN command */ std::string AdminNick; /** Constructor for admin. */ CommandAdmin(Module* parent); /** Handle command. * @param parameters The parameters to the command * @param user The user issuing the command * @return A value from CmdResult to indicate command success or failure. */ CmdResult Handle(User* user, const Params& parameters) CXX11_OVERRIDE; }; /** Handle /COMMANDS. */ class CommandCommands : public Command { public: /** Constructor for commands. */ CommandCommands(Module* parent); /** Handle command. * @param parameters The parameters to the command * @param user The user issuing the command * @return A value from CmdResult to indicate command success or failure. */ CmdResult Handle(User* user, const Params& parameters) CXX11_OVERRIDE; }; /** Handle /INFO. */ class CommandInfo : public ServerTargetCommand { public: /** Constructor for info. */ CommandInfo(Module* parent); /** Handle command. * @param parameters The parameters to the command * @param user The user issuing the command * @return A value from CmdResult to indicate command success or failure. */ CmdResult Handle(User* user, const Params& parameters) CXX11_OVERRIDE; }; /** Handle /MODULES. */ class CommandModules : public ServerTargetCommand { public: /** Constructor for modules. */ CommandModules(Module* parent); /** Handle command. * @param parameters The parameters to the command * @param user The user issuing the command * @return A value from CmdResult to indicate command success or failure. */ CmdResult Handle(User* user, const Params& parameters) CXX11_OVERRIDE; }; /** Handle /MOTD. */ class CommandMotd : public ServerTargetCommand { public: ConfigFileCache motds; /** Constructor for motd. */ CommandMotd(Module* parent); /** Handle command. * @param parameters The parameters to the command * @param user The user issuing the command * @return A value from CmdResult to indicate command success or failure. */ CmdResult Handle(User* user, const Params& parameters) CXX11_OVERRIDE; }; /** Handle /TIME. */ class CommandTime : public ServerTargetCommand { public: /** Constructor for time. */ CommandTime(Module* parent); /** Handle command. * @param parameters The parameters to the command * @param user The user issuing the command * @return A value from CmdResult to indicate command success or failure. */ CmdResult Handle(User* user, const Params& parameters) CXX11_OVERRIDE; }; /** Handle /VERSION. */ class CommandVersion : public Command { public: /** Constructor for version. */ CommandVersion(Module* parent); /** Handle command. * @param parameters The parameters to the command * @param user The user issuing the command * @return A value from CmdResult to indicate command success or failure. */ CmdResult Handle(User* user, const Params& parameters) CXX11_OVERRIDE; }; ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/src/coremods/core_list.cpp�����������������������������������������������������������0000664�0000000�0000000�00000014317�13554550454�0020442�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * InspIRCd -- Internet Relay Chat Daemon * * Copyright (C) 2009 Daniel De Graaf <danieldg@inspircd.org> * Copyright (C) 2007 Robin Burchell <robin+git@viroteck.net> * * 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 "inspircd.h" /** Handle /LIST. */ class CommandList : public Command { private: ChanModeReference secretmode; ChanModeReference privatemode; /** Parses the creation time or topic set time out of a LIST parameter. * @param value The parameter containing a minute count. * @return The UNIX time at \p value minutes ago. */ time_t ParseMinutes(const std::string& value) { time_t minutes = ConvToNum<time_t>(value.c_str() + 2); if (!minutes) return 0; return ServerInstance->Time() - (minutes * 60); } public: /** Constructor for list. */ CommandList(Module* parent) : Command(parent,"LIST", 0, 0) , secretmode(creator, "secret") , privatemode(creator, "private") { allow_empty_last_param = false; Penalty = 5; } /** Handle command. * @param parameters The parameters to the command * @param user The user issuing the command * @return A value from CmdResult to indicate command success or failure. */ CmdResult Handle(User* user, const Params& parameters) CXX11_OVERRIDE; }; /** Handle /LIST */ CmdResult CommandList::Handle(User* user, const Params& parameters) { // C: Searching based on creation time, via the "C<val" and "C>val" modifiers // to search for a channel creation time that is lower or higher than val // respectively. time_t mincreationtime = 0; time_t maxcreationtime = 0; // M: Searching based on mask. // N: Searching based on !mask. bool match_name_topic = false; bool match_inverted = false; const char* match = NULL; // T: Searching based on topic time, via the "T<val" and "T>val" modifiers to // search for a topic time that is lower or higher than val respectively. time_t mintopictime = 0; time_t maxtopictime = 0; // U: Searching based on user count within the channel, via the "<val" and // ">val" modifiers to search for a channel that has less than or more than // val users respectively. size_t minusers = 0; size_t maxusers = 0; for (Params::const_iterator iter = parameters.begin(); iter != parameters.end(); ++iter) { const std::string& constraint = *iter; if (constraint[0] == '<') { maxusers = ConvToNum<size_t>(constraint.c_str() + 1); } else if (constraint[0] == '>') { minusers = ConvToNum<size_t>(constraint.c_str() + 1); } else if (!constraint.compare(0, 2, "C<", 2) || !constraint.compare(0, 2, "c<", 2)) { mincreationtime = ParseMinutes(constraint); } else if (!constraint.compare(0, 2, "C>", 2) || !constraint.compare(0, 2, "c>", 2)) { maxcreationtime = ParseMinutes(constraint); } else if (!constraint.compare(0, 2, "T<", 2) || !constraint.compare(0, 2, "t<", 2)) { mintopictime = ParseMinutes(constraint); } else if (!constraint.compare(0, 2, "T>", 2) || !constraint.compare(0, 2, "t>", 2)) { maxtopictime = ParseMinutes(constraint); } else { // If the glob is prefixed with ! it is inverted. match = constraint.c_str(); if (match[0] == '!') { match_inverted = true; match += 1; } // Ensure that the user didn't just run "LIST !". if (match[0]) match_name_topic = true; } } const bool has_privs = user->HasPrivPermission("channels/auspex"); user->WriteNumeric(RPL_LISTSTART, "Channel", "Users Name"); const chan_hash& chans = ServerInstance->GetChans(); for (chan_hash::const_iterator i = chans.begin(); i != chans.end(); ++i) { Channel* const chan = i->second; // Check the user count if a search has been specified. const size_t users = chan->GetUserCounter(); if ((minusers && users <= minusers) || (maxusers && users >= maxusers)) continue; // Check the creation ts if a search has been specified. const time_t creationtime = chan->age; if ((mincreationtime && creationtime <= mincreationtime) || (maxcreationtime && creationtime >= maxcreationtime)) continue; // Check the topic ts if a search has been specified. const time_t topictime = chan->topicset; if ((mintopictime && (!topictime || topictime <= mintopictime)) || (maxtopictime && (!topictime || topictime >= maxtopictime))) continue; // Attempt to match a glob pattern. if (match_name_topic) { bool matches = InspIRCd::Match(chan->name, match) || InspIRCd::Match(chan->topic, match); // The user specified an match that we did not match. if (!matches && !match_inverted) continue; // The user specified an inverted match that we did match. if (matches && match_inverted) continue; } // if the channel is not private/secret, OR the user is on the channel anyway bool n = (has_privs || chan->HasUser(user)); // If we're not in the channel and +s is set on it, we want to ignore it if ((n) || (!chan->IsModeSet(secretmode))) { if ((!n) && (chan->IsModeSet(privatemode))) { // Channel is private (+p) and user is outside/not privileged user->WriteNumeric(RPL_LIST, '*', users, ""); } else { /* User is in the channel/privileged, channel is not +s */ user->WriteNumeric(RPL_LIST, chan->name, users, InspIRCd::Format("[+%s] %s", chan->ChanModes(n), chan->topic.c_str())); } } } user->WriteNumeric(RPL_LISTEND, "End of channel list."); return CMD_SUCCESS; } class CoreModList : public Module { private: CommandList cmd; public: CoreModList() : cmd(this) { } void On005Numeric(std::map<std::string, std::string>& tokens) CXX11_OVERRIDE { tokens["ELIST"] = "CMNTU"; tokens["SAFELIST"]; } Version GetVersion() CXX11_OVERRIDE { return Version("Provides the LIST command", VF_VENDOR|VF_CORE); } }; MODULE_INIT(CoreModList) �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/src/coremods/core_loadmodule.cpp�����������������������������������������������������0000664�0000000�0000000�00000007531�13554550454�0021614�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * InspIRCd -- Internet Relay Chat Daemon * * Copyright (C) 2009 Daniel De Graaf <danieldg@inspircd.org> * Copyright (C) 2007 Robin Burchell <robin+git@viroteck.net> * * 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 "inspircd.h" /** Handle /LOADMODULE. */ class CommandLoadmodule : public Command { public: /** Constructor for loadmodule. */ CommandLoadmodule ( Module* parent) : Command(parent,"LOADMODULE",1,1) { flags_needed='o'; syntax = "<modulename>"; } /** Handle command. * @param parameters The parameters to the command * @param user The user issuing the command * @return A value from CmdResult to indicate command success or failure. */ CmdResult Handle(User* user, const Params& parameters) CXX11_OVERRIDE; }; /** Handle /LOADMODULE */ CmdResult CommandLoadmodule::Handle(User* user, const Params& parameters) { if (ServerInstance->Modules->Load(parameters[0])) { ServerInstance->SNO->WriteGlobalSno('a', "NEW MODULE: %s loaded %s",user->nick.c_str(), parameters[0].c_str()); user->WriteNumeric(RPL_LOADEDMODULE, parameters[0], "Module successfully loaded."); return CMD_SUCCESS; } else { user->WriteNumeric(ERR_CANTLOADMODULE, parameters[0], ServerInstance->Modules->LastError()); return CMD_FAILURE; } } /** Handle /UNLOADMODULE. */ class CommandUnloadmodule : public Command { public: bool allowcoreunload; /** Constructor for unloadmodule. */ CommandUnloadmodule(Module* parent) : Command(parent, "UNLOADMODULE", 1) , allowcoreunload(false) { flags_needed = 'o'; syntax = "<modulename>"; } /** Handle command. * @param parameters The parameters to the command * @param user The user issuing the command * @return A value from CmdResult to indicate command success or failure. */ CmdResult Handle(User* user, const Params& parameters) CXX11_OVERRIDE; }; CmdResult CommandUnloadmodule::Handle(User* user, const Params& parameters) { if (!allowcoreunload && InspIRCd::Match(parameters[0], "core_*.so", ascii_case_insensitive_map)) { user->WriteNumeric(ERR_CANTUNLOADMODULE, parameters[0], "You cannot unload core commands!"); return CMD_FAILURE; } Module* m = ServerInstance->Modules->Find(parameters[0]); if (m == creator) { user->WriteNumeric(ERR_CANTUNLOADMODULE, parameters[0], "You cannot unload module loading commands!"); return CMD_FAILURE; } if (m && ServerInstance->Modules->Unload(m)) { ServerInstance->SNO->WriteGlobalSno('a', "MODULE UNLOADED: %s unloaded %s", user->nick.c_str(), parameters[0].c_str()); user->WriteNumeric(RPL_UNLOADEDMODULE, parameters[0], "Module successfully unloaded."); } else { user->WriteNumeric(ERR_CANTUNLOADMODULE, parameters[0], (m ? ServerInstance->Modules->LastError() : "No such module")); return CMD_FAILURE; } return CMD_SUCCESS; } class CoreModLoadModule : public Module { CommandLoadmodule cmdloadmod; CommandUnloadmodule cmdunloadmod; public: CoreModLoadModule() : cmdloadmod(this), cmdunloadmod(this) { } Version GetVersion() CXX11_OVERRIDE { return Version("Provides the LOADMODULE and UNLOADMODULE commands", VF_VENDOR|VF_CORE); } void ReadConfig(ConfigStatus& status) CXX11_OVERRIDE { ConfigTag* tag = ServerInstance->Config->ConfValue("security"); cmdunloadmod.allowcoreunload = tag->getBool("allowcoreunload"); } }; MODULE_INIT(CoreModLoadModule) �����������������������������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/src/coremods/core_lusers.cpp���������������������������������������������������������0000664�0000000�0000000�00000011626�13554550454�0021004�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * InspIRCd -- Internet Relay Chat Daemon * * Copyright (C) 2009-2010 Daniel De Graaf <danieldg@inspircd.org> * Copyright (C) 2007 Robin Burchell <robin+git@viroteck.net> * * 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 "inspircd.h" struct LusersCounters { unsigned int max_local; unsigned int max_global; unsigned int invisible; LusersCounters(unsigned int inv) : max_local(ServerInstance->Users->LocalUserCount()) , max_global(ServerInstance->Users->RegisteredUserCount()) , invisible(inv) { } inline void UpdateMaxUsers() { unsigned int current = ServerInstance->Users->LocalUserCount(); if (current > max_local) max_local = current; current = ServerInstance->Users->RegisteredUserCount(); if (current > max_global) max_global = current; } }; /** Handle /LUSERS. */ class CommandLusers : public Command { LusersCounters& counters; public: /** Constructor for lusers. */ CommandLusers(Module* parent, LusersCounters& Counters) : Command(parent,"LUSERS",0,0), counters(Counters) { } /** Handle command. * @param parameters The parameters to the command * @param user The user issuing the command * @return A value from CmdResult to indicate command success or failure. */ CmdResult Handle(User* user, const Params& parameters) CXX11_OVERRIDE; }; /** Handle /LUSERS */ CmdResult CommandLusers::Handle(User* user, const Params& parameters) { unsigned int n_users = ServerInstance->Users->RegisteredUserCount(); ProtocolInterface::ServerList serverlist; ServerInstance->PI->GetServerList(serverlist); unsigned int n_serv = serverlist.size(); unsigned int n_local_servs = 0; for (ProtocolInterface::ServerList::const_iterator i = serverlist.begin(); i != serverlist.end(); ++i) { if (i->parentname == ServerInstance->Config->ServerName) n_local_servs++; } // fix for default GetServerList not returning us if (!n_serv) n_serv = 1; counters.UpdateMaxUsers(); user->WriteNumeric(RPL_LUSERCLIENT, InspIRCd::Format("There are %d users and %d invisible on %d servers", n_users - counters.invisible, counters.invisible, n_serv)); if (ServerInstance->Users->OperCount()) user->WriteNumeric(RPL_LUSEROP, ServerInstance->Users.OperCount(), "operator(s) online"); if (ServerInstance->Users->UnregisteredUserCount()) user->WriteNumeric(RPL_LUSERUNKNOWN, ServerInstance->Users.UnregisteredUserCount(), "unknown connections"); user->WriteNumeric(RPL_LUSERCHANNELS, ServerInstance->GetChans().size(), "channels formed"); user->WriteNumeric(RPL_LUSERME, InspIRCd::Format("I have %d clients and %d servers", ServerInstance->Users.LocalUserCount(), n_local_servs)); user->WriteNumeric(RPL_LOCALUSERS, InspIRCd::Format("Current local users: %d Max: %d", ServerInstance->Users.LocalUserCount(), counters.max_local)); user->WriteNumeric(RPL_GLOBALUSERS, InspIRCd::Format("Current global users: %d Max: %d", n_users, counters.max_global)); return CMD_SUCCESS; } class InvisibleWatcher : public ModeWatcher { unsigned int& invisible; public: InvisibleWatcher(Module* mod, unsigned int& Invisible) : ModeWatcher(mod, "invisible", MODETYPE_USER), invisible(Invisible) { } void AfterMode(User* source, User* dest, Channel* channel, const std::string& parameter, bool adding) CXX11_OVERRIDE { if (dest->registered != REG_ALL) return; if (adding) invisible++; else invisible--; } }; class ModuleLusers : public Module { UserModeReference invisiblemode; LusersCounters counters; CommandLusers cmd; InvisibleWatcher mw; unsigned int CountInvisible() { unsigned int c = 0; const user_hash& users = ServerInstance->Users->GetUsers(); for (user_hash::const_iterator i = users.begin(); i != users.end(); ++i) { User* u = i->second; if (u->IsModeSet(invisiblemode)) c++; } return c; } public: ModuleLusers() : invisiblemode(this, "invisible") , counters(CountInvisible()) , cmd(this, counters) , mw(this, counters.invisible) { } void OnPostConnect(User* user) CXX11_OVERRIDE { counters.UpdateMaxUsers(); if (user->IsModeSet(invisiblemode)) counters.invisible++; } void OnUserQuit(User* user, const std::string& message, const std::string& oper_message) CXX11_OVERRIDE { if (user->IsModeSet(invisiblemode)) counters.invisible--; } Version GetVersion() CXX11_OVERRIDE { return Version("Provides the LUSERS command", VF_VENDOR | VF_CORE); } }; MODULE_INIT(ModuleLusers) ����������������������������������������������������������������������������������������������������������inspircd-3.4.0/src/coremods/core_message.cpp��������������������������������������������������������0000664�0000000�0000000�00000033326�13554550454�0021114�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * InspIRCd -- Internet Relay Chat Daemon * * Copyright (C) 2009 Daniel De Graaf <danieldg@inspircd.org> * Copyright (C) 2007-2008 Craig Edwards <craigedwards@brainbox.cc> * Copyright (C) 2007 Robin Burchell <robin+git@viroteck.net> * * 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 "inspircd.h" enum { // From RFC 2812. ERR_NOSUCHSERVICE = 408 }; class MessageDetailsImpl : public MessageDetails { public: MessageDetailsImpl(MessageType mt, const std::string& msg, const ClientProtocol::TagMap& tags) : MessageDetails(mt, msg, tags) { } bool IsCTCP(std::string& name, std::string& body) const CXX11_OVERRIDE { if (!this->IsCTCP()) return false; size_t end_of_name = text.find(' ', 2); size_t end_of_ctcp = *text.rbegin() == '\x1' ? 1 : 0; if (end_of_name == std::string::npos) { // The CTCP only contains a name. name.assign(text, 1, text.length() - 1 - end_of_ctcp); body.clear(); return true; } // The CTCP contains a name and a body. name.assign(text, 1, end_of_name - 1); size_t start_of_body = text.find_first_not_of(' ', end_of_name + 1); if (start_of_body == std::string::npos) { // The CTCP body is provided but empty. body.clear(); return true; } // The CTCP body provided was non-empty. body.assign(text, start_of_body, text.length() - start_of_body - end_of_ctcp); return true; } bool IsCTCP(std::string& name) const CXX11_OVERRIDE { if (!this->IsCTCP()) return false; size_t end_of_name = text.find(' ', 2); if (end_of_name == std::string::npos) { // The CTCP only contains a name. size_t end_of_ctcp = *text.rbegin() == '\x1' ? 1 : 0; name.assign(text, 1, text.length() - 1 - end_of_ctcp); return true; } // The CTCP contains a name and a body. name.assign(text, 1, end_of_name - 1); return true; } bool IsCTCP() const CXX11_OVERRIDE { // According to draft-oakley-irc-ctcp-02 a valid CTCP must begin with SOH and // contain at least one octet which is not NUL, SOH, CR, LF, or SPACE. As most // of these are restricted at the protocol level we only need to check for SOH // and SPACE. return (text.length() >= 2) && (text[0] == '\x1') && (text[1] != '\x1') && (text[1] != ' '); } }; namespace { bool FirePreEvents(User* source, MessageTarget& msgtarget, MessageDetails& msgdetails) { // Inform modules that a message wants to be sent. ModResult modres; FIRST_MOD_RESULT(OnUserPreMessage, modres, (source, msgtarget, msgdetails)); if (modres == MOD_RES_DENY) { // Inform modules that a module blocked the mssage. FOREACH_MOD(OnUserMessageBlocked, (source, msgtarget, msgdetails)); return false; } // Check whether a module zapped the message body. if (msgdetails.text.empty()) { source->WriteNumeric(ERR_NOTEXTTOSEND, "No text to send"); return false; } // Inform modules that a message is about to be sent. FOREACH_MOD(OnUserMessage, (source, msgtarget, msgdetails)); return true; } CmdResult FirePostEvent(User* source, const MessageTarget& msgtarget, const MessageDetails& msgdetails) { // If the source is local and was not sending a CTCP reply then update their idle time. LocalUser* lsource = IS_LOCAL(source); if (lsource && (msgdetails.type != MSG_NOTICE || !msgdetails.IsCTCP())) lsource->idle_lastmsg = ServerInstance->Time(); // Inform modules that a message was sent. FOREACH_MOD(OnUserPostMessage, (source, msgtarget, msgdetails)); return CMD_SUCCESS; } } class CommandMessage : public Command { private: const MessageType msgtype; CmdResult HandleChannelTarget(User* source, const Params& parameters, const char* target, PrefixMode* pm) { Channel* chan = ServerInstance->FindChan(target); if (!chan) { // The target channel does not exist. source->WriteNumeric(Numerics::NoSuchChannel(parameters[0])); return CMD_FAILURE; } // Fire the pre-message events. MessageTarget msgtarget(chan, pm ? pm->GetPrefix() : 0); MessageDetailsImpl msgdetails(msgtype, parameters[1], parameters.GetTags()); msgdetails.exemptions.insert(source); if (!FirePreEvents(source, msgtarget, msgdetails)) return CMD_FAILURE; // Send the message to the members of the channel. ClientProtocol::Messages::Privmsg privmsg(ClientProtocol::Messages::Privmsg::nocopy, source, chan, msgdetails.text, msgdetails.type, msgtarget.status); privmsg.AddTags(msgdetails.tags_out); privmsg.SetSideEffect(true); chan->Write(ServerInstance->GetRFCEvents().privmsg, privmsg, msgtarget.status, msgdetails.exemptions); // Create the outgoing message and message event. return FirePostEvent(source, msgtarget, msgdetails); } CmdResult HandleServerTarget(User* source, const Params& parameters) { // If the source isn't allowed to mass message users then reject // the attempt to mass-message users. if (!source->HasPrivPermission("users/mass-message")) return CMD_FAILURE; // Extract the server glob match from the target parameter. std::string servername(parameters[0], 1); // Fire the pre-message events. MessageTarget msgtarget(&servername); MessageDetailsImpl msgdetails(msgtype, parameters[1], parameters.GetTags()); if (!FirePreEvents(source, msgtarget, msgdetails)) return CMD_FAILURE; // If the current server name matches the server name glob then send // the message out to the local users. if (InspIRCd::Match(ServerInstance->Config->ServerName, servername)) { // Create the outgoing message and message event. ClientProtocol::Messages::Privmsg message(ClientProtocol::Messages::Privmsg::nocopy, source, "$*", msgdetails.text, msgdetails.type); message.AddTags(msgdetails.tags_out); message.SetSideEffect(true); ClientProtocol::Event messageevent(ServerInstance->GetRFCEvents().privmsg, message); const UserManager::LocalList& list = ServerInstance->Users.GetLocalUsers(); for (UserManager::LocalList::const_iterator i = list.begin(); i != list.end(); ++i) { LocalUser* luser = *i; // Don't send to unregistered users or the user who is the source. if (luser->registered != REG_ALL || luser == source) continue; // Only send to non-exempt users. if (!msgdetails.exemptions.count(luser)) luser->Send(messageevent); } } // Fire the post-message event. return FirePostEvent(source, msgtarget, msgdetails); } CmdResult HandleUserTarget(User* source, const Params& parameters) { User* target; if (IS_LOCAL(source)) { // Local sources can specify either a nick or a nick@server mask as the target. const char* targetserver = strchr(parameters[0].c_str(), '@'); if (targetserver) { // The target is a user on a specific server (e.g. jto@tolsun.oulu.fi). target = ServerInstance->FindNickOnly(parameters[0].substr(0, targetserver - parameters[0].c_str())); if (target && strcasecmp(target->server->GetName().c_str(), targetserver + 1)) target = NULL; } else { // If the source is a local user then we only look up the target by nick. target = ServerInstance->FindNickOnly(parameters[0]); } } else { // Remote users can only specify a nick or UUID as the target. target = ServerInstance->FindNick(parameters[0]); } if (!target || target->registered != REG_ALL) { // The target user does not exist or is not fully registered. source->WriteNumeric(Numerics::NoSuchNick(parameters[0])); return CMD_FAILURE; } // If the target is away then inform the user. if (target->IsAway() && msgtype == MSG_PRIVMSG) source->WriteNumeric(RPL_AWAY, target->nick, target->awaymsg); // Fire the pre-message events. MessageTarget msgtarget(target); MessageDetailsImpl msgdetails(msgtype, parameters[1], parameters.GetTags()); if (!FirePreEvents(source, msgtarget, msgdetails)) return CMD_FAILURE; LocalUser* const localtarget = IS_LOCAL(target); if (localtarget) { // Send to the target if they are a local user. ClientProtocol::Messages::Privmsg privmsg(ClientProtocol::Messages::Privmsg::nocopy, source, localtarget->nick, msgdetails.text, msgtype); privmsg.AddTags(msgdetails.tags_out); privmsg.SetSideEffect(true); localtarget->Send(ServerInstance->GetRFCEvents().privmsg, privmsg); } // Fire the post-message event. return FirePostEvent(source, msgtarget, msgdetails); } public: CommandMessage(Module* parent, MessageType mt) : Command(parent, ClientProtocol::Messages::Privmsg::CommandStrFromMsgType(mt), 2, 2) , msgtype(mt) { syntax = "<target>[,<target>]+ :<message>"; } /** Handle command. * @param parameters The parameters to the command * @param user The user issuing the command * @return A value from CmdResult to indicate command success or failure. */ CmdResult Handle(User* user, const Params& parameters) CXX11_OVERRIDE { if (CommandParser::LoopCall(user, this, parameters, 0)) return CMD_SUCCESS; // The specified message was empty. if (parameters[1].empty()) { user->WriteNumeric(ERR_NOTEXTTOSEND, "No text to send"); return CMD_FAILURE; } // The target is a server glob. if (parameters[0][0] == '$') return HandleServerTarget(user, parameters); // If the message begins with a status character then look it up. const char* target = parameters[0].c_str(); PrefixMode* pmh = ServerInstance->Modes->FindPrefix(target[0]); if (pmh) target++; // The target is a channel name. if (*target == '#') return HandleChannelTarget(user, parameters, target, pmh); // The target is a nickname. return HandleUserTarget(user, parameters); } RouteDescriptor GetRouting(User* user, const Params& parameters) CXX11_OVERRIDE { if (IS_LOCAL(user)) // This is handled by the OnUserPostMessage hook to split the LoopCall pieces return ROUTE_LOCALONLY; else return ROUTE_MESSAGE(parameters[0]); } }; class CommandSQuery : public SplitCommand { public: CommandSQuery(Module* Creator) : SplitCommand(Creator, "SQUERY", 2, 2) { syntax = "<service> :<message>"; } CmdResult HandleLocal(LocalUser* user, const Params& parameters) CXX11_OVERRIDE { // The specified message was empty. if (parameters[1].empty()) { user->WriteNumeric(ERR_NOTEXTTOSEND, "No text to send"); return CMD_FAILURE; } // The target can be either a nick or a nick@server mask. User* target; const char* targetserver = strchr(parameters[0].c_str(), '@'); if (targetserver) { // The target is a user on a specific server (e.g. jto@tolsun.oulu.fi). target = ServerInstance->FindNickOnly(parameters[0].substr(0, targetserver - parameters[0].c_str())); if (target && strcasecmp(target->server->GetName().c_str(), targetserver + 1)) target = NULL; } else { // The targer can be on any server. target = ServerInstance->FindNickOnly(parameters[0]); } if (!target || target->registered != REG_ALL || !target->server->IsULine()) { // The target user does not exist, is not fully registered, or is not a service. user->WriteNumeric(ERR_NOSUCHSERVICE, parameters[0], "No such service"); return CMD_FAILURE; } // Fire the pre-message events. MessageTarget msgtarget(target); MessageDetailsImpl msgdetails(MSG_PRIVMSG, parameters[1], parameters.GetTags()); if (!FirePreEvents(user, msgtarget, msgdetails)) return CMD_FAILURE; // The SQUERY command targets a service on a U-lined server. This can never // be on the server local to the source so we don't need to do any routing // logic and can forward it as a PRIVMSG. // Fire the post-message event. return FirePostEvent(user, msgtarget, msgdetails); } }; class ModuleCoreMessage : public Module { private: CommandMessage cmdprivmsg; CommandMessage cmdnotice; CommandSQuery cmdsquery; ChanModeReference moderatedmode; ChanModeReference noextmsgmode; public: ModuleCoreMessage() : cmdprivmsg(this, MSG_PRIVMSG) , cmdnotice(this, MSG_NOTICE) , cmdsquery(this) , moderatedmode(this, "moderated") , noextmsgmode(this, "noextmsg") { } ModResult OnUserPreMessage(User* user, const MessageTarget& target, MessageDetails& details) CXX11_OVERRIDE { if (!IS_LOCAL(user) || target.type != MessageTarget::TYPE_CHANNEL) return MOD_RES_PASSTHRU; Channel* chan = target.Get<Channel>(); if (chan->IsModeSet(noextmsgmode) && !chan->HasUser(user)) { // The noextmsg mode is set and the user is not in the channel. user->WriteNumeric(ERR_CANNOTSENDTOCHAN, chan->name, "Cannot send to channel (no external messages)"); return MOD_RES_DENY; } bool no_chan_priv = chan->GetPrefixValue(user) < VOICE_VALUE; if (no_chan_priv && chan->IsModeSet(moderatedmode)) { // The moderated mode is set and the user has no status rank. user->WriteNumeric(ERR_CANNOTSENDTOCHAN, chan->name, "Cannot send to channel (+m is set)"); return MOD_RES_DENY; } if (no_chan_priv && ServerInstance->Config->RestrictBannedUsers != ServerConfig::BUT_NORMAL && chan->IsBanned(user)) { // The user is banned in the channel and restrictbannedusers is enabled. if (ServerInstance->Config->RestrictBannedUsers == ServerConfig::BUT_RESTRICT_NOTIFY) user->WriteNumeric(ERR_CANNOTSENDTOCHAN, chan->name, "Cannot send to channel (you're banned)"); return MOD_RES_DENY; } return MOD_RES_PASSTHRU; } Version GetVersion() CXX11_OVERRIDE { return Version("Provides the NOTICE, PRIVMSG, and SQUERY commands", VF_CORE|VF_VENDOR); } }; MODULE_INIT(ModuleCoreMessage) ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/src/coremods/core_mode.cpp�����������������������������������������������������������0000664�0000000�0000000�00000020420�13554550454�0020403�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * InspIRCd -- Internet Relay Chat Daemon * * Copyright (C) 2014 Attila Molnar <attilamolnar@hush.com> * Copyright (C) 2009-2010 Daniel De Graaf <danieldg@inspircd.org> * Copyright (C) 2006-2008 Robin Burchell <robin+git@viroteck.net> * Copyright (C) 2004-2008 Craig Edwards <craigedwards@brainbox.cc> * * This file is part of InspIRCd. InspIRCd is free software: you can * redistribute it and/or modify it under the terms of the GNU General Public * License as published by the Free Software Foundation, version 2. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include "inspircd.h" class CommandMode : public Command { unsigned int sent[256]; unsigned int seq; /** Show the list of one or more list modes to a user. * @param user User to send to. * @param chan Channel whose lists to show. * @param mode_sequence Mode letters to show the lists of. */ void DisplayListModes(User* user, Channel* chan, const std::string& mode_sequence); /** Show the current modes of a channel or a user to a user. * @param user User to show the modes to. * @param targetuser User whose modes to show. NULL if showing the modes of a channel. * @param targetchannel Channel whose modes to show. NULL if showing the modes of a user. */ void DisplayCurrentModes(User* user, User* targetuser, Channel* targetchannel); public: /** Constructor for mode. */ CommandMode(Module* parent); /** Handle command. * @param parameters The parameters to the command * @param user The user issuing the command * @return A value from CmdResult to indicate command success or failure. */ CmdResult Handle(User* user, const Params& parameters) CXX11_OVERRIDE; RouteDescriptor GetRouting(User* user, const Params& parameters) CXX11_OVERRIDE; }; CommandMode::CommandMode(Module* parent) : Command(parent, "MODE", 1) , seq(0) { syntax = "<target> [[(+|-)]<modes> [<mode-parameters>]]"; memset(&sent, 0, sizeof(sent)); } CmdResult CommandMode::Handle(User* user, const Params& parameters) { const std::string& target = parameters[0]; Channel* targetchannel = ServerInstance->FindChan(target); User* targetuser = NULL; if (!targetchannel) { if (IS_LOCAL(user)) targetuser = ServerInstance->FindNickOnly(target); else targetuser = ServerInstance->FindNick(target); } if ((!targetchannel) && (!targetuser)) { if (target[0] == '#') user->WriteNumeric(Numerics::NoSuchChannel(target)); else user->WriteNumeric(Numerics::NoSuchNick(target)); return CMD_FAILURE; } if (parameters.size() == 1) { this->DisplayCurrentModes(user, targetuser, targetchannel); return CMD_SUCCESS; } // Populate a temporary Modes::ChangeList with the parameters Modes::ChangeList changelist; ModeType type = targetchannel ? MODETYPE_CHANNEL : MODETYPE_USER; ServerInstance->Modes.ModeParamsToChangeList(user, type, parameters, changelist); ModResult MOD_RESULT; FIRST_MOD_RESULT(OnPreMode, MOD_RESULT, (user, targetuser, targetchannel, changelist)); ModeParser::ModeProcessFlag flags = ModeParser::MODE_NONE; if (IS_LOCAL(user)) { if (MOD_RESULT == MOD_RES_PASSTHRU) { if ((targetuser) && (user != targetuser)) { // Local users may only change the modes of other users if a module explicitly allows it user->WriteNumeric(ERR_USERSDONTMATCH, "Can't change mode for other users"); return CMD_FAILURE; } // This is a mode change by a local user and modules didn't explicitly allow/deny. // Ensure access checks will happen for each mode being changed. flags |= ModeParser::MODE_CHECKACCESS; } else if (MOD_RESULT == MOD_RES_DENY) return CMD_FAILURE; // Entire mode change denied by a module } else flags |= ModeParser::MODE_LOCALONLY; if (IS_LOCAL(user)) ServerInstance->Modes->ProcessSingle(user, targetchannel, targetuser, changelist, flags); else ServerInstance->Modes->Process(user, targetchannel, targetuser, changelist, flags); if ((ServerInstance->Modes.GetLastChangeList().empty()) && (targetchannel) && (parameters.size() == 2)) { /* Special case for displaying the list for listmodes, * e.g. MODE #chan b, or MODE #chan +b without a parameter */ this->DisplayListModes(user, targetchannel, parameters[1]); } return CMD_SUCCESS; } RouteDescriptor CommandMode::GetRouting(User* user, const Params& parameters) { return (IS_LOCAL(user) ? ROUTE_LOCALONLY : ROUTE_BROADCAST); } void CommandMode::DisplayListModes(User* user, Channel* chan, const std::string& mode_sequence) { seq++; for (std::string::const_iterator i = mode_sequence.begin(); i != mode_sequence.end(); ++i) { unsigned char mletter = *i; if (mletter == '+') continue; ModeHandler* mh = ServerInstance->Modes->FindMode(mletter, MODETYPE_CHANNEL); if (!mh || !mh->IsListMode()) return; /* Ensure the user doesnt request the same mode twice, * so they can't flood themselves off out of idiocy. */ if (sent[mletter] == seq) continue; sent[mletter] = seq; ServerInstance->Modes.ShowListModeList(user, chan, mh); } } static std::string GetSnomasks(const User* user) { ModeHandler* const snomask = ServerInstance->Modes.FindMode('s', MODETYPE_USER); std::string snomaskstr = snomask->GetUserParameter(user); // snomaskstr is empty if the snomask mode isn't set, otherwise it begins with a '+'. // In the former case output a "+", not an empty string. if (snomaskstr.empty()) snomaskstr.push_back('+'); return snomaskstr; } namespace { void GetModeList(Numeric::Numeric& num, Channel* chan, User* user) { // We should only show the value of secret parameters (i.e. key) if // the user is a member of the channel. bool show_secret = chan->HasUser(user); size_t modepos = num.push("+").GetParams().size() - 1; std::string modes; std::string param; for (unsigned char chr = 65; chr < 123; ++chr) { // Check that the mode exists and is set. ModeHandler* mh = ServerInstance->Modes->FindMode(chr, MODETYPE_CHANNEL); if (!mh || !chan->IsModeSet(mh)) continue; // Add the mode to the set list. modes.push_back(mh->GetModeChar()); // If the mode has a parameter we need to include that too. ParamModeBase* pm = mh->IsParameterMode(); if (!pm) continue; // If a mode has a secret parameter and the user is not privy to // the value of it then we use <name> instead of the value. if (pm->IsParameterSecret() && !show_secret) { num.push("<" + pm->name + ">"); continue; } // Retrieve the parameter and add it to the mode list. pm->GetParameter(chan, param); num.push(param); param.clear(); } num.GetParams()[modepos].append(modes); } } void CommandMode::DisplayCurrentModes(User* user, User* targetuser, Channel* targetchannel) { if (targetchannel) { // Display channel's current mode string Numeric::Numeric modenum(RPL_CHANNELMODEIS); modenum.push(targetchannel->name); GetModeList(modenum, targetchannel, user); user->WriteNumeric(modenum); user->WriteNumeric(RPL_CHANNELCREATED, targetchannel->name, (unsigned long)targetchannel->age); } else { if (targetuser == user) { // Display user's current mode string user->WriteNumeric(RPL_UMODEIS, targetuser->GetModeLetters()); if (targetuser->IsOper()) user->WriteNumeric(RPL_SNOMASKIS, GetSnomasks(targetuser), "Server notice mask"); } else if (user->HasPrivPermission("users/auspex")) { // Querying the modes of another user. // We cannot use RPL_UMODEIS because that's only for showing the user's own modes. user->WriteNumeric(RPL_OTHERUMODEIS, targetuser->nick, targetuser->GetModeLetters()); if (targetuser->IsOper()) user->WriteNumeric(RPL_OTHERSNOMASKIS, targetuser->nick, GetSnomasks(targetuser), "Server notice mask"); } else { user->WriteNumeric(ERR_USERSDONTMATCH, "Can't view modes for other users"); } } } class CoreModMode : public Module { private: CommandMode cmdmode; public: CoreModMode() : cmdmode(this) { } Version GetVersion() CXX11_OVERRIDE { return Version("Provides the MODE command", VF_VENDOR|VF_CORE); } }; MODULE_INIT(CoreModMode) ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/src/coremods/core_oper/��������������������������������������������������������������0000775�0000000�0000000�00000000000�13554550454�0017722�5����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/src/coremods/core_oper/cmd_die.cpp���������������������������������������������������0000664�0000000�0000000�00000004332�13554550454�0022014�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * InspIRCd -- Internet Relay Chat Daemon * * Copyright (C) 2009 Daniel De Graaf <danieldg@inspircd.org> * Copyright (C) 2007 Robin Burchell <robin+git@viroteck.net> * * 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 "inspircd.h" #include "exitcodes.h" #include "core_oper.h" CommandDie::CommandDie(Module* parent, std::string& hashref) : Command(parent, "DIE", 1, 1) , hash(hashref) { flags_needed = 'o'; syntax = "<servername>"; } void DieRestart::SendError(const std::string& message) { ClientProtocol::Messages::Error errormsg(message); ClientProtocol::Event errorevent(ServerInstance->GetRFCEvents().error, errormsg); const UserManager::LocalList& list = ServerInstance->Users.GetLocalUsers(); for (UserManager::LocalList::const_iterator i = list.begin(); i != list.end(); ++i) { LocalUser* user = *i; if (user->registered == REG_ALL) { user->WriteNotice(message); } else { // Unregistered connections receive ERROR, not a NOTICE user->Send(errorevent); } } } /** Handle /DIE */ CmdResult CommandDie::Handle(User* user, const Params& parameters) { if (ServerInstance->PassCompare(user, password, parameters[0], hash)) { { std::string diebuf = "*** DIE command from " + user->GetFullHost() + ". Terminating."; ServerInstance->Logs->Log(MODNAME, LOG_SPARSE, diebuf); DieRestart::SendError(diebuf); } ServerInstance->Exit(EXIT_STATUS_DIE); } else { ServerInstance->Logs->Log(MODNAME, LOG_SPARSE, "Failed /DIE command from %s", user->GetFullRealHost().c_str()); ServerInstance->SNO->WriteGlobalSno('a', "Failed DIE command from %s.", user->GetFullRealHost().c_str()); return CMD_FAILURE; } return CMD_SUCCESS; } ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/src/coremods/core_oper/cmd_kill.cpp��������������������������������������������������0000664�0000000�0000000�00000011255�13554550454�0022210�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * InspIRCd -- Internet Relay Chat Daemon * * Copyright (C) 2009 Daniel De Graaf <danieldg@inspircd.org> * Copyright (C) 2008 Craig Edwards <craigedwards@brainbox.cc> * Copyright (C) 2007 Robin Burchell <robin+git@viroteck.net> * * 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 "inspircd.h" #include "core_oper.h" CommandKill::CommandKill(Module* parent) : Command(parent, "KILL", 2, 2) , protoev(parent, name) { flags_needed = 'o'; syntax = "<nick>[,<nick>]+ :<reason>"; TRANSLATE2(TR_CUSTOM, TR_CUSTOM); } class KillMessage : public ClientProtocol::Message { public: KillMessage(ClientProtocol::EventProvider& protoev, User* user, LocalUser* target, const std::string& text, const std::string& hidenick) : ClientProtocol::Message("KILL", NULL) { if (hidenick.empty()) SetSourceUser(user); else SetSource(hidenick); PushParamRef(target->nick); PushParamRef(text); } }; /** Handle /KILL */ CmdResult CommandKill::Handle(User* user, const Params& parameters) { /* Allow comma seperated lists of users for /KILL (thanks w00t) */ if (CommandParser::LoopCall(user, this, parameters, 0)) { // If we got a colon delimited list of nicks then the handler ran for each nick, // and KILL commands were broadcast for remote targets. return CMD_FAILURE; } User* target = ServerInstance->FindNick(parameters[0]); if (!target) { user->WriteNumeric(Numerics::NoSuchNick(parameters[0])); return CMD_FAILURE; } /* * Here, we need to decide how to munge kill messages. Whether to hide killer, what to show opers, etc. * We only do this when the command is being issued LOCALLY, for remote KILL, we just copy the message we got. * * This conditional is so that we only append the "Killed (" prefix ONCE. If killer is remote, then the kill * just gets processed and passed on, otherwise, if they are local, it gets prefixed. Makes sense :-) -- w00t */ if (IS_LOCAL(user)) { /* * Moved this event inside the IS_LOCAL check also, we don't want half the network killing a user * and the other half not. This would be a bad thing. ;p -- w00t */ ModResult MOD_RESULT; FIRST_MOD_RESULT(OnKill, MOD_RESULT, (user, target, parameters[1])); if (MOD_RESULT == MOD_RES_DENY) return CMD_FAILURE; killreason = "Killed ("; if (!hidenick.empty()) { // hidekills is on, use it killreason += hidenick; } else { // hidekills is off, do nothing killreason += user->nick; } killreason += " (" + parameters[1] + "))"; } else { /* Leave it alone, remote server has already formatted it */ killreason.assign(parameters[1], 0, ServerInstance->Config->Limits.MaxQuit); } if ((!hideuline) || (!user->server->IsULine())) { if (IS_LOCAL(user) && IS_LOCAL(target)) ServerInstance->SNO->WriteGlobalSno('k', "Local kill by %s: %s (%s)", user->nick.c_str(), target->GetFullRealHost().c_str(), parameters[1].c_str()); else ServerInstance->SNO->WriteToSnoMask('K', "Remote kill by %s: %s (%s)", user->nick.c_str(), target->GetFullRealHost().c_str(), parameters[1].c_str()); } if (IS_LOCAL(target)) { LocalUser* localu = IS_LOCAL(target); KillMessage msg(protoev, user, localu, killreason, hidenick); ClientProtocol::Event killevent(protoev, msg); localu->Send(killevent); this->lastuuid.clear(); } else { this->lastuuid = target->uuid; } // send the quit out ServerInstance->Users->QuitUser(target, killreason); return CMD_SUCCESS; } RouteDescriptor CommandKill::GetRouting(User* user, const Params& parameters) { // FindNick() doesn't work here because we quit the target user in Handle() which // removes it from the nicklist, so we check lastuuid: if it's empty then this KILL // was for a local user, otherwise it contains the uuid of the user who was killed. if (lastuuid.empty()) return ROUTE_LOCALONLY; return ROUTE_BROADCAST; } void CommandKill::EncodeParameter(std::string& param, unsigned int index) { // Manually translate the nick -> uuid (see above), and also the reason (params[1]) // because we decorate it if the oper is local and want remote servers to see the // decorated reason not the original. param = ((index == 0) ? lastuuid : killreason); } ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/src/coremods/core_oper/cmd_oper.cpp��������������������������������������������������0000664�0000000�0000000�00000004641�13554550454�0022223�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * InspIRCd -- Internet Relay Chat Daemon * * Copyright (C) 2009 Daniel De Graaf <danieldg@inspircd.org> * Copyright (C) 2008 Thomas Stagner <aquanight@inspircd.org> * Copyright (C) 2007 Robin Burchell <robin+git@viroteck.net> * * 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 "inspircd.h" #include "core_oper.h" CommandOper::CommandOper(Module* parent) : SplitCommand(parent, "OPER", 2, 2) { syntax = "<username> <password>"; } CmdResult CommandOper::HandleLocal(LocalUser* user, const Params& parameters) { bool match_login = false; bool match_pass = false; bool match_hosts = false; const std::string userHost = user->ident + "@" + user->GetRealHost(); const std::string userIP = user->ident + "@" + user->GetIPString(); ServerConfig::OperIndex::const_iterator i = ServerInstance->Config->oper_blocks.find(parameters[0]); if (i != ServerInstance->Config->oper_blocks.end()) { OperInfo* ifo = i->second; ConfigTag* tag = ifo->oper_block; match_login = true; match_pass = ServerInstance->PassCompare(user, tag->getString("password"), parameters[1], tag->getString("hash")); match_hosts = InspIRCd::MatchMask(tag->getString("host"), userHost, userIP); if (match_pass && match_hosts) { /* found this oper's opertype */ user->Oper(ifo); return CMD_SUCCESS; } } std::string fields; if (!match_login) fields.append("login "); if (!match_pass) fields.append("password "); if (!match_hosts) fields.append("hosts"); // tell them they suck, and lag them up to help prevent brute-force attacks user->WriteNumeric(ERR_NOOPERHOST, "Invalid oper credentials"); user->CommandFloodPenalty += 10000; ServerInstance->SNO->WriteGlobalSno('o', "WARNING! Failed oper attempt by %s using login '%s': The following fields do not match: %s", user->GetFullRealHost().c_str(), parameters[0].c_str(), fields.c_str()); return CMD_FAILURE; } �����������������������������������������������������������������������������������������������inspircd-3.4.0/src/coremods/core_oper/cmd_rehash.cpp������������������������������������������������0000664�0000000�0000000�00000005760�13554550454�0022533�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * InspIRCd -- Internet Relay Chat Daemon * * Copyright (C) 2009 Daniel De Graaf <danieldg@inspircd.org> * Copyright (C) 2007-2008 Robin Burchell <robin+git@viroteck.net> * Copyright (C) 2008 Craig Edwards <craigedwards@brainbox.cc> * * This file is part of InspIRCd. InspIRCd is free software: you can * redistribute it and/or modify it under the terms of the GNU General Public * License as published by the Free Software Foundation, version 2. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include "inspircd.h" #include "core_oper.h" CommandRehash::CommandRehash(Module* parent) : Command(parent, "REHASH", 0) { flags_needed = 'o'; Penalty = 2; syntax = "[<servermask>]"; } CmdResult CommandRehash::Handle(User* user, const Params& parameters) { std::string param = parameters.size() ? parameters[0] : ""; FOREACH_MOD(OnPreRehash, (user, param)); if (param.empty()) { // standard rehash of local server } else if (param.find_first_of("*.") != std::string::npos) { // rehash of servers by server name (with wildcard) if (!InspIRCd::Match(ServerInstance->Config->ServerName, parameters[0])) { // Doesn't match us. PreRehash is already done, nothing left to do return CMD_SUCCESS; } } else { // parameterized rehash // the leading "-" is optional; remove it if present. if (param[0] == '-') param.erase(param.begin()); FOREACH_MOD(OnModuleRehash, (user, param)); return CMD_SUCCESS; } // Rehash for me. Try to start the rehash thread if (!ServerInstance->ConfigThread) { std::string m = user->nick + " is rehashing config file " + FileSystem::GetFileName(ServerInstance->ConfigFileName) + " on " + ServerInstance->Config->ServerName; ServerInstance->SNO->WriteGlobalSno('a', m); if (IS_LOCAL(user)) user->WriteNumeric(RPL_REHASHING, FileSystem::GetFileName(ServerInstance->ConfigFileName), "Rehashing"); else ServerInstance->PI->SendUserNotice(user, "*** Rehashing server " + FileSystem::GetFileName(ServerInstance->ConfigFileName)); /* Don't do anything with the logs here -- logs are restarted * after the config thread has completed. */ ServerInstance->Rehash(user->uuid); } else { /* * A rehash is already in progress! ahh shit. * XXX, todo: we should find some way to kill runaway rehashes that are blocking, this is a major problem for unrealircd users */ if (IS_LOCAL(user)) user->WriteNotice("*** Could not rehash: A rehash is already in progress."); else ServerInstance->PI->SendUserNotice(user, "*** Could not rehash: A rehash is already in progress."); } // Always return success so spanningtree forwards an incoming REHASH even if we failed return CMD_SUCCESS; } ����������������inspircd-3.4.0/src/coremods/core_oper/cmd_restart.cpp�����������������������������������������������0000664�0000000�0000000�00000004536�13554550454�0022745�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * InspIRCd -- Internet Relay Chat Daemon * * Copyright (C) 2009 Daniel De Graaf <danieldg@inspircd.org> * Copyright (C) 2007 Robin Burchell <robin+git@viroteck.net> * * 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 "inspircd.h" #include "core_oper.h" CommandRestart::CommandRestart(Module* parent, std::string& hashref) : Command(parent, "RESTART", 1, 1) , hash(hashref) { flags_needed = 'o'; syntax = "<servername>"; } CmdResult CommandRestart::Handle(User* user, const Params& parameters) { ServerInstance->Logs->Log(MODNAME, LOG_DEFAULT, "Restart: %s", user->nick.c_str()); if (ServerInstance->PassCompare(user, password, parameters[0], hash)) { ServerInstance->SNO->WriteGlobalSno('a', "RESTART command from %s, restarting server.", user->GetFullRealHost().c_str()); DieRestart::SendError("Server restarting."); #ifndef _WIN32 /* XXX: This hack sets FD_CLOEXEC on all possible file descriptors, so they're closed if the execvp() below succeeds. * Certainly, this is not a nice way to do things and it's slow when the fd limit is high. * * A better solution would be to set the close-on-exec flag for each fd we create (or create them with O_CLOEXEC), * however there is no guarantee that third party libs will do the same. */ for (int i = getdtablesize(); --i > 2;) { int flags = fcntl(i, F_GETFD); if (flags != -1) fcntl(i, F_SETFD, flags | FD_CLOEXEC); } #endif execvp(ServerInstance->Config->cmdline.argv[0], ServerInstance->Config->cmdline.argv); ServerInstance->SNO->WriteGlobalSno('a', "Failed RESTART - could not execute '%s' (%s)", ServerInstance->Config->cmdline.argv[0], strerror(errno)); } else { ServerInstance->SNO->WriteGlobalSno('a', "Failed RESTART command from %s.", user->GetFullRealHost().c_str()); } return CMD_FAILURE; } ������������������������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/src/coremods/core_oper/core_oper.cpp�������������������������������������������������0000664�0000000�0000000�00000004315�13554550454�0022406�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * InspIRCd -- Internet Relay Chat Daemon * * Copyright (C) 2014 Attila Molnar <attilamolnar@hush.com> * * This file is part of InspIRCd. InspIRCd is free software: you can * redistribute it and/or modify it under the terms of the GNU General Public * License as published by the Free Software Foundation, version 2. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include "inspircd.h" #include "core_oper.h" class CoreModOper : public Module { std::string powerhash; CommandDie cmddie; CommandKill cmdkill; CommandOper cmdoper; CommandRehash cmdrehash; CommandRestart cmdrestart; public: CoreModOper() : cmddie(this, powerhash) , cmdkill(this) , cmdoper(this) , cmdrehash(this) , cmdrestart(this, powerhash) { } void ReadConfig(ConfigStatus& status) CXX11_OVERRIDE { ConfigTag* tag = ServerInstance->Config->ConfValue("power"); // The hash method for *BOTH* the die and restart passwords powerhash = tag->getString("hash"); cmddie.password = tag->getString("diepass", ServerInstance->Config->ServerName, 1); cmdrestart.password = tag->getString("restartpass", ServerInstance->Config->ServerName, 1); ConfigTag* security = ServerInstance->Config->ConfValue("security"); cmdkill.hidenick = security->getString("hidekills"); cmdkill.hideuline = security->getBool("hideulinekills"); } void OnPostOper(User* user, const std::string&, const std::string&) CXX11_OVERRIDE { LocalUser* luser = IS_LOCAL(user); if (!luser) return; const std::string vhost = luser->oper->getConfig("vhost"); if (!vhost.empty()) luser->ChangeDisplayedHost(vhost); const std::string klass = luser->oper->getConfig("class"); if (!klass.empty()) luser->SetClass(klass); } Version GetVersion() CXX11_OVERRIDE { return Version("Provides the DIE, KILL, OPER, REHASH, and RESTART commands", VF_VENDOR | VF_CORE); } }; MODULE_INIT(CoreModOper) �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/src/coremods/core_oper/core_oper.h���������������������������������������������������0000664�0000000�0000000�00000006744�13554550454�0022063�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * InspIRCd -- Internet Relay Chat Daemon * * Copyright (C) 2014 Attila Molnar <attilamolnar@hush.com> * * This file is part of InspIRCd. InspIRCd is free software: you can * redistribute it and/or modify it under the terms of the GNU General Public * License as published by the Free Software Foundation, version 2. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include "inspircd.h" namespace DieRestart { /** Send an ERROR to unregistered users and a NOTICE to all registered local users * @param message Message to send */ void SendError(const std::string& message); } /** Handle /DIE. */ class CommandDie : public Command { public: std::string& hash; std::string password; /** Constructor for die. */ CommandDie(Module* parent, std::string& hashref); /** Handle command. * @param parameters The parameters to the command * @param user The user issuing the command * @return A value from CmdResult to indicate command success or failure. */ CmdResult Handle(User* user, const Params& parameters) CXX11_OVERRIDE; }; /** Handle /KILL. */ class CommandKill : public Command { std::string lastuuid; std::string killreason; ClientProtocol::EventProvider protoev; public: /** Set to a non empty string to obfuscate nicknames prepended to a KILL. */ std::string hidenick; /** Set to hide kills from clients of ulined servers in snotices. */ bool hideuline; /** Constructor for kill. */ CommandKill(Module* parent); /** Handle command. * @param user User issuing the command * @param parameters Parameters to the command * @return A value from CmdResult to indicate command success or failure. */ CmdResult Handle(User* user, const Params& parameters) CXX11_OVERRIDE; RouteDescriptor GetRouting(User* user, const Params& parameters) CXX11_OVERRIDE; void EncodeParameter(std::string& param, unsigned int index) CXX11_OVERRIDE; }; /** Handle /OPER. */ class CommandOper : public SplitCommand { public: /** Constructor for oper. */ CommandOper(Module* parent); /** Handle command. * @param user User issuing the command * @param parameters Parameters to the command * @return A value from CmdResult to indicate command success or failure. */ CmdResult HandleLocal(LocalUser* user, const Params& parameters) CXX11_OVERRIDE; }; /** Handle /REHASH. */ class CommandRehash : public Command { public: /** Constructor for rehash. */ CommandRehash(Module* parent); /** Handle command. * @param user User issuing the command * @param parameters Parameters to the command * @return A value from CmdResult to indicate command success or failure. */ CmdResult Handle(User* user, const Params& parameters) CXX11_OVERRIDE; }; /** Handle /RESTART */ class CommandRestart : public Command { public: std::string& hash; std::string password; /** Constructor for restart. */ CommandRestart(Module* parent, std::string& hashref); /** Handle command. * @param user User issuing the command * @param parameters Parameters to the command * @return A value from CmdResult to indicate command success or failure. */ CmdResult Handle(User* user, const Params& parameters) CXX11_OVERRIDE; }; ����������������������������inspircd-3.4.0/src/coremods/core_reloadmodule.cpp���������������������������������������������������0000664�0000000�0000000�00000055737�13554550454�0022156�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * InspIRCd -- Internet Relay Chat Daemon * * Copyright (C) 2015 Attila Molnar <attilamolnar@hush.com> * Copyright (C) 2009 Daniel De Graaf <danieldg@inspircd.org> * Copyright (C) 2007 Robin Burchell <robin+git@viroteck.net> * * 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 "inspircd.h" #include "listmode.h" #include "modules/reload.h" static Events::ModuleEventProvider* reloadevprov; static ClientProtocol::Serializer* dummyserializer; class DummySerializer : public ClientProtocol::Serializer { bool Parse(LocalUser* user, const std::string& line, ClientProtocol::ParseOutput& parseoutput) CXX11_OVERRIDE { return false; } ClientProtocol::SerializedMessage Serialize(const ClientProtocol::Message& msg, const ClientProtocol::TagSelection& tagwl) const CXX11_OVERRIDE { return ClientProtocol::SerializedMessage(); } public: DummySerializer(Module* mod) : ClientProtocol::Serializer(mod, "dummy") { } }; class CommandReloadmodule : public Command { Events::ModuleEventProvider evprov; DummySerializer dummyser; public: /** Constructor for reloadmodule. */ CommandReloadmodule(Module* parent) : Command(parent, "RELOADMODULE", 1) , evprov(parent, "event/reloadmodule") , dummyser(parent) { reloadevprov = &evprov; dummyserializer = &dummyser; flags_needed = 'o'; syntax = "<modulename>"; } /** Handle command. * @param parameters The parameters to the command * @param user The user issuing the command * @return A value from CmdResult to indicate command success or failure. */ CmdResult Handle(User* user, const Params& parameters) CXX11_OVERRIDE; }; namespace ReloadModule { class DataKeeper { /** Data we save for each mode and extension provided by the module */ struct ProviderInfo { std::string itemname; union { ModeHandler* mh; ExtensionItem* extitem; ClientProtocol::Serializer* serializer; }; ProviderInfo(ModeHandler* mode) : itemname(mode->name) , mh(mode) { } ProviderInfo(ExtensionItem* ei) : itemname(ei->name) , extitem(ei) { } ProviderInfo(ClientProtocol::Serializer* ser) : itemname(ser->name) , serializer(ser) { } }; struct InstanceData { /** Position of the ModeHandler or ExtensionItem that the serialized data belongs to */ size_t index; /** Serialized data */ std::string serialized; InstanceData(size_t Index, const std::string& Serialized) : index(Index) , serialized(Serialized) { } }; struct ModesExts { /** Mode data for the object, one entry per mode set by the module being reloaded */ std::vector<InstanceData> modelist; /** Extensions for the object, one entry per extension set by the module being reloaded */ std::vector<InstanceData> extlist; bool empty() const { return ((modelist.empty()) && (extlist.empty())); } void swap(ModesExts& other) { modelist.swap(other.modelist); extlist.swap(other.extlist); } }; struct OwnedModesExts : public ModesExts { /** User uuid or channel name */ std::string owner; OwnedModesExts(const std::string& Owner) : owner(Owner) { } }; // Data saved for each channel struct ChanData : public OwnedModesExts { /** Type of data stored for each member who has any affected modes or extensions set */ typedef OwnedModesExts MemberData; /** List of data (modes and extensions) about each member */ std::vector<MemberData> memberdatalist; ChanData(Channel* chan) : OwnedModesExts(chan->name) { } }; // Data saved for each user struct UserData : public OwnedModesExts { static const size_t UNUSED_INDEX = (size_t)-1; size_t serializerindex; UserData(User* user, size_t serializeridx) : OwnedModesExts(user->uuid) , serializerindex(serializeridx) { } }; /** Module being reloaded */ Module* mod; /** Stores all user and channel modes provided by the module */ std::vector<ProviderInfo> handledmodes[2]; /** Stores all extensions provided by the module */ std::vector<ProviderInfo> handledexts; /** Stores all serializers provided by the module */ std::vector<ProviderInfo> handledserializers; /** Stores all of the module data related to users */ std::vector<UserData> userdatalist; /** Stores all of the module data related to channels and memberships */ std::vector<ChanData> chandatalist; /** Data attached by modules */ ReloadModule::CustomData moddata; void SaveExtensions(Extensible* extensible, std::vector<InstanceData>& extdatalist); void SaveMemberData(Channel* chan, std::vector<ChanData::MemberData>& memberdatalist); static void SaveListModes(Channel* chan, ListModeBase* lm, size_t index, ModesExts& currdata); size_t SaveSerializer(User* user); /** Get the index of a ProviderInfo representing the serializer in the handledserializers list. * If the serializer is not already in the list it is added. * @param serializer Serializer to get an index to. * @return Index of the ProviderInfo representing the serializer. */ size_t GetSerializerIndex(ClientProtocol::Serializer* serializer); void CreateModeList(ModeType modetype); void DoSaveUsers(); void DoSaveChans(); /** Link previously saved extension names to currently available ExtensionItems */ void LinkExtensions(); /** Link previously saved mode names to currently available ModeHandlers * @param modetype Type of the modes to look for */ void LinkModes(ModeType modetype); /** Link previously saved serializer names to currently available Serializers */ void LinkSerializers(); void DoRestoreUsers(); void DoRestoreChans(); void DoRestoreModules(); /** Restore previously saved modes and extensions on an Extensible. * The extensions are set directly on the extensible, the modes are added into the provided mode change list. * @param data Data to unserialize from * @param extensible Object to restore * @param modetype MODETYPE_USER if the object being restored is a User, MODETYPE_CHANNEL otherwise * (for Channels and Memberships). * @param modechange Mode change to populate with the modes */ void RestoreObj(const OwnedModesExts& data, Extensible* extensible, ModeType modetype, Modes::ChangeList& modechange); /** Restore all previously saved extensions on an Extensible * @param list List of extensions and their serialized data to restore * @param extensible Target Extensible */ void RestoreExtensions(const std::vector<InstanceData>& list, Extensible* extensible); /** Restore all previously saved modes on a User, Channel or Membership * @param list List of modes to restore * @param modetype MODETYPE_USER if the object being restored is a User, MODETYPE_CHANNEL otherwise * @param modechange Mode change to populate with the modes */ void RestoreModes(const std::vector<InstanceData>& list, ModeType modetype, Modes::ChangeList& modechange); /** Restore previously saved serializer on a User. * Quit the user if the serializer cannot be restored. * @param serializerindex Saved serializer index to restore. * @param user User whose serializer to restore. If not local then calling this method is a no-op. * @return True if the serializer didn't need restoring or was restored successfully. * False if the serializer should have been restored but the required serializer is unavailable and the user was quit. */ bool RestoreSerializer(size_t serializerindex, User* user); /** Restore all modes and extensions of all members on a channel * @param chan Channel whose members are being restored * @param memberdata Data to restore * @param modechange Mode change to populate with prefix modes */ void RestoreMemberData(Channel* chan, const std::vector<ChanData::MemberData>& memberdatalist, Modes::ChangeList& modechange); /** Verify that a service which had its data saved is available and owned by the module that owned it previously * @param service Service descriptor * @param type Human-readable type of the service for log messages */ void VerifyServiceProvider(const ProviderInfo& service, const char* type); public: /** Save module state * @param currmod Module whose data to save */ void Save(Module* currmod); /** Restore module state * @param newmod Newly loaded instance of the module which had its data saved */ void Restore(Module* newmod); /** Handle reload failure */ void Fail(); }; void DataKeeper::DoSaveUsers() { ModesExts currdata; const user_hash& users = ServerInstance->Users->GetUsers(); for (user_hash::const_iterator i = users.begin(); i != users.end(); ++i) { User* const user = i->second; // Serialize user modes for (size_t j = 0; j < handledmodes[MODETYPE_USER].size(); j++) { ModeHandler* mh = handledmodes[MODETYPE_USER][j].mh; if (user->IsModeSet(mh)) currdata.modelist.push_back(InstanceData(j, mh->GetUserParameter(user))); } // Serialize all extensions attached to the User SaveExtensions(user, currdata.extlist); // Save serializer name if applicable and get an index to it size_t serializerindex = SaveSerializer(user); // Add to list if the user has any modes or extensions set that we are interested in, otherwise we don't // have to do anything with this user when restoring if ((!currdata.empty()) || (serializerindex != UserData::UNUSED_INDEX)) { userdatalist.push_back(UserData(user, serializerindex)); userdatalist.back().swap(currdata); } } } size_t DataKeeper::GetSerializerIndex(ClientProtocol::Serializer* serializer) { for (size_t i = 0; i < handledserializers.size(); i++) { if (handledserializers[i].serializer == serializer) return i; } handledserializers.push_back(ProviderInfo(serializer)); return handledserializers.size()-1; } size_t DataKeeper::SaveSerializer(User* user) { LocalUser* const localuser = IS_LOCAL(user); if ((!localuser) || (!localuser->serializer)) return UserData::UNUSED_INDEX; if (localuser->serializer->creator != mod) return UserData::UNUSED_INDEX; const size_t serializerindex = GetSerializerIndex(localuser->serializer); localuser->serializer = dummyserializer; return serializerindex; } void DataKeeper::SaveExtensions(Extensible* extensible, std::vector<InstanceData>& extdata) { const Extensible::ExtensibleStore& setexts = extensible->GetExtList(); // Position of the extension saved in the handledexts list size_t index = 0; for (std::vector<ProviderInfo>::const_iterator i = handledexts.begin(); i != handledexts.end(); ++i, index++) { ExtensionItem* const item = i->extitem; Extensible::ExtensibleStore::const_iterator it = setexts.find(item); if (it == setexts.end()) continue; std::string value = item->ToInternal(extensible, it->second); // If the serialized value is empty the extension won't be saved and restored if (!value.empty()) extdata.push_back(InstanceData(index, value)); } } void DataKeeper::SaveListModes(Channel* chan, ListModeBase* lm, size_t index, ModesExts& currdata) { const ListModeBase::ModeList* list = lm->GetList(chan); if (!list) return; for (ListModeBase::ModeList::const_iterator i = list->begin(); i != list->end(); ++i) { const ListModeBase::ListItem& listitem = *i; currdata.modelist.push_back(InstanceData(index, listitem.mask)); } } void DataKeeper::DoSaveChans() { ModesExts currdata; std::vector<OwnedModesExts> currmemberdata; const chan_hash& chans = ServerInstance->GetChans(); for (chan_hash::const_iterator i = chans.begin(); i != chans.end(); ++i) { Channel* const chan = i->second; // Serialize channel modes for (size_t j = 0; j < handledmodes[MODETYPE_CHANNEL].size(); j++) { ModeHandler* mh = handledmodes[MODETYPE_CHANNEL][j].mh; ListModeBase* lm = mh->IsListModeBase(); if (lm) SaveListModes(chan, lm, j, currdata); else if (chan->IsModeSet(mh)) currdata.modelist.push_back(InstanceData(j, chan->GetModeParameter(mh))); } // Serialize all extensions attached to the Channel SaveExtensions(chan, currdata.extlist); // Serialize all extensions attached to and all modes set on all members of the channel SaveMemberData(chan, currmemberdata); // Same logic as in DoSaveUsers() plus we consider the modes and extensions of all members if ((!currdata.empty()) || (!currmemberdata.empty())) { chandatalist.push_back(ChanData(chan)); chandatalist.back().swap(currdata); chandatalist.back().memberdatalist.swap(currmemberdata); } } } void DataKeeper::SaveMemberData(Channel* chan, std::vector<OwnedModesExts>& memberdatalist) { ModesExts currdata; const Channel::MemberMap& users = chan->GetUsers(); for (Channel::MemberMap::const_iterator i = users.begin(); i != users.end(); ++i) { Membership* const memb = i->second; for (size_t j = 0; j < handledmodes[MODETYPE_CHANNEL].size(); j++) { ModeHandler* mh = handledmodes[MODETYPE_CHANNEL][j].mh; const PrefixMode* const pm = mh->IsPrefixMode(); if ((pm) && (memb->HasMode(pm))) currdata.modelist.push_back(InstanceData(j, memb->user->uuid)); // Need to pass the user's uuid to the mode parser to set the mode later } SaveExtensions(memb, currdata.extlist); // Same logic as in DoSaveUsers() if (!currdata.empty()) { memberdatalist.push_back(OwnedModesExts(memb->user->uuid)); memberdatalist.back().swap(currdata); } } } void DataKeeper::RestoreMemberData(Channel* chan, const std::vector<ChanData::MemberData>& memberdatalist, Modes::ChangeList& modechange) { for (std::vector<ChanData::MemberData>::const_iterator i = memberdatalist.begin(); i != memberdatalist.end(); ++i) { const ChanData::MemberData& md = *i; User* const user = ServerInstance->FindUUID(md.owner); if (!user) { ServerInstance->Logs->Log(MODNAME, LOG_DEBUG, "User %s is gone (while processing %s)", md.owner.c_str(), chan->name.c_str()); continue; } Membership* const memb = chan->GetUser(user); if (!memb) { ServerInstance->Logs->Log(MODNAME, LOG_DEBUG, "Member %s is no longer on channel %s", md.owner.c_str(), chan->name.c_str()); continue; } RestoreObj(md, memb, MODETYPE_CHANNEL, modechange); } } void DataKeeper::CreateModeList(ModeType modetype) { const ModeParser::ModeHandlerMap& modes = ServerInstance->Modes->GetModes(modetype); for (ModeParser::ModeHandlerMap::const_iterator i = modes.begin(); i != modes.end(); ++i) { ModeHandler* mh = i->second; if (mh->creator == mod) handledmodes[modetype].push_back(ProviderInfo(mh)); } } void DataKeeper::Save(Module* currmod) { this->mod = currmod; const ExtensionManager::ExtMap& allexts = ServerInstance->Extensions.GetExts(); for (ExtensionManager::ExtMap::const_iterator i = allexts.begin(); i != allexts.end(); ++i) { ExtensionItem* ext = i->second; if (ext->creator == mod) handledexts.push_back(ProviderInfo(ext)); } CreateModeList(MODETYPE_USER); DoSaveUsers(); CreateModeList(MODETYPE_CHANNEL); DoSaveChans(); FOREACH_MOD_CUSTOM(*reloadevprov, ReloadModule::EventListener, OnReloadModuleSave, (mod, this->moddata)); ServerInstance->Logs->Log(MODNAME, LOG_DEBUG, "Saved data about %lu users %lu chans %lu modules", (unsigned long)userdatalist.size(), (unsigned long)chandatalist.size(), (unsigned long)moddata.list.size()); } void DataKeeper::VerifyServiceProvider(const ProviderInfo& service, const char* type) { const ServiceProvider* sp = service.extitem; if (!sp) ServerInstance->Logs->Log(MODNAME, LOG_DEBUG, "%s \"%s\" is no longer available", type, service.itemname.c_str()); else if (sp->creator != mod) ServerInstance->Logs->Log(MODNAME, LOG_DEBUG, "%s \"%s\" is now handled by %s", type, service.itemname.c_str(), (sp->creator ? sp->creator->ModuleSourceFile.c_str() : "<core>")); } void DataKeeper::LinkModes(ModeType modetype) { std::vector<ProviderInfo>& list = handledmodes[modetype]; for (std::vector<ProviderInfo>::iterator i = list.begin(); i != list.end(); ++i) { ProviderInfo& item = *i; item.mh = ServerInstance->Modes->FindMode(item.itemname, modetype); VerifyServiceProvider(item, (modetype == MODETYPE_USER ? "User mode" : "Channel mode")); } } void DataKeeper::LinkExtensions() { for (std::vector<ProviderInfo>::iterator i = handledexts.begin(); i != handledexts.end(); ++i) { ProviderInfo& item = *i; item.extitem = ServerInstance->Extensions.GetItem(item.itemname); VerifyServiceProvider(item.extitem, "Extension"); } } void DataKeeper::LinkSerializers() { for (std::vector<ProviderInfo>::iterator i = handledserializers.begin(); i != handledserializers.end(); ++i) { ProviderInfo& item = *i; item.serializer = ServerInstance->Modules.FindDataService<ClientProtocol::Serializer>(item.itemname); VerifyServiceProvider(item.serializer, "Serializer"); } } void DataKeeper::Restore(Module* newmod) { this->mod = newmod; // Find the new extension items LinkExtensions(); LinkModes(MODETYPE_USER); LinkModes(MODETYPE_CHANNEL); LinkSerializers(); // Restore DoRestoreUsers(); DoRestoreChans(); DoRestoreModules(); ServerInstance->Logs->Log(MODNAME, LOG_DEBUG, "Restore finished"); } void DataKeeper::Fail() { this->mod = NULL; ServerInstance->Logs->Log(MODNAME, LOG_DEBUG, "Restore failed, notifying modules"); DoRestoreModules(); } void DataKeeper::RestoreObj(const OwnedModesExts& data, Extensible* extensible, ModeType modetype, Modes::ChangeList& modechange) { RestoreExtensions(data.extlist, extensible); RestoreModes(data.modelist, modetype, modechange); } void DataKeeper::RestoreExtensions(const std::vector<InstanceData>& list, Extensible* extensible) { for (std::vector<InstanceData>::const_iterator i = list.begin(); i != list.end(); ++i) { const InstanceData& id = *i; handledexts[id.index].extitem->FromInternal(extensible, id.serialized); } } void DataKeeper::RestoreModes(const std::vector<InstanceData>& list, ModeType modetype, Modes::ChangeList& modechange) { for (std::vector<InstanceData>::const_iterator i = list.begin(); i != list.end(); ++i) { const InstanceData& id = *i; modechange.push_add(handledmodes[modetype][id.index].mh, id.serialized); } } bool DataKeeper::RestoreSerializer(size_t serializerindex, User* user) { if (serializerindex == UserData::UNUSED_INDEX) return true; // The following checks are redundant LocalUser* const localuser = IS_LOCAL(user); if (!localuser) return true; if (localuser->serializer != dummyserializer) return true; const ProviderInfo& provinfo = handledserializers[serializerindex]; if (!provinfo.serializer) { // Users cannot exist without a serializer ServerInstance->Users.QuitUser(user, "Serializer lost in reload"); return false; } localuser->serializer = provinfo.serializer; return true; } void DataKeeper::DoRestoreUsers() { ServerInstance->Logs->Log(MODNAME, LOG_DEBUG, "Restoring user data"); Modes::ChangeList modechange; for (std::vector<UserData>::const_iterator i = userdatalist.begin(); i != userdatalist.end(); ++i) { const UserData& userdata = *i; User* const user = ServerInstance->FindUUID(userdata.owner); if (!user) { ServerInstance->Logs->Log(MODNAME, LOG_DEBUG, "User %s is gone", userdata.owner.c_str()); continue; } // Attempt to restore serializer first, if it fails it's a fatal error and RestoreSerializer() quits them if (!RestoreSerializer(userdata.serializerindex, user)) continue; RestoreObj(userdata, user, MODETYPE_USER, modechange); ServerInstance->Modes.Process(ServerInstance->FakeClient, NULL, user, modechange, ModeParser::MODE_LOCALONLY); modechange.clear(); } } void DataKeeper::DoRestoreChans() { ServerInstance->Logs->Log(MODNAME, LOG_DEBUG, "Restoring channel data"); Modes::ChangeList modechange; for (std::vector<ChanData>::const_iterator i = chandatalist.begin(); i != chandatalist.end(); ++i) { const ChanData& chandata = *i; Channel* const chan = ServerInstance->FindChan(chandata.owner); if (!chan) { ServerInstance->Logs->Log(MODNAME, LOG_DEBUG, "Channel %s not found", chandata.owner.c_str()); continue; } RestoreObj(chandata, chan, MODETYPE_CHANNEL, modechange); // Process the mode change before applying any prefix modes ServerInstance->Modes.Process(ServerInstance->FakeClient, chan, NULL, modechange, ModeParser::MODE_LOCALONLY); modechange.clear(); // Restore all member data RestoreMemberData(chan, chandata.memberdatalist, modechange); ServerInstance->Modes.Process(ServerInstance->FakeClient, chan, NULL, modechange, ModeParser::MODE_LOCALONLY); modechange.clear(); } } void DataKeeper::DoRestoreModules() { for (ReloadModule::CustomData::List::iterator i = moddata.list.begin(); i != moddata.list.end(); ++i) { ReloadModule::CustomData::Data& data = *i; ServerInstance->Logs->Log(MODNAME, LOG_DEBUG, "Calling module data handler %p", (void*)data.handler); data.handler->OnReloadModuleRestore(mod, data.data); } } } // namespace ReloadModule class ReloadAction : public ActionBase { Module* const mod; const std::string uuid; const std::string passedname; public: ReloadAction(Module* m, const std::string& uid, const std::string& passedmodname) : mod(m) , uuid(uid) , passedname(passedmodname) { } void Call() CXX11_OVERRIDE { ReloadModule::DataKeeper datakeeper; datakeeper.Save(mod); DLLManager* dll = mod->ModuleDLLManager; std::string name = mod->ModuleSourceFile; ServerInstance->Modules->DoSafeUnload(mod); ServerInstance->GlobalCulls.Apply(); delete dll; bool result = ServerInstance->Modules->Load(name); if (result) { Module* newmod = ServerInstance->Modules->Find(name); datakeeper.Restore(newmod); } else datakeeper.Fail(); ServerInstance->SNO->WriteGlobalSno('a', "RELOAD MODULE: %s %ssuccessfully reloaded", passedname.c_str(), result ? "" : "un"); User* user = ServerInstance->FindUUID(uuid); if (user) user->WriteNumeric(RPL_LOADEDMODULE, passedname, InspIRCd::Format("Module %ssuccessfully reloaded.", (result ? "" : "un"))); ServerInstance->GlobalCulls.AddItem(this); } }; CmdResult CommandReloadmodule::Handle(User* user, const Params& parameters) { Module* m = ServerInstance->Modules->Find(parameters[0]); if (m == creator) { user->WriteNumeric(RPL_LOADEDMODULE, parameters[0], "You cannot reload core_reloadmodule (unload and load it)"); return CMD_FAILURE; } if (creator->dying) return CMD_FAILURE; if ((m) && (ServerInstance->Modules.CanUnload(m))) { ServerInstance->AtomicActions.AddAction(new ReloadAction(m, user->uuid, parameters[0])); return CMD_SUCCESS; } else { user->WriteNumeric(RPL_LOADEDMODULE, parameters[0], "Could not find module by that name"); return CMD_FAILURE; } } class CoreModReloadmodule : public Module { private: CommandReloadmodule cmd; public: CoreModReloadmodule() : cmd(this) { } Version GetVersion() CXX11_OVERRIDE { return Version("Provides the RELOADMODULE command", VF_CORE | VF_VENDOR); } }; MODULE_INIT(CoreModReloadmodule) ���������������������������������inspircd-3.4.0/src/coremods/core_serialize_rfc.cpp��������������������������������������������������0000664�0000000�0000000�00000017202�13554550454�0022304�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * InspIRCd -- Internet Relay Chat Daemon * * Copyright (C) 2016 Attila Molnar <attilamolnar@hush.com> * * This file is part of InspIRCd. InspIRCd is free software: you can * redistribute it and/or modify it under the terms of the GNU General Public * License as published by the Free Software Foundation, version 2. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include "inspircd.h" enum { // From ircu. ERR_INPUTTOOLONG = 417 }; class RFCSerializer : public ClientProtocol::Serializer { /** The maximum size of client-originated message tags in an incoming message including the `@`. */ static const std::string::size_type MAX_CLIENT_MESSAGE_TAG_LENGTH = 4095; /** The maximum size of server-originated message tags in an outgoing message including the `@`. */ static const std::string::size_type MAX_SERVER_MESSAGE_TAG_LENGTH = 4095; static void SerializeTags(const ClientProtocol::TagMap& tags, const ClientProtocol::TagSelection& tagwl, std::string& line); public: RFCSerializer(Module* mod) : ClientProtocol::Serializer(mod, "rfc") { } bool Parse(LocalUser* user, const std::string& line, ClientProtocol::ParseOutput& parseoutput) CXX11_OVERRIDE; ClientProtocol::SerializedMessage Serialize(const ClientProtocol::Message& msg, const ClientProtocol::TagSelection& tagwl) const CXX11_OVERRIDE; }; bool RFCSerializer::Parse(LocalUser* user, const std::string& line, ClientProtocol::ParseOutput& parseoutput) { size_t start = line.find_first_not_of(" "); if (start == std::string::npos) { // Discourage the user from flooding the server. user->CommandFloodPenalty += 2000; return false; } // Work out how long the message can actually be. size_t maxline = ServerInstance->Config->Limits.MaxLine - start - 2; if (line[start] == '@') maxline += MAX_CLIENT_MESSAGE_TAG_LENGTH + 1; irc::tokenstream tokens(line, start, maxline); ServerInstance->Logs->Log("USERINPUT", LOG_RAWIO, "C[%s] I %s", user->uuid.c_str(), tokens.GetMessage().c_str()); // This will always exist because of the check at the start of the function. std::string token; tokens.GetMiddle(token); if (token[0] == '@') { // Check that the client tags fit within the client tag space. if (token.length() > MAX_CLIENT_MESSAGE_TAG_LENGTH) { user->WriteNumeric(ERR_INPUTTOOLONG, "Input line was too long"); user->CommandFloodPenalty += 2000; return false; } // Truncate the RFC part of the message if it is too long. size_t maxrfcline = token.length() + ServerInstance->Config->Limits.MaxLine - 1; if (tokens.GetMessage().length() > maxrfcline) tokens.GetMessage().erase(maxrfcline); // Line begins with message tags, parse them. std::string tagval; irc::sepstream ss(token.substr(1), ';'); while (ss.GetToken(token)) { // Two or more tags with the same key must not be sent, but if a client violates that we accept // the first occurence of duplicate tags and ignore all later occurences. // // Another option is to reject the message entirely but there is no standard way of doing that. const std::string::size_type p = token.find('='); if (p != std::string::npos) { // Tag has a value tagval.assign(token, p+1, std::string::npos); token.erase(p); } else tagval.clear(); HandleTag(user, token, tagval, parseoutput.tags); } // Try to read the prefix or command name. if (!tokens.GetMiddle(token)) { // Discourage the user from flooding the server. user->CommandFloodPenalty += 2000; return false; } } if (token[0] == ':') { // If this exists then the client sent a prefix as part of their // message. Section 2.3 of RFC 1459 technically says we should only // allow the nick of the client here but in practise everyone just // ignores it so we will copy them. // Try to read the command name. if (!tokens.GetMiddle(token)) { // Discourage the user from flooding the server. user->CommandFloodPenalty += 2000; return false; } } parseoutput.cmd.assign(token); // Build the parameter map. We intentionally do not respect the RFC 1459 // thirteen parameter limit here. while (tokens.GetTrailing(token)) parseoutput.params.push_back(token); return true; } namespace { void CheckTagLength(std::string& line, size_t prevsize, size_t& length, size_t maxlength) { const std::string::size_type diffsize = line.size() - prevsize; if (length + diffsize > maxlength) line.erase(prevsize); else length += diffsize; } } void RFCSerializer::SerializeTags(const ClientProtocol::TagMap& tags, const ClientProtocol::TagSelection& tagwl, std::string& line) { size_t client_tag_length = 0; size_t server_tag_length = 0; for (ClientProtocol::TagMap::const_iterator i = tags.begin(); i != tags.end(); ++i) { if (!tagwl.IsSelected(tags, i)) continue; const std::string::size_type prevsize = line.size(); line.push_back(prevsize ? ';' : '@'); line.append(i->first); const std::string& val = i->second.value; if (!val.empty()) { line.push_back('='); line.append(val); } // The tags part of the message must not contain more client and server tags than allowed by the // message tags specification. This is complicated by the tag space having separate limits for // both server-originated and client-originated tags. If either of the tag limits is exceeded then // the most recently added tag is removed. if (i->first[0] == '+') CheckTagLength(line, prevsize, client_tag_length, MAX_CLIENT_MESSAGE_TAG_LENGTH); else CheckTagLength(line, prevsize, server_tag_length, MAX_SERVER_MESSAGE_TAG_LENGTH); } if (!line.empty()) line.push_back(' '); } ClientProtocol::SerializedMessage RFCSerializer::Serialize(const ClientProtocol::Message& msg, const ClientProtocol::TagSelection& tagwl) const { std::string line; SerializeTags(msg.GetTags(), tagwl, line); // Save position for length calculation later const std::string::size_type rfcmsg_begin = line.size(); if (msg.GetSource()) { line.push_back(':'); line.append(*msg.GetSource()); line.push_back(' '); } line.append(msg.GetCommand()); const ClientProtocol::Message::ParamList& params = msg.GetParams(); if (!params.empty()) { for (ClientProtocol::Message::ParamList::const_iterator i = params.begin(); i != params.end()-1; ++i) { const std::string& param = *i; line.push_back(' '); line.append(param); } line.append(" :", 2).append(params.back()); } // Truncate if too long std::string::size_type maxline = ServerInstance->Config->Limits.MaxLine - 2; if (line.length() - rfcmsg_begin > maxline) line.erase(rfcmsg_begin + maxline); line.append("\r\n", 2); return line; } class ModuleCoreRFCSerializer : public Module { RFCSerializer rfcserializer; public: ModuleCoreRFCSerializer() : rfcserializer(this) { } void OnCleanup(ExtensionItem::ExtensibleType type, Extensible* item) CXX11_OVERRIDE { if (type != ExtensionItem::EXT_USER) return; LocalUser* const user = IS_LOCAL(static_cast<User*>(item)); if ((user) && (user->serializer == &rfcserializer)) ServerInstance->Users.QuitUser(user, "Protocol serializer module unloading"); } void OnUserInit(LocalUser* user) CXX11_OVERRIDE { if (!user->serializer) user->serializer = &rfcserializer; } Version GetVersion() CXX11_OVERRIDE { return Version("RFC client protocol serializer and unserializer", VF_CORE|VF_VENDOR); } }; MODULE_INIT(ModuleCoreRFCSerializer) ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/src/coremods/core_stats.cpp����������������������������������������������������������0000664�0000000�0000000�00000035660�13554550454�0020631�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * InspIRCd -- Internet Relay Chat Daemon * * Copyright (C) 2009-2010 Daniel De Graaf <danieldg@inspircd.org> * Copyright (C) 2007-2008 Craig Edwards <craigedwards@brainbox.cc> * Copyright (C) 2007 Robin Burchell <robin+git@viroteck.net> * * 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 "inspircd.h" #include "xline.h" #include "modules/stats.h" #ifdef _WIN32 #include <psapi.h> #pragma comment(lib, "psapi.lib") // For GetProcessMemoryInfo() #endif /** Handle /STATS. */ class CommandStats : public Command { Events::ModuleEventProvider statsevprov; void DoStats(Stats::Context& stats); public: /** STATS characters which non-opers can request. */ std::string userstats; CommandStats(Module* Creator) : Command(Creator, "STATS", 1, 2) , statsevprov(Creator, "event/stats") { allow_empty_last_param = false; syntax = "<symbol> [<servername>]"; } /** Handle command. * @param parameters The parameters to the command * @param user The user issuing the command * @return A value from CmdResult to indicate command success or failure. */ CmdResult Handle(User* user, const Params& parameters) CXX11_OVERRIDE; RouteDescriptor GetRouting(User* user, const Params& parameters) CXX11_OVERRIDE { if ((parameters.size() > 1) && (parameters[1].find('.') != std::string::npos)) return ROUTE_UNICAST(parameters[1]); return ROUTE_LOCALONLY; } }; static void GenerateStatsLl(Stats::Context& stats) { stats.AddRow(211, InspIRCd::Format("nick[ident@%s] sendq cmds_out bytes_out cmds_in bytes_in time_open", (stats.GetSymbol() == 'l' ? "host" : "ip"))); const UserManager::LocalList& list = ServerInstance->Users.GetLocalUsers(); for (UserManager::LocalList::const_iterator i = list.begin(); i != list.end(); ++i) { LocalUser* u = *i; stats.AddRow(211, u->nick+"["+u->ident+"@"+(stats.GetSymbol() == 'l' ? u->GetDisplayedHost() : u->GetIPString())+"] "+ConvToStr(u->eh.getSendQSize())+" "+ConvToStr(u->cmds_out)+" "+ConvToStr(u->bytes_out)+" "+ConvToStr(u->cmds_in)+" "+ConvToStr(u->bytes_in)+" "+ConvToStr(ServerInstance->Time() - u->signon)); } } void CommandStats::DoStats(Stats::Context& stats) { User* const user = stats.GetSource(); const char statschar = stats.GetSymbol(); bool isPublic = userstats.find(statschar) != std::string::npos; bool isRemoteOper = IS_REMOTE(user) && (user->IsOper()); bool isLocalOperWithPrivs = IS_LOCAL(user) && user->HasPrivPermission("servers/auspex"); if (!isPublic && !isRemoteOper && !isLocalOperWithPrivs) { ServerInstance->SNO->WriteToSnoMask('t', "%s '%c' denied for %s (%s@%s)", (IS_LOCAL(user) ? "Stats" : "Remote stats"), statschar, user->nick.c_str(), user->ident.c_str(), user->GetRealHost().c_str()); stats.AddRow(481, (std::string("Permission Denied - STATS ") + statschar + " requires the servers/auspex priv.")); return; } ModResult MOD_RESULT; FIRST_MOD_RESULT_CUSTOM(statsevprov, Stats::EventListener, OnStats, MOD_RESULT, (stats)); if (MOD_RESULT == MOD_RES_DENY) { stats.AddRow(219, statschar, "End of /STATS report"); ServerInstance->SNO->WriteToSnoMask('t',"%s '%c' requested by %s (%s@%s)", (IS_LOCAL(user) ? "Stats" : "Remote stats"), statschar, user->nick.c_str(), user->ident.c_str(), user->GetRealHost().c_str()); return; } switch (statschar) { /* stats p (show listening ports) */ case 'p': { for (std::vector<ListenSocket*>::const_iterator i = ServerInstance->ports.begin(); i != ServerInstance->ports.end(); ++i) { ListenSocket* ls = *i; std::string type = ls->bind_tag->getString("type", "clients"); std::string hook = ls->bind_tag->getString("ssl", "plaintext"); stats.AddRow(249, ls->bind_sa.str() + " (" + type + ", " + hook + ")"); } } break; /* These stats symbols must be handled by a linking module */ case 'n': case 'c': break; case 'i': { for (ServerConfig::ClassVector::const_iterator i = ServerInstance->Config->Classes.begin(); i != ServerInstance->Config->Classes.end(); ++i) { ConnectClass* c = *i; Stats::Row row(215); row.push("I").push(c->name); std::string param; if (c->type == CC_ALLOW) param.push_back('+'); if (c->type == CC_DENY) param.push_back('-'); if (c->type == CC_NAMED) param.push_back('*'); else param.append(c->host); row.push(param).push(c->config->getString("port", "*")); row.push(ConvToStr(c->GetRecvqMax())).push(ConvToStr(c->GetSendqSoftMax())).push(ConvToStr(c->GetSendqHardMax())).push(ConvToStr(c->GetCommandRate())); param = ConvToStr(c->GetPenaltyThreshold()); if (c->fakelag) param.push_back('*'); row.push(param); stats.AddRow(row); } } break; case 'Y': { int idx = 0; for (ServerConfig::ClassVector::const_iterator i = ServerInstance->Config->Classes.begin(); i != ServerInstance->Config->Classes.end(); i++) { ConnectClass* c = *i; stats.AddRow(215, 'i', "NOMATCH", '*', c->GetHost(), (c->limit ? c->limit : SocketEngine::GetMaxFds()), idx, ServerInstance->Config->ServerName, '*'); stats.AddRow(218, 'Y', idx, c->GetPingTime(), '0', c->GetSendqHardMax(), ConvToStr(c->GetRecvqMax())+" "+ConvToStr(c->GetRegTimeout())); idx++; } } break; case 'P': { unsigned int idx = 0; const UserManager::OperList& opers = ServerInstance->Users->all_opers; for (UserManager::OperList::const_iterator i = opers.begin(); i != opers.end(); ++i) { User* oper = *i; if (!oper->server->IsULine()) { LocalUser* lu = IS_LOCAL(oper); stats.AddRow(249, oper->nick + " (" + oper->ident + "@" + oper->GetDisplayedHost() + ") Idle: " + (lu ? ConvToStr(ServerInstance->Time() - lu->idle_lastmsg) + " secs" : "unavailable")); idx++; } } stats.AddRow(249, ConvToStr(idx)+" OPER(s)"); } break; case 'k': ServerInstance->XLines->InvokeStats("K",216,stats); break; case 'g': ServerInstance->XLines->InvokeStats("G",223,stats); break; case 'q': ServerInstance->XLines->InvokeStats("Q",217,stats); break; case 'Z': ServerInstance->XLines->InvokeStats("Z",223,stats); break; case 'e': ServerInstance->XLines->InvokeStats("E",223,stats); break; case 'E': { const SocketEngine::Statistics& sestats = SocketEngine::GetStats(); stats.AddRow(249, "Total events: "+ConvToStr(sestats.TotalEvents)); stats.AddRow(249, "Read events: "+ConvToStr(sestats.ReadEvents)); stats.AddRow(249, "Write events: "+ConvToStr(sestats.WriteEvents)); stats.AddRow(249, "Error events: "+ConvToStr(sestats.ErrorEvents)); break; } /* stats m (list number of times each command has been used, plus bytecount) */ case 'm': { const CommandParser::CommandMap& commands = ServerInstance->Parser.GetCommands(); for (CommandParser::CommandMap::const_iterator i = commands.begin(); i != commands.end(); ++i) { if (i->second->use_count) { /* RPL_STATSCOMMANDS */ stats.AddRow(212, i->second->name, i->second->use_count); } } } break; /* stats z (debug and memory info) */ case 'z': { stats.AddRow(249, "Users: "+ConvToStr(ServerInstance->Users->GetUsers().size())); stats.AddRow(249, "Channels: "+ConvToStr(ServerInstance->GetChans().size())); stats.AddRow(249, "Commands: "+ConvToStr(ServerInstance->Parser.GetCommands().size())); float kbitpersec_in, kbitpersec_out, kbitpersec_total; SocketEngine::GetStats().GetBandwidth(kbitpersec_in, kbitpersec_out, kbitpersec_total); stats.AddRow(249, InspIRCd::Format("Bandwidth total: %03.5f kilobits/sec", kbitpersec_total)); stats.AddRow(249, InspIRCd::Format("Bandwidth out: %03.5f kilobits/sec", kbitpersec_out)); stats.AddRow(249, InspIRCd::Format("Bandwidth in: %03.5f kilobits/sec", kbitpersec_in)); #ifndef _WIN32 /* Moved this down here so all the not-windows stuff (look w00tie, I didn't say win32!) is in one ifndef. * Also cuts out some identical code in both branches of the ifndef. -- Om */ rusage R; /* Not sure why we were doing '0' with a RUSAGE_SELF comment rather than just using RUSAGE_SELF -- Om */ if (!getrusage(RUSAGE_SELF,&R)) /* RUSAGE_SELF */ { #ifndef __HAIKU__ stats.AddRow(249, "Total allocation: "+ConvToStr(R.ru_maxrss)+"K"); stats.AddRow(249, "Signals: "+ConvToStr(R.ru_nsignals)); stats.AddRow(249, "Page faults: "+ConvToStr(R.ru_majflt)); stats.AddRow(249, "Swaps: "+ConvToStr(R.ru_nswap)); stats.AddRow(249, "Context Switches: Voluntary; "+ConvToStr(R.ru_nvcsw)+" Involuntary; "+ConvToStr(R.ru_nivcsw)); #endif float n_elapsed = (ServerInstance->Time() - ServerInstance->stats.LastSampled.tv_sec) * 1000000 + (ServerInstance->Time_ns() - ServerInstance->stats.LastSampled.tv_nsec) / 1000; float n_eaten = ((R.ru_utime.tv_sec - ServerInstance->stats.LastCPU.tv_sec) * 1000000 + R.ru_utime.tv_usec - ServerInstance->stats.LastCPU.tv_usec); float per = (n_eaten / n_elapsed) * 100; stats.AddRow(249, InspIRCd::Format("CPU Use (now): %03.5f%%", per)); n_elapsed = ServerInstance->Time() - ServerInstance->startup_time; n_eaten = (float)R.ru_utime.tv_sec + R.ru_utime.tv_usec / 100000.0; per = (n_eaten / n_elapsed) * 100; stats.AddRow(249, InspIRCd::Format("CPU Use (total): %03.5f%%", per)); } #else PROCESS_MEMORY_COUNTERS MemCounters; if (GetProcessMemoryInfo(GetCurrentProcess(), &MemCounters, sizeof(MemCounters))) { stats.AddRow(249, "Total allocation: "+ConvToStr((MemCounters.WorkingSetSize + MemCounters.PagefileUsage) / 1024)+"K"); stats.AddRow(249, "Pagefile usage: "+ConvToStr(MemCounters.PagefileUsage / 1024)+"K"); stats.AddRow(249, "Page faults: "+ConvToStr(MemCounters.PageFaultCount)); } FILETIME CreationTime; FILETIME ExitTime; FILETIME KernelTime; FILETIME UserTime; LARGE_INTEGER ThisSample; if(GetProcessTimes(GetCurrentProcess(), &CreationTime, &ExitTime, &KernelTime, &UserTime) && QueryPerformanceCounter(&ThisSample)) { KernelTime.dwHighDateTime += UserTime.dwHighDateTime; KernelTime.dwLowDateTime += UserTime.dwLowDateTime; double n_eaten = (double)( ( (uint64_t)(KernelTime.dwHighDateTime - ServerInstance->stats.LastCPU.dwHighDateTime) << 32 ) + (uint64_t)(KernelTime.dwLowDateTime - ServerInstance->stats.LastCPU.dwLowDateTime) )/100000; double n_elapsed = (double)(ThisSample.QuadPart - ServerInstance->stats.LastSampled.QuadPart) / ServerInstance->stats.QPFrequency.QuadPart; double per = (n_eaten/n_elapsed); stats.AddRow(249, InspIRCd::Format("CPU Use (now): %03.5f%%", per)); n_elapsed = ServerInstance->Time() - ServerInstance->startup_time; n_eaten = (double)(( (uint64_t)(KernelTime.dwHighDateTime) << 32 ) + (uint64_t)(KernelTime.dwLowDateTime))/100000; per = (n_eaten / n_elapsed); stats.AddRow(249, InspIRCd::Format("CPU Use (total): %03.5f%%", per)); } #endif } break; case 'T': { stats.AddRow(249, "accepts "+ConvToStr(ServerInstance->stats.Accept)+" refused "+ConvToStr(ServerInstance->stats.Refused)); stats.AddRow(249, "unknown commands "+ConvToStr(ServerInstance->stats.Unknown)); stats.AddRow(249, "nick collisions "+ConvToStr(ServerInstance->stats.Collisions)); stats.AddRow(249, "dns requests "+ConvToStr(ServerInstance->stats.DnsGood+ServerInstance->stats.DnsBad)+" succeeded "+ConvToStr(ServerInstance->stats.DnsGood)+" failed "+ConvToStr(ServerInstance->stats.DnsBad)); stats.AddRow(249, "connection count "+ConvToStr(ServerInstance->stats.Connects)); stats.AddRow(249, InspIRCd::Format("bytes sent %5.2fK recv %5.2fK", ServerInstance->stats.Sent / 1024.0, ServerInstance->stats.Recv / 1024.0)); } break; /* stats o */ case 'o': { for (ServerConfig::OperIndex::const_iterator i = ServerInstance->Config->oper_blocks.begin(); i != ServerInstance->Config->oper_blocks.end(); ++i) { OperInfo* ifo = i->second; ConfigTag* tag = ifo->oper_block; stats.AddRow(243, 'O', tag->getString("host"), '*', tag->getString("name"), tag->getString("type"), '0'); } } break; case 'O': { for (ServerConfig::OperIndex::const_iterator i = ServerInstance->Config->OperTypes.begin(); i != ServerInstance->Config->OperTypes.end(); ++i) { OperInfo* tag = i->second; tag->init(); std::string umodes; std::string cmodes; for(char c='A'; c <= 'z'; c++) { ModeHandler* mh = ServerInstance->Modes->FindMode(c, MODETYPE_USER); if (mh && mh->NeedsOper() && tag->AllowedUserModes[c - 'A']) umodes.push_back(c); mh = ServerInstance->Modes->FindMode(c, MODETYPE_CHANNEL); if (mh && mh->NeedsOper() && tag->AllowedChanModes[c - 'A']) cmodes.push_back(c); } stats.AddRow(243, 'O', tag->name, umodes, cmodes); } } break; /* stats l (show user I/O stats) */ case 'l': /* stats L (show user I/O stats with IP addresses) */ case 'L': GenerateStatsLl(stats); break; /* stats u (show server uptime) */ case 'u': { unsigned int up = static_cast<unsigned int>(ServerInstance->Time() - ServerInstance->startup_time); stats.AddRow(242, InspIRCd::Format("Server up %u days, %.2u:%.2u:%.2u", up / 86400, (up / 3600) % 24, (up / 60) % 60, up % 60)); } break; default: break; } stats.AddRow(219, statschar, "End of /STATS report"); ServerInstance->SNO->WriteToSnoMask('t',"%s '%c' requested by %s (%s@%s)", (IS_LOCAL(user) ? "Stats" : "Remote stats"), statschar, user->nick.c_str(), user->ident.c_str(), user->GetRealHost().c_str()); return; } CmdResult CommandStats::Handle(User* user, const Params& parameters) { if (parameters.size() > 1 && !irc::equals(parameters[1], ServerInstance->Config->ServerName)) { // Give extra penalty if a non-oper does /STATS <remoteserver> LocalUser* localuser = IS_LOCAL(user); if ((localuser) && (!user->IsOper())) localuser->CommandFloodPenalty += 2000; return CMD_SUCCESS; } Stats::Context stats(user, parameters[0][0]); DoStats(stats); const std::vector<Stats::Row>& rows = stats.GetRows(); for (std::vector<Stats::Row>::const_iterator i = rows.begin(); i != rows.end(); ++i) { const Stats::Row& row = *i; user->WriteRemoteNumeric(row); } return CMD_SUCCESS; } class CoreModStats : public Module { private: CommandStats cmd; public: CoreModStats() : cmd(this) { } void ReadConfig(ConfigStatus& status) CXX11_OVERRIDE { ConfigTag* security = ServerInstance->Config->ConfValue("security"); cmd.userstats = security->getString("userstats"); } Version GetVersion() CXX11_OVERRIDE { return Version("Provides the STATS command", VF_CORE | VF_VENDOR); } }; MODULE_INIT(CoreModStats) ��������������������������������������������������������������������������������inspircd-3.4.0/src/coremods/core_stub.cpp�����������������������������������������������������������0000664�0000000�0000000�00000011661�13554550454�0020443�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * InspIRCd -- Internet Relay Chat Daemon * * Copyright (C) 2014 Attila Molnar <attilamolnar@hush.com> * Copyright (C) 2009 Daniel De Graaf <danieldg@inspircd.org> * Copyright (C) 2007 Robin Burchell <robin+git@viroteck.net> * * 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 "inspircd.h" enum { // From RFC 1459. ERR_SUMMONDISABLED = 445, ERR_USERSDISABLED = 446 }; /** Handle /CONNECT. */ class CommandConnect : public Command { public: /** Constructor for connect. */ CommandConnect(Module* parent) : Command(parent, "CONNECT", 1) { flags_needed = 'o'; syntax = "<servermask>"; } /** Handle command. * @param parameters The parameters to the command * @param user The user issuing the command * @return A value from CmdResult to indicate command success or failure. */ CmdResult Handle(User* user, const Params& parameters) CXX11_OVERRIDE { /* * This is handled by the server linking module, if necessary. Do not remove this stub. */ user->WriteNotice("Look into loading a linking module (like m_spanningtree) if you want this to do anything useful."); return CMD_SUCCESS; } }; /** Handle /LINKS. */ class CommandLinks : public Command { public: /** Constructor for links. */ CommandLinks(Module* parent) : Command(parent, "LINKS", 0, 0) { } /** Handle command. * @param parameters The parameters to the command * @param user The user issuing the command * @return A value from CmdResult to indicate command success or failure. */ CmdResult Handle(User* user, const Params& parameters) CXX11_OVERRIDE { user->WriteNumeric(RPL_LINKS, ServerInstance->Config->ServerName, ServerInstance->Config->ServerName, InspIRCd::Format("0 %s", ServerInstance->Config->ServerDesc.c_str())); user->WriteNumeric(RPL_ENDOFLINKS, '*', "End of /LINKS list."); return CMD_SUCCESS; } }; /** Handle /SERVER. */ class CommandServer : public Command { public: /** Constructor for server. */ CommandServer(Module* parent) : Command(parent, "SERVER") { works_before_reg = true; } /** Handle command. * @param parameters The parameters to the command * @param user The user issuing the command * @return A value from CmdResult to indicate command success or failure. */ CmdResult Handle(User* user, const Params& parameters) CXX11_OVERRIDE { if (user->registered == REG_ALL) { user->WriteNumeric(ERR_ALREADYREGISTERED, "You are already registered. (Perhaps your IRC client does not have a /SERVER command)."); } else { user->WriteNumeric(ERR_NOTREGISTERED, "SERVER", "You may not register as a server (servers have separate ports from clients, change your config)"); } return CMD_FAILURE; } }; /** Handle /SQUIT. */ class CommandSquit : public Command { public: /** Constructor for squit. */ CommandSquit(Module* parent) : Command(parent, "SQUIT", 1, 2) { flags_needed = 'o'; syntax = "<servermask>"; } /** Handle command. * @param parameters The parameters to the command * @param user The user issuing the command * @return A value from CmdResult to indicate command success or failure. */ CmdResult Handle(User* user, const Params& parameters) CXX11_OVERRIDE { user->WriteNotice("Look into loading a linking module (like m_spanningtree) if you want this to do anything useful."); return CMD_FAILURE; } }; class CommandSummon : public SplitCommand { public: CommandSummon(Module* Creator) : SplitCommand(Creator, "SUMMON", 1) { } CmdResult HandleLocal(LocalUser* user, const Params& parameters) CXX11_OVERRIDE { user->WriteNumeric(ERR_SUMMONDISABLED, "SUMMON has been disabled"); return CMD_SUCCESS; } }; class CommandUsers : public SplitCommand { public: CommandUsers(Module* Creator) : SplitCommand(Creator, "USERS") { } CmdResult HandleLocal(LocalUser* user, const Params& parameters) CXX11_OVERRIDE { user->WriteNumeric(ERR_USERSDISABLED, "USERS has been disabled"); return CMD_SUCCESS; } }; class CoreModStub : public Module { CommandConnect cmdconnect; CommandLinks cmdlinks; CommandServer cmdserver; CommandSquit cmdsquit; CommandSummon cmdsummon; CommandUsers cmdusers; public: CoreModStub() : cmdconnect(this) , cmdlinks(this) , cmdserver(this) , cmdsquit(this) , cmdsummon(this) , cmdusers(this) { } Version GetVersion() CXX11_OVERRIDE { return Version("Provides stubs for unimplemented commands", VF_VENDOR|VF_CORE); } }; MODULE_INIT(CoreModStub) �������������������������������������������������������������������������������inspircd-3.4.0/src/coremods/core_user/��������������������������������������������������������������0000775�0000000�0000000�00000000000�13554550454�0017733�5����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/src/coremods/core_user/cmd_away.cpp��������������������������������������������������0000664�0000000�0000000�00000004375�13554550454�0022234�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * InspIRCd -- Internet Relay Chat Daemon * * Copyright (C) 2009 Daniel De Graaf <danieldg@inspircd.org> * Copyright (C) 2007 Robin Burchell <robin+git@viroteck.net> * * 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 "inspircd.h" #include "core_user.h" enum { // From RFC 1459. RPL_UNAWAY = 305, RPL_NOWAWAY = 306 }; CommandAway::CommandAway(Module* parent) : Command(parent, "AWAY", 0, 1) , awayevprov(parent) { allow_empty_last_param = false; syntax = "[:<message>]"; } /** Handle /AWAY */ CmdResult CommandAway::Handle(User* user, const Params& parameters) { LocalUser* luser = IS_LOCAL(user); ModResult MOD_RESULT; if (!parameters.empty()) { std::string message(parameters[0]); if (luser) { FIRST_MOD_RESULT_CUSTOM(awayevprov, Away::EventListener, OnUserPreAway, MOD_RESULT, (luser, message)); if (MOD_RESULT == MOD_RES_DENY) return CMD_FAILURE; } user->awaytime = ServerInstance->Time(); user->awaymsg.assign(message, 0, ServerInstance->Config->Limits.MaxAway); user->WriteNumeric(RPL_NOWAWAY, "You have been marked as being away"); FOREACH_MOD_CUSTOM(awayevprov, Away::EventListener, OnUserAway, (user)); } else { if (luser) { FIRST_MOD_RESULT_CUSTOM(awayevprov, Away::EventListener, OnUserPreBack, MOD_RESULT, (luser)); if (MOD_RESULT == MOD_RES_DENY) return CMD_FAILURE; } user->awaytime = 0; user->awaymsg.clear(); user->WriteNumeric(RPL_UNAWAY, "You are no longer marked as being away"); FOREACH_MOD_CUSTOM(awayevprov, Away::EventListener, OnUserBack, (user)); } return CMD_SUCCESS; } RouteDescriptor CommandAway::GetRouting(User* user, const Params& parameters) { return (IS_LOCAL(user) ? ROUTE_LOCALONLY : ROUTE_BROADCAST); } �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/src/coremods/core_user/cmd_ison.cpp��������������������������������������������������0000664�0000000�0000000�00000003235�13554550454�0022235�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * InspIRCd -- Internet Relay Chat Daemon * * Copyright (C) 2009 Daniel De Graaf <danieldg@inspircd.org> * Copyright (C) 2007 Robin Burchell <robin+git@viroteck.net> * * 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 "inspircd.h" #include "core_user.h" class IsonReplyBuilder : public Numeric::Builder<' ', true> { public: IsonReplyBuilder(LocalUser* user) : Numeric::Builder<' ', true>(user, RPL_ISON) { } void AddNick(const std::string& nickname) { User* const user = ServerInstance->FindNickOnly(nickname); if ((user) && (user->registered == REG_ALL)) Add(user->nick); } }; /** Handle /ISON */ CmdResult CommandIson::HandleLocal(LocalUser* user, const Params& parameters) { IsonReplyBuilder reply(user); for (std::vector<std::string>::const_iterator i = parameters.begin(); i != parameters.end()-1; ++i) { const std::string& targetstr = *i; reply.AddNick(targetstr); } // Last parameter can be a space separated list irc::spacesepstream ss(parameters.back()); for (std::string token; ss.GetToken(token); ) reply.AddNick(token); reply.Flush(); return CMD_SUCCESS; } �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/src/coremods/core_user/cmd_nick.cpp��������������������������������������������������0000664�0000000�0000000�00000005770�13554550454�0022217�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * InspIRCd -- Internet Relay Chat Daemon * * Copyright (C) 2009-2010 Daniel De Graaf <danieldg@inspircd.org> * Copyright (C) 2008 Craig Edwards <craigedwards@brainbox.cc> * Copyright (C) 2008 Thomas Stagner <aquanight@inspircd.org> * Copyright (C) 2007-2008 Robin Burchell <robin+git@viroteck.net> * * 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 "inspircd.h" #include "core_user.h" CommandNick::CommandNick(Module* parent) : SplitCommand(parent, "NICK", 1, 1) { works_before_reg = true; syntax = "<newnick>"; Penalty = 0; } /** Handle nick changes from users. * NOTE: If you are used to ircds based on ircd2.8, and are looking * for the client introduction code in here, youre in the wrong place. * You need to look in the spanningtree module for this! */ CmdResult CommandNick::HandleLocal(LocalUser* user, const Params& parameters) { std::string oldnick = user->nick; std::string newnick = parameters[0]; // anything except the initial NICK gets a flood penalty if (user->registered == REG_ALL) user->CommandFloodPenalty += 4000; if (newnick.empty()) { user->WriteNumeric(ERR_NONICKNAMEGIVEN, "No nickname given"); return CMD_FAILURE; } if (newnick == "0") { newnick = user->uuid; } else if (!ServerInstance->IsNick(newnick)) { user->WriteNumeric(ERR_ERRONEUSNICKNAME, newnick, "Erroneous Nickname"); return CMD_FAILURE; } ModResult MOD_RESULT; FIRST_MOD_RESULT(OnUserPreNick, MOD_RESULT, (user, newnick)); // If a module denied the change, abort now if (MOD_RESULT == MOD_RES_DENY) return CMD_FAILURE; // Disallow the nick change if <security:restrictbannedusers> is on and there is a ban matching this user in // one of the channels they are on if (ServerInstance->Config->RestrictBannedUsers != ServerConfig::BUT_NORMAL) { for (User::ChanList::iterator i = user->chans.begin(); i != user->chans.end(); ++i) { Channel* chan = (*i)->chan; if (chan->GetPrefixValue(user) < VOICE_VALUE && chan->IsBanned(user)) { if (ServerInstance->Config->RestrictBannedUsers == ServerConfig::BUT_RESTRICT_NOTIFY) user->WriteNumeric(ERR_CANTCHANGENICK, InspIRCd::Format("Cannot change nickname while on %s (you're banned)", chan->name.c_str())); return CMD_FAILURE; } } } if (!user->ChangeNick(newnick)) return CMD_FAILURE; if (user->registered < REG_NICKUSER) { user->registered = (user->registered | REG_NICK); return CommandUser::CheckRegister(user); } return CMD_SUCCESS; } ��������inspircd-3.4.0/src/coremods/core_user/cmd_part.cpp��������������������������������������������������0000664�0000000�0000000�00000003332�13554550454�0022231�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * InspIRCd -- Internet Relay Chat Daemon * * Copyright (C) 2009 Daniel De Graaf <danieldg@inspircd.org> * Copyright (C) 2007-2008 Robin Burchell <robin+git@viroteck.net> * * 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 "inspircd.h" #include "core_user.h" CommandPart::CommandPart(Module* parent) : Command(parent, "PART", 1, 2) { Penalty = 5; syntax = "<channel>[,<channel>]+ [:<reason>]"; } CmdResult CommandPart::Handle(User* user, const Params& parameters) { std::string reason; if (parameters.size() > 1) { if (IS_LOCAL(user)) msgwrap.Wrap(parameters[1], reason); else reason = parameters[1]; } if (CommandParser::LoopCall(user, this, parameters, 0)) return CMD_SUCCESS; Channel* c = ServerInstance->FindChan(parameters[0]); if (!c) { user->WriteNumeric(Numerics::NoSuchChannel(parameters[0])); return CMD_FAILURE; } if (!c->PartUser(user, reason)) { user->WriteNumeric(ERR_NOTONCHANNEL, c->name, "You're not on that channel"); return CMD_FAILURE; } return CMD_SUCCESS; } RouteDescriptor CommandPart::GetRouting(User* user, const Params& parameters) { return (IS_LOCAL(user) ? ROUTE_LOCALONLY : ROUTE_BROADCAST); } ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/src/coremods/core_user/cmd_quit.cpp��������������������������������������������������0000664�0000000�0000000�00000003022�13554550454�0022241�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * InspIRCd -- Internet Relay Chat Daemon * * Copyright (C) 2009 Daniel De Graaf <danieldg@inspircd.org> * Copyright (C) 2007 Robin Burchell <robin+git@viroteck.net> * * 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 "inspircd.h" #include "core_user.h" CommandQuit::CommandQuit(Module* parent) : Command(parent, "QUIT", 0, 1) , operquit("operquit", ExtensionItem::EXT_USER, parent) { works_before_reg = true; syntax = "[:<message>]"; } CmdResult CommandQuit::Handle(User* user, const Params& parameters) { std::string quitmsg; if (parameters.empty()) quitmsg = "Client exited"; else if (IS_LOCAL(user)) msgwrap.Wrap(parameters[0], quitmsg); else quitmsg = parameters[0]; std::string* operquitmsg = operquit.get(user); ServerInstance->Users->QuitUser(user, quitmsg, operquitmsg); return CMD_SUCCESS; } RouteDescriptor CommandQuit::GetRouting(User* user, const Params& parameters) { return (IS_LOCAL(user) ? ROUTE_LOCALONLY : ROUTE_BROADCAST); } ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/src/coremods/core_user/cmd_user.cpp��������������������������������������������������0000664�0000000�0000000�00000004360�13554550454�0022243�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * InspIRCd -- Internet Relay Chat Daemon * * Copyright (C) 2009 Daniel De Graaf <danieldg@inspircd.org> * Copyright (C) 2007 Robin Burchell <robin+git@viroteck.net> * * 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 "inspircd.h" #include "core_user.h" enum { // From ircu. ERR_INVALIDUSERNAME = 468 }; CommandUser::CommandUser(Module* parent) : SplitCommand(parent, "USER", 4, 4) { allow_empty_last_param = false; works_before_reg = true; Penalty = 0; syntax = "<username> <unused> <unused> :<realname>"; } CmdResult CommandUser::HandleLocal(LocalUser* user, const Params& parameters) { /* A user may only send the USER command once */ if (!(user->registered & REG_USER)) { if (!ServerInstance->IsIdent(parameters[0])) { user->WriteNumeric(ERR_INVALIDUSERNAME, name, "Your username is not valid"); return CMD_FAILURE; } else { user->ChangeIdent(parameters[0]); user->ChangeRealName(parameters[3]); user->registered = (user->registered | REG_USER); } } else { user->WriteNumeric(ERR_ALREADYREGISTERED, "You may not reregister"); user->CommandFloodPenalty += 1000; return CMD_FAILURE; } /* parameters 2 and 3 are local and remote hosts, and are ignored */ return CheckRegister(user); } CmdResult CommandUser::CheckRegister(LocalUser* user) { // If the user is registered, return CMD_SUCCESS/CMD_FAILURE depending on what modules say, otherwise just // return CMD_SUCCESS without doing anything, knowing the other handler will call us again if (user->registered == REG_NICKUSER) { ModResult MOD_RESULT; FIRST_MOD_RESULT(OnUserRegister, MOD_RESULT, (user)); if (MOD_RESULT == MOD_RES_DENY) return CMD_FAILURE; } return CMD_SUCCESS; } ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/src/coremods/core_user/cmd_userhost.cpp����������������������������������������������0000664�0000000�0000000�00000003165�13554550454�0023143�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * InspIRCd -- Internet Relay Chat Daemon * * Copyright (C) 2009 Daniel De Graaf <danieldg@inspircd.org> * Copyright (C) 2007 Robin Burchell <robin+git@viroteck.net> * * 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 "inspircd.h" #include "core_user.h" CmdResult CommandUserhost::Handle(User* user, const Params& parameters) { const bool has_privs = user->HasPrivPermission("users/auspex"); std::string retbuf; unsigned int max = parameters.size(); if (max > 5) max = 5; for (unsigned int i = 0; i < max; i++) { User *u = ServerInstance->FindNickOnly(parameters[i]); if ((u) && (u->registered == REG_ALL)) { retbuf += u->nick; if (u->IsOper()) { // XXX: +H hidden opers must not be shown as opers if ((u == user) || (has_privs) || (!u->IsModeSet(hideopermode))) retbuf += '*'; } retbuf += '='; retbuf += (u->IsAway() ? '-' : '+'); retbuf += u->ident; retbuf += '@'; retbuf += u->GetHost(u == user || has_privs); retbuf += ' '; } } user->WriteNumeric(RPL_USERHOST, retbuf); return CMD_SUCCESS; } �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/src/coremods/core_user/core_user.cpp�������������������������������������������������0000664�0000000�0000000�00000011240�13554550454�0022423�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * InspIRCd -- Internet Relay Chat Daemon * * Copyright (C) 2014 Attila Molnar <attilamolnar@hush.com> * * This file is part of InspIRCd. InspIRCd is free software: you can * redistribute it and/or modify it under the terms of the GNU General Public * License as published by the Free Software Foundation, version 2. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include "inspircd.h" #include "core_user.h" /** Handle /PASS. */ class CommandPass : public SplitCommand { public: /** Constructor for pass. */ CommandPass(Module* parent) : SplitCommand(parent, "PASS", 1, 1) { works_before_reg = true; Penalty = 0; syntax = "<password>"; } /** Handle command. * @param parameters The parameters to the command * @param user The user issuing the command * @return A value from CmdResult to indicate command success or failure. */ CmdResult HandleLocal(LocalUser* user, const Params& parameters) CXX11_OVERRIDE { // Check to make sure they haven't registered -- Fix by FCS if (user->registered == REG_ALL) { user->CommandFloodPenalty += 1000; user->WriteNumeric(ERR_ALREADYREGISTERED, "You may not reregister"); return CMD_FAILURE; } user->password = parameters[0]; return CMD_SUCCESS; } }; /** Handle /PING. */ class CommandPing : public SplitCommand { public: /** Constructor for ping. */ CommandPing(Module* parent) : SplitCommand(parent, "PING", 1, 2) { syntax = "<servername> [:<servername>]"; } /** Handle command. * @param parameters The parameters to the command * @param user The user issuing the command * @return A value from CmdResult to indicate command success or failure. */ CmdResult HandleLocal(LocalUser* user, const Params& parameters) CXX11_OVERRIDE { ClientProtocol::Messages::Pong pong(parameters[0]); user->Send(ServerInstance->GetRFCEvents().pong, pong); return CMD_SUCCESS; } }; /** Handle /PONG. */ class CommandPong : public Command { public: /** Constructor for pong. */ CommandPong(Module* parent) : Command(parent, "PONG", 0, 1) { Penalty = 0; syntax = "<ping-text>"; } /** Handle command. * @param parameters The parameters to the command * @param user The user issuing the command * @return A value from CmdResult to indicate command success or failure. */ CmdResult Handle(User* user, const Params& parameters) CXX11_OVERRIDE { // set the user as alive so they survive to next ping LocalUser* localuser = IS_LOCAL(user); if (localuser) { // Increase penalty unless we've sent a PING and this is the reply if (localuser->lastping) localuser->CommandFloodPenalty += 1000; else localuser->lastping = 1; } return CMD_SUCCESS; } }; void MessageWrapper::Wrap(const std::string& message, std::string& out) { // If there is a fixed message, it is stored in prefix. Otherwise prefix contains // only the prefix, so append the message and the suffix out.assign(prefix); if (!fixed) out.append(message).append(suffix); } void MessageWrapper::ReadConfig(const char* prefixname, const char* suffixname, const char* fixedname) { ConfigTag* tag = ServerInstance->Config->ConfValue("options"); prefix = tag->getString(fixedname); fixed = (!prefix.empty()); if (!fixed) { prefix = tag->getString(prefixname); suffix = tag->getString(suffixname); } } class CoreModUser : public Module { CommandAway cmdaway; CommandNick cmdnick; CommandPart cmdpart; CommandPass cmdpass; CommandPing cmdping; CommandPong cmdpong; CommandQuit cmdquit; CommandUser cmduser; CommandIson cmdison; CommandUserhost cmduserhost; SimpleUserModeHandler invisiblemode; ModeUserOperator operatormode; ModeUserServerNoticeMask snomaskmode; public: CoreModUser() : cmdaway(this) , cmdnick(this) , cmdpart(this) , cmdpass(this) , cmdping(this) , cmdpong(this) , cmdquit(this) , cmduser(this) , cmdison(this) , cmduserhost(this) , invisiblemode(this, "invisible", 'i') , operatormode(this) , snomaskmode(this) { } void ReadConfig(ConfigStatus& status) CXX11_OVERRIDE { cmdpart.msgwrap.ReadConfig("prefixpart", "suffixpart", "fixedpart"); cmdquit.msgwrap.ReadConfig("prefixquit", "suffixquit", "fixedquit"); } Version GetVersion() CXX11_OVERRIDE { return Version("Provides the AWAY, ISON, NICK, PART, PASS, PING, PONG, QUIT, USERHOST, and USER commands", VF_VENDOR|VF_CORE); } }; MODULE_INIT(CoreModUser) ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/src/coremods/core_user/core_user.h���������������������������������������������������0000664�0000000�0000000�00000015655�13554550454�0022106�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * InspIRCd -- Internet Relay Chat Daemon * * Copyright (C) 2014 Attila Molnar <attilamolnar@hush.com> * Copyright (C) 2008 Robin Burchell <robin+git@viroteck.net> * Copyright (C) 2007 Dennis Friis <peavey@inspircd.org> * Copyright (C) 2006 Craig Edwards <craigedwards@brainbox.cc> * * This file is part of InspIRCd. InspIRCd is free software: you can * redistribute it and/or modify it under the terms of the GNU General Public * License as published by the Free Software Foundation, version 2. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include "inspircd.h" #include "listmode.h" #include "modules/away.h" class MessageWrapper { std::string prefix; std::string suffix; bool fixed; public: /** * Wrap the given message according to the config rules * @param message The message to wrap * @param out String where the result is placed */ void Wrap(const std::string& message, std::string& out); /** * Read the settings from the given config keys (options block) * @param prefixname Name of the config key to read the prefix from * @param suffixname Name of the config key to read the suffix from * @param fixedname Name of the config key to read the fixed string string from. * If this key has a non-empty value, all messages will be replaced with it. */ void ReadConfig(const char* prefixname, const char* suffixname, const char* fixedname); }; /** Handle /AWAY. */ class CommandAway : public Command { private: Away::EventProvider awayevprov; public: /** Constructor for away. */ CommandAway(Module* parent); /** Handle command. * @param parameters The parameters to the command * @param user The user issuing the command * @return A value from CmdResult to indicate command success or failure. */ CmdResult Handle(User* user, const Params& parameters) CXX11_OVERRIDE; RouteDescriptor GetRouting(User* user, const Params& parameters) CXX11_OVERRIDE; }; /** Handle /ISON. */ class CommandIson : public SplitCommand { public: /** Constructor for ison. */ CommandIson(Module* parent) : SplitCommand(parent, "ISON", 1) { allow_empty_last_param = false; syntax = "<nick> [<nick>]+"; } /** Handle command. * @param parameters The parameters to the command * @param user The user issuing the command * @return A value from CmdResult to indicate command success or failure. */ CmdResult HandleLocal(LocalUser* user, const Params& parameters) CXX11_OVERRIDE; }; /** Handle /NICK. */ class CommandNick : public SplitCommand { public: /** Constructor for nick. */ CommandNick(Module* parent); /** Handle command. * @param parameters The parameters to the command * @param user The user issuing the command * @return A value from CmdResult to indicate command success or failure. */ CmdResult HandleLocal(LocalUser* user, const Params& parameters) CXX11_OVERRIDE; }; /** Handle /PART. */ class CommandPart : public Command { public: MessageWrapper msgwrap; /** Constructor for part. */ CommandPart(Module* parent); /** Handle command. * @param parameters The parameters to the command * @param user The user issuing the command * @return A value from CmdResult to indicate command success or failure. */ CmdResult Handle(User* user, const Params& parameters) CXX11_OVERRIDE; RouteDescriptor GetRouting(User* user, const Params& parameters) CXX11_OVERRIDE; }; /** Handle /QUIT. */ class CommandQuit : public Command { private: StringExtItem operquit; public: MessageWrapper msgwrap; /** Constructor for quit. */ CommandQuit(Module* parent); /** Handle command. * @param parameters The parameters to the command * @param user The user issuing the command * @return A value from CmdResult to indicate command success or failure. */ CmdResult Handle(User* user, const Params& parameters) CXX11_OVERRIDE; RouteDescriptor GetRouting(User* user, const Params& parameters) CXX11_OVERRIDE; }; /** Handle /USER. */ class CommandUser : public SplitCommand { public: /** Constructor for user. */ CommandUser(Module* parent); /** Handle command. * @param parameters The parameters to the command * @param user The user issuing the command * @return A value from CmdResult to indicate command success or failure. */ CmdResult HandleLocal(LocalUser* user, const Params& parameters) CXX11_OVERRIDE; /** Run the OnUserRegister hook if the user has sent both NICK and USER. Called after an unregistered user * successfully executes the USER or the NICK command. * @param user User to inspect and possibly pass to the OnUserRegister hook * @return CMD_FAILURE if OnUserRegister was called and it returned MOD_RES_DENY, CMD_SUCCESS in every other case * (i.e. if the hook wasn't fired because the user still needs to send NICK/USER or if it was fired and finished with * a non-MOD_RES_DENY result). */ static CmdResult CheckRegister(LocalUser* user); }; /** Handle /USERHOST. */ class CommandUserhost : public Command { UserModeReference hideopermode; public: /** Constructor for userhost. */ CommandUserhost(Module* parent) : Command(parent,"USERHOST", 1) , hideopermode(parent, "hideoper") { allow_empty_last_param = false; syntax = "<nick> [<nick>]+"; } /** Handle command. * @param parameters The parameters to the command * @param user The user issuing the command * @return A value from CmdResult to indicate command success or failure. */ CmdResult Handle(User* user, const Params& parameters) CXX11_OVERRIDE; }; /** User mode +s */ class ModeUserServerNoticeMask : public ModeHandler { /** Process a snomask modifier string, e.g. +abc-de * @param user The target user * @param input A sequence of notice mask characters * @return The cleaned mode sequence which can be output, * e.g. in the above example if masks c and e are not * valid, this function will return +ab-d */ std::string ProcessNoticeMasks(User* user, const std::string& input); public: ModeUserServerNoticeMask(Module* Creator); ModeAction OnModeChange(User* source, User* dest, Channel* channel, std::string &parameter, bool adding) CXX11_OVERRIDE; void OnParameterMissing(User* user, User* dest, Channel* channel) CXX11_OVERRIDE; /** Create a displayable mode string of the snomasks set on a given user * @param user The user whose notice masks to format * @return The notice mask character sequence */ std::string GetUserParameter(const User* user) const CXX11_OVERRIDE; }; /** User mode +o */ class ModeUserOperator : public ModeHandler { public: ModeUserOperator(Module* Creator); ModeAction OnModeChange(User* source, User* dest, Channel* channel, std::string &parameter, bool adding) CXX11_OVERRIDE; }; �����������������������������������������������������������������������������������inspircd-3.4.0/src/coremods/core_user/umode_o.cpp���������������������������������������������������0000664�0000000�0000000�00000003310�13554550454�0022063�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * InspIRCd -- Internet Relay Chat Daemon * * Copyright (C) 2007 Dennis Friis <peavey@inspircd.org> * Copyright (C) 2006 Craig Edwards <craigedwards@brainbox.cc> * * This file is part of InspIRCd. InspIRCd is free software: you can * redistribute it and/or modify it under the terms of the GNU General Public * License as published by the Free Software Foundation, version 2. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include "inspircd.h" #include "core_user.h" ModeUserOperator::ModeUserOperator(Module* Creator) : ModeHandler(Creator, "oper", 'o', PARAM_NONE, MODETYPE_USER) { oper = true; } ModeAction ModeUserOperator::OnModeChange(User* source, User* dest, Channel*, std::string&, bool adding) { /* Only opers can execute this class at all */ if (!source->server->IsULine() && !source->IsOper()) return MODEACTION_DENY; /* Not even opers can GIVE the +o mode, only take it away */ if (adding) return MODEACTION_DENY; /* Set the bitfields. * Note that oper status is only given in User::Oper() * NOT here. It is impossible to directly set +o without * verifying as an oper and getting an opertype assigned * to your User! */ char snomask = IS_LOCAL(dest) ? 'o' : 'O'; ServerInstance->SNO->WriteToSnoMask(snomask, "User %s de-opered (by %s)", dest->nick.c_str(), source->nick.c_str()); dest->UnOper(); return MODEACTION_ALLOW; } ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/src/coremods/core_user/umode_s.cpp���������������������������������������������������0000664�0000000�0000000�00000007546�13554550454�0022106�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * InspIRCd -- Internet Relay Chat Daemon * * Copyright (C) 2008 Robin Burchell <robin+git@viroteck.net> * Copyright (C) 2007 Dennis Friis <peavey@inspircd.org> * Copyright (C) 2006 Craig Edwards <craigedwards@brainbox.cc> * * This file is part of InspIRCd. InspIRCd is free software: you can * redistribute it and/or modify it under the terms of the GNU General Public * License as published by the Free Software Foundation, version 2. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include "inspircd.h" #include "core_user.h" ModeUserServerNoticeMask::ModeUserServerNoticeMask(Module* Creator) : ModeHandler(Creator, "snomask", 's', PARAM_SETONLY, MODETYPE_USER) { oper = true; syntax = "(+|-)<snomasks>"; } ModeAction ModeUserServerNoticeMask::OnModeChange(User* source, User* dest, Channel*, std::string &parameter, bool adding) { if (adding) { dest->SetMode(this, true); // Process the parameter (remove chars we don't understand, remove redundant chars, etc.) parameter = ProcessNoticeMasks(dest, parameter); return MODEACTION_ALLOW; } else { if (dest->IsModeSet(this)) { dest->SetMode(this, false); dest->snomasks.reset(); return MODEACTION_ALLOW; } } // Mode not set and trying to unset, deny return MODEACTION_DENY; } std::string ModeUserServerNoticeMask::GetUserParameter(const User* user) const { std::string ret; if (!user->IsModeSet(this)) return ret; ret.push_back('+'); for (unsigned char n = 0; n < 64; n++) { if (user->snomasks[n]) ret.push_back(n + 'A'); } return ret; } void ModeUserServerNoticeMask::OnParameterMissing(User* user, User* dest, Channel* channel) { user->WriteNotice("*** The user mode +s requires a parameter (server notice mask). Please provide a parameter, e.g. '+s +*'."); } std::string ModeUserServerNoticeMask::ProcessNoticeMasks(User* user, const std::string& input) { bool adding = true; std::bitset<64> curr = user->snomasks; for (std::string::const_iterator i = input.begin(); i != input.end(); ++i) { switch (*i) { case '+': adding = true; break; case '-': adding = false; break; case '*': for (size_t j = 0; j < 64; j++) { if (ServerInstance->SNO->IsSnomaskUsable(j+'A')) curr[j] = adding; } break; default: // For local users check whether the given snomask is valid and enabled - IsSnomaskUsable() tests both. // For remote users accept what we were told, unless the snomask char is not a letter. if (IS_LOCAL(user)) { if (!ServerInstance->SNO->IsSnomaskUsable(*i)) { user->WriteNumeric(ERR_UNKNOWNSNOMASK, *i, "is an unknown snomask character"); continue; } } else if (!(((*i >= 'a') && (*i <= 'z')) || ((*i >= 'A') && (*i <= 'Z')))) continue; size_t index = ((*i) - 'A'); curr[index] = adding; break; } } std::string plus = "+"; std::string minus = "-"; // Apply changes and construct two strings consisting of the newly added and the removed snomask chars for (size_t i = 0; i < 64; i++) { bool isset = curr[i]; if (user->snomasks[i] != isset) { user->snomasks[i] = isset; std::string& appendhere = (isset ? plus : minus); appendhere.push_back(i+'A'); } } // Create the final string that will be shown to the user and sent to servers // Form: "+ABc-de" std::string output; if (plus.length() > 1) output = plus; if (minus.length() > 1) output += minus; // Unset the snomask usermode itself if every snomask was unset if (user->snomasks.none()) user->SetMode(this, false); return output; } ����������������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/src/coremods/core_wallops.cpp��������������������������������������������������������0000664�0000000�0000000�00000004636�13554550454�0021153�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * InspIRCd -- Internet Relay Chat Daemon * * Copyright (C) 2009 Daniel De Graaf <danieldg@inspircd.org> * Copyright (C) 2007 Robin Burchell <robin+git@viroteck.net> * * 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 "inspircd.h" /** Handle /WALLOPS. */ class CommandWallops : public Command { SimpleUserModeHandler wallopsmode; ClientProtocol::EventProvider protoevprov; public: /** Constructor for wallops. */ CommandWallops(Module* parent) : Command(parent, "WALLOPS", 1, 1) , wallopsmode(parent, "wallops", 'w') , protoevprov(parent, name) { flags_needed = 'o'; syntax = ":<message>"; } /** Handle command. * @param parameters The parameters to the command * @param user The user issuing the command * @return A value from CmdResult to indicate command success or failure. */ CmdResult Handle(User* user, const Params& parameters) CXX11_OVERRIDE; RouteDescriptor GetRouting(User* user, const Params& parameters) CXX11_OVERRIDE { return ROUTE_BROADCAST; } }; CmdResult CommandWallops::Handle(User* user, const Params& parameters) { if (parameters[0].empty()) { user->WriteNumeric(ERR_NOTEXTTOSEND, "No text to send"); return CMD_FAILURE; } ClientProtocol::Message msg("WALLOPS", user); msg.PushParamRef(parameters[0]); ClientProtocol::Event wallopsevent(protoevprov, msg); const UserManager::LocalList& list = ServerInstance->Users.GetLocalUsers(); for (UserManager::LocalList::const_iterator i = list.begin(); i != list.end(); ++i) { LocalUser* curr = *i; if (curr->IsModeSet(wallopsmode)) curr->Send(wallopsevent); } return CMD_SUCCESS; } class CoreModWallops : public Module { private: CommandWallops cmd; public: CoreModWallops() : cmd(this) { } Version GetVersion() CXX11_OVERRIDE { return Version("Provides the WALLOPS command", VF_CORE | VF_VENDOR); } }; MODULE_INIT(CoreModWallops) ��������������������������������������������������������������������������������������������������inspircd-3.4.0/src/coremods/core_who.cpp������������������������������������������������������������0000664�0000000�0000000�00000044077�13554550454�0020272�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * InspIRCd -- Internet Relay Chat Daemon * * Copyright (C) 2018 Peter Powell <petpow@saberuk.com> * Copyright (C) 2014 Adam <Adam@anope.org> * Copyright (C) 2009-2010 Daniel De Graaf <danieldg@inspircd.org> * Copyright (C) 2007-2008 Robin Burchell <robin+git@viroteck.net> * * 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 "inspircd.h" #include "modules/account.h" #include "modules/who.h" enum { // From RFC 1459. RPL_ENDOFWHO = 315, RPL_WHOREPLY = 352, // From ircu. RPL_WHOSPCRPL = 354 }; static const char whox_field_order[] = "tcuihsnfdlaor"; static const char who_field_order[] = "cuhsnf"; struct WhoData : public Who::Request { bool GetFieldIndex(char flag, size_t& out) const CXX11_OVERRIDE { if (!whox) { const char* pos = strchr(who_field_order, flag); if (pos == NULL) return false; out = pos - who_field_order; return true; } if (!whox_fields[flag]) return false; out = 0; for (const char* c = whox_field_order; *c && *c != flag; ++c) { if (whox_fields[*c]) ++out; } return whox_field_order[out]; } WhoData(const CommandBase::Params& parameters) { // Find the matchtext and swap the 0 for a * so we can use InspIRCd::Match on it. matchtext = parameters.size() > 2 ? parameters[2] : parameters[0]; if (matchtext == "0") matchtext = "*"; // Fuzzy matches are when the source has not specified a specific user. fuzzy_match = (parameters.size() > 1) || (matchtext.find_first_of("*?.") != std::string::npos); // If flags have been specified by the source. if (parameters.size() > 1) { std::bitset<UCHAR_MAX>* current_bitset = &flags; for (std::string::const_iterator iter = parameters[1].begin(); iter != parameters[1].end(); ++iter) { unsigned char chr = static_cast<unsigned char>(*iter); // If the source specifies a percentage the rest of the flags are WHOX fields. if (chr == '%') { whox = true; current_bitset = &whox_fields; continue; } // If we are in WHOX mode and the source specifies a comma // the rest of the parameter is the query type. if (whox && chr == ',') { whox_querytype.assign(++iter, parameters[1].end()); break; } // The source specified a matching flag. current_bitset->set(chr); } } } }; class CommandWho : public SplitCommand { private: ChanModeReference secretmode; ChanModeReference privatemode; UserModeReference hidechansmode; UserModeReference invisiblemode; Events::ModuleEventProvider whoevprov; /** Determines whether a user can view the users of a channel. */ bool CanView(Channel* chan, User* user) { // If we are in a channel we can view all users in it. if (chan->HasUser(user)) return true; // Opers with the users/auspex priv can see everything. if (user->HasPrivPermission("users/auspex")) return true; // You can see inside a channel from outside unless it is secret or private. return !chan->IsModeSet(secretmode) && !chan->IsModeSet(privatemode); } /** Gets the first channel which is visible between the source and the target users. */ Membership* GetFirstVisibleChannel(LocalUser* source, User* user) { for (User::ChanList::iterator iter = user->chans.begin(); iter != user->chans.end(); ++iter) { Membership* memb = *iter; // TODO: move the +I check into m_hidechans. bool has_modes = memb->chan->IsModeSet(secretmode) || memb->chan->IsModeSet(privatemode) || user->IsModeSet(hidechansmode); if (source == user || !has_modes || memb->chan->HasUser(source)) return memb; } return NULL; } /** Determines whether WHO flags match a specific channel user. */ bool MatchChannel(LocalUser* source, Membership* memb, WhoData& data); /** Determines whether WHO flags match a specific user. */ static bool MatchUser(LocalUser* source, User* target, WhoData& data); /** Performs a WHO request on a channel. */ void WhoChannel(LocalUser* source, const std::vector<std::string>& parameters, Channel* c, WhoData& data); /** Template for getting a user from various types of collection. */ template<typename T> static User* GetUser(T& t); /** Performs a WHO request on a list of users. */ template<typename T> void WhoUsers(LocalUser* source, const std::vector<std::string>& parameters, const T& users, WhoData& data); public: CommandWho(Module* parent) : SplitCommand(parent, "WHO", 1, 3) , secretmode(parent, "secret") , privatemode(parent, "private") , hidechansmode(parent, "hidechans") , invisiblemode(parent, "invisible") , whoevprov(parent, "event/who") { allow_empty_last_param = false; syntax = "<server>|<nick>|<channel>|<realname>|<host>|0 [[Aafhilmnoprstux][%acdfhilnorstu] <server>|<nick>|<channel>|<realname>|<host>|0]"; } /** Sends a WHO reply to a user. */ void SendWhoLine(LocalUser* user, const std::vector<std::string>& parameters, Membership* memb, User* u, WhoData& data); CmdResult HandleLocal(LocalUser* user, const Params& parameters) CXX11_OVERRIDE; }; template<> User* CommandWho::GetUser(UserManager::OperList::const_iterator& t) { return *t; } template<> User* CommandWho::GetUser(user_hash::const_iterator& t) { return t->second; } bool CommandWho::MatchChannel(LocalUser* source, Membership* memb, WhoData& data) { bool source_has_users_auspex = source->HasPrivPermission("users/auspex"); bool source_can_see_server = ServerInstance->Config->HideServer.empty() || source_has_users_auspex; // The source only wants remote users. This user is eligible if: // (1) The source can't see server information. // (2) The source is not local to the current server. LocalUser* lu = IS_LOCAL(memb->user); if (data.flags['f'] && source_can_see_server && lu) return false; // The source only wants local users. This user is eligible if: // (1) The source can't see server information. // (2) The source is local to the current server. if (data.flags['l'] && source_can_see_server && !lu) return false; // Only show operators if the oper flag has been specified. if (data.flags['o'] && !memb->user->IsOper()) return false; // All other flags are ignored for channels. return true; } bool CommandWho::MatchUser(LocalUser* source, User* user, WhoData& data) { // Users who are not fully registered can never match. if (user->registered != REG_ALL) return false; bool source_has_users_auspex = source->HasPrivPermission("users/auspex"); bool source_can_see_target = source == user || source_has_users_auspex; bool source_can_see_server = ServerInstance->Config->HideServer.empty() || source_has_users_auspex; // The source only wants remote users. This user is eligible if: // (1) The source can't see server information. // (2) The source is not local to the current server. LocalUser* lu = IS_LOCAL(user); if (data.flags['f'] && source_can_see_server && lu) return false; // The source only wants local users. This user is eligible if: // (1) The source can't see server information. // (2) The source is local to the current server. if (data.flags['l'] && source_can_see_server && !lu) return false; // The source wants to match against users' away messages. bool match = false; if (data.flags['A']) match = user->IsAway() && InspIRCd::Match(user->awaymsg, data.matchtext, ascii_case_insensitive_map); // The source wants to match against users' account names. else if (data.flags['a']) { const AccountExtItem* accountext = GetAccountExtItem(); const std::string* account = accountext ? accountext->get(user) : NULL; match = account && InspIRCd::Match(*account, data.matchtext); } // The source wants to match against users' hostnames. else if (data.flags['h']) { const std::string host = user->GetHost(source_can_see_target && data.flags['x']); match = InspIRCd::Match(host, data.matchtext, ascii_case_insensitive_map); } // The source wants to match against users' IP addresses. else if (data.flags['i']) match = source_can_see_target && InspIRCd::MatchCIDR(user->GetIPString(), data.matchtext, ascii_case_insensitive_map); // The source wants to match against users' modes. else if (data.flags['m']) { if (source_can_see_target) { bool set = true; for (std::string::const_iterator iter = data.matchtext.begin(); iter != data.matchtext.end(); ++iter) { unsigned char chr = static_cast<unsigned char>(*iter); switch (chr) { // The following user modes should be set. case '+': set = true; break; // The following user modes should be unset. case '-': set = false; break; default: if (user->IsModeSet(chr) != set) return false; break; } } // All of the modes matched. return true; } } // The source wants to match against users' nicks. else if (data.flags['n']) match = InspIRCd::Match(user->nick, data.matchtext); // The source wants to match against users' connection ports. else if (data.flags['p']) { if (source_can_see_target && lu) { irc::portparser portrange(data.matchtext, false); long port; while ((port = portrange.GetToken())) { if (port == lu->server_sa.port()) { match = true; break; } } } } // The source wants to match against users' real names. else if (data.flags['r']) match = InspIRCd::Match(user->GetRealName(), data.matchtext, ascii_case_insensitive_map); else if (data.flags['s']) { bool show_real_server_name = ServerInstance->Config->HideServer.empty() || (source->HasPrivPermission("servers/auspex") && data.flags['x']); const std::string server = show_real_server_name ? user->server->GetName() : ServerInstance->Config->HideServer; match = InspIRCd::Match(server, data.matchtext, ascii_case_insensitive_map); } // The source wants to match against users' connection times. else if (data.flags['t']) { time_t seconds = ServerInstance->Time() - InspIRCd::Duration(data.matchtext); if (user->signon >= seconds) match = true; } // The source wants to match against users' idents. else if (data.flags['u']) match = InspIRCd::Match(user->ident, data.matchtext, ascii_case_insensitive_map); // The <name> passed to WHO is matched against users' host, server, // real name and nickname if the channel <name> cannot be found. else { const std::string host = user->GetHost(source_can_see_target && data.flags['x']); match = InspIRCd::Match(host, data.matchtext, ascii_case_insensitive_map); if (!match) { bool show_real_server_name = ServerInstance->Config->HideServer.empty() || (source->HasPrivPermission("servers/auspex") && data.flags['x']); const std::string server = show_real_server_name ? user->server->GetName() : ServerInstance->Config->HideServer; match = InspIRCd::Match(server, data.matchtext, ascii_case_insensitive_map); } if (!match) match = InspIRCd::Match(user->GetRealName(), data.matchtext, ascii_case_insensitive_map); if (!match) match = InspIRCd::Match(user->nick, data.matchtext); } return match; } void CommandWho::WhoChannel(LocalUser* source, const std::vector<std::string>& parameters, Channel* chan, WhoData& data) { if (!CanView(chan, source)) return; bool inside = chan->HasUser(source); const Channel::MemberMap& users = chan->GetUsers(); for (Channel::MemberMap::const_iterator iter = users.begin(); iter != users.end(); ++iter) { User* user = iter->first; Membership* memb = iter->second; // Only show invisible users if the source is in the channel or has the users/auspex priv. if (!inside && user->IsModeSet(invisiblemode) && !source->HasPrivPermission("users/auspex")) continue; // Skip the user if it doesn't match the query. if (!MatchChannel(source, memb, data)) continue; SendWhoLine(source, parameters, memb, user, data); } } template<typename T> void CommandWho::WhoUsers(LocalUser* source, const std::vector<std::string>& parameters, const T& users, WhoData& data) { for (typename T::const_iterator iter = users.begin(); iter != users.end(); ++iter) { User* user = GetUser(iter); // Only show users in response to a fuzzy WHO if we can see them normally. bool can_see_normally = user == source || source->SharesChannelWith(user) || !user->IsModeSet(invisiblemode); if (data.fuzzy_match && !can_see_normally && !source->HasPrivPermission("users/auspex")) continue; // Skip the user if it doesn't match the query. if (!MatchUser(source, user, data)) continue; SendWhoLine(source, parameters, NULL, user, data); } } void CommandWho::SendWhoLine(LocalUser* source, const std::vector<std::string>& parameters, Membership* memb, User* user, WhoData& data) { if (!memb) memb = GetFirstVisibleChannel(source, user); bool source_can_see_target = source == user || source->HasPrivPermission("users/auspex"); Numeric::Numeric wholine(data.whox ? RPL_WHOSPCRPL : RPL_WHOREPLY); if (data.whox) { // The source used WHOX so we send a fancy customised response. // Include the query type in the reply. if (data.whox_fields['t']) wholine.push(data.whox_querytype.empty() || data.whox_querytype.length() > 3 ? "0" : data.whox_querytype); // Include the first channel name. if (data.whox_fields['c']) wholine.push(memb ? memb->chan->name : "*"); // Include the user's ident. if (data.whox_fields['u']) wholine.push(user->ident); // Include the user's IP address. if (data.whox_fields['i']) wholine.push(source_can_see_target ? user->GetIPString() : "255.255.255.255"); // Include the user's hostname. if (data.whox_fields['h']) wholine.push(user->GetHost(source_can_see_target && data.flags['x'])); // Include the server name. if (data.whox_fields['s']) { if (ServerInstance->Config->HideServer.empty() || (source->HasPrivPermission("servers/auspex") && data.flags['x'])) wholine.push(user->server->GetName()); else wholine.push(ServerInstance->Config->HideServer); } // Include the user's nickname. if (data.whox_fields['n']) wholine.push(user->nick); // Include the user's flags. if (data.whox_fields['f']) { // Away state. std::string flags(user->IsAway() ? "G" : "H"); // Operator status. if (user->IsOper()) flags.push_back('*'); // Membership prefix. if (memb) { char prefix = memb->GetPrefixChar(); if (prefix) flags.push_back(prefix); } wholine.push(flags); } // Include the number of hops between the users. if (data.whox_fields['d']) wholine.push("0"); // Include the user's idle time. if (data.whox_fields['l']) { LocalUser* lu = IS_LOCAL(user); unsigned long idle = lu ? ServerInstance->Time() - lu->idle_lastmsg : 0; wholine.push(ConvToStr(idle)); } // Include the user's account name. if (data.whox_fields['a']) { const AccountExtItem* accountext = GetAccountExtItem(); const std::string* account = accountext ? accountext->get(user) : NULL; wholine.push(account ? *account : "0"); } // Include the user's operator rank level. if (data.whox_fields['o']) wholine.push(memb ? ConvToStr(memb->getRank()) : "0"); // Include the user's real name. if (data.whox_fields['r']) wholine.push(user->GetRealName()); } else { // We are not using WHOX so we just send a plain RFC response. // Include the channel name. wholine.push(memb ? memb->chan->name : "*"); // Include the user's ident. wholine.push(user->ident); // Include the user's hostname. wholine.push(user->GetHost(source_can_see_target && data.flags['x'])); // Include the server name. if (ServerInstance->Config->HideServer.empty() || (source->HasPrivPermission("servers/auspex") && data.flags['x'])) wholine.push(user->server->GetName()); else wholine.push(ServerInstance->Config->HideServer); // Include the user's nick. wholine.push(user->nick); // Include the user's flags. { // Away state. std::string flags(user->IsAway() ? "G" : "H"); // Operator status. if (user->IsOper()) flags.push_back('*'); // Membership prefix. if (memb) { char prefix = memb->GetPrefixChar(); if (prefix) flags.push_back(prefix); } wholine.push(flags); } // Include the number of hops between the users and the user's real name. wholine.push("0 "); wholine.GetParams().back().append(user->GetRealName()); } ModResult res; FIRST_MOD_RESULT_CUSTOM(whoevprov, Who::EventListener, OnWhoLine, res, (data, source, user, memb, wholine)); if (res != MOD_RES_DENY) data.results.push_back(wholine); } CmdResult CommandWho::HandleLocal(LocalUser* user, const Params& parameters) { WhoData data(parameters); // Is the source running a WHO on a channel? Channel* chan = ServerInstance->FindChan(data.matchtext); if (chan) WhoChannel(user, parameters, chan, data); // If we only want to match against opers we only have to iterate the oper list. else if (data.flags['o']) WhoUsers(user, parameters, ServerInstance->Users->all_opers, data); // Otherwise we have to use the global user list. else WhoUsers(user, parameters, ServerInstance->Users->GetUsers(), data); // Send the results to the source. for (std::vector<Numeric::Numeric>::const_iterator n = data.results.begin(); n != data.results.end(); ++n) user->WriteNumeric(*n); user->WriteNumeric(RPL_ENDOFWHO, (data.matchtext.empty() ? "*" : data.matchtext.c_str()), "End of /WHO list."); // Penalize the source a bit for large queries with one unit of penalty per 200 results. user->CommandFloodPenalty += data.results.size() * 5; return CMD_SUCCESS; } class CoreModWho : public Module { private: CommandWho cmd; public: CoreModWho() : cmd(this) { } void On005Numeric(std::map<std::string, std::string>& tokens) CXX11_OVERRIDE { tokens["WHOX"]; } Version GetVersion() CXX11_OVERRIDE { return Version("Provides the WHO command", VF_VENDOR|VF_CORE); } }; MODULE_INIT(CoreModWho) �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/src/coremods/core_whois.cpp����������������������������������������������������������0000664�0000000�0000000�00000026014�13554550454�0020615�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * InspIRCd -- Internet Relay Chat Daemon * * Copyright (C) 2009 Daniel De Graaf <danieldg@inspircd.org> * Copyright (C) 2008 Thomas Stagner <aquanight@inspircd.org> * Copyright (C) 2007 Robin Burchell <robin+git@viroteck.net> * * 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 "inspircd.h" #include "modules/whois.h" enum { // From RFC 1459. RPL_WHOISUSER = 311, RPL_WHOISOPERATOR = 313, RPL_WHOISIDLE = 317, RPL_WHOISCHANNELS = 319, // From UnrealIRCd. RPL_WHOISHOST = 378, RPL_WHOISMODES = 379, // InspIRCd-specific. RPL_CHANNELSMSG = 651 }; enum SplitWhoisState { // Don't split private/secret channels into a separate RPL_WHOISCHANNELS numeric. SPLITWHOIS_NONE, // Split private/secret channels into a separate RPL_WHOISCHANNELS numeric. SPLITWHOIS_SPLIT, // Split private/secret channels into a separate RPL_WHOISCHANNELS numeric with RPL_CHANNELSMSG to explain the split. SPLITWHOIS_SPLITMSG }; class WhoisContextImpl : public Whois::Context { Events::ModuleEventProvider& lineevprov; public: WhoisContextImpl(LocalUser* src, User* targ, Events::ModuleEventProvider& evprov) : Whois::Context(src, targ) , lineevprov(evprov) { } using Whois::Context::SendLine; void SendLine(Numeric::Numeric& numeric) CXX11_OVERRIDE; }; void WhoisContextImpl::SendLine(Numeric::Numeric& numeric) { ModResult MOD_RESULT; FIRST_MOD_RESULT_CUSTOM(lineevprov, Whois::LineEventListener, OnWhoisLine, MOD_RESULT, (*this, numeric)); if (MOD_RESULT != MOD_RES_DENY) source->WriteNumeric(numeric); } /** Handle /WHOIS. */ class CommandWhois : public SplitCommand { ChanModeReference secretmode; ChanModeReference privatemode; UserModeReference snomaskmode; Events::ModuleEventProvider evprov; Events::ModuleEventProvider lineevprov; void DoWhois(LocalUser* user, User* dest, time_t signon, unsigned long idle); void SendChanList(WhoisContextImpl& whois); public: /** If true then all opers are shown with a generic 'is a server operator' line rather than the oper type. */ bool genericoper; /** How to handle private/secret channels in the WHOIS response. */ SplitWhoisState splitwhois; /** Constructor for whois. */ CommandWhois(Module* parent) : SplitCommand(parent, "WHOIS", 1) , secretmode(parent, "secret") , privatemode(parent, "private") , snomaskmode(parent, "snomask") , evprov(parent, "event/whois") , lineevprov(parent, "event/whoisline") { Penalty = 2; syntax = "[<servername>] <nick>[,<nick>]+"; } /** Handle command. * @param parameters The parameters to the command * @param user The user issuing the command * @return A value from CmdResult to indicate command success or failure. */ CmdResult HandleLocal(LocalUser* user, const Params& parameters) CXX11_OVERRIDE; CmdResult HandleRemote(RemoteUser* target, const Params& parameters) CXX11_OVERRIDE; }; class WhoisNumericSink { WhoisContextImpl& whois; public: WhoisNumericSink(WhoisContextImpl& whoisref) : whois(whoisref) { } void operator()(Numeric::Numeric& numeric) const { whois.SendLine(numeric); } }; class WhoisChanListNumericBuilder : public Numeric::GenericBuilder<' ', false, WhoisNumericSink> { public: WhoisChanListNumericBuilder(WhoisContextImpl& whois) : Numeric::GenericBuilder<' ', false, WhoisNumericSink>(WhoisNumericSink(whois), RPL_WHOISCHANNELS, false, whois.GetSource()->nick.size() + whois.GetTarget()->nick.size() + 1) { GetNumeric().push(whois.GetTarget()->nick).push(std::string()); } }; class WhoisChanList { const SplitWhoisState& splitwhois; WhoisChanListNumericBuilder num; WhoisChanListNumericBuilder secretnum; std::string prefixstr; void AddMember(Membership* memb, WhoisChanListNumericBuilder& out) { prefixstr.clear(); const char prefix = memb->GetPrefixChar(); if (prefix) prefixstr.push_back(prefix); out.Add(prefixstr, memb->chan->name); } public: WhoisChanList(WhoisContextImpl& whois, const SplitWhoisState& sws) : splitwhois(sws) , num(whois) , secretnum(whois) { } void AddVisible(Membership* memb) { AddMember(memb, num); } void AddHidden(Membership* memb) { AddMember(memb, splitwhois == SPLITWHOIS_NONE ? num : secretnum); } void Flush(WhoisContextImpl& whois) { num.Flush(); if (!secretnum.IsEmpty() && splitwhois == SPLITWHOIS_SPLITMSG) whois.SendLine(RPL_CHANNELSMSG, "is on private/secret channels:"); secretnum.Flush(); } }; void CommandWhois::SendChanList(WhoisContextImpl& whois) { WhoisChanList chanlist(whois, splitwhois); User* const target = whois.GetTarget(); bool hasoperpriv = whois.GetSource()->HasPrivPermission("users/channel-spy"); for (User::ChanList::iterator i = target->chans.begin(); i != target->chans.end(); ++i) { Membership* memb = *i; Channel* c = memb->chan; // Anyone can view channels which are not private or secret. if (!c->IsModeSet(privatemode) && !c->IsModeSet(secretmode)) chanlist.AddVisible(memb); // Hidden channels are visible when the following conditions are true: // (1) The source user and the target user are the same. // (2) The source user is a member of the hidden channel. // (3) The source user is an oper with the users/channel-spy privilege. else if (whois.IsSelfWhois() || c->HasUser(whois.GetSource()) || hasoperpriv) chanlist.AddHidden(memb); } chanlist.Flush(whois); } void CommandWhois::DoWhois(LocalUser* user, User* dest, time_t signon, unsigned long idle) { WhoisContextImpl whois(user, dest, lineevprov); whois.SendLine(RPL_WHOISUSER, dest->ident, dest->GetDisplayedHost(), '*', dest->GetRealName()); if (whois.IsSelfWhois() || user->HasPrivPermission("users/auspex")) { whois.SendLine(RPL_WHOISHOST, InspIRCd::Format("is connecting from %s@%s %s", dest->ident.c_str(), dest->GetRealHost().c_str(), dest->GetIPString().c_str())); } SendChanList(whois); if (!whois.IsSelfWhois() && !ServerInstance->Config->HideServer.empty() && !user->HasPrivPermission("servers/auspex")) { whois.SendLine(RPL_WHOISSERVER, ServerInstance->Config->HideServer, ServerInstance->Config->Network); } else { whois.SendLine(RPL_WHOISSERVER, dest->server->GetName(), dest->server->GetDesc()); } if (dest->IsAway()) { whois.SendLine(RPL_AWAY, dest->awaymsg); } if (dest->IsOper()) { if (genericoper) whois.SendLine(RPL_WHOISOPERATOR, "is a server operator"); else whois.SendLine(RPL_WHOISOPERATOR, InspIRCd::Format("is %s %s on %s", (strchr("AEIOUaeiou",dest->oper->name[0]) ? "an" : "a"), dest->oper->name.c_str(), ServerInstance->Config->Network.c_str())); } if (whois.IsSelfWhois() || user->HasPrivPermission("users/auspex")) { if (dest->IsModeSet(snomaskmode)) { whois.SendLine(RPL_WHOISMODES, InspIRCd::Format("is using modes %s %s", dest->GetModeLetters().c_str(), snomaskmode->GetUserParameter(dest).c_str())); } else { whois.SendLine(RPL_WHOISMODES, InspIRCd::Format("is using modes %s", dest->GetModeLetters().c_str())); } } FOREACH_MOD_CUSTOM(evprov, Whois::EventListener, OnWhois, (whois)); /* * We only send these if we've been provided them. That is, if hideserver is turned off, and user is local, or * if remote whois is queried, too. This is to keep the user hidden, and also since you can't reliably tell remote time. -- w00t */ if ((idle) || (signon)) { whois.SendLine(RPL_WHOISIDLE, idle, signon, "seconds idle, signon time"); } whois.SendLine(RPL_ENDOFWHOIS, "End of /WHOIS list."); } CmdResult CommandWhois::HandleRemote(RemoteUser* target, const Params& parameters) { if (parameters.size() < 2) return CMD_FAILURE; User* user = ServerInstance->FindUUID(parameters[0]); if (!user) return CMD_FAILURE; // User doing the whois must be on this server LocalUser* localuser = IS_LOCAL(user); if (!localuser) return CMD_FAILURE; unsigned long idle = ConvToNum<unsigned long>(parameters.back()); DoWhois(localuser, target, target->signon, idle); return CMD_SUCCESS; } CmdResult CommandWhois::HandleLocal(LocalUser* user, const Params& parameters) { User *dest; unsigned int userindex = 0; unsigned long idle = 0; time_t signon = 0; if (CommandParser::LoopCall(user, this, parameters, 0)) return CMD_SUCCESS; /* * If 2 paramters are specified (/whois nick nick), ignore the first one like spanningtree * does, and use the second one, otherwise, use the only paramter. -- djGrrr */ if (parameters.size() > 1) userindex = 1; dest = ServerInstance->FindNickOnly(parameters[userindex]); if ((dest) && (dest->registered == REG_ALL)) { /* * Okay. Umpteenth attempt at doing this, so let's re-comment... * For local users (/w localuser), we show idletime if hideserver is disabled * For local users (/w localuser localuser), we always show idletime, hence parameters.size() > 1 check. * For remote users (/w remoteuser), we do NOT show idletime * For remote users (/w remoteuser remoteuser), spanningtree will handle calling do_whois, so we can ignore this case. * Thanks to djGrrr for not being impatient while I have a crap day coding. :p -- w00t */ LocalUser* localuser = IS_LOCAL(dest); if (localuser && (ServerInstance->Config->HideServer.empty() || parameters.size() > 1)) { idle = labs((long)((localuser->idle_lastmsg)-ServerInstance->Time())); signon = dest->signon; } DoWhois(user,dest,signon,idle); } else { /* no such nick/channel */ user->WriteNumeric(Numerics::NoSuchNick(!parameters[userindex].empty() ? parameters[userindex] : "*")); user->WriteNumeric(RPL_ENDOFWHOIS, (!parameters[userindex].empty() ? parameters[userindex] : "*"), "End of /WHOIS list."); return CMD_FAILURE; } return CMD_SUCCESS; } class CoreModWhois : public Module { private: CommandWhois cmd; public: CoreModWhois() : cmd(this) { } void ReadConfig(ConfigStatus&) CXX11_OVERRIDE { ConfigTag* tag = ServerInstance->Config->ConfValue("options"); const std::string splitwhois = tag->getString("splitwhois", "no"); SplitWhoisState newsplitstate; if (stdalgo::string::equalsci(splitwhois, "no")) newsplitstate = SPLITWHOIS_NONE; else if (stdalgo::string::equalsci(splitwhois, "split")) newsplitstate = SPLITWHOIS_SPLIT; else if (stdalgo::string::equalsci(splitwhois, "splitmsg")) newsplitstate = SPLITWHOIS_SPLITMSG; else throw ModuleException(splitwhois + " is an invalid <options:splitwhois> value, at " + tag->getTagLocation()); ConfigTag* security = ServerInstance->Config->ConfValue("security"); cmd.genericoper = security->getBool("genericoper"); cmd.splitwhois = newsplitstate; } Version GetVersion() CXX11_OVERRIDE { return Version("Provides the WHOIS command", VF_VENDOR|VF_CORE); } }; MODULE_INIT(CoreModWhois) ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/src/coremods/core_whowas.cpp���������������������������������������������������������0000664�0000000�0000000�00000017507�13554550454�0021003�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * InspIRCd -- Internet Relay Chat Daemon * * Copyright (C) 2009 Daniel De Graaf <danieldg@inspircd.org> * Copyright (C) 2008 Thomas Stagner <aquanight@inspircd.org> * Copyright (C) 2008 Craig Edwards <craigedwards@brainbox.cc> * Copyright (C) 2007-2008 Robin Burchell <robin+git@viroteck.net> * * 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 "inspircd.h" #include "commands/cmd_whowas.h" #include "modules/stats.h" enum { // From RFC 1459. RPL_WHOWASUSER = 314, RPL_ENDOFWHOWAS = 369, // InspIRCd-specific. RPL_WHOWASIP = 652 }; CommandWhowas::CommandWhowas( Module* parent) : Command(parent, "WHOWAS", 1) { syntax = "<nick>"; Penalty = 2; } CmdResult CommandWhowas::Handle(User* user, const Params& parameters) { /* if whowas disabled in config */ if (!manager.IsEnabled()) { user->WriteNumeric(ERR_UNKNOWNCOMMAND, name, "This command has been disabled."); return CMD_FAILURE; } const WhoWas::Nick* const nick = manager.FindNick(parameters[0]); if (!nick) { user->WriteNumeric(ERR_WASNOSUCHNICK, parameters[0], "There was no such nickname"); } else { const WhoWas::Nick::List& list = nick->entries; for (WhoWas::Nick::List::const_iterator i = list.begin(); i != list.end(); ++i) { WhoWas::Entry* u = *i; user->WriteNumeric(RPL_WHOWASUSER, parameters[0], u->ident, u->dhost, '*', u->real); if (user->HasPrivPermission("users/auspex")) user->WriteNumeric(RPL_WHOWASIP, parameters[0], InspIRCd::Format("was connecting from *@%s", u->host.c_str())); std::string signon = InspIRCd::TimeString(u->signon); bool hide_server = (!ServerInstance->Config->HideServer.empty() && !user->HasPrivPermission("servers/auspex")); user->WriteNumeric(RPL_WHOISSERVER, parameters[0], (hide_server ? ServerInstance->Config->HideServer : u->server), signon); } } user->WriteNumeric(RPL_ENDOFWHOWAS, parameters[0], "End of WHOWAS"); return CMD_SUCCESS; } WhoWas::Manager::Manager() : GroupSize(0), MaxGroups(0), MaxKeep(0) { } const WhoWas::Nick* WhoWas::Manager::FindNick(const std::string& nickname) const { whowas_users::const_iterator it = whowas.find(nickname); if (it == whowas.end()) return NULL; return it->second; } WhoWas::Manager::Stats WhoWas::Manager::GetStats() const { size_t entrycount = 0; for (whowas_users::const_iterator i = whowas.begin(); i != whowas.end(); ++i) { WhoWas::Nick::List& list = i->second->entries; entrycount += list.size(); } Stats stats; stats.entrycount = entrycount; return stats; } void WhoWas::Manager::Add(User* user) { if (!IsEnabled()) return; // Insert nick if it doesn't exist // 'first' will point to the newly inserted element or to the existing element with an equivalent key std::pair<whowas_users::iterator, bool> ret = whowas.insert(std::make_pair(user->nick, static_cast<WhoWas::Nick*>(NULL))); if (ret.second) // If inserted { // This nick is new, create a list for it and add the first record to it WhoWas::Nick* nick = new WhoWas::Nick(ret.first->first); nick->entries.push_back(new Entry(user)); ret.first->second = nick; // Add this nick to the fifo too whowas_fifo.push_back(nick); if (whowas.size() > this->MaxGroups) { // Too many nicks, remove the nick which was inserted the longest time ago from both the map and the fifo PurgeNick(whowas_fifo.front()); } } else { // We've met this nick before, add a new record to the list WhoWas::Nick::List& list = ret.first->second->entries; list.push_back(new Entry(user)); // If there are too many records for this nick, remove the oldest (front) if (list.size() > this->GroupSize) { delete list.front(); list.pop_front(); } } } /* on rehash, refactor maps according to new conf values */ void WhoWas::Manager::Prune() { time_t min = ServerInstance->Time() - this->MaxKeep; /* first cut the list to new size (maxgroups) and also prune entries that are timed out. */ while (!whowas_fifo.empty()) { WhoWas::Nick* nick = whowas_fifo.front(); if ((whowas_fifo.size() > this->MaxGroups) || (nick->addtime < min)) PurgeNick(nick); else break; } /* Then cut the whowas sets to new size (groupsize) */ for (whowas_users::iterator i = whowas.begin(); i != whowas.end(); ) { WhoWas::Nick::List& list = i->second->entries; while (list.size() > this->GroupSize) { delete list.front(); list.pop_front(); } if (list.empty()) PurgeNick(i++); else ++i; } } /* call maintain once an hour to remove expired nicks */ void WhoWas::Manager::Maintain() { time_t min = ServerInstance->Time() - this->MaxKeep; for (whowas_users::iterator i = whowas.begin(); i != whowas.end(); ) { WhoWas::Nick::List& list = i->second->entries; while (!list.empty() && list.front()->signon < min) { delete list.front(); list.pop_front(); } if (list.empty()) PurgeNick(i++); else ++i; } } WhoWas::Manager::~Manager() { for (whowas_users::iterator i = whowas.begin(); i != whowas.end(); ++i) { WhoWas::Nick* nick = i->second; delete nick; } } bool WhoWas::Manager::IsEnabled() const { return ((GroupSize != 0) && (MaxGroups != 0)); } void WhoWas::Manager::UpdateConfig(unsigned int NewGroupSize, unsigned int NewMaxGroups, unsigned int NewMaxKeep) { if ((NewGroupSize == GroupSize) && (NewMaxGroups == MaxGroups) && (NewMaxKeep == MaxKeep)) return; GroupSize = NewGroupSize; MaxGroups = NewMaxGroups; MaxKeep = NewMaxKeep; Prune(); } void WhoWas::Manager::PurgeNick(whowas_users::iterator it) { WhoWas::Nick* nick = it->second; whowas_fifo.erase(nick); whowas.erase(it); delete nick; } void WhoWas::Manager::PurgeNick(WhoWas::Nick* nick) { whowas_users::iterator it = whowas.find(nick->nick); if (it == whowas.end()) { ServerInstance->Logs->Log(MODNAME, LOG_DEFAULT, "ERROR: Inconsistency detected in whowas database, please report"); return; } PurgeNick(it); } WhoWas::Entry::Entry(User* user) : host(user->GetRealHost()) , dhost(user->GetDisplayedHost()) , ident(user->ident) , server(user->server->GetName()) , real(user->GetRealName()) , signon(user->signon) { } WhoWas::Nick::Nick(const std::string& nickname) : addtime(ServerInstance->Time()) , nick(nickname) { } WhoWas::Nick::~Nick() { stdalgo::delete_all(entries); } class ModuleWhoWas : public Module, public Stats::EventListener { CommandWhowas cmd; public: ModuleWhoWas() : Stats::EventListener(this) , cmd(this) { } void OnGarbageCollect() CXX11_OVERRIDE { // Remove all entries older than MaxKeep cmd.manager.Maintain(); } void OnUserQuit(User* user, const std::string& message, const std::string& oper_message) CXX11_OVERRIDE { cmd.manager.Add(user); } ModResult OnStats(Stats::Context& stats) CXX11_OVERRIDE { if (stats.GetSymbol() == 'z') stats.AddRow(249, "Whowas entries: "+ConvToStr(cmd.manager.GetStats().entrycount)); return MOD_RES_PASSTHRU; } void ReadConfig(ConfigStatus& status) CXX11_OVERRIDE { ConfigTag* tag = ServerInstance->Config->ConfValue("whowas"); unsigned int NewGroupSize = tag->getUInt("groupsize", 10, 0, 10000); unsigned int NewMaxGroups = tag->getUInt("maxgroups", 10240, 0, 1000000); unsigned int NewMaxKeep = tag->getDuration("maxkeep", 3600, 3600); cmd.manager.UpdateConfig(NewGroupSize, NewMaxGroups, NewMaxKeep); } Version GetVersion() CXX11_OVERRIDE { return Version("Provides the WHOWAS command", VF_VENDOR); } }; MODULE_INIT(ModuleWhoWas) �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/src/coremods/core_xline/�������������������������������������������������������������0000775�0000000�0000000�00000000000�13554550454�0020074�5����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/src/coremods/core_xline/cmd_eline.cpp������������������������������������������������0000664�0000000�0000000�00000005720�13554550454�0022523�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * InspIRCd -- Internet Relay Chat Daemon * * Copyright (C) 2009 Daniel De Graaf <danieldg@inspircd.org> * Copyright (C) 2007-2008 Robin Burchell <robin+git@viroteck.net> * * 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 "inspircd.h" #include "xline.h" #include "core_xline.h" CommandEline::CommandEline(Module* parent) : Command(parent, "ELINE", 1, 3) { flags_needed = 'o'; syntax = "<user@host> [<duration> :<reason>]"; } /** Handle /ELINE */ CmdResult CommandEline::Handle(User* user, const Params& parameters) { std::string target = parameters[0]; if (parameters.size() >= 3) { IdentHostPair ih; User* find = ServerInstance->FindNick(target); if ((find) && (find->registered == REG_ALL)) { ih.first = "*"; ih.second = find->GetIPString(); target = std::string("*@") + find->GetIPString(); } else ih = ServerInstance->XLines->IdentSplit(target); if (ih.first.empty()) { user->WriteNotice("*** Target not found."); return CMD_FAILURE; } InsaneBan::IPHostMatcher matcher; if (InsaneBan::MatchesEveryone(ih.first+"@"+ih.second, matcher, user, "E", "hostmasks")) return CMD_FAILURE; unsigned long duration; if (!InspIRCd::Duration(parameters[1], duration)) { user->WriteNotice("*** Invalid duration for E-line."); return CMD_FAILURE; } ELine* el = new ELine(ServerInstance->Time(), duration, user->nick.c_str(), parameters[2].c_str(), ih.first.c_str(), ih.second.c_str()); if (ServerInstance->XLines->AddLine(el, user)) { if (!duration) { ServerInstance->SNO->WriteToSnoMask('x', "%s added permanent E-line for %s: %s", user->nick.c_str(), target.c_str(), parameters[2].c_str()); } else { ServerInstance->SNO->WriteToSnoMask('x', "%s added timed E-line for %s, expires in %s (on %s): %s", user->nick.c_str(), target.c_str(), InspIRCd::DurationString(duration).c_str(), InspIRCd::TimeString(ServerInstance->Time() + duration).c_str(), parameters[2].c_str()); } } else { delete el; user->WriteNotice("*** E-line for " + target + " already exists."); } } else { std::string reason; if (ServerInstance->XLines->DelLine(target.c_str(), "E", reason, user)) { ServerInstance->SNO->WriteToSnoMask('x', "%s removed E-line on %s: %s", user->nick.c_str(), target.c_str(), reason.c_str()); } else { user->WriteNotice("*** E-line " + target + " not found on the list."); } } return CMD_SUCCESS; } ������������������������������������������������inspircd-3.4.0/src/coremods/core_xline/cmd_gline.cpp������������������������������������������������0000664�0000000�0000000�00000006230�13554550454�0022522�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * InspIRCd -- Internet Relay Chat Daemon * * Copyright (C) 2009 Daniel De Graaf <danieldg@inspircd.org> * Copyright (C) 2007-2008 Robin Burchell <robin+git@viroteck.net> * * 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 "inspircd.h" #include "xline.h" #include "core_xline.h" CommandGline::CommandGline(Module* parent) : Command(parent, "GLINE", 1, 3) { flags_needed = 'o'; syntax = "<user@host> [<duration> :<reason>]"; } /** Handle /GLINE */ CmdResult CommandGline::Handle(User* user, const Params& parameters) { std::string target = parameters[0]; if (parameters.size() >= 3) { IdentHostPair ih; User* find = ServerInstance->FindNick(target); if ((find) && (find->registered == REG_ALL)) { ih.first = "*"; ih.second = find->GetIPString(); target = std::string("*@") + find->GetIPString(); } else ih = ServerInstance->XLines->IdentSplit(target); if (ih.first.empty()) { user->WriteNotice("*** Target not found."); return CMD_FAILURE; } InsaneBan::IPHostMatcher matcher; if (InsaneBan::MatchesEveryone(ih.first+"@"+ih.second, matcher, user, "G", "hostmasks")) return CMD_FAILURE; else if (target.find('!') != std::string::npos) { user->WriteNotice("*** G-line cannot operate on nick!user@host masks."); return CMD_FAILURE; } unsigned long duration; if (!InspIRCd::Duration(parameters[1], duration)) { user->WriteNotice("*** Invalid duration for G-line."); return CMD_FAILURE; } GLine* gl = new GLine(ServerInstance->Time(), duration, user->nick.c_str(), parameters[2].c_str(), ih.first.c_str(), ih.second.c_str()); if (ServerInstance->XLines->AddLine(gl, user)) { if (!duration) { ServerInstance->SNO->WriteToSnoMask('x', "%s added permanent G-line for %s: %s", user->nick.c_str(), target.c_str(), parameters[2].c_str()); } else { ServerInstance->SNO->WriteToSnoMask('x', "%s added timed G-line for %s, expires in %s (on %s): %s", user->nick.c_str(), target.c_str(), InspIRCd::DurationString(duration).c_str(), InspIRCd::TimeString(ServerInstance->Time() + duration).c_str(), parameters[2].c_str()); } ServerInstance->XLines->ApplyLines(); } else { delete gl; user->WriteNotice("** G-line for " + target + " already exists."); } } else { std::string reason; if (ServerInstance->XLines->DelLine(target.c_str(), "G", reason, user)) { ServerInstance->SNO->WriteToSnoMask('x', "%s removed G-line on %s: %s", user->nick.c_str(), target.c_str(), reason.c_str()); } else { user->WriteNotice("*** G-line " + target + " not found on the list."); } } return CMD_SUCCESS; } ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/src/coremods/core_xline/cmd_kline.cpp������������������������������������������������0000664�0000000�0000000�00000006222�13554550454�0022527�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * InspIRCd -- Internet Relay Chat Daemon * * Copyright (C) 2009 Daniel De Graaf <danieldg@inspircd.org> * Copyright (C) 2007-2008 Robin Burchell <robin+git@viroteck.net> * * 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 "inspircd.h" #include "xline.h" #include "core_xline.h" CommandKline::CommandKline(Module* parent) : Command(parent, "KLINE", 1, 3) { flags_needed = 'o'; syntax = "<user@host> [<duration> :<reason>]"; } /** Handle /KLINE */ CmdResult CommandKline::Handle(User* user, const Params& parameters) { std::string target = parameters[0]; if (parameters.size() >= 3) { IdentHostPair ih; User* find = ServerInstance->FindNick(target); if ((find) && (find->registered == REG_ALL)) { ih.first = "*"; ih.second = find->GetIPString(); target = std::string("*@") + find->GetIPString(); } else ih = ServerInstance->XLines->IdentSplit(target); if (ih.first.empty()) { user->WriteNotice("*** Target not found."); return CMD_FAILURE; } InsaneBan::IPHostMatcher matcher; if (InsaneBan::MatchesEveryone(ih.first+"@"+ih.second, matcher, user, "K", "hostmasks")) return CMD_FAILURE; if (target.find('!') != std::string::npos) { user->WriteNotice("*** K-line cannot operate on nick!user@host masks."); return CMD_FAILURE; } unsigned long duration; if (!InspIRCd::Duration(parameters[1], duration)) { user->WriteNotice("*** Invalid duration for K-line."); return CMD_FAILURE; } KLine* kl = new KLine(ServerInstance->Time(), duration, user->nick.c_str(), parameters[2].c_str(), ih.first.c_str(), ih.second.c_str()); if (ServerInstance->XLines->AddLine(kl,user)) { if (!duration) { ServerInstance->SNO->WriteToSnoMask('x', "%s added permanent K-line for %s: %s", user->nick.c_str(), target.c_str(), parameters[2].c_str()); } else { ServerInstance->SNO->WriteToSnoMask('x', "%s added timed K-line for %s, expires in %s (on %s): %s", user->nick.c_str(), target.c_str(), InspIRCd::DurationString(duration).c_str(), InspIRCd::TimeString(ServerInstance->Time() + duration).c_str(), parameters[2].c_str()); } ServerInstance->XLines->ApplyLines(); } else { delete kl; user->WriteNotice("*** K-line for " + target + " already exists."); } } else { std::string reason; if (ServerInstance->XLines->DelLine(target.c_str(), "K", reason, user)) { ServerInstance->SNO->WriteToSnoMask('x', "%s removed K-line on %s: %s", user->nick.c_str(), target.c_str(), reason.c_str()); } else { user->WriteNotice("*** K-line " + target + " not found on the list."); } } return CMD_SUCCESS; } ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/src/coremods/core_xline/cmd_qline.cpp������������������������������������������������0000664�0000000�0000000�00000006034�13554550454�0022536�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * InspIRCd -- Internet Relay Chat Daemon * * Copyright (C) 2009 Daniel De Graaf <danieldg@inspircd.org> * Copyright (C) 2008 Craig Edwards <craigedwards@brainbox.cc> * Copyright (C) 2007 Robin Burchell <robin+git@viroteck.net> * * 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 "inspircd.h" #include "xline.h" #include "core_xline.h" CommandQline::CommandQline(Module* parent) : Command(parent, "QLINE", 1, 3) { flags_needed = 'o'; syntax = "<nickmask> [<duration> :<reason>]"; } CmdResult CommandQline::Handle(User* user, const Params& parameters) { if (parameters.size() >= 3) { NickMatcher matcher; if (InsaneBan::MatchesEveryone(parameters[0], matcher, user, "Q", "nickmasks")) return CMD_FAILURE; if (parameters[0].find('@') != std::string::npos || parameters[0].find('!') != std::string::npos || parameters[0].find('.') != std::string::npos) { user->WriteNotice("*** A Q-line only bans a nick pattern, not a nick!user@host pattern."); return CMD_FAILURE; } unsigned long duration; if (!InspIRCd::Duration(parameters[1], duration)) { user->WriteNotice("*** Invalid duration for Q-line."); return CMD_FAILURE; } QLine* ql = new QLine(ServerInstance->Time(), duration, user->nick.c_str(), parameters[2].c_str(), parameters[0].c_str()); if (ServerInstance->XLines->AddLine(ql,user)) { if (!duration) { ServerInstance->SNO->WriteToSnoMask('x', "%s added permanent Q-line for %s: %s", user->nick.c_str(), parameters[0].c_str(), parameters[2].c_str()); } else { ServerInstance->SNO->WriteToSnoMask('x', "%s added timed Q-line for %s, expires in %s (on %s): %s", user->nick.c_str(), parameters[0].c_str(), InspIRCd::DurationString(duration).c_str(), InspIRCd::TimeString(ServerInstance->Time() + duration).c_str(), parameters[2].c_str()); } ServerInstance->XLines->ApplyLines(); } else { delete ql; user->WriteNotice("*** Q-line for " + parameters[0] + " already exists."); } } else { std::string reason; if (ServerInstance->XLines->DelLine(parameters[0].c_str(), "Q", reason, user)) { ServerInstance->SNO->WriteToSnoMask('x', "%s removed Q-line on %s: %s", user->nick.c_str(), parameters[0].c_str(), reason.c_str()); } else { user->WriteNotice("*** Q-line " + parameters[0] + " not found on the list."); return CMD_FAILURE; } } return CMD_SUCCESS; } bool CommandQline::NickMatcher::Check(User* user, const std::string& nick) const { return InspIRCd::Match(user->nick, nick); } ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/src/coremods/core_xline/cmd_zline.cpp������������������������������������������������0000664�0000000�0000000�00000006272�13554550454�0022553�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * InspIRCd -- Internet Relay Chat Daemon * * Copyright (C) 2009 Daniel De Graaf <danieldg@inspircd.org> * Copyright (C) 2009 Matt Smith <dz@inspircd.org> * Copyright (C) 2007-2008 Robin Burchell <robin+git@viroteck.net> * * 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 "inspircd.h" #include "xline.h" #include "core_xline.h" CommandZline::CommandZline(Module* parent) : Command(parent, "ZLINE", 1, 3) { flags_needed = 'o'; syntax = "<ipmask> [<duration> :<reason>]"; } CmdResult CommandZline::Handle(User* user, const Params& parameters) { std::string target = parameters[0]; if (parameters.size() >= 3) { if (target.find('!') != std::string::npos) { user->WriteNotice("*** You cannot include a nickname in a Z-line, a Z-line must ban only an IP mask."); return CMD_FAILURE; } User *u = ServerInstance->FindNick(target); if ((u) && (u->registered == REG_ALL)) { target = u->GetIPString(); } const char* ipaddr = target.c_str(); if (strchr(ipaddr,'@')) { while (*ipaddr != '@') ipaddr++; ipaddr++; } IPMatcher matcher; if (InsaneBan::MatchesEveryone(ipaddr, matcher, user, "Z", "ipmasks")) return CMD_FAILURE; unsigned long duration; if (!InspIRCd::Duration(parameters[1], duration)) { user->WriteNotice("*** Invalid duration for Z-line."); return CMD_FAILURE; } ZLine* zl = new ZLine(ServerInstance->Time(), duration, user->nick.c_str(), parameters[2].c_str(), ipaddr); if (ServerInstance->XLines->AddLine(zl,user)) { if (!duration) { ServerInstance->SNO->WriteToSnoMask('x', "%s added permanent Z-line for %s: %s", user->nick.c_str(), ipaddr, parameters[2].c_str()); } else { ServerInstance->SNO->WriteToSnoMask('x', "%s added timed Z-line for %s, expires in %s (on %s): %s", user->nick.c_str(), ipaddr, InspIRCd::DurationString(duration).c_str(), InspIRCd::TimeString(ServerInstance->Time() + duration).c_str(), parameters[2].c_str()); } ServerInstance->XLines->ApplyLines(); } else { delete zl; user->WriteNotice("*** Z-line for " + std::string(ipaddr) + " already exists."); } } else { std::string reason; if (ServerInstance->XLines->DelLine(target.c_str(), "Z", reason, user)) { ServerInstance->SNO->WriteToSnoMask('x', "%s removed Z-line on %s: %s", user->nick.c_str(), target.c_str(), reason.c_str()); } else { user->WriteNotice("*** Z-line " + target + " not found on the list."); return CMD_FAILURE; } } return CMD_SUCCESS; } bool CommandZline::IPMatcher::Check(User* user, const std::string& ip) const { return InspIRCd::MatchCIDR(user->GetIPString(), ip, ascii_case_insensitive_map); } ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/src/coremods/core_xline/core_xline.cpp�����������������������������������������������0000664�0000000�0000000�00000006223�13554550454�0022732�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * InspIRCd -- Internet Relay Chat Daemon * * Copyright (C) 2014 Attila Molnar <attilamolnar@hush.com> * * This file is part of InspIRCd. InspIRCd is free software: you can * redistribute it and/or modify it under the terms of the GNU General Public * License as published by the Free Software Foundation, version 2. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include "inspircd.h" #include "xline.h" #include "core_xline.h" bool InsaneBan::MatchesEveryone(const std::string& mask, MatcherBase& test, User* user, const char* bantype, const char* confkey) { ConfigTag* insane = ServerInstance->Config->ConfValue("insane"); if (insane->getBool(confkey)) return false; float itrigger = insane->getFloat("trigger", 95.5, 0.0, 100.0); long matches = test.Run(mask); if (!matches) return false; float percent = ((float)matches / (float)ServerInstance->Users->GetUsers().size()) * 100; if (percent > itrigger) { ServerInstance->SNO->WriteToSnoMask('a', "\002WARNING\002: %s tried to set a %s-line mask of %s, which covers %.2f%% of the network!", user->nick.c_str(), bantype, mask.c_str(), percent); return true; } return false; } bool InsaneBan::IPHostMatcher::Check(User* user, const std::string& mask) const { return ((InspIRCd::MatchCIDR(user->MakeHost(), mask, ascii_case_insensitive_map)) || (InspIRCd::MatchCIDR(user->MakeHostIP(), mask, ascii_case_insensitive_map))); } class CoreModXLine : public Module { CommandEline cmdeline; CommandGline cmdgline; CommandKline cmdkline; CommandQline cmdqline; CommandZline cmdzline; public: CoreModXLine() : cmdeline(this), cmdgline(this), cmdkline(this), cmdqline(this), cmdzline(this) { } void OnSetUserIP(LocalUser* user) CXX11_OVERRIDE { if (user->quitting) return; user->exempt = (ServerInstance->XLines->MatchesLine("E", user) != NULL); user->CheckLines(true); } ModResult OnUserPreNick(LocalUser* user, const std::string& newnick) CXX11_OVERRIDE { // Check Q-lines (for local nick changes only, remote servers have our Q-lines to enforce themselves) XLine* xline = ServerInstance->XLines->MatchesLine("Q", newnick); if (!xline) return MOD_RES_PASSTHRU; // No match // A Q-line matched the new nick, tell opers if the user is registered if (user->registered == REG_ALL) { ServerInstance->SNO->WriteGlobalSno('a', "Q-lined nickname %s from %s: %s", newnick.c_str(), user->GetFullRealHost().c_str(), xline->reason.c_str()); } // Send a numeric because if we deny then the core doesn't reply anything user->WriteNumeric(ERR_ERRONEUSNICKNAME, newnick, InspIRCd::Format("Invalid nickname: %s", xline->reason.c_str())); return MOD_RES_DENY; } Version GetVersion() CXX11_OVERRIDE { return Version("Provides the ELINE, GLINE, KLINE, QLINE, and ZLINE commands", VF_VENDOR|VF_CORE); } }; MODULE_INIT(CoreModXLine) �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/src/coremods/core_xline/core_xline.h�������������������������������������������������0000664�0000000�0000000�00000010541�13554550454�0022375�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * InspIRCd -- Internet Relay Chat Daemon * * Copyright (C) 2014 Attila Molnar <attilamolnar@hush.com> * * This file is part of InspIRCd. InspIRCd is free software: you can * redistribute it and/or modify it under the terms of the GNU General Public * License as published by the Free Software Foundation, version 2. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include "inspircd.h" class InsaneBan { public: class MatcherBase { public: virtual long Run(const std::string& mask) = 0; }; template <typename T> class Matcher : public MatcherBase { public: long Run(const std::string& mask) CXX11_OVERRIDE { long matches = 0; const T* c = static_cast<T*>(this); const user_hash& users = ServerInstance->Users->GetUsers(); for (user_hash::const_iterator i = users.begin(); i != users.end(); ++i) { if (c->Check(i->second, mask)) matches++; } return matches; } }; class IPHostMatcher : public Matcher<IPHostMatcher> { public: bool Check(User* user, const std::string& mask) const; }; /** Check if the given mask matches too many users according to the config, send an announcement if yes * @param mask A mask to match against * @param test The test that determines if a user matches the mask or not * @param user A user whose nick will be included in the announcement if one is made * @param bantype Type of the ban being set, will be used in the announcement if one is made * @param confkey Name of the config key (inside the insane tag) which if false disables any checking * @return True if the given mask matches too many users, false if not */ static bool MatchesEveryone(const std::string& mask, MatcherBase& test, User* user, const char* bantype, const char* confkey); }; /** Handle /ELINE. */ class CommandEline : public Command { public: /** Constructor for E-line. */ CommandEline(Module* parent); /** Handle command. * @param parameters The parameters to the command * @param user The user issuing the command * @return A value from CmdResult to indicate command success or failure. */ CmdResult Handle(User* user, const Params& parameters) CXX11_OVERRIDE; }; /** Handle /GLINE. */ class CommandGline : public Command { public: /** Constructor for G-line. */ CommandGline(Module* parent); /** Handle command. * @param parameters The parameters to the command * @param user The user issuing the command * @return A value from CmdResult to indicate command success or failure. */ CmdResult Handle(User* user, const Params& parameters) CXX11_OVERRIDE; }; /** Handle /KLINE. */ class CommandKline : public Command { public: /** Constructor for K-line. */ CommandKline(Module* parent); /** Handle command. * @param parameters The parameters to the command * @param user The user issuing the command * @return A value from CmdResult to indicate command success or failure. */ CmdResult Handle(User* user, const Params& parameters) CXX11_OVERRIDE; }; /** Handle /QLINE. */ class CommandQline : public Command { class NickMatcher : public InsaneBan::Matcher<NickMatcher> { public: bool Check(User* user, const std::string& mask) const; }; public: /** Constructor for Q-line. */ CommandQline(Module* parent); /** Handle command. * @param parameters The parameters to the command * @param user The user issuing the command * @return A value from CmdResult to indicate command success or failure. */ CmdResult Handle(User* user, const Params& parameters) CXX11_OVERRIDE; }; /** Handle /ZLINE. */ class CommandZline : public Command { class IPMatcher : public InsaneBan::Matcher<IPMatcher> { public: bool Check(User* user, const std::string& mask) const; }; public: /** Constructor for Z-line. */ CommandZline(Module* parent); /** Handle command. * @param parameters The parameters to the command * @param user The user issuing the command * @return A value from CmdResult to indicate command success or failure. */ CmdResult Handle(User* user, const Params& parameters) CXX11_OVERRIDE; }; ���������������������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/src/cull_list.cpp��������������������������������������������������������������������0000664�0000000�0000000�00000004562�13554550454�0016637�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * InspIRCd -- Internet Relay Chat Daemon * * Copyright (C) 2009 Daniel De Graaf <danieldg@inspircd.org> * Copyright (C) 2006-2008 Robin Burchell <robin+git@viroteck.net> * Copyright (C) 2007 Dennis Friis <peavey@inspircd.org> * Copyright (C) 2005-2007 Craig Edwards <craigedwards@brainbox.cc> * * This file is part of InspIRCd. InspIRCd is free software: you can * redistribute it and/or modify it under the terms of the GNU General Public * License as published by the Free Software Foundation, version 2. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include "inspircd.h" #ifdef INSPIRCD_ENABLE_RTTI #include <typeinfo> #endif void CullList::Apply() { std::vector<LocalUser *> working; while (!SQlist.empty()) { working.swap(SQlist); for(std::vector<LocalUser *>::iterator a = working.begin(); a != working.end(); a++) { LocalUser *u = *a; ServerInstance->SNO->WriteGlobalSno('a', "User %s SendQ exceeds connect class maximum of %lu", u->nick.c_str(), u->MyClass->GetSendqHardMax()); ServerInstance->Users->QuitUser(u, "SendQ exceeded"); } working.clear(); } std::set<classbase*> gone; std::vector<classbase*> queue; queue.reserve(list.size() + 32); for(unsigned int i=0; i < list.size(); i++) { classbase* c = list[i]; if (gone.insert(c).second) { #ifdef INSPIRCD_ENABLE_RTTI ServerInstance->Logs->Log("CULLLIST", LOG_DEBUG, "Deleting %s @%p", typeid(*c).name(), (void*)c); #else ServerInstance->Logs->Log("CULLLIST", LOG_DEBUG, "Deleting @%p", (void*)c); #endif c->cull(); queue.push_back(c); } else { ServerInstance->Logs->Log("CULLLIST", LOG_DEBUG, "WARNING: Object @%p culled twice!", (void*)c); } } list.clear(); for(unsigned int i=0; i < queue.size(); i++) { classbase* c = queue[i]; delete c; } if (list.size()) { ServerInstance->Logs->Log("CULLLIST", LOG_DEBUG, "WARNING: Objects added to cull list in a destructor"); Apply(); } } void ActionList::Run() { for(unsigned int i=0; i < list.size(); i++) { list[i]->Call(); } list.clear(); } ����������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/src/dynamic.cpp����������������������������������������������������������������������0000664�0000000�0000000�00000005030�13554550454�0016260�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * InspIRCd -- Internet Relay Chat Daemon * * Copyright (C) 2009 Daniel De Graaf <danieldg@inspircd.org> * Copyright (C) 2007 Oliver Lupton <oliverlupton@gmail.com> * Copyright (C) 2007 Robin Burchell <robin+git@viroteck.net> * Copyright (C) 2007 Dennis Friis <peavey@inspircd.org> * Copyright (C) 2003, 2006 Craig Edwards <craigedwards@brainbox.cc> * * This file is part of InspIRCd. InspIRCd is free software: you can * redistribute it and/or modify it under the terms of the GNU General Public * License as published by the Free Software Foundation, version 2. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include "inspircd.h" #ifndef _WIN32 #include <dlfcn.h> #else #define dlopen(path, state) (void*)LoadLibraryA(path) #define dlsym(handle, export) (void*)GetProcAddress((HMODULE)handle, export) #define dlclose(handle) FreeLibrary((HMODULE)handle) #endif DLLManager::DLLManager(const char *fname) { if (!strstr(fname,".so")) { err = "This doesn't look like a module file to me..."; h = NULL; return; } h = dlopen(fname, RTLD_NOW|RTLD_LOCAL); if (!h) { RetrieveLastError(); } } DLLManager::~DLLManager() { /* close the library */ if (h) dlclose(h); } Module* DLLManager::CallInit() { union { void* vptr; Module* (*fptr)(); }; vptr = GetSymbol(MODULE_INIT_STR); if (!vptr) return NULL; return (*fptr)(); } void* DLLManager::GetSymbol(const char* name) { return h ? dlsym(h, name) : NULL; } std::string DLLManager::GetVersion() { const char* srcver = static_cast<const char*>(GetSymbol("inspircd_src_version")); return srcver ? srcver : ""; } void DLLManager::RetrieveLastError() { #if defined _WIN32 char errmsg[500]; DWORD dwErrorCode = GetLastError(); if (FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, dwErrorCode, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPSTR)errmsg, _countof(errmsg), NULL) == 0) sprintf_s(errmsg, _countof(errmsg), "Error code: %u", dwErrorCode); SetLastError(ERROR_SUCCESS); err = errmsg; #else const char* errmsg = dlerror(); err = errmsg ? errmsg : "Unknown error"; #endif std::string::size_type p; while ((p = err.find_last_of("\r\n")) != std::string::npos) err.erase(p, 1); } ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/src/filelogger.cpp�������������������������������������������������������������������0000664�0000000�0000000�00000003026�13554550454�0016756�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * InspIRCd -- Internet Relay Chat Daemon * * Copyright (C) 2008 Thomas Stagner <aquanight@inspircd.org> * Copyright (C) 2008 Robin Burchell <robin+git@viroteck.net> * Copyright (C) 2007 Dennis Friis <peavey@inspircd.org> * * This file is part of InspIRCd. InspIRCd is free software: you can * redistribute it and/or modify it under the terms of the GNU General Public * License as published by the Free Software Foundation, version 2. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include "inspircd.h" #include <fstream> FileLogStream::FileLogStream(LogLevel loglevel, FileWriter *fw) : LogStream(loglevel), f(fw) { ServerInstance->Logs->AddLoggerRef(f); } FileLogStream::~FileLogStream() { /* FileWriter is managed externally now */ ServerInstance->Logs->DelLoggerRef(f); } void FileLogStream::OnLog(LogLevel loglevel, const std::string &type, const std::string &text) { static std::string TIMESTR; static time_t LAST = 0; if (loglevel < this->loglvl) { return; } if (ServerInstance->Time() != LAST) { TIMESTR = InspIRCd::TimeString(ServerInstance->Time()); LAST = ServerInstance->Time(); } this->f->WriteLogLine(TIMESTR + " " + type + ": " + text + "\n"); } ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/src/fileutils.cpp��������������������������������������������������������������������0000664�0000000�0000000�00000006532�13554550454�0016644�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * InspIRCd -- Internet Relay Chat Daemon * * Copyright (C) 2013 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 "inspircd.h" #include <fstream> #ifndef _WIN32 # include <dirent.h> #endif FileReader::FileReader(const std::string& filename) { Load(filename); } void FileReader::Load(const std::string& filename) { // If the file is stored in the file cache then we used that version instead. ConfigFileCache::const_iterator it = ServerInstance->Config->Files.find(filename); if (it != ServerInstance->Config->Files.end()) { this->lines = it->second; } else { const std::string realName = ServerInstance->Config->Paths.PrependConfig(filename); lines.clear(); std::ifstream stream(realName.c_str()); if (!stream.is_open()) throw CoreException(filename + " does not exist or is not readable!"); std::string line; while (std::getline(stream, line)) { lines.push_back(line); totalSize += line.size() + 2; } stream.close(); } } std::string FileReader::GetString() const { std::string buffer; for (file_cache::const_iterator it = this->lines.begin(); it != this->lines.end(); ++it) { buffer.append(*it); buffer.append("\r\n"); } return buffer; } std::string FileSystem::ExpandPath(const std::string& base, const std::string& fragment) { // The fragment is an absolute path, don't modify it. if (fragment[0] == '/' || FileSystem::StartsWithWindowsDriveLetter(fragment)) return fragment; return base + '/' + fragment; } bool FileSystem::FileExists(const std::string& file) { struct stat sb; if (stat(file.c_str(), &sb) == -1) return false; if ((sb.st_mode & S_IFDIR) > 0) return false; return !access(file.c_str(), F_OK); } bool FileSystem::GetFileList(const std::string& directory, std::vector<std::string>& entries, const std::string& match) { #ifdef _WIN32 const std::string search_path = directory + "\\" + match; WIN32_FIND_DATAA wfd; HANDLE fh = FindFirstFileA(search_path.c_str(), &wfd); if (fh == INVALID_HANDLE_VALUE) return false; do { entries.push_back(wfd.cFileName); } while (FindNextFile(fh, &wfd) != 0); FindClose(fh); return true; #else DIR* library = opendir(directory.c_str()); if (!library) return false; dirent* entry = NULL; while ((entry = readdir(library))) { if (InspIRCd::Match(entry->d_name, match, ascii_case_insensitive_map)) entries.push_back(entry->d_name); } closedir(library); return true; #endif } std::string FileSystem::GetFileName(const std::string& name) { #ifdef _WIN32 size_t pos = name.find_last_of("\\/"); #else size_t pos = name.rfind('/'); #endif return pos == std::string::npos ? name : name.substr(++pos); } bool FileSystem::StartsWithWindowsDriveLetter(const std::string& path) { return (path.length() > 2 && isalpha(path[0]) && path[1] == ':'); } ����������������������������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/src/hashcomp.cpp���������������������������������������������������������������������0000664�0000000�0000000�00000026527�13554550454�0016454�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * InspIRCd -- Internet Relay Chat Daemon * * Copyright (C) 2009 Daniel De Graaf <danieldg@inspircd.org> * Copyright (C) 2005-2009 Craig Edwards <craigedwards@brainbox.cc> * Copyright (C) 2007-2008 Robin Burchell <robin+git@viroteck.net> * Copyright (C) 2007 Dennis Friis <peavey@inspircd.org> * * This file is part of InspIRCd. InspIRCd is free software: you can * redistribute it and/or modify it under the terms of the GNU General Public * License as published by the Free Software Foundation, version 2. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include "inspircd.h" /****************************************************** * * The hash functions of InspIRCd are the centrepoint * of the entire system. If these functions are * inefficient or wasteful, the whole program suffers * as a result. A lot of C programmers in the ircd * scene spend a lot of time debating (arguing) about * the best way to write hash functions to hash irc * nicknames, channels etc. * We are lucky as C++ developers as unordered_map does * a lot of this for us. It does intellegent memory * requests, bucketing, search functions, insertion * and deletion etc. All we have to do is write some * overloaded comparison and hash value operators which * cause it to act in an irc-like way. The features we * add to the standard hash_map are: * * Case insensitivity: The hash_map will be case * insensitive. * * Scandanavian Comparisons: The characters [, ], \ will * be considered the lowercase of {, } and |. * ******************************************************/ /** * A case insensitive mapping of characters from upper case to lower case for * the ASCII character set. */ unsigned const char ascii_case_insensitive_map[256] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, // 0-9 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, // 10-19 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, // 20-29 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, // 30-39 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, // 40-49 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, // 50-59 60, 61, 62, 63, 64, 97, 98, 99, 100, 101, // 60-69 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, // 70-79 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, // 80-89 122, 91, 92, 93, 94, 95, 96, 97, 98, 99, // 90-99 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, // 100-109 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, // 110-119 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, // 120-129 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, // 130-139 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, // 140-149 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, // 150-159 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, // 160-169 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, // 170-179 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, // 180-189 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, // 190-199 200, 201, 202, 203, 204, 205, 206, 207, 208, 209, // 200-209 210, 211, 212, 213, 214, 215, 216, 217, 218, 219, // 210-219 220, 221, 222, 223, 224, 225, 226, 227, 228, 229, // 220-229 230, 231, 232, 233, 234, 235, 236, 237, 238, 239, // 230-249 240, 241, 242, 243, 244, 245, 246, 247, 248, 249, // 240-249 250, 251, 252, 253, 254, 255, // 250-255 }; /** * A case insensitive mapping of characters from upper case to lower case for * the character set of RFC 1459. This is identical to ASCII with the small * exception of {}| being considered to be the lower case equivalents of the * characters []\ respectively. */ unsigned const char rfc_case_insensitive_map[256] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, // 0-9 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, // 10-19 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, // 20-29 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, // 30-39 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, // 40-49 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, // 50-59 60, 61, 62, 63, 64, 97, 98, 99, 100, 101, // 60-69 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, // 70-79 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, // 80-89 122, 123, 124, 125, 94, 95, 96, 97, 98, 99, // 90-99 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, // 100-109 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, // 110-119 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, // 120-129 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, // 130-139 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, // 140-149 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, // 150-159 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, // 160-169 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, // 170-179 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, // 180-189 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, // 190-199 200, 201, 202, 203, 204, 205, 206, 207, 208, 209, // 200-209 210, 211, 212, 213, 214, 215, 216, 217, 218, 219, // 210-219 220, 221, 222, 223, 224, 225, 226, 227, 228, 229, // 220-229 230, 231, 232, 233, 234, 235, 236, 237, 238, 239, // 230-239 240, 241, 242, 243, 244, 245, 246, 247, 248, 249, // 240-249 250, 251, 252, 253, 254, 255, // 250-255 }; bool irc::equals(const std::string& s1, const std::string& s2) { const unsigned char* n1 = (const unsigned char*)s1.c_str(); const unsigned char* n2 = (const unsigned char*)s2.c_str(); for (; *n1 && *n2; n1++, n2++) if (national_case_insensitive_map[*n1] != national_case_insensitive_map[*n2]) return false; return (national_case_insensitive_map[*n1] == national_case_insensitive_map[*n2]); } size_t irc::find(const std::string& haystack, const std::string& needle) { // The haystack can't contain the needle if it is smaller than it. if (needle.length() > haystack.length()) return std::string::npos; // The inner loop checks the characters between haystack_last and the end of the haystack. size_t haystack_last = haystack.length() - needle.length(); for (size_t hpos = 0; hpos <= haystack_last; ++hpos) { // Check for the needle at the current haystack position. bool found = true; for (size_t npos = 0; npos < needle.length(); ++npos) { if (national_case_insensitive_map[(unsigned char)needle[npos]] != national_case_insensitive_map[(unsigned char)haystack[hpos + npos]]) { // Uh-oh, characters at the current haystack position don't match. found = false; break; } } // The entire needle was found in the haystack! if (found) return hpos; } // We didn't find anything. return std::string::npos; } bool irc::insensitive_swo::operator()(const std::string& a, const std::string& b) const { const unsigned char* charmap = national_case_insensitive_map; std::string::size_type asize = a.size(); std::string::size_type bsize = b.size(); std::string::size_type maxsize = std::min(asize, bsize); for (std::string::size_type i = 0; i < maxsize; i++) { unsigned char A = charmap[(unsigned char)a[i]]; unsigned char B = charmap[(unsigned char)b[i]]; if (A > B) return false; else if (A < B) return true; } return (asize < bsize); } size_t irc::insensitive::operator()(const std::string &s) const { /* XXX: NO DATA COPIES! :) * The hash function here is practically * a copy of the one in STL's hash_fun.h, * only with *x replaced with national_case_insensitive_map[*x]. * This avoids a copy to use hash<const char*> */ size_t t = 0; for (std::string::const_iterator x = s.begin(); x != s.end(); ++x) /* ++x not x++, as its faster */ t = 5 * t + national_case_insensitive_map[(unsigned char)*x]; return t; } irc::tokenstream::tokenstream(const std::string& msg, size_t start, size_t end) : message(msg, start, end) , position(0) { } bool irc::tokenstream::GetMiddle(std::string& token) { // If we are past the end of the string we can't do anything. if (position >= message.length()) { token.clear(); return false; } // If we can't find another separator this is the last token in the message. size_t separator = message.find(' ', position); if (separator == std::string::npos) { token.assign(message, position, std::string::npos); position = message.length(); return true; } token.assign(message, position, separator - position); position = message.find_first_not_of(' ', separator); return true; } bool irc::tokenstream::GetTrailing(std::string& token) { // If we are past the end of the string we can't do anything. if (position >= message.length()) { token.clear(); return false; } // If this is true then we have a <trailing> token! if (message[position] == ':') { token.assign(message, position + 1, std::string::npos); position = message.length(); return true; } // There is no <trailing> token so it must be a <middle> token. return GetMiddle(token); } irc::sepstream::sepstream(const std::string& source, char separator, bool allowempty) : tokens(source), sep(separator), pos(0), allow_empty(allowempty) { } bool irc::sepstream::GetToken(std::string &token) { if (this->StreamEnd()) { token.clear(); return false; } if (!this->allow_empty) { this->pos = this->tokens.find_first_not_of(this->sep, this->pos); if (this->pos == std::string::npos) { this->pos = this->tokens.length() + 1; token.clear(); return false; } } size_t p = this->tokens.find(this->sep, this->pos); if (p == std::string::npos) p = this->tokens.length(); token.assign(tokens, this->pos, p - this->pos); this->pos = p + 1; return true; } const std::string irc::sepstream::GetRemaining() { return !this->StreamEnd() ? this->tokens.substr(this->pos) : ""; } bool irc::sepstream::StreamEnd() { return this->pos > this->tokens.length(); } bool irc::sepstream::Contains(const std::string& value) { std::string token; while (GetToken(token)) if (value == token) return true; return false; } irc::portparser::portparser(const std::string &source, bool allow_overlapped) : sep(source), in_range(0), range_begin(0), range_end(0), overlapped(allow_overlapped) { } bool irc::portparser::Overlaps(long val) { if (overlapped) return false; return (!overlap_set.insert(val).second); } long irc::portparser::GetToken() { if (in_range > 0) { in_range++; if (in_range <= range_end) { if (!Overlaps(in_range)) { return in_range; } else { while (((Overlaps(in_range)) && (in_range <= range_end))) in_range++; if (in_range <= range_end) return in_range; } } else in_range = 0; } std::string x; sep.GetToken(x); if (x.empty()) return 0; while (Overlaps(ConvToNum<long>(x))) { if (!sep.GetToken(x)) return 0; } std::string::size_type dash = x.rfind('-'); if (dash != std::string::npos) { std::string sbegin(x, 0, dash); range_begin = ConvToNum<long>(sbegin); range_end = ConvToNum<long>(x.c_str() + dash + 1); if ((range_begin > 0) && (range_end > 0) && (range_begin < 65536) && (range_end < 65536) && (range_begin < range_end)) { in_range = range_begin; return in_range; } else { /* Assume its just the one port */ return ConvToNum<long>(sbegin); } } else { return ConvToNum<long>(x); } } �������������������������������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/src/helperfuncs.cpp������������������������������������������������������������������0000664�0000000�0000000�00000034240�13554550454�0017157�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * InspIRCd -- Internet Relay Chat Daemon * * Copyright (C) 2009-2010 Daniel De Graaf <danieldg@inspircd.org> * Copyright (C) 2006-2008 Robin Burchell <robin+git@viroteck.net> * Copyright (C) 2005-2008 Craig Edwards <craigedwards@brainbox.cc> * Copyright (C) 2008 Thomas Stagner <aquanight@inspircd.org> * Copyright (C) 2006-2007 Oliver Lupton <oliverlupton@gmail.com> * Copyright (C) 2007 Dennis Friis <peavey@inspircd.org> * Copyright (C) 2003-2019 Anope Team <team@anope.org> * * This file is part of InspIRCd. InspIRCd is free software: you can * redistribute it and/or modify it under the terms of the GNU General Public * License as published by the Free Software Foundation, version 2. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #ifdef _WIN32 #define _CRT_RAND_S #include <stdlib.h> #endif #include "inspircd.h" #include "xline.h" #include "exitcodes.h" #include <iostream> /* Find a user record by nickname and return a pointer to it */ User* InspIRCd::FindNick(const std::string &nick) { if (!nick.empty() && isdigit(*nick.begin())) return FindUUID(nick); return FindNickOnly(nick); } User* InspIRCd::FindNickOnly(const std::string &nick) { user_hash::iterator iter = this->Users->clientlist.find(nick); if (iter == this->Users->clientlist.end()) return NULL; return iter->second; } User *InspIRCd::FindUUID(const std::string &uid) { user_hash::iterator finduuid = this->Users->uuidlist.find(uid); if (finduuid == this->Users->uuidlist.end()) return NULL; return finduuid->second; } /* find a channel record by channel name and return a pointer to it */ Channel* InspIRCd::FindChan(const std::string &chan) { chan_hash::iterator iter = chanlist.find(chan); if (iter == chanlist.end()) /* Couldn't find it */ return NULL; return iter->second; } bool InspIRCd::IsValidMask(const std::string &mask) { const char* dest = mask.c_str(); int exclamation = 0; int atsign = 0; for (const char* i = dest; *i; i++) { /* out of range character, bad mask */ if (*i < 32 || *i > 126) { return false; } switch (*i) { case '!': exclamation++; break; case '@': atsign++; break; } } /* valid masks only have 1 ! and @ */ if (exclamation != 1 || atsign != 1) return false; if (mask.length() > ServerInstance->Config->Limits.GetMaxMask()) return false; return true; } void InspIRCd::StripColor(std::string &sentence) { /* refactor this completely due to SQUIT bug since the old code would strip last char and replace with \0 --peavey */ int seq = 0; for (std::string::iterator i = sentence.begin(); i != sentence.end();) { if (*i == 3) seq = 1; else if (seq && (( ((*i >= '0') && (*i <= '9')) || (*i == ',') ) )) { seq++; if ( (seq <= 4) && (*i == ',') ) seq = 1; else if (seq > 3) seq = 0; } else seq = 0; // Strip all control codes too except \001 for CTCP if (seq || ((*i >= 0) && (*i < 32) && (*i != 1))) i = sentence.erase(i); else ++i; } } void InspIRCd::ProcessColors(file_cache& input) { /* * Replace all color codes from the special[] array to actual * color code chars using C++ style escape sequences. You * can append other chars to replace if you like -- Justasic */ static struct special_chars { std::string character; std::string replace; special_chars(const std::string& c, const std::string& r) : character(c) , replace(r) { } } special[] = { special_chars("\\b", "\x02"), // Bold special_chars("\\c", "\x03"), // Color special_chars("\\i", "\x1D"), // Italic special_chars("\\m", "\x11"), // Monospace special_chars("\\r", "\x16"), // Reverse special_chars("\\s", "\x1E"), // Strikethrough special_chars("\\u", "\x1F"), // Underline special_chars("\\x", "\x0F"), // Reset special_chars("", "") }; for(file_cache::iterator it = input.begin(), it_end = input.end(); it != it_end; it++) { std::string ret = *it; for(int i = 0; special[i].character.empty() == false; ++i) { std::string::size_type pos = ret.find(special[i].character); if(pos == std::string::npos) // Couldn't find the character, skip this line continue; if((pos > 0) && (ret[pos-1] == '\\') && (ret[pos] == '\\')) continue; // Skip double slashes. // Replace all our characters in the array while(pos != std::string::npos) { ret = ret.substr(0, pos) + special[i].replace + ret.substr(pos + special[i].character.size()); pos = ret.find(special[i].character, pos + special[i].replace.size()); } } // Replace double slashes with a single slash before we return std::string::size_type pos = ret.find("\\\\"); while(pos != std::string::npos) { ret = ret.substr(0, pos) + "\\" + ret.substr(pos + 2); pos = ret.find("\\\\", pos + 1); } *it = ret; } } /* true for valid channel name, false else */ bool InspIRCd::DefaultIsChannel(const std::string& chname) { if (chname.empty() || chname.length() > ServerInstance->Config->Limits.ChanMax) return false; if (chname[0] != '#') return false; for (std::string::const_iterator i = chname.begin()+1; i != chname.end(); ++i) { switch (*i) { case ' ': case ',': case 7: return false; } } return true; } /* true for valid nickname, false else */ bool InspIRCd::DefaultIsNick(const std::string& n) { if (n.empty() || n.length() > ServerInstance->Config->Limits.NickMax) return false; for (std::string::const_iterator i = n.begin(); i != n.end(); ++i) { if ((*i >= 'A') && (*i <= '}')) { /* "A"-"}" can occur anywhere in a nickname */ continue; } if ((((*i >= '0') && (*i <= '9')) || (*i == '-')) && (i != n.begin())) { /* "0"-"9", "-" can occur anywhere BUT the first char of a nickname */ continue; } /* invalid character! abort */ return false; } return true; } /* return true for good ident, false else */ bool InspIRCd::DefaultIsIdent(const std::string& n) { if (n.empty()) return false; for (std::string::const_iterator i = n.begin(); i != n.end(); ++i) { if ((*i >= 'A') && (*i <= '}')) { continue; } if (((*i >= '0') && (*i <= '9')) || (*i == '-') || (*i == '.')) { continue; } return false; } return true; } bool InspIRCd::IsHost(const std::string& host) { // Hostnames must be non-empty and shorter than the maximum hostname length. if (host.empty() || host.length() > ServerInstance->Config->Limits.MaxHost) return false; unsigned int numdashes = 0; unsigned int numdots = 0; bool seendot = false; const std::string::const_iterator hostend = host.end() - 1; for (std::string::const_iterator iter = host.begin(); iter != host.end(); ++iter) { unsigned char chr = static_cast<unsigned char>(*iter); // If the current character is a label separator. if (chr == '.') { numdots++; // Consecutive separators are not allowed and dashes can not exist at the start or end // of labels and separators must only exist between labels. if (seendot || numdashes || iter == host.begin() || iter == hostend) return false; seendot = true; continue; } // If this point is reached then the character is not a dot. seendot = false; // If the current character is a dash. if (chr == '-') { // Consecutive separators are not allowed and dashes can not exist at the start or end // of labels and separators must only exist between labels. if (seendot || numdashes >= 2 || iter == host.begin() || iter == hostend) return false; numdashes += 1; continue; } // If this point is reached then the character is not a dash. numdashes = 0; // Alphanumeric characters are allowed at any position. if ((chr >= '0' && chr <= '9') || (chr >= 'A' && chr <= 'Z') || (chr >= 'a' && chr <= 'z')) continue; return false; } // Whilst simple hostnames (e.g. localhost) are valid we do not allow the server to use // them to prevent issues with clients that differentiate between short client and server // prefixes by checking whether the nickname contains a dot. return numdots; } bool InspIRCd::IsSID(const std::string &str) { /* Returns true if the string given is exactly 3 characters long, * starts with a digit, and the other two characters are A-Z or digits */ return ((str.length() == 3) && isdigit(str[0]) && ((str[1] >= 'A' && str[1] <= 'Z') || isdigit(str[1])) && ((str[2] >= 'A' && str[2] <= 'Z') || isdigit(str[2]))); } void InspIRCd::CheckRoot() { #ifndef _WIN32 if (geteuid() == 0) { std::cout << "ERROR: You are running an irc server as root! DO NOT DO THIS!" << std::endl << std::endl; this->Logs->Log("STARTUP", LOG_DEFAULT, "Can't start as root"); Exit(EXIT_STATUS_ROOT); } #endif } /** A lookup table of values for multiplier characters used by * InspIRCd::Duration(). In this lookup table, the indexes for * the ascii values 'm' and 'M' have the value '60', the indexes * for the ascii values 'D' and 'd' have a value of '86400', etc. */ static const unsigned int duration_multi[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 86400, 0, 0, 0, 3600, 0, 0, 0, 0, 60, 0, 0, 0, 0, 0, 1, 0, 0, 0, 604800, 0, 31557600, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 86400, 0, 0, 0, 3600, 0, 0, 0, 0, 60, 0, 0, 0, 0, 0, 1, 0, 0, 0, 604800, 0, 31557600, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }; bool InspIRCd::Duration(const std::string& str, unsigned long& duration) { unsigned long total = 0; unsigned long subtotal = 0; /* Iterate each item in the string, looking for number or multiplier */ for (std::string::const_iterator i = str.begin(); i != str.end(); ++i) { /* Found a number, queue it onto the current number */ if ((*i >= '0') && (*i <= '9')) { subtotal = (subtotal * 10) + (*i - '0'); } else { /* Found something thats not a number, find out how much * it multiplies the built up number by, multiply the total * and reset the built up number. */ unsigned int multiplier = duration_multi[static_cast<unsigned char>(*i)]; if (multiplier == 0) return false; total += subtotal * multiplier; /* Next subtotal please */ subtotal = 0; } } /* Any trailing values built up are treated as raw seconds */ duration = total + subtotal; return true; } unsigned long InspIRCd::Duration(const std::string& str) { unsigned long out = 0; InspIRCd::Duration(str, out); return out; } bool InspIRCd::IsValidDuration(const std::string& duration) { for (std::string::const_iterator i = duration.begin(); i != duration.end(); ++i) { unsigned char c = *i; if (((c >= '0') && (c <= '9'))) continue; if (!duration_multi[c]) return false; } return true; } std::string InspIRCd::DurationString(time_t duration) { if (duration == 0) return "0s"; time_t years = duration / 31449600; time_t weeks = (duration / 604800) % 52; time_t days = (duration / 86400) % 7; time_t hours = (duration / 3600) % 24; time_t minutes = (duration / 60) % 60; time_t seconds = duration % 60; std::string ret; if (years) ret = ConvToStr(years) + "y"; if (weeks) ret += ConvToStr(weeks) + "w"; if (days) ret += ConvToStr(days) + "d"; if (hours) ret += ConvToStr(hours) + "h"; if (minutes) ret += ConvToStr(minutes) + "m"; if (seconds) ret += ConvToStr(seconds) + "s"; return ret; } std::string InspIRCd::Format(va_list& vaList, const char* formatString) { static std::vector<char> formatBuffer(1024); while (true) { va_list dst; va_copy(dst, vaList); int vsnret = vsnprintf(&formatBuffer[0], formatBuffer.size(), formatString, dst); va_end(dst); if (vsnret > 0 && static_cast<unsigned>(vsnret) < formatBuffer.size()) { break; } formatBuffer.resize(formatBuffer.size() * 2); } return std::string(&formatBuffer[0]); } std::string InspIRCd::Format(const char* formatString, ...) { std::string ret; VAFORMAT(ret, formatString, formatString); return ret; } std::string InspIRCd::TimeString(time_t curtime, const char* format, bool utc) { #ifdef _WIN32 if (curtime < 0) curtime = 0; #endif struct tm* timeinfo = utc ? gmtime(&curtime) : localtime(&curtime); if (!timeinfo) { curtime = 0; timeinfo = localtime(&curtime); } // If the calculated year exceeds four digits or is less than the year 1000, // the behavior of asctime() is undefined if (timeinfo->tm_year + 1900 > 9999) timeinfo->tm_year = 9999 - 1900; else if (timeinfo->tm_year + 1900 < 1000) timeinfo->tm_year = 0; // This is the default format used by asctime without the terminating new line. if (!format) format = "%a %b %d %Y %H:%M:%S"; char buffer[512]; if (!strftime(buffer, sizeof(buffer), format, timeinfo)) buffer[0] = '\0'; return buffer; } std::string InspIRCd::GenRandomStr(unsigned int length, bool printable) { char* buf = new char[length]; GenRandom(buf, length); std::string rv; rv.resize(length); for(size_t i = 0; i < length; i++) rv[i] = printable ? 0x3F + (buf[i] & 0x3F) : buf[i]; delete[] buf; return rv; } // NOTE: this has a slight bias for lower values if max is not a power of 2. // Don't use it if that matters. unsigned long InspIRCd::GenRandomInt(unsigned long max) { unsigned long rv; GenRandom((char*)&rv, sizeof(rv)); return rv % max; } // This is overridden by a higher-quality algorithm when SSL support is loaded void InspIRCd::DefaultGenRandom(char* output, size_t max) { #if defined HAS_ARC4RANDOM_BUF arc4random_buf(output, max); #else for (unsigned int i = 0; i < max; ++i) # ifdef _WIN32 { unsigned int uTemp; if(rand_s(&uTemp) != 0) output[i] = rand(); else output[i] = uTemp; } # else output[i] = random(); # endif #endif } ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/src/inspircd.cpp���������������������������������������������������������������������0000664�0000000�0000000�00000046761�13554550454�0016467�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * InspIRCd -- Internet Relay Chat Daemon * * Copyright (C) 2012 William Pitcock <nenolod@dereferenced.org> * Copyright (C) 2009-2010 Daniel De Graaf <danieldg@inspircd.org> * Copyright (C) 2003-2008 Craig Edwards <craigedwards@brainbox.cc> * Copyright (C) 2008 Uli Schlachter <psychon@znc.in> * Copyright (C) 2006-2008 Robin Burchell <robin+git@viroteck.net> * Copyright (C) 2006-2007 Oliver Lupton <oliverlupton@gmail.com> * Copyright (C) 2007 Dennis Friis <peavey@inspircd.org> * Copyright (C) 2007 Burlex <???@???> * Copyright (C) 2003 Craig McLure <craig@chatspike.net> * Copyright (C) 2003 randomdan <???@???> * * 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 "inspircd.h" #include <signal.h> #ifndef _WIN32 #include <unistd.h> #include <sys/resource.h> #include <dlfcn.h> #include <getopt.h> #include <pwd.h> // setuid #include <grp.h> // setgid #else WORD g_wOriginalColors; WORD g_wBackgroundColor; HANDLE g_hStdout; #endif #include <fstream> #include <iostream> #include "xline.h" #include "exitcodes.h" InspIRCd* ServerInstance = NULL; /** Seperate from the other casemap tables so that code *can* still exclusively rely on RFC casemapping * if it must. * * This is provided as a pointer so that modules can change it to their custom mapping tables, * e.g. for national character support. */ unsigned const char *national_case_insensitive_map = rfc_case_insensitive_map; /* Moved from exitcodes.h -- due to duplicate symbols -- Burlex * XXX this is a bit ugly. -- w00t */ const char* ExitCodes[] = { "No error", // 0 "DIE command", // 1 "Config file error", // 2 "Logfile error", // 3 "POSIX fork failed", // 4 "Bad commandline parameters", // 5 "Can't write PID file", // 6 "SocketEngine could not initialize", // 7 "Refusing to start up as root", // 8 "Couldn't load module on startup", // 9 "Received SIGTERM" // 10 }; template<typename T> static void DeleteZero(T*&n) { T* t = n; n = NULL; delete t; } void InspIRCd::Cleanup() { // Close all listening sockets for (unsigned int i = 0; i < ports.size(); i++) { ports[i]->cull(); delete ports[i]; } ports.clear(); // Tell modules that we're shutting down. const std::string quitmsg = "Server shutting down"; FOREACH_MOD(OnShutdown, (quitmsg)); // Disconnect all local users const UserManager::LocalList& list = Users.GetLocalUsers(); while (!list.empty()) ServerInstance->Users.QuitUser(list.front(), quitmsg); GlobalCulls.Apply(); Modules->UnloadAll(); /* Delete objects dynamically allocated in constructor (destructor would be more appropriate, but we're likely exiting) */ /* Must be deleted before modes as it decrements modelines */ if (FakeClient) { delete FakeClient->server; FakeClient->cull(); } DeleteZero(this->FakeClient); DeleteZero(this->XLines); DeleteZero(this->Config); SocketEngine::Deinit(); Logs->CloseLogs(); } void InspIRCd::SetSignals() { #ifndef _WIN32 signal(SIGALRM, SIG_IGN); signal(SIGCHLD, SIG_IGN); signal(SIGHUP, InspIRCd::SetSignal); signal(SIGPIPE, SIG_IGN); signal(SIGUSR1, SIG_IGN); signal(SIGUSR2, SIG_IGN); signal(SIGXFSZ, SIG_IGN); #endif signal(SIGTERM, InspIRCd::SetSignal); } // Required for returning the proper value of EXIT_SUCCESS for the parent process static void VoidSignalHandler(int signalreceived) { exit(EXIT_STATUS_NOERROR); } bool InspIRCd::DaemonSeed() { #ifdef _WIN32 std::cout << "InspIRCd Process ID: " << con_green << GetCurrentProcessId() << con_reset << std::endl; return true; #else // Do not use exit() here: It will exit with status SIGTERM which would break e.g. daemon scripts signal(SIGTERM, VoidSignalHandler); int childpid = fork(); if (childpid < 0) return false; else if (childpid > 0) { /* We wait here for the child process to kill us, * so that the shell prompt doesnt come back over * the output. * Sending a kill with a signal of 0 just checks * if the child pid is still around. If theyre not, * they threw an error and we should give up. */ while (kill(childpid, 0) != -1) sleep(1); exit(EXIT_STATUS_NOERROR); } setsid (); std::cout << "InspIRCd Process ID: " << con_green << getpid() << con_reset << std::endl; signal(SIGTERM, InspIRCd::SetSignal); rlimit rl; if (getrlimit(RLIMIT_CORE, &rl) == -1) { this->Logs->Log("STARTUP", LOG_DEFAULT, "Failed to getrlimit()!"); return false; } rl.rlim_cur = rl.rlim_max; if (setrlimit(RLIMIT_CORE, &rl) == -1) this->Logs->Log("STARTUP", LOG_DEFAULT, "setrlimit() failed, cannot increase coredump size."); return true; #endif } void InspIRCd::WritePID(const std::string& filename, bool exitonfail) { #ifndef _WIN32 if (!ServerInstance->Config->cmdline.writepid) { this->Logs->Log("STARTUP", LOG_DEFAULT, "--nopid specified on command line; PID file not written."); return; } std::string fname = ServerInstance->Config->Paths.PrependData(filename.empty() ? "inspircd.pid" : filename); std::ofstream outfile(fname.c_str()); if (outfile.is_open()) { outfile << getpid(); outfile.close(); } else { if (exitonfail) std::cout << "Failed to write PID-file '" << fname << "', exiting." << std::endl; this->Logs->Log("STARTUP", LOG_DEFAULT, "Failed to write PID-file '%s'%s", fname.c_str(), (exitonfail ? ", exiting." : "")); if (exitonfail) Exit(EXIT_STATUS_PID); } #endif } InspIRCd::InspIRCd(int argc, char** argv) : ConfigFileName(INSPIRCD_CONFIG_PATH "/inspircd.conf"), PI(&DefaultProtocolInterface), /* Functor pointer initialisation. * * THIS MUST MATCH THE ORDER OF DECLARATION OF THE FUNCTORS, e.g. the methods * themselves within the class. */ GenRandom(&DefaultGenRandom), IsChannel(&DefaultIsChannel), IsNick(&DefaultIsNick), IsIdent(&DefaultIsIdent) { ServerInstance = this; FailedPortList pl; // Flag variables passed to getopt_long() later int do_version = 0, do_nofork = 0, do_debug = 0, do_nolog = 0, do_nopid = 0, do_root = 0; // Initialize so that if we exit before proper initialization they're not deleted this->Config = 0; this->XLines = 0; this->ConfigThread = NULL; this->FakeClient = NULL; UpdateTime(); this->startup_time = TIME.tv_sec; SocketEngine::Init(); this->Config = new ServerConfig; dynamic_reference_base::reset_all(); this->XLines = new XLineManager; this->Config->cmdline.argv = argv; this->Config->cmdline.argc = argc; #ifdef _WIN32 srand(TIME.tv_nsec ^ TIME.tv_sec); // Initialize the console values g_hStdout = GetStdHandle(STD_OUTPUT_HANDLE); CONSOLE_SCREEN_BUFFER_INFO bufinf; if(GetConsoleScreenBufferInfo(g_hStdout, &bufinf)) { g_wOriginalColors = bufinf.wAttributes & 0x00FF; g_wBackgroundColor = bufinf.wAttributes & 0x00F0; } else { g_wOriginalColors = FOREGROUND_RED|FOREGROUND_BLUE|FOREGROUND_GREEN; g_wBackgroundColor = 0; } #else srandom(TIME.tv_nsec ^ TIME.tv_sec); #endif { ServiceProvider* provs[] = { &rfcevents.numeric, &rfcevents.join, &rfcevents.part, &rfcevents.kick, &rfcevents.quit, &rfcevents.nick, &rfcevents.mode, &rfcevents.topic, &rfcevents.privmsg, &rfcevents.invite, &rfcevents.ping, &rfcevents.pong, &rfcevents.error }; Modules.AddServices(provs, sizeof(provs)/sizeof(provs[0])); } struct option longopts[] = { { "nofork", no_argument, &do_nofork, 1 }, { "config", required_argument, NULL, 'c' }, { "debug", no_argument, &do_debug, 1 }, { "nolog", no_argument, &do_nolog, 1 }, { "nopid", no_argument, &do_nopid, 1 }, { "runasroot", no_argument, &do_root, 1 }, { "version", no_argument, &do_version, 1 }, { 0, 0, 0, 0 } }; int c; int index; while ((c = getopt_long(argc, argv, ":c:", longopts, &index)) != -1) { switch (c) { case 'c': /* Config filename was set */ ConfigFileName = optarg; #ifdef _WIN32 TCHAR configPath[MAX_PATH + 1]; if (GetFullPathName(optarg, MAX_PATH, configPath, NULL) > 0) ConfigFileName = configPath; #else char configPath[PATH_MAX + 1]; if (realpath(optarg, configPath)) ConfigFileName = configPath; #endif break; case 0: /* getopt_long_only() set an int variable, just keep going */ break; case '?': /* Unknown parameter */ default: /* Fall through to handle other weird values too */ std::cout << "Unknown parameter '" << argv[optind-1] << "'" << std::endl; std::cout << "Usage: " << argv[0] << " [--nofork] [--nolog] [--nopid] [--debug] [--config <config>]" << std::endl << std::string(static_cast<size_t>(8+strlen(argv[0])), ' ') << "[--runasroot] [--version]" << std::endl; Exit(EXIT_STATUS_ARGV); break; } } if (do_version) { std::cout << std::endl << INSPIRCD_VERSION << std::endl; Exit(EXIT_STATUS_NOERROR); } #ifdef _WIN32 // Set up winsock WSADATA wsadata; WSAStartup(MAKEWORD(2,2), &wsadata); #endif /* Set the finished argument values */ Config->cmdline.nofork = (do_nofork != 0); Config->cmdline.forcedebug = (do_debug != 0); Config->cmdline.writelog = !do_nolog; Config->cmdline.writepid = !do_nopid; if (do_debug) { FileWriter* fw = new FileWriter(stdout, 1); FileLogStream* fls = new FileLogStream(LOG_RAWIO, fw); Logs->AddLogTypes("*", fls, true); } if (!FileSystem::FileExists(ConfigFileName)) { #ifdef _WIN32 /* Windows can (and defaults to) hide file extensions, so let's play a bit nice for windows users. */ std::string txtconf = this->ConfigFileName; txtconf.append(".txt"); if (FileSystem::FileExists(txtconf)) { ConfigFileName = txtconf; } else #endif { std::cout << "ERROR: Cannot open config file: " << ConfigFileName << std::endl << "Exiting..." << std::endl; this->Logs->Log("STARTUP", LOG_DEFAULT, "Unable to open config file %s", ConfigFileName.c_str()); Exit(EXIT_STATUS_CONFIG); } } std::cout << con_green << "InspIRCd - Internet Relay Chat Daemon" << con_reset << std::endl; std::cout << "For contributors & authors: " << con_green << "See /INFO Output" << con_reset << std::endl; #ifndef _WIN32 if (!do_root) this->CheckRoot(); else { std::cout << "* WARNING * WARNING * WARNING * WARNING * WARNING *" << std::endl << "YOU ARE RUNNING INSPIRCD AS ROOT. THIS IS UNSUPPORTED" << std::endl << "AND IF YOU ARE HACKED, CRACKED, SPINDLED OR MUTILATED" << std::endl << "OR ANYTHING ELSE UNEXPECTED HAPPENS TO YOU OR YOUR" << std::endl << "SERVER, THEN IT IS YOUR OWN FAULT. IF YOU DID NOT MEAN" << std::endl << "TO START INSPIRCD AS ROOT, HIT CTRL+C NOW AND RESTART" << std::endl << "THE PROGRAM AS A NORMAL USER. YOU HAVE BEEN WARNED!" << std::endl << std::endl << "InspIRCd starting in 20 seconds, ctrl+c to abort..." << std::endl; sleep(20); } #endif this->SetSignals(); if (!Config->cmdline.nofork) { if (!this->DaemonSeed()) { std::cout << "ERROR: could not go into daemon mode. Shutting down." << std::endl; Logs->Log("STARTUP", LOG_DEFAULT, "ERROR: could not go into daemon mode. Shutting down."); Exit(EXIT_STATUS_FORK); } } SocketEngine::RecoverFromFork(); /* During startup we read the configuration now, not in * a seperate thread */ this->Config->Read(); this->Config->Apply(NULL, ""); Logs->OpenFileLogs(); // If we don't have a SID, generate one based on the server name and the server description if (Config->sid.empty()) Config->sid = UIDGenerator::GenerateSID(Config->ServerName, Config->ServerDesc); // Initialize the UID generator with our sid this->UIDGen.init(Config->sid); // Create the server user for this server this->FakeClient = new FakeUser(Config->sid, Config->ServerName, Config->ServerDesc); // This is needed as all new XLines are marked pending until ApplyLines() is called this->XLines->ApplyLines(); int bounditems = BindPorts(pl); std::cout << std::endl; this->Modules->LoadAll(); // Build ISupport as ModuleManager::LoadAll() does not do it this->ISupport.Build(); if (!pl.empty()) { std::cout << std::endl << "WARNING: Not all your client ports could be bound -- " << std::endl << "starting anyway with " << bounditems << " of " << bounditems + (int)pl.size() << " client ports bound." << std::endl << std::endl; std::cout << "The following port(s) failed to bind:" << std::endl << std::endl; int j = 1; for (FailedPortList::iterator i = pl.begin(); i != pl.end(); i++, j++) { std::cout << j << ".\tAddress: " << i->first.str() << " \tReason: " << strerror(i->second) << std::endl; } std::cout << std::endl << "Hint: Try using a public IP instead of blank or *" << std::endl; } std::cout << "InspIRCd is now running as '" << Config->ServerName << "'[" << Config->GetSID() << "] with " << SocketEngine::GetMaxFds() << " max open sockets" << std::endl; #ifndef _WIN32 if (!Config->cmdline.nofork) { if (kill(getppid(), SIGTERM) == -1) { std::cout << "Error killing parent process: " << strerror(errno) << std::endl; Logs->Log("STARTUP", LOG_DEFAULT, "Error killing parent process: %s",strerror(errno)); } } /* Explicitly shut down stdio's stdin/stdout/stderr. * * The previous logic here was to only do this if stdio was connected to a controlling * terminal. However, we must do this always to avoid information leaks and other * problems related to stdio. * * The only exception is if we are in debug mode. * * -- nenolod */ if ((!do_nofork) && (!Config->cmdline.forcedebug)) { int fd = open("/dev/null", O_RDWR); fclose(stdin); fclose(stderr); fclose(stdout); if (dup2(fd, STDIN_FILENO) < 0) Logs->Log("STARTUP", LOG_DEFAULT, "Failed to dup /dev/null to stdin."); if (dup2(fd, STDOUT_FILENO) < 0) Logs->Log("STARTUP", LOG_DEFAULT, "Failed to dup /dev/null to stdout."); if (dup2(fd, STDERR_FILENO) < 0) Logs->Log("STARTUP", LOG_DEFAULT, "Failed to dup /dev/null to stderr."); close(fd); } else { Logs->Log("STARTUP", LOG_DEFAULT, "Keeping pseudo-tty open as we are running in the foreground."); } #else /* Set win32 service as running, if we are running as a service */ SetServiceRunning(); // Handle forking if(!do_nofork) { FreeConsole(); } QueryPerformanceFrequency(&stats.QPFrequency); #endif Logs->Log("STARTUP", LOG_DEFAULT, "Startup complete as '%s'[%s], %lu max open sockets", Config->ServerName.c_str(),Config->GetSID().c_str(), SocketEngine::GetMaxFds()); #ifndef _WIN32 ConfigTag* security = Config->ConfValue("security"); const std::string SetGroup = security->getString("runasgroup"); if (!SetGroup.empty()) { errno = 0; if (setgroups(0, NULL) == -1) { this->Logs->Log("STARTUP", LOG_DEFAULT, "setgroups() failed (wtf?): %s", strerror(errno)); exit(EXIT_STATUS_CONFIG); } struct group* g = getgrnam(SetGroup.c_str()); if (!g) { this->Logs->Log("STARTUP", LOG_DEFAULT, "getgrnam(%s) failed (wrong group?): %s", SetGroup.c_str(), strerror(errno)); exit(EXIT_STATUS_CONFIG); } if (setgid(g->gr_gid) == -1) { this->Logs->Log("STARTUP", LOG_DEFAULT, "setgid(%d) failed (wrong group?): %s", g->gr_gid, strerror(errno)); exit(EXIT_STATUS_CONFIG); } } const std::string SetUser = security->getString("runasuser"); if (!SetUser.empty()) { errno = 0; struct passwd* u = getpwnam(SetUser.c_str()); if (!u) { this->Logs->Log("STARTUP", LOG_DEFAULT, "getpwnam(%s) failed (wrong user?): %s", SetUser.c_str(), strerror(errno)); exit(EXIT_STATUS_CONFIG); } if (setuid(u->pw_uid) == -1) { this->Logs->Log("STARTUP", LOG_DEFAULT, "setuid(%d) failed (wrong user?): %s", u->pw_uid, strerror(errno)); exit(EXIT_STATUS_CONFIG); } } this->WritePID(Config->PID); #endif } void InspIRCd::UpdateTime() { #ifdef _WIN32 SYSTEMTIME st; GetSystemTime(&st); TIME.tv_sec = time(NULL); TIME.tv_nsec = st.wMilliseconds; #else #ifdef HAS_CLOCK_GETTIME clock_gettime(CLOCK_REALTIME, &TIME); #else struct timeval tv; gettimeofday(&tv, NULL); TIME.tv_sec = tv.tv_sec; TIME.tv_nsec = tv.tv_usec * 1000; #endif #endif } void InspIRCd::Run() { UpdateTime(); time_t OLDTIME = TIME.tv_sec; while (true) { #ifndef _WIN32 static rusage ru; #endif /* Check if there is a config thread which has finished executing but has not yet been freed */ if (this->ConfigThread && this->ConfigThread->IsDone()) { /* Rehash has completed */ this->Logs->Log("CONFIG", LOG_DEBUG, "Detected ConfigThread exiting, tidying up..."); this->ConfigThread->Finish(); ConfigThread->join(); delete ConfigThread; ConfigThread = NULL; } UpdateTime(); /* Run background module timers every few seconds * (the docs say modules shouldnt rely on accurate * timing using this event, so we dont have to * time this exactly). */ if (TIME.tv_sec != OLDTIME) { #ifndef _WIN32 getrusage(RUSAGE_SELF, &ru); stats.LastSampled = TIME; stats.LastCPU = ru.ru_utime; #else if(QueryPerformanceCounter(&stats.LastSampled)) { FILETIME CreationTime; FILETIME ExitTime; FILETIME KernelTime; FILETIME UserTime; GetProcessTimes(GetCurrentProcess(), &CreationTime, &ExitTime, &KernelTime, &UserTime); stats.LastCPU.dwHighDateTime = KernelTime.dwHighDateTime + UserTime.dwHighDateTime; stats.LastCPU.dwLowDateTime = KernelTime.dwLowDateTime + UserTime.dwLowDateTime; } #endif if (Config->TimeSkipWarn) { time_t timediff = TIME.tv_sec - OLDTIME; if (timediff > Config->TimeSkipWarn) SNO->WriteToSnoMask('a', "\002Performance warning!\002 Server clock jumped forwards by %lu seconds!", timediff); else if (timediff < -Config->TimeSkipWarn) SNO->WriteToSnoMask('a', "\002Performance warning!\002 Server clock jumped backwards by %lu seconds!", labs(timediff)); } OLDTIME = TIME.tv_sec; if ((TIME.tv_sec % 3600) == 0) { FOREACH_MOD(OnGarbageCollect, ()); // HACK: ELines are not expired properly at the moment but it can't be fixed as // the 2.0 XLine system is a spaghetti nightmare. Instead we skip over expired // ELines in XLineManager::CheckELines() and expire them here instead. XLines->GetAll("E"); } Timers.TickTimers(TIME.tv_sec); Users->DoBackgroundUserStuff(); if ((TIME.tv_sec % 5) == 0) { FOREACH_MOD(OnBackgroundTimer, (TIME.tv_sec)); SNO->FlushSnotices(); } } /* Call the socket engine to wait on the active * file descriptors. The socket engine has everything's * descriptors in its list... dns, modules, users, * servers... so its nice and easy, just one call. * This will cause any read or write events to be * dispatched to their handlers. */ SocketEngine::DispatchTrialWrites(); SocketEngine::DispatchEvents(); /* if any users were quit, take them out */ GlobalCulls.Apply(); AtomicActions.Run(); if (s_signal) { this->SignalHandler(s_signal); s_signal = 0; } } } sig_atomic_t InspIRCd::s_signal = 0; void InspIRCd::SetSignal(int signal) { s_signal = signal; } /* On posix systems, the flow of the program starts right here, with * ENTRYPOINT being a #define that defines main(). On Windows, ENTRYPOINT * defines smain() and the real main() is in the service code under * win32service.cpp. This allows the service control manager to control * the process where we are running as a windows service. */ ENTRYPOINT { new InspIRCd(argc, argv); ServerInstance->Run(); delete ServerInstance; return 0; } ���������������inspircd-3.4.0/src/inspsocket.cpp�������������������������������������������������������������������0000664�0000000�0000000�00000030401�13554550454�0017016�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * InspIRCd -- Internet Relay Chat Daemon * * Copyright (C) 2009 Daniel De Graaf <danieldg@inspircd.org> * Copyright (C) 2007-2009 Robin Burchell <robin+git@viroteck.net> * Copyright (C) 2008 Thomas Stagner <aquanight@inspircd.org> * Copyright (C) 2006-2007 Craig Edwards <craigedwards@brainbox.cc> * Copyright (C) 2007 Dennis Friis <peavey@inspircd.org> * Copyright (C) 2006 Oliver Lupton <oliverlupton@gmail.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 "inspircd.h" #include "iohook.h" static IOHook* GetNextHook(IOHook* hook) { IOHookMiddle* const iohm = IOHookMiddle::ToMiddleHook(hook); if (iohm) return iohm->GetNextHook(); return NULL; } BufferedSocket::BufferedSocket() { Timeout = NULL; state = I_ERROR; } BufferedSocket::BufferedSocket(int newfd) { Timeout = NULL; this->fd = newfd; this->state = I_CONNECTED; if (fd > -1) SocketEngine::AddFd(this, FD_WANT_FAST_READ | FD_WANT_EDGE_WRITE); } void BufferedSocket::DoConnect(const irc::sockets::sockaddrs& dest, const irc::sockets::sockaddrs& bind, unsigned int maxtime) { BufferedSocketError err = BeginConnect(dest, bind, maxtime); if (err != I_ERR_NONE) { state = I_ERROR; SetError(SocketEngine::LastError()); OnError(err); } } BufferedSocketError BufferedSocket::BeginConnect(const irc::sockets::sockaddrs& dest, const irc::sockets::sockaddrs& bind, unsigned int timeout) { if (fd < 0) fd = socket(dest.family(), SOCK_STREAM, 0); if (fd < 0) return I_ERR_SOCKET; if (bind.family() != 0) { if (SocketEngine::Bind(fd, bind) < 0) return I_ERR_BIND; } SocketEngine::NonBlocking(fd); if (SocketEngine::Connect(this, dest) == -1) { if (errno != EINPROGRESS) return I_ERR_CONNECT; } this->state = I_CONNECTING; if (!SocketEngine::AddFd(this, FD_WANT_NO_READ | FD_WANT_SINGLE_WRITE | FD_WRITE_WILL_BLOCK)) return I_ERR_NOMOREFDS; this->Timeout = new SocketTimeout(this->GetFd(), this, timeout); ServerInstance->Timers.AddTimer(this->Timeout); ServerInstance->Logs->Log("SOCKET", LOG_DEBUG, "BufferedSocket::DoConnect success"); return I_ERR_NONE; } void StreamSocket::Close() { if (closing) return; closing = true; if (this->fd > -1) { // final chance, dump as much of the sendq as we can DoWrite(); IOHook* hook = GetIOHook(); DelIOHook(); while (hook) { hook->OnStreamSocketClose(this); IOHook* const nexthook = GetNextHook(hook); delete hook; hook = nexthook; } SocketEngine::Shutdown(this, 2); SocketEngine::Close(this); } } void StreamSocket::Close(bool writeblock) { if (getSendQSize() != 0 && writeblock) closeonempty = true; else Close(); } CullResult StreamSocket::cull() { Close(); return EventHandler::cull(); } bool StreamSocket::GetNextLine(std::string& line, char delim) { std::string::size_type i = recvq.find(delim); if (i == std::string::npos) return false; line.assign(recvq, 0, i); recvq.erase(0, i + 1); return true; } int StreamSocket::HookChainRead(IOHook* hook, std::string& rq) { if (!hook) return ReadToRecvQ(rq); IOHookMiddle* const iohm = IOHookMiddle::ToMiddleHook(hook); if (iohm) { // Call the next hook to put data into the recvq of the current hook const int ret = HookChainRead(iohm->GetNextHook(), iohm->GetRecvQ()); if (ret <= 0) return ret; } return hook->OnStreamSocketRead(this, rq); } void StreamSocket::DoRead() { const std::string::size_type prevrecvqsize = recvq.size(); const int result = HookChainRead(GetIOHook(), recvq); if (result < 0) { SetError("Read Error"); // will not overwrite a better error message return; } if (recvq.size() > prevrecvqsize) OnDataReady(); } int StreamSocket::ReadToRecvQ(std::string& rq) { char* ReadBuffer = ServerInstance->GetReadBuffer(); int n = SocketEngine::Recv(this, ReadBuffer, ServerInstance->Config->NetBufferSize, 0); if (n == ServerInstance->Config->NetBufferSize) { SocketEngine::ChangeEventMask(this, FD_WANT_FAST_READ | FD_ADD_TRIAL_READ); rq.append(ReadBuffer, n); } else if (n > 0) { SocketEngine::ChangeEventMask(this, FD_WANT_FAST_READ); rq.append(ReadBuffer, n); } else if (n == 0) { error = "Connection closed"; SocketEngine::ChangeEventMask(this, FD_WANT_NO_READ | FD_WANT_NO_WRITE); return -1; } else if (SocketEngine::IgnoreError()) { SocketEngine::ChangeEventMask(this, FD_WANT_FAST_READ | FD_READ_WILL_BLOCK); return 0; } else if (errno == EINTR) { SocketEngine::ChangeEventMask(this, FD_WANT_FAST_READ | FD_ADD_TRIAL_READ); return 0; } else { error = SocketEngine::LastError(); SocketEngine::ChangeEventMask(this, FD_WANT_NO_READ | FD_WANT_NO_WRITE); return -1; } return n; } /* Don't try to prepare huge blobs of data to send to a blocked socket */ static const int MYIOV_MAX = IOV_MAX < 128 ? IOV_MAX : 128; void StreamSocket::DoWrite() { if (getSendQSize() == 0) { if (closeonempty) Close(); return; } if (!error.empty() || fd < 0) { ServerInstance->Logs->Log("SOCKET", LOG_DEBUG, "DoWrite on errored or closed socket"); return; } SendQueue* psendq = &sendq; IOHook* hook = GetIOHook(); while (hook) { int rv = hook->OnStreamSocketWrite(this, *psendq); psendq = NULL; // rv == 0 means the socket has blocked. Stop trying to send data. // IOHook has requested unblock notification from the socketengine. if (rv == 0) break; if (rv < 0) { SetError("Write Error"); // will not overwrite a better error message break; } IOHookMiddle* const iohm = IOHookMiddle::ToMiddleHook(hook); hook = NULL; if (iohm) { psendq = &iohm->GetSendQ(); hook = iohm->GetNextHook(); } } if (psendq) FlushSendQ(*psendq); if (getSendQSize() == 0 && closeonempty) Close(); } void StreamSocket::FlushSendQ(SendQueue& sq) { // don't even try if we are known to be blocking if (GetEventMask() & FD_WRITE_WILL_BLOCK) return; // start out optimistic - we won't need to write any more int eventChange = FD_WANT_EDGE_WRITE; while (error.empty() && !sq.empty() && eventChange == FD_WANT_EDGE_WRITE) { // Prepare a writev() call to write all buffers efficiently int bufcount = sq.size(); // cap the number of buffers at MYIOV_MAX if (bufcount > MYIOV_MAX) { bufcount = MYIOV_MAX; } int rv_max = 0; int rv; { SocketEngine::IOVector iovecs[MYIOV_MAX]; size_t j = 0; for (SendQueue::const_iterator i = sq.begin(), end = i+bufcount; i != end; ++i, j++) { const SendQueue::Element& elem = *i; iovecs[j].iov_base = const_cast<char*>(elem.data()); iovecs[j].iov_len = elem.length(); rv_max += iovecs[j].iov_len; } rv = SocketEngine::WriteV(this, iovecs, bufcount); } if (rv == (int)sq.bytes()) { // it's our lucky day, everything got written out. Fast cleanup. // This won't ever happen if the number of buffers got capped. sq.clear(); } else if (rv > 0) { // Partial write. Clean out strings from the sendq if (rv < rv_max) { // it's going to block now eventChange = FD_WANT_FAST_WRITE | FD_WRITE_WILL_BLOCK; } while (rv > 0 && !sq.empty()) { const SendQueue::Element& front = sq.front(); if (front.length() <= (size_t)rv) { // this string got fully written out rv -= front.length(); sq.pop_front(); } else { // stopped in the middle of this string sq.erase_front(rv); rv = 0; } } } else if (rv == 0) { error = "Connection closed"; } else if (SocketEngine::IgnoreError()) { eventChange = FD_WANT_FAST_WRITE | FD_WRITE_WILL_BLOCK; } else if (errno == EINTR) { // restart interrupted syscall errno = 0; } else { error = SocketEngine::LastError(); } } if (!error.empty()) { // error - kill all events SocketEngine::ChangeEventMask(this, FD_WANT_NO_READ | FD_WANT_NO_WRITE); } else { SocketEngine::ChangeEventMask(this, eventChange); } } bool StreamSocket::OnSetEndPoint(const irc::sockets::sockaddrs& local, const irc::sockets::sockaddrs& remote) { return false; } void StreamSocket::WriteData(const std::string &data) { if (fd < 0) { ServerInstance->Logs->Log("SOCKET", LOG_DEBUG, "Attempt to write data to dead socket: %s", data.c_str()); return; } /* Append the data to the back of the queue ready for writing */ sendq.push_back(data); SocketEngine::ChangeEventMask(this, FD_ADD_TRIAL_WRITE); } bool SocketTimeout::Tick(time_t) { ServerInstance->Logs->Log("SOCKET", LOG_DEBUG, "SocketTimeout::Tick"); if (SocketEngine::GetRef(this->sfd) != this->sock) { delete this; return false; } if (this->sock->state == I_CONNECTING) { // for connecting sockets, the timeout can occur // which causes termination of the connection after // the given number of seconds without a successful // connection. this->sock->OnTimeout(); this->sock->OnError(I_ERR_TIMEOUT); this->sock->state = I_ERROR; ServerInstance->GlobalCulls.AddItem(sock); } this->sock->Timeout = NULL; delete this; return false; } void BufferedSocket::OnConnected() { } void BufferedSocket::OnTimeout() { return; } void BufferedSocket::OnEventHandlerWrite() { if (state == I_CONNECTING) { state = I_CONNECTED; this->OnConnected(); if (!GetIOHook()) SocketEngine::ChangeEventMask(this, FD_WANT_FAST_READ | FD_WANT_EDGE_WRITE); } this->StreamSocket::OnEventHandlerWrite(); } BufferedSocket::~BufferedSocket() { this->Close(); // The timer is removed from the TimerManager in Timer::~Timer() delete Timeout; } void StreamSocket::OnEventHandlerError(int errornum) { if (!error.empty()) return; if (errornum == 0) SetError("Connection closed"); else SetError(SocketEngine::GetError(errornum)); BufferedSocketError errcode = I_ERR_OTHER; switch (errornum) { case ETIMEDOUT: errcode = I_ERR_TIMEOUT; break; case ECONNREFUSED: case 0: errcode = I_ERR_CONNECT; break; case EADDRINUSE: errcode = I_ERR_BIND; break; case EPIPE: case EIO: errcode = I_ERR_WRITE; break; } // Log and call OnError() CheckError(errcode); } void StreamSocket::OnEventHandlerRead() { if (!error.empty()) return; try { DoRead(); } catch (CoreException& ex) { ServerInstance->Logs->Log("SOCKET", LOG_DEFAULT, "Caught exception in socket processing on FD %d - '%s'", fd, ex.GetReason().c_str()); SetError(ex.GetReason()); } CheckError(I_ERR_OTHER); } void StreamSocket::OnEventHandlerWrite() { if (!error.empty()) return; DoWrite(); CheckError(I_ERR_OTHER); } void StreamSocket::CheckError(BufferedSocketError errcode) { if (!error.empty()) { ServerInstance->Logs->Log("SOCKET", LOG_DEBUG, "Error on FD %d - '%s'", fd, error.c_str()); OnError(errcode); } } IOHook* StreamSocket::GetModHook(Module* mod) const { for (IOHook* curr = GetIOHook(); curr; curr = GetNextHook(curr)) { if (curr->prov->creator == mod) return curr; } return NULL; } void StreamSocket::AddIOHook(IOHook* newhook) { IOHook* curr = GetIOHook(); if (!curr) { iohook = newhook; return; } IOHookMiddle* lasthook; while (curr) { lasthook = IOHookMiddle::ToMiddleHook(curr); if (!lasthook) return; curr = lasthook->GetNextHook(); } lasthook->SetNextHook(newhook); } size_t StreamSocket::getSendQSize() const { size_t ret = sendq.bytes(); IOHook* curr = GetIOHook(); while (curr) { const IOHookMiddle* const iohm = IOHookMiddle::ToMiddleHook(curr); if (!iohm) break; ret += iohm->GetSendQ().bytes(); curr = iohm->GetNextHook(); } return ret; } void StreamSocket::SwapInternals(StreamSocket& other) { if (type != other.type) return; EventHandler::SwapInternals(other); std::swap(closeonempty, other.closeonempty); std::swap(closing, other.closing); std::swap(error, other.error); std::swap(iohook, other.iohook); std::swap(recvq, other.recvq); std::swap(sendq, other.sendq); } ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/src/inspstring.cpp�������������������������������������������������������������������0000664�0000000�0000000�00000013234�13554550454�0017041�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * InspIRCd -- Internet Relay Chat Daemon * * Copyright (C) 2010 Daniel De Graaf <danieldg@inspircd.org> * Copyright (C) 2007 Dennis Friis <peavey@inspircd.org> * Copyright (C) 2005-2007 Craig Edwards <craigedwards@brainbox.cc> * * This file is part of InspIRCd. InspIRCd is free software: you can * redistribute it and/or modify it under the terms of the GNU General Public * License as published by the Free Software Foundation, version 2. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include "inspircd.h" static const char hextable[] = "0123456789abcdef"; std::string BinToHex(const void* raw, size_t l) { const char* data = static_cast<const char*>(raw); std::string rv; rv.reserve(l * 2); for (size_t i = 0; i < l; i++) { unsigned char c = data[i]; rv.push_back(hextable[c >> 4]); rv.push_back(hextable[c & 0xF]); } return rv; } static const char b64table[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; std::string BinToBase64(const std::string& data_str, const char* table, char pad) { if (!table) table = b64table; uint32_t buffer; uint8_t* data = (uint8_t*)data_str.data(); std::string rv; size_t i = 0; while (i + 2 < data_str.length()) { buffer = (data[i] << 16 | data[i+1] << 8 | data[i+2]); rv.push_back(table[0x3F & (buffer >> 18)]); rv.push_back(table[0x3F & (buffer >> 12)]); rv.push_back(table[0x3F & (buffer >> 6)]); rv.push_back(table[0x3F & (buffer >> 0)]); i += 3; } if (data_str.length() == i) { // no extra characters } else if (data_str.length() == i + 1) { buffer = data[i] << 16; rv.push_back(table[0x3F & (buffer >> 18)]); rv.push_back(table[0x3F & (buffer >> 12)]); if (pad) { rv.push_back(pad); rv.push_back(pad); } } else if (data_str.length() == i + 2) { buffer = (data[i] << 16 | data[i+1] << 8); rv.push_back(table[0x3F & (buffer >> 18)]); rv.push_back(table[0x3F & (buffer >> 12)]); rv.push_back(table[0x3F & (buffer >> 6)]); if (pad) rv.push_back(pad); } return rv; } std::string Base64ToBin(const std::string& data_str, const char* table) { if (!table) table = b64table; int bitcount = 0; uint32_t buffer = 0; const char* data = data_str.c_str(); std::string rv; while (true) { const char* find = strchr(table, *data++); if (!find || find >= table + 64) break; buffer = (buffer << 6) | (find - table); bitcount += 6; if (bitcount >= 8) { bitcount -= 8; rv.push_back((buffer >> bitcount) & 0xFF); } } return rv; } bool InspIRCd::TimingSafeCompare(const std::string& one, const std::string& two) { if (one.length() != two.length()) return false; unsigned int diff = 0; for (std::string::const_iterator i = one.begin(), j = two.begin(); i != one.end(); ++i, ++j) { unsigned char a = static_cast<unsigned char>(*i); unsigned char b = static_cast<unsigned char>(*j); diff |= a ^ b; } return (diff == 0); } void TokenList::AddList(const std::string& tokenlist) { std::string token; irc::spacesepstream tokenstream(tokenlist); while (tokenstream.GetToken(token)) { if (token[0] == '-') Remove(token.substr(1)); else Add(token); } } void TokenList::Add(const std::string& token) { // If the token is empty or contains just whitespace it is invalid. if (token.empty() || token.find_first_not_of(" \t") == std::string::npos) return; // If the token is a wildcard entry then permissive mode has been enabled. if (token == "*") { permissive = true; tokens.clear(); return; } // If we are in permissive mode then remove the token from the token list. // Otherwise, add it to the token list. if (permissive) tokens.erase(token); else tokens.insert(token); } void TokenList::Clear() { permissive = false; tokens.clear(); } bool TokenList::Contains(const std::string& token) const { // If we are in permissive mode and the token is in the list // then we don't have it. if (permissive && tokens.find(token) != tokens.end()) return false; // If we are not in permissive mode and the token is not in // the list then we don't have it. if (!permissive && tokens.find(token) == tokens.end()) return false; // We have the token! return true; } void TokenList::Remove(const std::string& token) { // If the token is empty or contains just whitespace it is invalid. if (token.empty() || token.find_first_not_of(" \t") == std::string::npos) return; // If the token is a wildcard entry then permissive mode has been disabled. if (token == "*") { permissive = false; tokens.clear(); return; } // If we are in permissive mode then add the token to the token list. // Otherwise, remove it from the token list. if (permissive) tokens.insert(token); else tokens.erase(token); } std::string TokenList::ToString() const { std::string buffer(permissive ? "* " : "-* "); buffer.append(stdalgo::string::join(tokens)); return buffer; } bool TokenList::operator==(const TokenList& other) const { // Both sets must be in the same mode to be equal. if (permissive != other.permissive) return false; // Both sets must be the same size to be equal. if (tokens.size() != other.tokens.size()) return false; for (insp::flat_set<std::string>::const_iterator iter = tokens.begin(); iter != tokens.end(); ++iter) { // Both sets must contain the same tokens to be equal. if (other.tokens.find(*iter) == other.tokens.end()) return false; } return true; } ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/src/listensocket.cpp�����������������������������������������������������������������0000664�0000000�0000000�00000016665�13554550454�0017363�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * InspIRCd -- Internet Relay Chat Daemon * * Copyright (C) 2009-2010 Daniel De Graaf <danieldg@inspircd.org> * Copyright (C) 2008 Robin Burchell <robin+git@viroteck.net> * * 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 "inspircd.h" #include "iohook.h" #ifndef _WIN32 #include <netinet/tcp.h> #endif ListenSocket::ListenSocket(ConfigTag* tag, const irc::sockets::sockaddrs& bind_to) : bind_tag(tag) , bind_sa(bind_to) { // Are we creating a UNIX socket? if (bind_to.family() == AF_UNIX) { // Is 'replace' enabled? const bool replace = tag->getBool("replace"); if (replace && irc::sockets::isunix(bind_to.str())) unlink(bind_to.str().c_str()); } fd = socket(bind_to.family(), SOCK_STREAM, 0); if (this->fd == -1) return; #ifdef IPV6_V6ONLY /* This OS supports IPv6 sockets that can also listen for IPv4 * connections. If our address is "*" or empty, enable both v4 and v6 to * allow for simpler configuration on dual-stack hosts. Otherwise, if it * is "::" or an IPv6 address, disable support so that an IPv4 bind will * work on the port (by us or another application). */ if (bind_to.family() == AF_INET6) { std::string addr = tag->getString("address"); /* This must be >= sizeof(DWORD) on Windows */ const int enable = (addr.empty() || addr == "*") ? 0 : 1; /* This must be before bind() */ setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, reinterpret_cast<const char *>(&enable), sizeof(enable)); // errors ignored intentionally } #endif if (tag->getBool("free")) { socklen_t enable = 1; #if defined IP_FREEBIND // Linux 2.4+ setsockopt(fd, SOL_IP, IP_FREEBIND, &enable, sizeof(enable)); #elif defined IP_BINDANY // FreeBSD setsockopt(fd, IPPROTO_IP, IP_BINDANY, &enable, sizeof(enable)); #elif defined SO_BINDANY // NetBSD/OpenBSD setsockopt(fd, SOL_SOCKET, SO_BINDANY, &enable, sizeof(enable)); #else (void)enable; #endif } if (bind_to.family() == AF_UNIX) { const std::string permissionstr = tag->getString("permissions"); unsigned int permissions = strtoul(permissionstr.c_str(), NULL, 8); if (permissions && permissions <= 07777) chmod(bind_to.str().c_str(), permissions); } SocketEngine::SetReuse(fd); int rv = SocketEngine::Bind(this->fd, bind_to); if (rv >= 0) rv = SocketEngine::Listen(this->fd, ServerInstance->Config->MaxConn); // Default defer to on for TLS listeners because in TLS the client always speaks first int timeout = tag->getDuration("defer", (tag->getString("ssl").empty() ? 0 : 3)); if (timeout && !rv) { #if defined TCP_DEFER_ACCEPT setsockopt(fd, IPPROTO_TCP, TCP_DEFER_ACCEPT, &timeout, sizeof(timeout)); #elif defined SO_ACCEPTFILTER struct accept_filter_arg afa; memset(&afa, 0, sizeof(afa)); strcpy(afa.af_name, "dataready"); setsockopt(fd, SOL_SOCKET, SO_ACCEPTFILTER, &afa, sizeof(afa)); #endif } if (rv < 0) { int errstore = errno; SocketEngine::Shutdown(this, 2); SocketEngine::Close(this->GetFd()); this->fd = -1; errno = errstore; } else { SocketEngine::NonBlocking(this->fd); SocketEngine::AddFd(this, FD_WANT_POLL_READ | FD_WANT_NO_WRITE); this->ResetIOHookProvider(); } } ListenSocket::~ListenSocket() { if (this->GetFd() > -1) { ServerInstance->Logs->Log("SOCKET", LOG_DEBUG, "Shut down listener on fd %d", this->fd); SocketEngine::Shutdown(this, 2); if (SocketEngine::Close(this) != 0) ServerInstance->Logs->Log("SOCKET", LOG_DEBUG, "Failed to cancel listener: %s", strerror(errno)); if (bind_sa.family() == AF_UNIX && unlink(bind_sa.un.sun_path)) ServerInstance->Logs->Log("SOCKET", LOG_DEBUG, "Failed to unlink UNIX socket: %s", strerror(errno)); } } void ListenSocket::OnEventHandlerRead() { irc::sockets::sockaddrs client; irc::sockets::sockaddrs server(bind_sa); socklen_t length = sizeof(client); int incomingSockfd = SocketEngine::Accept(this, &client.sa, &length); ServerInstance->Logs->Log("SOCKET", LOG_DEBUG, "Accepting connection on socket %s fd %d", bind_sa.str().c_str(), incomingSockfd); if (incomingSockfd < 0) { ServerInstance->stats.Refused++; return; } socklen_t sz = sizeof(server); if (getsockname(incomingSockfd, &server.sa, &sz)) { ServerInstance->Logs->Log("SOCKET", LOG_DEBUG, "Can't get peername: %s", strerror(errno)); } if (client.family() == AF_INET6) { /* * This case is the be all and end all patch to catch and nuke 4in6 * instead of special-casing shit all over the place and wreaking merry * havoc with crap, instead, we just recreate sockaddr and strip ::ffff: prefix * if it's a 4in6 IP. * * This is, of course, much improved over the older way of handling this * (pretend it doesn't exist + hack around it -- yes, both were done!) * * Big, big thanks to danieldg for his work on this. * -- w00t */ static const unsigned char prefix4in6[12] = { 0,0,0,0, 0,0,0,0, 0,0,0xFF,0xFF }; if (!memcmp(prefix4in6, &client.in6.sin6_addr, 12)) { // recreate as a sockaddr_in using the IPv4 IP uint16_t sport = client.in6.sin6_port; client.in4.sin_family = AF_INET; client.in4.sin_port = sport; memcpy(&client.in4.sin_addr.s_addr, client.in6.sin6_addr.s6_addr + 12, sizeof(uint32_t)); sport = server.in6.sin6_port; server.in4.sin_family = AF_INET; server.in4.sin_port = sport; memcpy(&server.in4.sin_addr.s_addr, server.in6.sin6_addr.s6_addr + 12, sizeof(uint32_t)); } } else if (client.family() == AF_UNIX) { // Clients connecting via UNIX sockets don't have paths so give them // the server path as defined in RFC 1459 section 8.1.1. // // strcpy is safe here because sizeof(sockaddr_un.sun_path) is equal on both. strcpy(client.un.sun_path, server.un.sun_path); } SocketEngine::NonBlocking(incomingSockfd); ModResult res; FIRST_MOD_RESULT(OnAcceptConnection, res, (incomingSockfd, this, &client, &server)); if (res == MOD_RES_PASSTHRU) { std::string type = bind_tag->getString("type", "clients"); if (stdalgo::string::equalsci(type, "clients")) { ServerInstance->Users->AddUser(incomingSockfd, this, &client, &server); res = MOD_RES_ALLOW; } } if (res == MOD_RES_ALLOW) { ServerInstance->stats.Accept++; } else { ServerInstance->stats.Refused++; ServerInstance->Logs->Log("SOCKET", LOG_DEFAULT, "Refusing connection on %s - %s", bind_sa.str().c_str(), res == MOD_RES_DENY ? "Connection refused by module" : "Module for this port not found"); SocketEngine::Close(incomingSockfd); } } void ListenSocket::ResetIOHookProvider() { iohookprovs[0].SetProvider(bind_tag->getString("hook")); // Check that all non-last hooks support being in the middle for (IOHookProvList::iterator i = iohookprovs.begin(); i != iohookprovs.end()-1; ++i) { IOHookProvRef& curr = *i; // Ignore if cannot be in the middle if ((curr) && (!curr->IsMiddle())) curr.SetProvider(std::string()); } std::string provname = bind_tag->getString("ssl"); if (!provname.empty()) provname.insert(0, "ssl/"); // SSL should be the last iohookprovs.back().SetProvider(provname); } ���������������������������������������������������������������������������inspircd-3.4.0/src/listmode.cpp���������������������������������������������������������������������0000664�0000000�0000000�00000016165�13554550454�0016467�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * InspIRCd -- Internet Relay Chat Daemon * * Copyright (C) 2009 Daniel De Graaf <danieldg@inspircd.org> * * This file is part of InspIRCd. InspIRCd is free software: you can * redistribute it and/or modify it under the terms of the GNU General Public * License as published by the Free Software Foundation, version 2. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include "inspircd.h" #include "listmode.h" ListModeBase::ListModeBase(Module* Creator, const std::string& Name, char modechar, const std::string& eolstr, unsigned int lnum, unsigned int eolnum, bool autotidy) : ModeHandler(Creator, Name, modechar, PARAM_ALWAYS, MODETYPE_CHANNEL, MC_LIST) , listnumeric(lnum) , endoflistnumeric(eolnum) , endofliststring(eolstr) , tidy(autotidy) , extItem(name + "_mode_list", ExtensionItem::EXT_CHANNEL, Creator) { list = true; } void ListModeBase::DisplayList(User* user, Channel* channel) { ChanData* cd = extItem.get(channel); if (cd) { for (ModeList::const_iterator it = cd->list.begin(); it != cd->list.end(); ++it) { user->WriteNumeric(listnumeric, channel->name, it->mask, it->setter, (unsigned long) it->time); } } user->WriteNumeric(endoflistnumeric, channel->name, endofliststring); } void ListModeBase::DisplayEmptyList(User* user, Channel* channel) { user->WriteNumeric(endoflistnumeric, channel->name, endofliststring); } void ListModeBase::RemoveMode(Channel* channel, Modes::ChangeList& changelist) { ChanData* cd = extItem.get(channel); if (cd) { for (ModeList::iterator it = cd->list.begin(); it != cd->list.end(); it++) { changelist.push_remove(this, it->mask); } } } void ListModeBase::DoRehash() { ConfigTagList tags = ServerInstance->Config->ConfTags("maxlist"); limitlist newlimits; bool seen_default = false; for (ConfigIter i = tags.first; i != tags.second; i++) { ConfigTag* c = i->second; const std::string mname = c->getString("mode"); if (!mname.empty() && !stdalgo::string::equalsci(mname, name) && !(mname.length() == 1 && GetModeChar() == mname[0])) continue; ListLimit limit(c->getString("chan", "*", 1), c->getUInt("limit", DEFAULT_LIST_SIZE)); if (limit.mask.empty()) throw ModuleException(InspIRCd::Format("<maxlist:chan> is empty, at %s", c->getTagLocation().c_str())); if (limit.mask == "*" || limit.mask == "#*") seen_default = true; newlimits.push_back(limit); } // If no default limit has been specified then insert one. if (!seen_default) { ServerInstance->Logs->Log("MODE", LOG_DEBUG, "No default <maxlist> entry was found for the %s mode; defaulting to %u", name.c_str(), DEFAULT_LIST_SIZE); newlimits.push_back(ListLimit("*", DEFAULT_LIST_SIZE)); } // Most of the time our settings are unchanged, so we can avoid iterating the chanlist if (chanlimits == newlimits) return; chanlimits.swap(newlimits); const chan_hash& chans = ServerInstance->GetChans(); for (chan_hash::const_iterator i = chans.begin(); i != chans.end(); ++i) { ChanData* cd = extItem.get(i->second); if (cd) cd->maxitems = -1; } } unsigned int ListModeBase::FindLimit(const std::string& channame) { for (limitlist::iterator it = chanlimits.begin(); it != chanlimits.end(); ++it) { if (InspIRCd::Match(channame, it->mask)) { // We have a pattern matching the channel return it->limit; } } return 0; } unsigned int ListModeBase::GetLimitInternal(const std::string& channame, ChanData* cd) { if (cd->maxitems < 0) cd->maxitems = FindLimit(channame); return cd->maxitems; } unsigned int ListModeBase::GetLimit(Channel* channel) { ChanData* cd = extItem.get(channel); if (!cd) // just find the limit return FindLimit(channel->name); return GetLimitInternal(channel->name, cd); } unsigned int ListModeBase::GetLowerLimit() { if (chanlimits.empty()) return DEFAULT_LIST_SIZE; unsigned int limit = UINT_MAX; for (limitlist::iterator iter = chanlimits.begin(); iter != chanlimits.end(); ++iter) { if (iter->limit < limit) limit = iter->limit; } return limit; } ModeAction ListModeBase::OnModeChange(User* source, User*, Channel* channel, std::string &parameter, bool adding) { // Try and grab the list ChanData* cd = extItem.get(channel); if (adding) { if (tidy) ModeParser::CleanMask(parameter); // If there was no list if (!cd) { // Make one cd = new ChanData; extItem.set(channel, cd); } // Check if the item already exists in the list for (ModeList::iterator it = cd->list.begin(); it != cd->list.end(); it++) { if (parameter == it->mask) { /* Give a subclass a chance to error about this */ TellAlreadyOnList(source, channel, parameter); // it does, deny the change return MODEACTION_DENY; } } if ((IS_LOCAL(source)) && (cd->list.size() >= GetLimitInternal(channel->name, cd))) { /* List is full, give subclass a chance to send a custom message */ TellListTooLong(source, channel, parameter); return MODEACTION_DENY; } /* Ok, it *could* be allowed, now give someone subclassing us * a chance to validate the parameter. * The param is passed by reference, so they can both modify it * and tell us if we allow it or not. * * eg, the subclass could: * 1) allow * 2) 'fix' parameter and then allow * 3) deny */ if (ValidateParam(source, channel, parameter)) { // And now add the mask onto the list... cd->list.push_back(ListItem(parameter, source->nick, ServerInstance->Time())); return MODEACTION_ALLOW; } else { /* If they deny it they have the job of giving an error message */ return MODEACTION_DENY; } } else { // We're taking the mode off if (cd) { for (ModeList::iterator it = cd->list.begin(); it != cd->list.end(); ++it) { if (parameter == it->mask) { stdalgo::vector::swaperase(cd->list, it); return MODEACTION_ALLOW; } } } /* Tried to remove something that wasn't set */ TellNotSet(source, channel, parameter); return MODEACTION_DENY; } } bool ListModeBase::ValidateParam(User*, Channel*, std::string&) { return true; } void ListModeBase::OnParameterMissing(User*, User*, Channel*) { // Intentionally left blank. } void ListModeBase::TellListTooLong(User* source, Channel* channel, std::string& parameter) { source->WriteNumeric(ERR_BANLISTFULL, channel->name, parameter, mode, InspIRCd::Format("Channel %s list is full", name.c_str())); } void ListModeBase::TellAlreadyOnList(User* source, Channel* channel, std::string& parameter) { source->WriteNumeric(ERR_LISTMODEALREADYSET, channel->name, parameter, mode, InspIRCd::Format("Channel %s list already contains %s", name.c_str(), parameter.c_str())); } void ListModeBase::TellNotSet(User* source, Channel* channel, std::string& parameter) { source->WriteNumeric(ERR_LISTMODENOTSET, channel->name, parameter, mode, InspIRCd::Format("Channel %s list does not contain %s", name.c_str(), parameter.c_str())); } �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/src/logger.cpp�����������������������������������������������������������������������0000664�0000000�0000000�00000021545�13554550454�0016124�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * InspIRCd -- Internet Relay Chat Daemon * * Copyright (C) 2009 Daniel De Graaf <danieldg@inspircd.org> * Copyright (C) 2008 Craig Edwards <craigedwards@brainbox.cc> * Copyright (C) 2008 Thomas Stagner <aquanight@inspircd.org> * Copyright (C) 2008 Robin Burchell <robin+git@viroteck.net> * * 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 "inspircd.h" /* * Suggested implementation... * class LogManager * bool AddLogType(const std::string &type, enum loglevel, LogStream *) * bool DelLogType(const std::string &type, LogStream *) * Log(const std::string &type, enum loglevel, const std::string &msg) * std::map<std::string, std::vector<LogStream *> > logstreams (holds a 'chain' of logstreams for each type that are all notified when a log happens) * * class LogStream * std::string type * virtual void OnLog(enum loglevel, const std::string &msg) * * How it works: * Modules create their own logstream types (core will create one for 'file logging' for example) and create instances of these logstream types * and register interest in a certain logtype. Globbing is not here, with the exception of * - for all events.. loglevel is used to drop * events that are of no interest to a logstream. * * When Log is called, the vector of logstreams for that type is iterated (along with the special vector for "*"), and all registered logstreams * are called back ("OnLog" or whatever) to do whatever they like with the message. In the case of the core, this will write to a file. * In the case of the module I plan to write (m_logtochannel or something), it will log to the channel(s) for that logstream, etc. * * NOTE: Somehow we have to let LogManager manage the non-blocking file streams and provide an interface to share them with various LogStreams, * as, for example, a user may want to let 'KILL' and 'XLINE' snotices go to /home/ircd/inspircd/logs/operactions.log, or whatever. How * can we accomplish this easily? I guess with a map of pre-loved logpaths, and a pointer of FILE *.. * */ const char LogStream::LogHeader[] = "Log started for " INSPIRCD_VERSION " (" MODULE_INIT_STR ")"; LogManager::LogManager() : Logging(false) { } LogManager::~LogManager() { } void LogManager::OpenFileLogs() { if (ServerInstance->Config->cmdline.forcedebug) { ServerInstance->Config->RawLog = true; return; } /* Skip rest of logfile opening if we are running -nolog. */ if (!ServerInstance->Config->cmdline.writelog) return; std::map<std::string, FileWriter*> logmap; ConfigTagList tags = ServerInstance->Config->ConfTags("log"); for(ConfigIter i = tags.first; i != tags.second; ++i) { ConfigTag* tag = i->second; std::string method = tag->getString("method"); if (!stdalgo::string::equalsci(method, "file")) { continue; } std::string type = tag->getString("type"); std::string level = tag->getString("level"); LogLevel loglevel = LOG_DEFAULT; if (stdalgo::string::equalsci(level, "rawio")) { loglevel = LOG_RAWIO; ServerInstance->Config->RawLog = true; } else if (stdalgo::string::equalsci(level, "debug")) { loglevel = LOG_DEBUG; } else if (stdalgo::string::equalsci(level, "verbose")) { loglevel = LOG_VERBOSE; } else if (stdalgo::string::equalsci(level, "default")) { loglevel = LOG_DEFAULT; } else if (stdalgo::string::equalsci(level, "sparse")) { loglevel = LOG_SPARSE; } else if (stdalgo::string::equalsci(level, "none")) { loglevel = LOG_NONE; } FileWriter* fw; std::string target = ServerInstance->Config->Paths.PrependLog(tag->getString("target")); std::map<std::string, FileWriter*>::iterator fwi = logmap.find(target); if (fwi == logmap.end()) { char realtarget[256]; time_t time = ServerInstance->Time(); struct tm *mytime = gmtime(&time); strftime(realtarget, sizeof(realtarget), target.c_str(), mytime); FILE* f = fopen(realtarget, "a"); fw = new FileWriter(f, tag->getUInt("flush", 20, 1, UINT_MAX)); logmap.insert(std::make_pair(target, fw)); } else { fw = fwi->second; } FileLogStream* fls = new FileLogStream(loglevel, fw); fls->OnLog(LOG_SPARSE, "HEADER", LogStream::LogHeader); AddLogTypes(type, fls, true); } } void LogManager::CloseLogs() { if (ServerInstance->Config && ServerInstance->Config->cmdline.forcedebug) return; LogStreams.clear(); GlobalLogStreams.clear(); for (std::map<LogStream*, int>::iterator i = AllLogStreams.begin(); i != AllLogStreams.end(); ++i) { delete i->first; } AllLogStreams.clear(); } void LogManager::AddLogTypes(const std::string &types, LogStream* l, bool autoclose) { irc::spacesepstream css(types); std::string tok; std::vector<std::string> excludes; while (css.GetToken(tok)) { if (tok.empty()) { continue; } if (tok.at(0) == '-') { /* Exclude! */ excludes.push_back(tok.substr(1)); } else { AddLogType(tok, l, autoclose); } } // Handle doing things like: USERINPUT USEROUTPUT -USERINPUT should be the same as saying just USEROUTPUT. // (This is so modules could, for example, inject exclusions for logtypes they can't handle.) for (std::vector<std::string>::iterator i = excludes.begin(); i != excludes.end(); ++i) { if (*i == "*") { /* -* == Exclude all. Why someone would do this, I dunno. */ DelLogStream(l); return; } DelLogType(*i, l); } // Now if it's registered as a global, add the exclusions there too. std::map<LogStream *, std::vector<std::string> >::iterator gi = GlobalLogStreams.find(l); if (gi != GlobalLogStreams.end()) { gi->second.swap(excludes); // Swap with the vector in the hash. } } bool LogManager::AddLogType(const std::string &type, LogStream *l, bool autoclose) { LogStreams[type].push_back(l); if (type == "*") GlobalLogStreams.insert(std::make_pair(l, std::vector<std::string>())); if (autoclose) AllLogStreams[l]++; return true; } void LogManager::DelLogStream(LogStream* l) { for (std::map<std::string, std::vector<LogStream*> >::iterator i = LogStreams.begin(); i != LogStreams.end(); ++i) { while (stdalgo::erase(i->second, l)) { // Keep erasing while it exists } } GlobalLogStreams.erase(l); std::map<LogStream*, int>::iterator ai = AllLogStreams.begin(); if (ai == AllLogStreams.end()) { return; /* Done. */ } delete ai->first; AllLogStreams.erase(ai); } bool LogManager::DelLogType(const std::string &type, LogStream *l) { std::map<std::string, std::vector<LogStream *> >::iterator i = LogStreams.find(type); if (type == "*") { GlobalLogStreams.erase(l); } if (i != LogStreams.end()) { if (stdalgo::erase(i->second, l)) { if (i->second.size() == 0) { LogStreams.erase(i); } } else { return false; } } else { return false; } std::map<LogStream*, int>::iterator ai = AllLogStreams.find(l); if (ai == AllLogStreams.end()) { return true; } if ((--ai->second) < 1) { AllLogStreams.erase(ai); delete l; } return true; } void LogManager::Log(const std::string &type, LogLevel loglevel, const char *fmt, ...) { if (Logging) return; std::string buf; VAFORMAT(buf, fmt, fmt); this->Log(type, loglevel, buf); } void LogManager::Log(const std::string &type, LogLevel loglevel, const std::string &msg) { if (Logging) { return; } Logging = true; for (std::map<LogStream *, std::vector<std::string> >::iterator gi = GlobalLogStreams.begin(); gi != GlobalLogStreams.end(); ++gi) { if (stdalgo::isin(gi->second, type)) { continue; } gi->first->OnLog(loglevel, type, msg); } std::map<std::string, std::vector<LogStream *> >::iterator i = LogStreams.find(type); if (i != LogStreams.end()) { for (std::vector<LogStream *>::iterator it = i->second.begin(); it != i->second.end(); ++it) { (*it)->OnLog(loglevel, type, msg); } } Logging = false; } FileWriter::FileWriter(FILE* logfile, unsigned int flushcount) : log(logfile) , flush(flushcount) , writeops(0) { } void FileWriter::WriteLogLine(const std::string &line) { if (log == NULL) return; // XXX: For now, just return. Don't throw an exception. It'd be nice to find out if this is happening, but I'm terrified of breaking so close to final release. -- w00t // throw CoreException("FileWriter::WriteLogLine called with a closed logfile"); fputs(line.c_str(), log); if (++writeops % flush == 0) { fflush(log); } } FileWriter::~FileWriter() { if (log) { fflush(log); fclose(log); log = NULL; } } �����������������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/src/mode.cpp�������������������������������������������������������������������������0000664�0000000�0000000�00000062740�13554550454�0015573�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * InspIRCd -- Internet Relay Chat Daemon * * Copyright (C) 2012 Shawn Smith <shawn@inspircd.org> * Copyright (C) 2009-2010 Daniel De Graaf <danieldg@inspircd.org> * Copyright (C) 2007, 2009 Dennis Friis <peavey@inspircd.org> * Copyright (C) 2006-2008 Robin Burchell <robin+git@viroteck.net> * Copyright (C) 2008 Thomas Stagner <aquanight@inspircd.org> * Copyright (C) 2004-2008 Craig Edwards <craigedwards@brainbox.cc> * Copyright (C) 2006 Oliver Lupton <oliverlupton@gmail.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 "inspircd.h" ModeHandler::ModeHandler(Module* Creator, const std::string& Name, char modeletter, ParamSpec Params, ModeType type, Class mclass) : ServiceProvider(Creator, Name, SERVICE_MODE) , modeid(ModeParser::MODEID_MAX) , parameters_taken(Params) , mode(modeletter) , oper(false) , list(false) , m_type(type) , type_id(mclass) , ranktoset(HALFOP_VALUE) , ranktounset(HALFOP_VALUE) { } CullResult ModeHandler::cull() { if (ServerInstance) ServerInstance->Modes->DelMode(this); return classbase::cull(); } ModeHandler::~ModeHandler() { } bool ModeHandler::NeedsParam(bool adding) const { switch (parameters_taken) { case PARAM_ALWAYS: return true; case PARAM_SETONLY: return adding; case PARAM_NONE: break; } return false; } std::string ModeHandler::GetUserParameter(const User* user) const { return ""; } ModResult ModeHandler::AccessCheck(User*, Channel*, std::string &, bool) { return MOD_RES_PASSTHRU; } ModeAction ModeHandler::OnModeChange(User*, User*, Channel*, std::string&, bool) { return MODEACTION_DENY; } void ModeHandler::DisplayList(User*, Channel*) { } void ModeHandler::DisplayEmptyList(User*, Channel*) { } void ModeHandler::OnParameterMissing(User* user, User* dest, Channel* channel) { std::string message = InspIRCd::Format("You must specify a parameter for the %s mode.", name.c_str()); if (!syntax.empty()) message.append(InspIRCd::Format(" Syntax: %s.", syntax.c_str())); if (channel) user->WriteNumeric(Numerics::InvalidModeParameter(channel, this, "*", message)); else user->WriteNumeric(Numerics::InvalidModeParameter(dest, this, "*", message)); } bool ModeHandler::ResolveModeConflict(std::string& theirs, const std::string& ours, Channel*) { return (theirs < ours); } void ModeHandler::RegisterService() { ServerInstance->Modes.AddMode(this); ServerInstance->Modules.AddReferent((GetModeType() == MODETYPE_CHANNEL ? "mode/" : "umode/") + name, this); } ModeAction SimpleUserModeHandler::OnModeChange(User* source, User* dest, Channel* channel, std::string &parameter, bool adding) { /* We're either trying to add a mode we already have or remove a mode we don't have, deny. */ if (dest->IsModeSet(this) == adding) return MODEACTION_DENY; /* adding will be either true or false, depending on if we are adding or removing the mode, since we already checked to make sure we aren't adding a mode we have or that we aren't removing a mode we don't have, we don't have to do any other checks here to see if it's true or false, just add or remove the mode */ dest->SetMode(this, adding); return MODEACTION_ALLOW; } ModeAction SimpleChannelModeHandler::OnModeChange(User* source, User* dest, Channel* channel, std::string &parameter, bool adding) { /* We're either trying to add a mode we already have or remove a mode we don't have, deny. */ if (channel->IsModeSet(this) == adding) return MODEACTION_DENY; /* adding will be either true or false, depending on if we are adding or removing the mode, since we already checked to make sure we aren't adding a mode we have or that we aren't removing a mode we don't have, we don't have to do any other checks here to see if it's true or false, just add or remove the mode */ channel->SetMode(this, adding); return MODEACTION_ALLOW; } ModeWatcher::ModeWatcher(Module* Creator, const std::string& modename, ModeType type) : mode(modename), m_type(type), creator(Creator) { ServerInstance->Modes->AddModeWatcher(this); } ModeWatcher::~ModeWatcher() { ServerInstance->Modes->DelModeWatcher(this); } bool ModeWatcher::BeforeMode(User*, User*, Channel*, std::string&, bool) { return true; } void ModeWatcher::AfterMode(User*, User*, Channel*, const std::string&, bool) { } PrefixMode::PrefixMode(Module* Creator, const std::string& Name, char ModeLetter, unsigned int Rank, char PrefixChar) : ModeHandler(Creator, Name, ModeLetter, PARAM_ALWAYS, MODETYPE_CHANNEL, MC_PREFIX) , prefix(PrefixChar) , prefixrank(Rank) , selfremove(true) { list = true; syntax = "<nick>"; } ModResult PrefixMode::AccessCheck(User* src, Channel*, std::string& value, bool adding) { if (!adding && src->nick == value && selfremove) return MOD_RES_ALLOW; return MOD_RES_PASSTHRU; } ModeAction PrefixMode::OnModeChange(User* source, User*, Channel* chan, std::string& parameter, bool adding) { User* target; if (IS_LOCAL(source)) target = ServerInstance->FindNickOnly(parameter); else target = ServerInstance->FindNick(parameter); if (!target) { source->WriteNumeric(Numerics::NoSuchNick(parameter)); return MODEACTION_DENY; } Membership* memb = chan->GetUser(target); if (!memb) return MODEACTION_DENY; parameter = target->nick; return (memb->SetPrefix(this, adding) ? MODEACTION_ALLOW : MODEACTION_DENY); } void PrefixMode::Update(unsigned int rank, unsigned int setrank, unsigned int unsetrank, bool selfrm) { prefixrank = rank; ranktoset = setrank; ranktounset = unsetrank; selfremove = selfrm; } ModeAction ParamModeBase::OnModeChange(User* source, User*, Channel* chan, std::string& parameter, bool adding) { if (adding) { if (chan->GetModeParameter(this) == parameter) return MODEACTION_DENY; if (OnSet(source, chan, parameter) != MODEACTION_ALLOW) return MODEACTION_DENY; chan->SetMode(this, true); // Handler might have changed the parameter internally parameter.clear(); this->GetParameter(chan, parameter); } else { if (!chan->IsModeSet(this)) return MODEACTION_DENY; this->OnUnsetInternal(source, chan); chan->SetMode(this, false); } return MODEACTION_ALLOW; } ModeAction ModeParser::TryMode(User* user, User* targetuser, Channel* chan, Modes::Change& mcitem, bool SkipACL) { ModeType type = chan ? MODETYPE_CHANNEL : MODETYPE_USER; ModeHandler* mh = mcitem.mh; bool adding = mcitem.adding; const bool needs_param = mh->NeedsParam(adding); std::string& parameter = mcitem.param; // crop mode parameter size to MODE_PARAM_MAX characters if (parameter.length() > MODE_PARAM_MAX && adding) parameter.erase(MODE_PARAM_MAX); ModResult MOD_RESULT; FIRST_MOD_RESULT(OnRawMode, MOD_RESULT, (user, chan, mh, parameter, adding)); if (IS_LOCAL(user) && (MOD_RESULT == MOD_RES_DENY)) return MODEACTION_DENY; const char modechar = mh->GetModeChar(); if (chan && !SkipACL && (MOD_RESULT != MOD_RES_ALLOW)) { MOD_RESULT = mh->AccessCheck(user, chan, parameter, adding); if (MOD_RESULT == MOD_RES_DENY) return MODEACTION_DENY; if (MOD_RESULT == MOD_RES_PASSTHRU) { unsigned int neededrank = mh->GetLevelRequired(adding); /* Compare our rank on the channel against the rank of the required prefix, * allow if >= ours. Because mIRC and xchat throw a tizz if the modes shown * in NAMES(X) are not in rank order, we know the most powerful mode is listed * first, so we don't need to iterate, we just look up the first instead. */ unsigned int ourrank = chan->GetPrefixValue(user); if (ourrank < neededrank) { const PrefixMode* neededmh = NULL; const PrefixModeList& prefixmodes = GetPrefixModes(); for (PrefixModeList::const_iterator i = prefixmodes.begin(); i != prefixmodes.end(); ++i) { const PrefixMode* const privmh = *i; if (privmh->GetPrefixRank() >= neededrank) { // this mode is sufficient to allow this action if (!neededmh || privmh->GetPrefixRank() < neededmh->GetPrefixRank()) neededmh = privmh; } } if (neededmh) user->WriteNumeric(ERR_CHANOPRIVSNEEDED, chan->name, InspIRCd::Format("You must have channel %s access or above to %sset channel mode %c", neededmh->name.c_str(), adding ? "" : "un", modechar)); else user->WriteNumeric(ERR_CHANOPRIVSNEEDED, chan->name, InspIRCd::Format("You cannot %sset channel mode %c", (adding ? "" : "un"), modechar)); return MODEACTION_DENY; } } } // Ask mode watchers whether this mode change is OK std::pair<ModeWatcherMap::iterator, ModeWatcherMap::iterator> itpair = modewatchermap.equal_range(mh->name); for (ModeWatcherMap::iterator i = itpair.first; i != itpair.second; ++i) { ModeWatcher* mw = i->second; if (mw->GetModeType() == type) { if (!mw->BeforeMode(user, targetuser, chan, parameter, adding)) return MODEACTION_DENY; // A module whacked the parameter completely, and there was one. Abort. if ((needs_param) && (parameter.empty())) return MODEACTION_DENY; } } if ((chan || (!chan && adding)) && IS_LOCAL(user) && mh->NeedsOper() && !user->HasModePermission(mh)) { /* It's an oper only mode, and they don't have access to it. */ if (user->IsOper()) { user->WriteNumeric(ERR_NOPRIVILEGES, InspIRCd::Format("Permission Denied - Oper type %s does not have access to %sset %s mode %c", user->oper->name.c_str(), adding ? "" : "un", type == MODETYPE_CHANNEL ? "channel" : "user", modechar)); } else { user->WriteNumeric(ERR_NOPRIVILEGES, InspIRCd::Format("Permission Denied - Only operators may %sset %s mode %c", adding ? "" : "un", type == MODETYPE_CHANNEL ? "channel" : "user", modechar)); } return MODEACTION_DENY; } /* Call the handler for the mode */ ModeAction ma = mh->OnModeChange(user, targetuser, chan, parameter, adding); if ((needs_param) && (parameter.empty())) return MODEACTION_DENY; if (ma != MODEACTION_ALLOW) return ma; itpair = modewatchermap.equal_range(mh->name); for (ModeWatcherMap::iterator i = itpair.first; i != itpair.second; ++i) { ModeWatcher* mw = i->second; if (mw->GetModeType() == type) mw->AfterMode(user, targetuser, chan, parameter, adding); } return MODEACTION_ALLOW; } void ModeParser::ModeParamsToChangeList(User* user, ModeType type, const std::vector<std::string>& parameters, Modes::ChangeList& changelist, unsigned int beginindex, unsigned int endindex) { if (endindex > parameters.size()) endindex = parameters.size(); const std::string& mode_sequence = parameters[beginindex]; bool adding = true; unsigned int param_at = beginindex+1; for (std::string::const_iterator letter = mode_sequence.begin(); letter != mode_sequence.end(); letter++) { unsigned char modechar = *letter; if (modechar == '+' || modechar == '-') { adding = (modechar == '+'); continue; } ModeHandler *mh = this->FindMode(modechar, type); if (!mh) { /* No mode handler? Unknown mode character then. */ user->WriteNumeric(type == MODETYPE_CHANNEL ? ERR_UNKNOWNMODE : ERR_UNKNOWNSNOMASK, modechar, "is an unknown mode character"); continue; } std::string parameter; if ((mh->NeedsParam(adding)) && (param_at < endindex)) parameter = parameters[param_at++]; changelist.push(mh, adding, parameter); } } static bool IsModeParamValid(User* user, Channel* targetchannel, User* targetuser, const Modes::Change& item) { // An empty parameter is never acceptable if (item.param.empty()) { item.mh->OnParameterMissing(user, targetuser, targetchannel); return false; } // The parameter cannot begin with a ':' character or contain a space if ((item.param[0] == ':') || (item.param.find(' ') != std::string::npos)) return false; return true; } // Returns true if we should apply a merged mode, false if we should skip it static bool ShouldApplyMergedMode(Channel* chan, Modes::Change& item) { ModeHandler* mh = item.mh; if ((!chan) || (!chan->IsModeSet(mh)) || (mh->IsListMode())) // Mode not set here or merge is not applicable, apply the incoming mode return true; // Mode handler decides std::string ours = chan->GetModeParameter(mh); return mh->ResolveModeConflict(item.param, ours, chan); } void ModeParser::Process(User* user, Channel* targetchannel, User* targetuser, Modes::ChangeList& changelist, ModeProcessFlag flags) { // Call ProcessSingle until the entire list is processed, but at least once to ensure // LastParse and LastChangeList are cleared unsigned int processed = 0; do { unsigned int n = ProcessSingle(user, targetchannel, targetuser, changelist, flags, processed); processed += n; } while (processed < changelist.size()); } unsigned int ModeParser::ProcessSingle(User* user, Channel* targetchannel, User* targetuser, Modes::ChangeList& changelist, ModeProcessFlag flags, unsigned int beginindex) { LastChangeList.clear(); unsigned int modes_processed = 0; Modes::ChangeList::List& list = changelist.getlist(); for (Modes::ChangeList::List::iterator i = list.begin()+beginindex; i != list.end(); ++i) { modes_processed++; Modes::Change& item = *i; ModeHandler* mh = item.mh; // If a mode change has been given for a mode that does not exist then reject // it. This can happen when core_reloadmodule attempts to restore a mode that // no longer exists. if (!mh) continue; // If the mode is supposed to have a parameter then we first take a look at item.param // and, if we were asked to, also handle mode merges now if (mh->NeedsParam(item.adding)) { // Skip the mode if the parameter does not pass basic validation if (!IsModeParamValid(user, targetchannel, targetuser, item)) continue; // If this is a merge and we won we don't apply this mode if ((flags & MODE_MERGE) && (!ShouldApplyMergedMode(targetchannel, item))) continue; } ModeAction ma = TryMode(user, targetuser, targetchannel, item, (!(flags & MODE_CHECKACCESS))); if (ma != MODEACTION_ALLOW) continue; LastChangeList.push(mh, item.adding, item.param); if (LastChangeList.size() >= ServerInstance->Config->Limits.MaxModes) { /* mode sequence is getting too long */ break; } } if (!LastChangeList.empty()) { ClientProtocol::Events::Mode modeevent(user, targetchannel, targetuser, LastChangeList); if (targetchannel) { targetchannel->Write(modeevent); } else { LocalUser* localtarget = IS_LOCAL(targetuser); if (localtarget) localtarget->Send(modeevent); } FOREACH_MOD(OnMode, (user, targetuser, targetchannel, LastChangeList, flags)); } return modes_processed; } void ModeParser::ShowListModeList(User* user, Channel* chan, ModeHandler* mh) { { ModResult MOD_RESULT; FIRST_MOD_RESULT(OnRawMode, MOD_RESULT, (user, chan, mh, "", true)); if (MOD_RESULT == MOD_RES_DENY) return; bool display = true; // Ask mode watchers whether it's OK to show the list std::pair<ModeWatcherMap::iterator, ModeWatcherMap::iterator> itpair = modewatchermap.equal_range(mh->name); for (ModeWatcherMap::iterator i = itpair.first; i != itpair.second; ++i) { ModeWatcher* mw = i->second; if (mw->GetModeType() == MODETYPE_CHANNEL) { std::string dummyparam; if (!mw->BeforeMode(user, NULL, chan, dummyparam, true)) { // A mode watcher doesn't want us to show the list display = false; break; } } } if (display) mh->DisplayList(user, chan); else mh->DisplayEmptyList(user, chan); } } void ModeParser::CleanMask(std::string &mask) { std::string::size_type pos_of_pling = mask.find_first_of('!'); std::string::size_type pos_of_at = mask.find_first_of('@'); std::string::size_type pos_of_dot = mask.find_first_of('.'); std::string::size_type pos_of_colons = mask.find("::"); /* Because ipv6 addresses are colon delimited -- double so it treats extban as nick */ if (mask.length() >= 2 && mask[1] == ':') return; // if it's an extban, don't even try guess how it needs to be formed. if ((pos_of_pling == std::string::npos) && (pos_of_at == std::string::npos)) { /* Just a nick, or just a host - or clearly ipv6 (starting with :) */ if ((pos_of_dot == std::string::npos) && (pos_of_colons == std::string::npos) && mask[0] != ':') { /* It has no '.' in it, it must be a nick. */ mask.append("!*@*"); } else { /* Got a dot in it? Has to be a host */ mask = "*!*@" + mask; } } else if ((pos_of_pling == std::string::npos) && (pos_of_at != std::string::npos)) { /* Has an @ but no !, its a user@host */ mask = "*!" + mask; } else if ((pos_of_pling != std::string::npos) && (pos_of_at == std::string::npos)) { /* Has a ! but no @, it must be a nick!ident */ mask.append("@*"); } } ModeHandler::Id ModeParser::AllocateModeId(ModeType mt) { for (ModeHandler::Id i = 0; i != MODEID_MAX; ++i) { if (!modehandlersbyid[mt][i]) return i; } throw ModuleException("Out of ModeIds"); } void ModeParser::AddMode(ModeHandler* mh) { if (!ModeParser::IsModeChar(mh->GetModeChar())) throw ModuleException(InspIRCd::Format("Mode letter for %s is invalid: %c", mh->name.c_str(), mh->GetModeChar())); /* A mode prefix of ',' is not acceptable, it would fuck up server to server. * A mode prefix of ':' will fuck up both server to server, and client to server. * A mode prefix of '#' will mess up /whois and /privmsg */ PrefixMode* pm = mh->IsPrefixMode(); if (pm) { if ((pm->GetPrefix() > 126) || (pm->GetPrefix() == ',') || (pm->GetPrefix() == ':') || (pm->GetPrefix() == '#')) throw ModuleException(InspIRCd::Format("Mode prefix for %s is invalid: %c", mh->name.c_str(), pm->GetPrefix())); PrefixMode* otherpm = FindPrefix(pm->GetPrefix()); if (otherpm) throw ModuleException(InspIRCd::Format("Mode prefix for %s already used by %s from %s: %c", mh->name.c_str(), otherpm->name.c_str(), otherpm->creator->ModuleSourceFile.c_str(), pm->GetPrefix())); } ModeHandler*& slot = modehandlers[mh->GetModeType()][mh->GetModeChar()-65]; if (slot) throw ModuleException(InspIRCd::Format("Mode letter for %s already used by %s from %s: %c", mh->name.c_str(), slot->name.c_str(), slot->creator->ModuleSourceFile.c_str(), mh->GetModeChar())); // The mode needs an id if it is either a user mode, a simple mode (flag) or a parameter mode. // Otherwise (for listmodes and prefix modes) the id remains MODEID_MAX, which is invalid. ModeHandler::Id modeid = MODEID_MAX; if ((mh->GetModeType() == MODETYPE_USER) || (mh->IsParameterMode()) || (!mh->IsListMode())) modeid = AllocateModeId(mh->GetModeType()); std::pair<ModeHandlerMap::iterator, bool> res = modehandlersbyname[mh->GetModeType()].insert(std::make_pair(mh->name, mh)); if (!res.second) { ModeHandler* othermh = res.first->second; throw ModuleException(InspIRCd::Format("Mode name %s already used by %c from %s", mh->name.c_str(), othermh->GetModeChar(), othermh->creator->ModuleSourceFile.c_str())); } // Everything is fine, add the mode // If we allocated an id for this mode then save it and put the mode handler into the slot if (modeid != MODEID_MAX) { mh->modeid = modeid; modehandlersbyid[mh->GetModeType()][modeid] = mh; } slot = mh; if (pm) mhlist.prefix.push_back(pm); else if (mh->IsListModeBase()) mhlist.list.push_back(mh->IsListModeBase()); } bool ModeParser::DelMode(ModeHandler* mh) { if (!ModeParser::IsModeChar(mh->GetModeChar())) return false; ModeHandlerMap& mhmap = modehandlersbyname[mh->GetModeType()]; ModeHandlerMap::iterator mhmapit = mhmap.find(mh->name); if ((mhmapit == mhmap.end()) || (mhmapit->second != mh)) return false; ModeHandler*& slot = modehandlers[mh->GetModeType()][mh->GetModeChar()-65]; if (slot != mh) return false; /* Note: We can't stack here, as we have modes potentially being removed across many different channels. * To stack here we have to make the algorithm slower. Discuss. */ switch (mh->GetModeType()) { case MODETYPE_USER: { const user_hash& users = ServerInstance->Users->GetUsers(); for (user_hash::const_iterator i = users.begin(); i != users.end(); ) { User* user = i->second; ++i; mh->RemoveMode(user); } } break; case MODETYPE_CHANNEL: { const chan_hash& chans = ServerInstance->GetChans(); for (chan_hash::const_iterator i = chans.begin(); i != chans.end(); ) { // The channel may not be in the hash after RemoveMode(), see m_permchannels Channel* chan = i->second; ++i; Modes::ChangeList changelist; mh->RemoveMode(chan, changelist); this->Process(ServerInstance->FakeClient, chan, NULL, changelist, MODE_LOCALONLY); } } break; } mhmap.erase(mhmapit); if (mh->GetId() != MODEID_MAX) modehandlersbyid[mh->GetModeType()][mh->GetId()] = NULL; slot = NULL; if (mh->IsPrefixMode()) mhlist.prefix.erase(std::find(mhlist.prefix.begin(), mhlist.prefix.end(), mh->IsPrefixMode())); else if (mh->IsListModeBase()) mhlist.list.erase(std::find(mhlist.list.begin(), mhlist.list.end(), mh->IsListModeBase())); return true; } ModeHandler* ModeParser::FindMode(const std::string& modename, ModeType mt) { ModeHandlerMap& mhmap = modehandlersbyname[mt]; ModeHandlerMap::const_iterator it = mhmap.find(modename); if (it != mhmap.end()) return it->second; return NULL; } ModeHandler* ModeParser::FindMode(unsigned const char modeletter, ModeType mt) { if (!ModeParser::IsModeChar(modeletter)) return NULL; return modehandlers[mt][modeletter-65]; } PrefixMode* ModeParser::FindPrefixMode(unsigned char modeletter) { ModeHandler* mh = FindMode(modeletter, MODETYPE_CHANNEL); if (!mh) return NULL; return mh->IsPrefixMode(); } PrefixMode* ModeParser::FindPrefix(unsigned const char pfxletter) { const PrefixModeList& list = GetPrefixModes(); for (PrefixModeList::const_iterator i = list.begin(); i != list.end(); ++i) { PrefixMode* pm = *i; if (pm->GetPrefix() == pfxletter) return pm; } return NULL; } std::string ModeParser::GiveModeList(ModeType mt) { std::string type1; /* Listmodes EXCEPT those with a prefix */ std::string type2; /* Modes that take a param when adding or removing */ std::string type3; /* Modes that only take a param when adding */ std::string type4; /* Modes that dont take a param */ for (unsigned char mode = 'A'; mode <= 'z'; mode++) { ModeHandler* mh = modehandlers[mt][mode-65]; /* One parameter when adding */ if (mh) { if (mh->NeedsParam(true)) { PrefixMode* pm = mh->IsPrefixMode(); if ((mh->IsListMode()) && ((!pm) || (pm->GetPrefix() == 0))) { type1 += mh->GetModeChar(); } else { /* ... and one parameter when removing */ if (mh->NeedsParam(false)) { /* But not a list mode */ if (!pm) { type2 += mh->GetModeChar(); } } else { /* No parameters when removing */ type3 += mh->GetModeChar(); } } } else { type4 += mh->GetModeChar(); } } } return type1 + "," + type2 + "," + type3 + "," + type4; } struct PrefixModeSorter { bool operator()(PrefixMode* lhs, PrefixMode* rhs) { return lhs->GetPrefixRank() < rhs->GetPrefixRank(); } }; std::string ModeParser::BuildPrefixes(bool lettersAndModes) { std::string mletters; std::string mprefixes; std::vector<PrefixMode*> prefixes; const PrefixModeList& list = GetPrefixModes(); for (PrefixModeList::const_iterator i = list.begin(); i != list.end(); ++i) { PrefixMode* pm = *i; if (pm->GetPrefix()) prefixes.push_back(pm); } std::sort(prefixes.begin(), prefixes.end(), PrefixModeSorter()); for (std::vector<PrefixMode*>::const_reverse_iterator n = prefixes.rbegin(); n != prefixes.rend(); ++n) { mletters += (*n)->GetPrefix(); mprefixes += (*n)->GetModeChar(); } return lettersAndModes ? "(" + mprefixes + ")" + mletters : mletters; } void ModeParser::AddModeWatcher(ModeWatcher* mw) { modewatchermap.insert(std::make_pair(mw->GetModeName(), mw)); } bool ModeParser::DelModeWatcher(ModeWatcher* mw) { std::pair<ModeWatcherMap::iterator, ModeWatcherMap::iterator> itpair = modewatchermap.equal_range(mw->GetModeName()); for (ModeWatcherMap::iterator i = itpair.first; i != itpair.second; ++i) { if (i->second == mw) { modewatchermap.erase(i); return true; } } return false; } void ModeHandler::RemoveMode(User* user) { // Remove the mode if it's set on the user if (user->IsModeSet(this->GetModeChar())) { Modes::ChangeList changelist; changelist.push_remove(this); ServerInstance->Modes->Process(ServerInstance->FakeClient, NULL, user, changelist, ModeParser::MODE_LOCALONLY); } } void ModeHandler::RemoveMode(Channel* channel, Modes::ChangeList& changelist) { if (channel->IsModeSet(this)) { if (this->NeedsParam(false)) // Removing this mode requires a parameter changelist.push_remove(this, channel->GetModeParameter(this)); else changelist.push_remove(this); } } void PrefixMode::RemoveMode(Channel* chan, Modes::ChangeList& changelist) { const Channel::MemberMap& userlist = chan->GetUsers(); for (Channel::MemberMap::const_iterator i = userlist.begin(); i != userlist.end(); ++i) { if (i->second->HasMode(this)) changelist.push_remove(this, i->first->nick); } } bool ModeParser::IsModeChar(char chr) { return ((chr >= 'A' && chr <= 'Z') || (chr >= 'a' && chr <= 'z')); } ModeParser::ModeParser() { /* Clear mode handler list */ memset(modehandlers, 0, sizeof(modehandlers)); memset(modehandlersbyid, 0, sizeof(modehandlersbyid)); } ModeParser::~ModeParser() { } ��������������������������������inspircd-3.4.0/src/modulemanager.cpp����������������������������������������������������������������0000664�0000000�0000000�00000010441�13554550454�0017456�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * InspIRCd -- Internet Relay Chat Daemon * * 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 * 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 "inspircd.h" #include "exitcodes.h" #include <iostream> bool ModuleManager::Load(const std::string& modname, bool defer) { /* Don't allow people to specify paths for modules, it doesn't work as expected */ if (modname.find('/') != std::string::npos) { LastModuleError = "You can't load modules with a path: " + modname; return false; } const std::string filename = ExpandModName(modname); const std::string moduleFile = ServerInstance->Config->Paths.PrependModule(filename); if (!FileSystem::FileExists(moduleFile)) { LastModuleError = "Module file could not be found: " + filename; ServerInstance->Logs->Log("MODULE", LOG_DEFAULT, LastModuleError); return false; } if (Modules.find(filename) != Modules.end()) { LastModuleError = "Module " + filename + " is already loaded, cannot load a module twice!"; ServerInstance->Logs->Log("MODULE", LOG_DEFAULT, LastModuleError); return false; } Module* newmod = NULL; DLLManager* newhandle = new DLLManager(moduleFile.c_str()); ServiceList newservices; if (!defer) this->NewServices = &newservices; try { newmod = newhandle->CallInit(); this->NewServices = NULL; if (newmod) { newmod->ModuleSourceFile = filename; newmod->ModuleDLLManager = newhandle; Modules[filename] = newmod; std::string version = newhandle->GetVersion(); if (version.empty()) version.assign("unknown"); if (defer) { ServerInstance->Logs->Log("MODULE", LOG_DEFAULT, "New module introduced: %s (Module version %s)", filename.c_str(), version.c_str()); } else { ConfigStatus confstatus; AttachAll(newmod); AddServices(newservices); newmod->init(); newmod->ReadConfig(confstatus); Version v = newmod->GetVersion(); ServerInstance->Logs->Log("MODULE", LOG_DEFAULT, "New module introduced: %s (Module version %s)%s", filename.c_str(), version.c_str(), (!(v.Flags & VF_VENDOR) ? " [3rd Party]" : " [Vendor]")); } } else { LastModuleError = "Unable to load " + filename + ": " + newhandle->LastError(); ServerInstance->Logs->Log("MODULE", LOG_DEFAULT, LastModuleError); delete newhandle; return false; } } catch (CoreException& modexcept) { this->NewServices = NULL; // failure in module constructor if (newmod) { DoSafeUnload(newmod); ServerInstance->GlobalCulls.AddItem(newhandle); } else delete newhandle; LastModuleError = "Unable to load " + filename + ": " + modexcept.GetReason(); ServerInstance->Logs->Log("MODULE", LOG_DEFAULT, LastModuleError); return false; } if (defer) return true; FOREACH_MOD(OnLoadModule, (newmod)); PrioritizeHooks(); ServerInstance->ISupport.Build(); return true; } /* We must load the modules AFTER initializing the socket engine, now */ void ModuleManager::LoadCoreModules(std::map<std::string, ServiceList>& servicemap) { std::cout << "Loading core modules " << std::flush; std::vector<std::string> files; if (!FileSystem::GetFileList(ServerInstance->Config->Paths.Module, files, "core_*.so")) { std::cout << "failed!" << std::endl; ServerInstance->Exit(EXIT_STATUS_MODULE); } for (std::vector<std::string>::const_iterator iter = files.begin(); iter != files.end(); ++iter) { std::cout << "." << std::flush; const std::string& name = *iter; this->NewServices = &servicemap[name]; if (!Load(name, true)) { ServerInstance->Logs->Log("MODULE", LOG_DEFAULT, this->LastError()); std::cout << std::endl << "[" << con_red << "*" << con_reset << "] " << this->LastError() << std::endl << std::endl; ServerInstance->Exit(EXIT_STATUS_MODULE); } } std::cout << std::endl; } �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/src/modules.cpp����������������������������������������������������������������������0000664�0000000�0000000�00000061677�13554550454�0016327�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * InspIRCd -- Internet Relay Chat Daemon * * Copyright (C) 2009-2010 Daniel De Graaf <danieldg@inspircd.org> * Copyright (C) 2007, 2009 Dennis Friis <peavey@inspircd.org> * Copyright (C) 2003-2008 Craig Edwards <craigedwards@brainbox.cc> * Copyright (C) 2008 Thomas Stagner <aquanight@inspircd.org> * Copyright (C) 2006-2007 Robin Burchell <robin+git@viroteck.net> * Copyright (C) 2006-2007 Oliver Lupton <oliverlupton@gmail.com> * Copyright (C) 2007 Pippijn van Steenhoven <pip88nl@gmail.com> * Copyright (C) 2003 randomdan <???@???> * * 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 "inspircd.h" #include "exitcodes.h" #include <iostream> static insp::intrusive_list<dynamic_reference_base>* dynrefs = NULL; void dynamic_reference_base::reset_all() { if (!dynrefs) return; for (insp::intrusive_list<dynamic_reference_base>::iterator i = dynrefs->begin(); i != dynrefs->end(); ++i) (*i)->resolve(); } // Version is a simple class for holding a modules version number Version::Version(const std::string &desc, int flags) : description(desc), Flags(flags) { } Version::Version(const std::string &desc, int flags, const std::string& linkdata) : description(desc), Flags(flags), link_data(linkdata) { } // These declarations define the behavours of the base class Module (which does nothing at all) Module::Module() : ModuleDLLManager(NULL) , dying(false) { } CullResult Module::cull() { return classbase::cull(); } Module::~Module() { } void Module::DetachEvent(Implementation i) { ServerInstance->Modules->Detach(i, this); } void Module::ReadConfig(ConfigStatus& status) { } ModResult Module::OnSendSnotice(char &snomask, std::string &type, const std::string &message) { DetachEvent(I_OnSendSnotice); return MOD_RES_PASSTHRU; } void Module::OnUserConnect(LocalUser*) { DetachEvent(I_OnUserConnect); } ModResult Module::OnUserPreQuit(LocalUser*, std::string&, std::string&) { DetachEvent(I_OnUserPreQuit); return MOD_RES_PASSTHRU; } void Module::OnUserQuit(User*, const std::string&, const std::string&) { DetachEvent(I_OnUserQuit); } void Module::OnUserDisconnect(LocalUser*) { DetachEvent(I_OnUserDisconnect); } void Module::OnUserJoin(Membership*, bool, bool, CUList&) { DetachEvent(I_OnUserJoin); } void Module::OnPostJoin(Membership*) { DetachEvent(I_OnPostJoin); } void Module::OnUserPart(Membership*, std::string&, CUList&) { DetachEvent(I_OnUserPart); } void Module::OnPreRehash(User*, const std::string&) { DetachEvent(I_OnPreRehash); } void Module::OnModuleRehash(User*, const std::string&) { DetachEvent(I_OnModuleRehash); } ModResult Module::OnUserPreJoin(LocalUser*, Channel*, const std::string&, std::string&, const std::string&) { DetachEvent(I_OnUserPreJoin); return MOD_RES_PASSTHRU; } void Module::OnMode(User*, User*, Channel*, const Modes::ChangeList&, ModeParser::ModeProcessFlag) { DetachEvent(I_OnMode); } void Module::OnOper(User*, const std::string&) { DetachEvent(I_OnOper); } void Module::OnPostOper(User*, const std::string&, const std::string &) { DetachEvent(I_OnPostOper); } void Module::OnPostDeoper(User*) { DetachEvent(I_OnPostDeoper); } ModResult Module::OnUserPreInvite(User*, User*, Channel*, time_t) { DetachEvent(I_OnUserPreInvite); return MOD_RES_PASSTHRU; } ModResult Module::OnUserPreMessage(User*, const MessageTarget&, MessageDetails&) { DetachEvent(I_OnUserPreMessage); return MOD_RES_PASSTHRU; } ModResult Module::OnUserPreNick(LocalUser*, const std::string&) { DetachEvent(I_OnUserPreNick); return MOD_RES_PASSTHRU; } void Module::OnUserPostNick(User*, const std::string&) { DetachEvent(I_OnUserPostNick); } ModResult Module::OnPreMode(User*, User*, Channel*, Modes::ChangeList&) { DetachEvent(I_OnPreMode); return MOD_RES_PASSTHRU; } void Module::On005Numeric(std::map<std::string, std::string>&) { DetachEvent(I_On005Numeric); } ModResult Module::OnKill(User*, User*, const std::string&) { DetachEvent(I_OnKill); return MOD_RES_PASSTHRU; } void Module::OnLoadModule(Module*) { DetachEvent(I_OnLoadModule); } void Module::OnUnloadModule(Module*) { DetachEvent(I_OnUnloadModule); } void Module::OnBackgroundTimer(time_t) { DetachEvent(I_OnBackgroundTimer); } ModResult Module::OnPreCommand(std::string&, CommandBase::Params&, LocalUser*, bool) { DetachEvent(I_OnPreCommand); return MOD_RES_PASSTHRU; } void Module::OnPostCommand(Command*, const CommandBase::Params&, LocalUser*, CmdResult, bool) { DetachEvent(I_OnPostCommand); } void Module::OnUserInit(LocalUser*) { DetachEvent(I_OnUserInit); } void Module::OnUserPostInit(LocalUser*) { DetachEvent(I_OnUserPostInit); } ModResult Module::OnCheckReady(LocalUser*) { DetachEvent(I_OnCheckReady); return MOD_RES_PASSTHRU; } ModResult Module::OnUserRegister(LocalUser*) { DetachEvent(I_OnUserRegister); return MOD_RES_PASSTHRU; } ModResult Module::OnUserPreKick(User*, Membership*, const std::string&) { DetachEvent(I_OnUserPreKick); return MOD_RES_PASSTHRU; } void Module::OnUserKick(User*, Membership*, const std::string&, CUList&) { DetachEvent(I_OnUserKick); } ModResult Module::OnRawMode(User*, Channel*, ModeHandler*, const std::string&, bool) { DetachEvent(I_OnRawMode); return MOD_RES_PASSTHRU; } ModResult Module::OnCheckInvite(User*, Channel*) { DetachEvent(I_OnCheckInvite); return MOD_RES_PASSTHRU; } ModResult Module::OnCheckKey(User*, Channel*, const std::string&) { DetachEvent(I_OnCheckKey); return MOD_RES_PASSTHRU; } ModResult Module::OnCheckLimit(User*, Channel*) { DetachEvent(I_OnCheckLimit); return MOD_RES_PASSTHRU; } ModResult Module::OnCheckChannelBan(User*, Channel*) { DetachEvent(I_OnCheckChannelBan); return MOD_RES_PASSTHRU; } ModResult Module::OnCheckBan(User*, Channel*, const std::string&) { DetachEvent(I_OnCheckBan); return MOD_RES_PASSTHRU; } ModResult Module::OnExtBanCheck(User*, Channel*, char) { DetachEvent(I_OnExtBanCheck); return MOD_RES_PASSTHRU; } ModResult Module::OnPreChangeHost(LocalUser*, const std::string&) { DetachEvent(I_OnPreChangeHost); return MOD_RES_PASSTHRU; } ModResult Module::OnPreChangeRealName(LocalUser*, const std::string&) { DetachEvent(I_OnPreChangeRealName); return MOD_RES_PASSTHRU; } ModResult Module::OnPreTopicChange(User*, Channel*, const std::string&) { DetachEvent(I_OnPreTopicChange); return MOD_RES_PASSTHRU; } ModResult Module::OnPassCompare(Extensible* ex, const std::string &password, const std::string &input, const std::string& hashtype) { DetachEvent(I_OnPassCompare); return MOD_RES_PASSTHRU; } void Module::OnPostConnect(User*) { DetachEvent(I_OnPostConnect); } void Module::OnUserPostMessage(User*, const MessageTarget&, const MessageDetails&) { DetachEvent(I_OnUserPostMessage); } void Module::OnUserMessageBlocked(User*, const MessageTarget&, const MessageDetails&) { DetachEvent(I_OnUserMessageBlocked); } void Module::OnUserInvite(User*, User*, Channel*, time_t, unsigned int, CUList&) { DetachEvent(I_OnUserInvite); } void Module::OnPostTopicChange(User*, Channel*, const std::string&) { DetachEvent(I_OnPostTopicChange); } void Module::OnDecodeMetaData(Extensible*, const std::string&, const std::string&) { DetachEvent(I_OnDecodeMetaData); } void Module::OnChangeHost(User*, const std::string&) { DetachEvent(I_OnChangeHost); } void Module::OnChangeRealName(User*, const std::string&) { DetachEvent(I_OnChangeRealName); } void Module::OnChangeIdent(User*, const std::string&) { DetachEvent(I_OnChangeIdent); } void Module::OnAddLine(User*, XLine*) { DetachEvent(I_OnAddLine); } void Module::OnDelLine(User*, XLine*) { DetachEvent(I_OnDelLine); } void Module::OnExpireLine(XLine*) { DetachEvent(I_OnExpireLine); } void Module::OnCleanup(ExtensionItem::ExtensibleType, Extensible*) { } ModResult Module::OnChannelPreDelete(Channel*) { DetachEvent(I_OnChannelPreDelete); return MOD_RES_PASSTHRU; } void Module::OnChannelDelete(Channel*) { DetachEvent(I_OnChannelDelete); } void Module::OnBuildNeighborList(User*, IncludeChanList&, std::map<User*,bool>&) { DetachEvent(I_OnBuildNeighborList); } void Module::OnGarbageCollect() { DetachEvent(I_OnGarbageCollect); } ModResult Module::OnSetConnectClass(LocalUser* user, ConnectClass* myclass) { DetachEvent(I_OnSetConnectClass); return MOD_RES_PASSTHRU; } void Module::OnUserMessage(User*, const MessageTarget&, const MessageDetails&) { DetachEvent(I_OnUserMessage); } ModResult Module::OnNumeric(User*, const Numeric::Numeric&) { DetachEvent(I_OnNumeric); return MOD_RES_PASSTHRU; } ModResult Module::OnAcceptConnection(int, ListenSocket*, irc::sockets::sockaddrs*, irc::sockets::sockaddrs*) { DetachEvent(I_OnAcceptConnection); return MOD_RES_PASSTHRU; } void Module::OnSetUserIP(LocalUser*) { DetachEvent(I_OnSetUserIP); } void Module::OnServiceAdd(ServiceProvider&) { DetachEvent(I_OnServiceAdd); } void Module::OnServiceDel(ServiceProvider&) { DetachEvent(I_OnServiceDel); } ModResult Module::OnUserWrite(LocalUser*, ClientProtocol::Message&) { DetachEvent(I_OnUserWrite); return MOD_RES_PASSTHRU; } ModResult Module::OnConnectionFail(LocalUser*, BufferedSocketError) { DetachEvent(I_OnConnectionFail); return MOD_RES_PASSTHRU; } void Module::OnShutdown(const std::string& reason) { DetachEvent(I_OnShutdown); } ServiceProvider::ServiceProvider(Module* Creator, const std::string& Name, ServiceType Type) : creator(Creator), name(Name), service(Type) { if ((ServerInstance) && (ServerInstance->Modules->NewServices)) ServerInstance->Modules->NewServices->push_back(this); } void ServiceProvider::DisableAutoRegister() { if ((ServerInstance) && (ServerInstance->Modules->NewServices)) stdalgo::erase(*ServerInstance->Modules->NewServices, this); } ModuleManager::ModuleManager() { } ModuleManager::~ModuleManager() { } bool ModuleManager::Attach(Implementation i, Module* mod) { if (stdalgo::isin(EventHandlers[i], mod)) return false; EventHandlers[i].push_back(mod); return true; } bool ModuleManager::Detach(Implementation i, Module* mod) { return stdalgo::erase(EventHandlers[i], mod); } void ModuleManager::Attach(Implementation* i, Module* mod, size_t sz) { for (size_t n = 0; n < sz; ++n) Attach(i[n], mod); } void ModuleManager::AttachAll(Module* mod) { for (size_t i = 0; i != I_END; ++i) Attach((Implementation)i, mod); } void ModuleManager::DetachAll(Module* mod) { for (size_t n = 0; n != I_END; ++n) Detach((Implementation)n, mod); } void ModuleManager::SetPriority(Module* mod, Priority s) { for (size_t n = 0; n != I_END; ++n) SetPriority(mod, (Implementation)n, s); } bool ModuleManager::SetPriority(Module* mod, Implementation i, Priority s, Module* which) { /** To change the priority of a module, we first find its position in the vector, * then we find the position of the other modules in the vector that this module * wants to be before/after. We pick off either the first or last of these depending * on which they want, and we make sure our module is *at least* before or after * the first or last of this subset, depending again on the type of priority. */ size_t my_pos = 0; /* Locate our module. This is O(n) but it only occurs on module load so we're * not too bothered about it */ for (size_t x = 0; x != EventHandlers[i].size(); ++x) { if (EventHandlers[i][x] == mod) { my_pos = x; goto found_src; } } /* Eh? this module doesnt exist, probably trying to set priority on an event * theyre not attached to. */ return false; found_src: // The modules registered for a hook are called in reverse order (to allow for easier removal // of list entries while looping), meaning that the Priority given to us has the exact opposite effect // on the list, e.g.: PRIORITY_BEFORE will actually put 'mod' after 'which', etc. size_t swap_pos = my_pos; switch (s) { case PRIORITY_LAST: if (prioritizationState != PRIO_STATE_FIRST) return true; else swap_pos = 0; break; case PRIORITY_FIRST: if (prioritizationState != PRIO_STATE_FIRST) return true; else swap_pos = EventHandlers[i].size() - 1; break; case PRIORITY_BEFORE: { /* Find the latest possible position, only searching AFTER our position */ for (size_t x = EventHandlers[i].size() - 1; x > my_pos; --x) { if (EventHandlers[i][x] == which) { swap_pos = x; goto swap_now; } } // didn't find it - either not loaded or we're already after return true; } /* Place this module before a set of other modules */ case PRIORITY_AFTER: { for (size_t x = 0; x < my_pos; ++x) { if (EventHandlers[i][x] == which) { swap_pos = x; goto swap_now; } } // didn't find it - either not loaded or we're already before return true; } } swap_now: /* Do we need to swap? */ if (swap_pos != my_pos) { // We are going to change positions; we'll need to run again to verify all requirements if (prioritizationState == PRIO_STATE_LAST) prioritizationState = PRIO_STATE_AGAIN; /* Suggestion from Phoenix, "shuffle" the modules to better retain call order */ int incrmnt = 1; if (my_pos > swap_pos) incrmnt = -1; for (unsigned int j = my_pos; j != swap_pos; j += incrmnt) { if ((j + incrmnt > EventHandlers[i].size() - 1) || ((incrmnt == -1) && (j == 0))) continue; std::swap(EventHandlers[i][j], EventHandlers[i][j+incrmnt]); } } return true; } bool ModuleManager::PrioritizeHooks() { /* We give every module a chance to re-prioritize when we introduce a new one, * not just the one thats loading, as the new module could affect the preference * of others */ for (int tries = 0; tries < 20; tries++) { prioritizationState = tries > 0 ? PRIO_STATE_LAST : PRIO_STATE_FIRST; for (std::map<std::string, Module*>::iterator n = Modules.begin(); n != Modules.end(); ++n) n->second->Prioritize(); if (prioritizationState == PRIO_STATE_LAST) break; if (tries == 19) { ServerInstance->Logs->Log("MODULE", LOG_DEFAULT, "Hook priority dependency loop detected"); return false; } } return true; } bool ModuleManager::CanUnload(Module* mod) { std::map<std::string, Module*>::iterator modfind = Modules.find(mod->ModuleSourceFile); if ((modfind == Modules.end()) || (modfind->second != mod) || (mod->dying)) { LastModuleError = "Module " + mod->ModuleSourceFile + " is not loaded, cannot unload it!"; ServerInstance->Logs->Log("MODULE", LOG_DEFAULT, LastModuleError); return false; } mod->dying = true; return true; } void ModuleManager::UnregisterModes(Module* mod, ModeType modetype) { const ModeParser::ModeHandlerMap& modes = ServerInstance->Modes.GetModes(modetype); for (ModeParser::ModeHandlerMap::const_iterator i = modes.begin(); i != modes.end(); ) { ModeHandler* const mh = i->second; ++i; if (mh->creator == mod) this->DelService(*mh); } } void ModuleManager::DoSafeUnload(Module* mod) { // First, notify all modules that a module is about to be unloaded, so in case // they pass execution to the soon to be unloaded module, it will happen now, // i.e. before we unregister the services of the module being unloaded FOREACH_MOD(OnUnloadModule, (mod)); std::map<std::string, Module*>::iterator modfind = Modules.find(mod->ModuleSourceFile); // Unregister modes before extensions because modes may require their extension to show the mode being unset UnregisterModes(mod, MODETYPE_USER); UnregisterModes(mod, MODETYPE_CHANNEL); std::vector<reference<ExtensionItem> > items; ServerInstance->Extensions.BeginUnregister(modfind->second, items); /* Give the module a chance to tidy out all its metadata */ const chan_hash& chans = ServerInstance->GetChans(); for (chan_hash::const_iterator c = chans.begin(); c != chans.end(); ) { Channel* chan = c->second; ++c; mod->OnCleanup(ExtensionItem::EXT_CHANNEL, chan); chan->doUnhookExtensions(items); const Channel::MemberMap& users = chan->GetUsers(); for (Channel::MemberMap::const_iterator mi = users.begin(); mi != users.end(); ++mi) { mod->OnCleanup(ExtensionItem::EXT_MEMBERSHIP, mi->second); mi->second->doUnhookExtensions(items); } } const user_hash& users = ServerInstance->Users->GetUsers(); for (user_hash::const_iterator u = users.begin(); u != users.end(); ) { User* user = u->second; // The module may quit the user (e.g. SSL mod unloading) and that will remove it from the container ++u; mod->OnCleanup(ExtensionItem::EXT_USER, user); user->doUnhookExtensions(items); } for(std::multimap<std::string, ServiceProvider*>::iterator i = DataProviders.begin(); i != DataProviders.end(); ) { std::multimap<std::string, ServiceProvider*>::iterator curr = i++; if (curr->second->creator == mod) DataProviders.erase(curr); } dynamic_reference_base::reset_all(); DetachAll(mod); Modules.erase(modfind); ServerInstance->GlobalCulls.AddItem(mod); ServerInstance->Logs->Log("MODULE", LOG_DEFAULT, "Module %s unloaded",mod->ModuleSourceFile.c_str()); ServerInstance->ISupport.Build(); } void ModuleManager::UnloadAll() { /* We do this more than once, so that any service providers get a * chance to be unhooked by the modules using them, but then get * a chance to be removed themsleves. * * Note: this deliberately does NOT delete the DLLManager objects */ for (int tries = 0; tries < 4; tries++) { std::map<std::string, Module*>::iterator i = Modules.begin(); while (i != Modules.end()) { std::map<std::string, Module*>::iterator me = i++; if (CanUnload(me->second)) { DoSafeUnload(me->second); } } ServerInstance->GlobalCulls.Apply(); } } namespace { struct UnloadAction : public ActionBase { Module* const mod; UnloadAction(Module* m) : mod(m) {} void Call() CXX11_OVERRIDE { DLLManager* dll = mod->ModuleDLLManager; ServerInstance->Modules->DoSafeUnload(mod); ServerInstance->GlobalCulls.Apply(); // In pure static mode this is always NULL delete dll; ServerInstance->GlobalCulls.AddItem(this); } }; } bool ModuleManager::Unload(Module* mod) { if (!CanUnload(mod)) return false; ServerInstance->AtomicActions.AddAction(new UnloadAction(mod)); return true; } void ModuleManager::LoadAll() { std::map<std::string, ServiceList> servicemap; LoadCoreModules(servicemap); // Step 1: load all of the modules. ConfigTagList tags = ServerInstance->Config->ConfTags("module"); for (ConfigIter i = tags.first; i != tags.second; ++i) { ConfigTag* tag = i->second; std::string name = ExpandModName(tag->getString("name")); this->NewServices = &servicemap[name]; // Skip modules which are already loaded. if (Modules.find(name) != Modules.end()) continue; std::cout << "[" << con_green << "*" << con_reset << "] Loading module:\t" << con_green << name << con_reset << std::endl; if (!this->Load(name, true)) { ServerInstance->Logs->Log("MODULE", LOG_DEFAULT, this->LastError()); std::cout << std::endl << "[" << con_red << "*" << con_reset << "] " << this->LastError() << std::endl << std::endl; ServerInstance->Exit(EXIT_STATUS_MODULE); } } // Step 2: initialize the modules and register their services. for (ModuleMap::const_iterator i = Modules.begin(); i != Modules.end(); ++i) { Module* mod = i->second; try { ServerInstance->Logs->Log("MODULE", LOG_DEBUG, "Initializing %s", i->first.c_str()); AttachAll(mod); AddServices(servicemap[i->first]); mod->init(); } catch (CoreException& modexcept) { LastModuleError = "Unable to initialize " + mod->ModuleSourceFile + ": " + modexcept.GetReason(); ServerInstance->Logs->Log("MODULE", LOG_DEFAULT, LastModuleError); std::cout << std::endl << "[" << con_red << "*" << con_reset << "] " << LastModuleError << std::endl << std::endl; ServerInstance->Exit(EXIT_STATUS_MODULE); } } this->NewServices = NULL; ConfigStatus confstatus(NULL, true); // Step 3: Read the configuration for the modules. This must be done as part of // its own step so that services provided by modules can be registered before // the configuration is read. for (ModuleMap::const_iterator i = Modules.begin(); i != Modules.end(); ++i) { Module* mod = i->second; try { ServerInstance->Logs->Log("MODULE", LOG_DEBUG, "Reading configuration for %s", i->first.c_str()); mod->ReadConfig(confstatus); } catch (CoreException& modexcept) { LastModuleError = "Unable to read the configuration for " + mod->ModuleSourceFile + ": " + modexcept.GetReason(); ServerInstance->Logs->Log("MODULE", LOG_DEFAULT, LastModuleError); std::cout << std::endl << "[" << con_red << "*" << con_reset << "] " << LastModuleError << std::endl << std::endl; ServerInstance->Exit(EXIT_STATUS_CONFIG); } } if (!PrioritizeHooks()) ServerInstance->Exit(EXIT_STATUS_MODULE); } std::string& ModuleManager::LastError() { return LastModuleError; } void ModuleManager::AddServices(const ServiceList& list) { for (ServiceList::const_iterator i = list.begin(); i != list.end(); ++i) { ServiceProvider& s = **i; AddService(s); } } void ModuleManager::AddService(ServiceProvider& item) { switch (item.service) { case SERVICE_DATA: case SERVICE_IOHOOK: { if ((!item.name.compare(0, 5, "mode/", 5)) || (!item.name.compare(0, 6, "umode/", 6))) throw ModuleException("The \"mode/\" and the \"umode\" service name prefixes are reserved."); DataProviders.insert(std::make_pair(item.name, &item)); std::string::size_type slash = item.name.find('/'); if (slash != std::string::npos) { DataProviders.insert(std::make_pair(item.name.substr(0, slash), &item)); DataProviders.insert(std::make_pair(item.name.substr(slash + 1), &item)); } dynamic_reference_base::reset_all(); break; } default: item.RegisterService(); } FOREACH_MOD(OnServiceAdd, (item)); } void ModuleManager::DelService(ServiceProvider& item) { switch (item.service) { case SERVICE_MODE: if (!ServerInstance->Modes->DelMode(static_cast<ModeHandler*>(&item))) throw ModuleException("Mode "+std::string(item.name)+" does not exist."); // Fall through case SERVICE_DATA: case SERVICE_IOHOOK: { DelReferent(&item); return; } default: throw ModuleException("Cannot delete unknown service type"); } FOREACH_MOD(OnServiceDel, (item)); } ServiceProvider* ModuleManager::FindService(ServiceType type, const std::string& name) { switch (type) { case SERVICE_DATA: case SERVICE_IOHOOK: { std::multimap<std::string, ServiceProvider*>::iterator i = DataProviders.find(name); if (i != DataProviders.end() && i->second->service == type) return i->second; return NULL; } // TODO implement finding of the other types default: throw ModuleException("Cannot find unknown service type"); } } std::string ModuleManager::ExpandModName(const std::string& modname) { // Transform "callerid" -> "m_callerid.so" unless it already has a ".so" extension, // so coremods in the "core_*.so" form aren't changed std::string ret = modname; if ((modname.length() < 3) || (modname.compare(modname.size() - 3, 3, ".so"))) ret.insert(0, "m_").append(".so"); return ret; } dynamic_reference_base::dynamic_reference_base(Module* Creator, const std::string& Name) : name(Name), hook(NULL), value(NULL), creator(Creator) { if (!dynrefs) dynrefs = new insp::intrusive_list<dynamic_reference_base>; dynrefs->push_front(this); // Resolve unless there is no ModuleManager (part of class InspIRCd) if (ServerInstance) resolve(); } dynamic_reference_base::~dynamic_reference_base() { dynrefs->erase(this); if (dynrefs->empty()) { delete dynrefs; dynrefs = NULL; } } void dynamic_reference_base::SetProvider(const std::string& newname) { name = newname; resolve(); } void dynamic_reference_base::resolve() { // Because find() may return any element with a matching key in case count(key) > 1 use lower_bound() // to ensure a dynref with the same name as another one resolves to the same object std::multimap<std::string, ServiceProvider*>::iterator i = ServerInstance->Modules.DataProviders.lower_bound(name); if ((i != ServerInstance->Modules.DataProviders.end()) && (i->first == this->name)) { ServiceProvider* newvalue = i->second; if (value != newvalue) { value = newvalue; if (hook) hook->OnCapture(); } } else value = NULL; } Module* ModuleManager::Find(const std::string &name) { std::map<std::string, Module*>::const_iterator modfind = Modules.find(ExpandModName(name)); if (modfind == Modules.end()) return NULL; else return modfind->second; } void ModuleManager::AddReferent(const std::string& name, ServiceProvider* service) { DataProviders.insert(std::make_pair(name, service)); dynamic_reference_base::reset_all(); } void ModuleManager::DelReferent(ServiceProvider* service) { for (std::multimap<std::string, ServiceProvider*>::iterator i = DataProviders.begin(); i != DataProviders.end(); ) { ServiceProvider* curr = i->second; if (curr == service) DataProviders.erase(i++); else ++i; } dynamic_reference_base::reset_all(); } �����������������������������������������������������������������inspircd-3.4.0/src/modules/�������������������������������������������������������������������������0000775�0000000�0000000�00000000000�13554550454�0015602�5����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/src/modules/extra/�������������������������������������������������������������������0000775�0000000�0000000�00000000000�13554550454�0016725�5����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/src/modules/extra/README�������������������������������������������������������������0000664�0000000�0000000�00000002006�13554550454�0017603�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������This directory stores modules which require external libraries to compile. For example, m_regex_pcre requires the PCRE libraries. To compile any of these modules first ensure you have the required dependencies (read the online documentation at https://docs.inspircd.org) and then symlink the .cpp file from this directory into the parent directory (src/modules/). Alternatively, use the command: ./configure --enable-extras=m_extra.cpp, which will automatically take care of symlinking the module of that name and any headers it needs from the extras directory. You can also use ./configure --list-extras to see what modules are available, and whether they are enabled or not. You still are responsible for resolving any external dependencies however (ie, PCRE, MySQL, GnuTLS, etc). NOTE: Some modules require you to copy other dependencies too, such as a related header. If you get missing header errors when building these modules, check that the header is not within modules/extra before checking for external dependencies. ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/src/modules/extra/m_geo_maxmind.cpp��������������������������������������������������0000664�0000000�0000000�00000014051�13554550454�0022235�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * InspIRCd -- Internet Relay Chat Daemon * * Copyright (C) 2019 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/>. */ /// $CompilerFlags: find_compiler_flags("libmaxminddb" "") /// $LinkerFlags: find_linker_flags("libmaxminddb" "-lmaxminddb") /// $PackageInfo: require_system("arch") libmaxminddb pkgconf /// $PackageInfo: require_system("darwin") libmaxminddb pkg-config /// $PackageInfo: require_system("debian" "9.0") libmaxminddb-dev pkg-config /// $PackageInfo: require_system("ubuntu" "16.04") libmaxminddb-dev pkg-config #ifdef _WIN32 # pragma comment(lib, "libmaxminddb.lib") #endif #include "inspircd.h" #include "modules/geolocation.h" #include <maxminddb.h> class GeolocationExtItem : public ExtensionItem { public: GeolocationExtItem(Module* parent) : ExtensionItem("geolocation", ExtensionItem::EXT_USER, parent) { } void free(Extensible* container, void* item) CXX11_OVERRIDE { Geolocation::Location* old = static_cast<Geolocation::Location*>(item); if (old) old->refcount_dec(); } Geolocation::Location* get(const Extensible* item) const { return static_cast<Geolocation::Location*>(get_raw(item)); } void set(Extensible* item, Geolocation::Location* value) { value->refcount_inc(); free(item, set_raw(item, value)); } void unset(Extensible* container) { free(container, unset_raw(container)); } }; typedef insp::flat_map<std::string, Geolocation::Location*> LocationMap; class GeolocationAPIImpl : public Geolocation::APIBase { public: GeolocationExtItem ext; LocationMap locations; MMDB_s mmdb; GeolocationAPIImpl(Module* parent) : Geolocation::APIBase(parent) , ext(parent) { } Geolocation::Location* GetLocation(User* user) CXX11_OVERRIDE { // If we have the location cached then use that instead. Geolocation::Location* location = ext.get(user); if (location) return location; // Attempt to locate this user. location = GetLocation(user->client_sa); if (!location) return NULL; // We found the user. Cache their location for future use. ext.set(user, location); return location; } Geolocation::Location* GetLocation(irc::sockets::sockaddrs& sa) CXX11_OVERRIDE { // Skip trying to look up a UNIX socket. if (sa.family() != AF_INET && sa.family() != AF_INET6) return NULL; // Attempt to look up the socket address. int result; MMDB_lookup_result_s lookup = MMDB_lookup_sockaddr(&mmdb, &sa.sa, &result); if (result != MMDB_SUCCESS || !lookup.found_entry) return NULL; // Attempt to retrieve the country code. MMDB_entry_data_s country_code; result = MMDB_get_value(&lookup.entry, &country_code, "country", "iso_code", NULL); if (result != MMDB_SUCCESS || !country_code.has_data || country_code.type != MMDB_DATA_TYPE_UTF8_STRING || country_code.data_size != 2) return NULL; // If the country has been seen before then use our cached Location object. const std::string code(country_code.utf8_string, country_code.data_size); LocationMap::iterator liter = locations.find(code); if (liter != locations.end()) return liter->second; // Attempt to retrieve the country name. MMDB_entry_data_s country_name; result = MMDB_get_value(&lookup.entry, &country_name, "country", "names", "en", NULL); if (result != MMDB_SUCCESS || !country_name.has_data || country_name.type != MMDB_DATA_TYPE_UTF8_STRING) return NULL; // Create a Location object and cache it. const std::string cname(country_name.utf8_string, country_name.data_size); Geolocation::Location* location = new Geolocation::Location(code, cname); locations[code] = location; return location; } }; class ModuleGeoMaxMind : public Module { private: GeolocationAPIImpl geoapi; public: ModuleGeoMaxMind() : geoapi(this) { memset(&geoapi.mmdb, 0, sizeof(geoapi.mmdb)); } ~ModuleGeoMaxMind() { MMDB_close(&geoapi.mmdb); } Version GetVersion() CXX11_OVERRIDE { return Version("Provides Geolocation lookups using the libMaxMindDB library", VF_VENDOR); } void ReadConfig(ConfigStatus& status) CXX11_OVERRIDE { ConfigTag* tag = ServerInstance->Config->ConfValue("maxmind"); const std::string file = ServerInstance->Config->Paths.PrependConfig(tag->getString("file", "GeoLite2-Country.mmdb")); // Try to read the new database. MMDB_s mmdb; int result = MMDB_open(file.c_str(), MMDB_MODE_MMAP, &mmdb); if (result != MMDB_SUCCESS) throw ModuleException(InspIRCd::Format("Unable to load the MaxMind database (%s): %s", file.c_str(), MMDB_strerror(result))); // Swap the new database with the old database. std::swap(mmdb, geoapi.mmdb); // Free the old database. MMDB_close(&mmdb); } void OnGarbageCollect() CXX11_OVERRIDE { for (LocationMap::iterator iter = geoapi.locations.begin(); iter != geoapi.locations.end(); ) { Geolocation::Location* location = iter->second; if (location->GetUseCount()) { ServerInstance->Logs->Log(MODNAME, LOG_DEBUG, "Preserving geolocation data for %s (%s) with use count %u... ", location->GetName().c_str(), location->GetCode().c_str(), location->GetUseCount()); iter++; } else { ServerInstance->Logs->Log(MODNAME, LOG_DEBUG, "Deleting unused geolocation data for %s (%s)", location->GetName().c_str(), location->GetCode().c_str()); delete location; iter = geoapi.locations.erase(iter); } } } void OnSetUserIP(LocalUser* user) CXX11_OVERRIDE { // Unset the extension so that the location of this user is looked // up again next time it is requested. geoapi.ext.unset(user); } }; MODULE_INIT(ModuleGeoMaxMind) ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/src/modules/extra/m_ldap.cpp���������������������������������������������������������0000664�0000000�0000000�00000035656�13554550454�0020704�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * InspIRCd -- Internet Relay Chat Daemon * * Copyright (C) 2013-2015 Adam <Adam@anope.org> * Copyright (C) 2003-2015 Anope Team <team@anope.org> * * This file is part of InspIRCd. InspIRCd is free software: you can * redistribute it and/or modify it under the terms of the GNU General Public * License as published by the Free Software Foundation, version 2. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ /// $LinkerFlags: -llber -lldap_r /// $PackageInfo: require_system("arch") libldap /// $PackageInfo: require_system("centos") openldap-devel /// $PackageInfo: require_system("debian") libldap2-dev /// $PackageInfo: require_system("ubuntu") libldap2-dev #include "inspircd.h" #include "modules/ldap.h" // Ignore OpenLDAP deprecation warnings on OS X Yosemite and newer. #if defined __APPLE__ # pragma GCC diagnostic push # pragma GCC diagnostic ignored "-Wdeprecated-declarations" #endif #include <ldap.h> #ifdef __APPLE__ # pragma GCC diagnostic pop #endif #ifdef _WIN32 # pragma comment(lib, "libldap_r.lib") # pragma comment(lib, "liblber.lib") #endif class LDAPService; class LDAPRequest { public: LDAPService* service; LDAPInterface* inter; LDAPMessage* message; /* message returned by ldap_ */ LDAPResult* result; /* final result */ struct timeval tv; QueryType type; LDAPRequest(LDAPService* s, LDAPInterface* i) : service(s) , inter(i) , message(NULL) , result(NULL) { type = QUERY_UNKNOWN; tv.tv_sec = 0; tv.tv_usec = 100000; } virtual ~LDAPRequest() { delete result; if (message != NULL) ldap_msgfree(message); } virtual int run() = 0; }; class LDAPBind : public LDAPRequest { std::string who, pass; public: LDAPBind(LDAPService* s, LDAPInterface* i, const std::string& w, const std::string& p) : LDAPRequest(s, i) , who(w) , pass(p) { type = QUERY_BIND; } int run() CXX11_OVERRIDE; }; class LDAPSearch : public LDAPRequest { std::string base; int searchscope; std::string filter; public: LDAPSearch(LDAPService* s, LDAPInterface* i, const std::string& b, int se, const std::string& f) : LDAPRequest(s, i) , base(b) , searchscope(se) , filter(f) { type = QUERY_SEARCH; } int run() CXX11_OVERRIDE; }; class LDAPAdd : public LDAPRequest { std::string dn; LDAPMods attributes; public: LDAPAdd(LDAPService* s, LDAPInterface* i, const std::string& d, const LDAPMods& attr) : LDAPRequest(s, i) , dn(d) , attributes(attr) { type = QUERY_ADD; } int run() CXX11_OVERRIDE; }; class LDAPDel : public LDAPRequest { std::string dn; public: LDAPDel(LDAPService* s, LDAPInterface* i, const std::string& d) : LDAPRequest(s, i) , dn(d) { type = QUERY_DELETE; } int run() CXX11_OVERRIDE; }; class LDAPModify : public LDAPRequest { std::string base; LDAPMods attributes; public: LDAPModify(LDAPService* s, LDAPInterface* i, const std::string& b, const LDAPMods& attr) : LDAPRequest(s, i) , base(b) , attributes(attr) { type = QUERY_MODIFY; } int run() CXX11_OVERRIDE; }; class LDAPCompare : public LDAPRequest { std::string dn, attr, val; public: LDAPCompare(LDAPService* s, LDAPInterface* i, const std::string& d, const std::string& a, const std::string& v) : LDAPRequest(s, i) , dn(d) , attr(a) , val(v) { type = QUERY_COMPARE; } int run() CXX11_OVERRIDE; }; class LDAPService : public LDAPProvider, public SocketThread { LDAP* con; reference<ConfigTag> config; time_t last_connect; int searchscope; time_t timeout; public: static LDAPMod** BuildMods(const LDAPMods& attributes) { LDAPMod** mods = new LDAPMod*[attributes.size() + 1]; memset(mods, 0, sizeof(LDAPMod*) * (attributes.size() + 1)); for (unsigned int x = 0; x < attributes.size(); ++x) { const LDAPModification& l = attributes[x]; LDAPMod* mod = new LDAPMod; mods[x] = mod; if (l.op == LDAPModification::LDAP_ADD) mod->mod_op = LDAP_MOD_ADD; else if (l.op == LDAPModification::LDAP_DEL) mod->mod_op = LDAP_MOD_DELETE; else if (l.op == LDAPModification::LDAP_REPLACE) mod->mod_op = LDAP_MOD_REPLACE; else if (l.op != 0) { FreeMods(mods); throw LDAPException("Unknown LDAP operation"); } mod->mod_type = strdup(l.name.c_str()); mod->mod_values = new char*[l.values.size() + 1]; memset(mod->mod_values, 0, sizeof(char*) * (l.values.size() + 1)); for (unsigned int j = 0, c = 0; j < l.values.size(); ++j) if (!l.values[j].empty()) mod->mod_values[c++] = strdup(l.values[j].c_str()); } return mods; } static void FreeMods(LDAPMod** mods) { for (unsigned int i = 0; mods[i] != NULL; ++i) { LDAPMod* mod = mods[i]; if (mod->mod_type != NULL) free(mod->mod_type); if (mod->mod_values != NULL) { for (unsigned int j = 0; mod->mod_values[j] != NULL; ++j) free(mod->mod_values[j]); delete[] mod->mod_values; } } delete[] mods; } private: void Reconnect() { // Only try one connect a minute. It is an expensive blocking operation if (last_connect > ServerInstance->Time() - 60) throw LDAPException("Unable to connect to LDAP service " + this->name + ": reconnecting too fast"); last_connect = ServerInstance->Time(); ldap_unbind_ext(this->con, NULL, NULL); Connect(); } int SetOption(int option, const void* value) { int ret = ldap_set_option(this->con, option, value); if (ret != LDAP_OPT_SUCCESS) { ldap_unbind_ext(this->con, NULL, NULL); this->con = NULL; } return ret; } void QueueRequest(LDAPRequest* r) { this->LockQueue(); this->queries.push_back(r); this->UnlockQueueWakeup(); } public: typedef std::vector<LDAPRequest*> query_queue; query_queue queries, results; Mutex process_mutex; /* held when processing requests not in either queue */ LDAPService(Module* c, ConfigTag* tag) : LDAPProvider(c, "LDAP/" + tag->getString("id")) , con(NULL), config(tag), last_connect(0) { std::string scope = config->getString("searchscope"); if (stdalgo::string::equalsci(scope, "base")) searchscope = LDAP_SCOPE_BASE; else if (stdalgo::string::equalsci(scope, "onelevel")) searchscope = LDAP_SCOPE_ONELEVEL; else searchscope = LDAP_SCOPE_SUBTREE; timeout = config->getDuration("timeout", 5); Connect(); } ~LDAPService() { this->LockQueue(); for (unsigned int i = 0; i < this->queries.size(); ++i) { LDAPRequest* req = this->queries[i]; /* queries have no results yet */ req->result = new LDAPResult(); req->result->type = req->type; req->result->error = "LDAP Interface is going away"; req->inter->OnError(*req->result); delete req; } this->queries.clear(); for (unsigned int i = 0; i < this->results.size(); ++i) { LDAPRequest* req = this->results[i]; /* even though this may have already finished successfully we return that it didn't */ req->result->error = "LDAP Interface is going away"; req->inter->OnError(*req->result); delete req; } this->results.clear(); this->UnlockQueue(); ldap_unbind_ext(this->con, NULL, NULL); } void Connect() { std::string server = config->getString("server"); int i = ldap_initialize(&this->con, server.c_str()); if (i != LDAP_SUCCESS) throw LDAPException("Unable to connect to LDAP service " + this->name + ": " + ldap_err2string(i)); const int version = LDAP_VERSION3; i = SetOption(LDAP_OPT_PROTOCOL_VERSION, &version); if (i != LDAP_OPT_SUCCESS) throw LDAPException("Unable to set protocol version for " + this->name + ": " + ldap_err2string(i)); const struct timeval tv = { 0, 0 }; i = SetOption(LDAP_OPT_NETWORK_TIMEOUT, &tv); if (i != LDAP_OPT_SUCCESS) throw LDAPException("Unable to set timeout for " + this->name + ": " + ldap_err2string(i)); } void BindAsManager(LDAPInterface* i) CXX11_OVERRIDE { std::string binddn = config->getString("binddn"); std::string bindauth = config->getString("bindauth"); this->Bind(i, binddn, bindauth); } void Bind(LDAPInterface* i, const std::string& who, const std::string& pass) CXX11_OVERRIDE { LDAPBind* b = new LDAPBind(this, i, who, pass); QueueRequest(b); } void Search(LDAPInterface* i, const std::string& base, const std::string& filter) CXX11_OVERRIDE { if (i == NULL) throw LDAPException("No interface"); LDAPSearch* s = new LDAPSearch(this, i, base, searchscope, filter); QueueRequest(s); } void Add(LDAPInterface* i, const std::string& dn, LDAPMods& attributes) CXX11_OVERRIDE { LDAPAdd* add = new LDAPAdd(this, i, dn, attributes); QueueRequest(add); } void Del(LDAPInterface* i, const std::string& dn) CXX11_OVERRIDE { LDAPDel* del = new LDAPDel(this, i, dn); QueueRequest(del); } void Modify(LDAPInterface* i, const std::string& base, LDAPMods& attributes) CXX11_OVERRIDE { LDAPModify* mod = new LDAPModify(this, i, base, attributes); QueueRequest(mod); } void Compare(LDAPInterface* i, const std::string& dn, const std::string& attr, const std::string& val) CXX11_OVERRIDE { LDAPCompare* comp = new LDAPCompare(this, i, dn, attr, val); QueueRequest(comp); } private: void BuildReply(int res, LDAPRequest* req) { LDAPResult* ldap_result = req->result = new LDAPResult(); req->result->type = req->type; if (res != LDAP_SUCCESS) { ldap_result->error = ldap_err2string(res); return; } if (req->message == NULL) { return; } /* a search result */ for (LDAPMessage* cur = ldap_first_message(this->con, req->message); cur; cur = ldap_next_message(this->con, cur)) { LDAPAttributes attributes; char* dn = ldap_get_dn(this->con, cur); if (dn != NULL) { attributes["dn"].push_back(dn); ldap_memfree(dn); dn = NULL; } BerElement* ber = NULL; for (char* attr = ldap_first_attribute(this->con, cur, &ber); attr; attr = ldap_next_attribute(this->con, cur, ber)) { berval** vals = ldap_get_values_len(this->con, cur, attr); int count = ldap_count_values_len(vals); std::vector<std::string> attrs; for (int j = 0; j < count; ++j) attrs.push_back(vals[j]->bv_val); attributes[attr] = attrs; ldap_value_free_len(vals); ldap_memfree(attr); } if (ber != NULL) ber_free(ber, 0); ldap_result->messages.push_back(attributes); } } void SendRequests() { process_mutex.Lock(); query_queue q; this->LockQueue(); queries.swap(q); this->UnlockQueue(); if (q.empty()) { process_mutex.Unlock(); return; } for (unsigned int i = 0; i < q.size(); ++i) { LDAPRequest* req = q[i]; int ret = req->run(); if (ret == LDAP_SERVER_DOWN || ret == LDAP_TIMEOUT) { /* try again */ try { Reconnect(); } catch (const LDAPException &) { } ret = req->run(); } BuildReply(ret, req); this->LockQueue(); this->results.push_back(req); this->UnlockQueue(); } this->NotifyParent(); process_mutex.Unlock(); } public: void Run() CXX11_OVERRIDE { while (!this->GetExitFlag()) { this->LockQueue(); if (this->queries.empty()) this->WaitForQueue(); this->UnlockQueue(); SendRequests(); } } void OnNotify() CXX11_OVERRIDE { query_queue r; this->LockQueue(); this->results.swap(r); this->UnlockQueue(); for (unsigned int i = 0; i < r.size(); ++i) { LDAPRequest* req = r[i]; LDAPInterface* li = req->inter; LDAPResult* res = req->result; if (!res->error.empty()) li->OnError(*res); else li->OnResult(*res); delete req; } } LDAP* GetConnection() { return con; } }; class ModuleLDAP : public Module { typedef insp::flat_map<std::string, LDAPService*> ServiceMap; ServiceMap LDAPServices; public: void ReadConfig(ConfigStatus& status) CXX11_OVERRIDE { ServiceMap conns; ConfigTagList tags = ServerInstance->Config->ConfTags("database"); for (ConfigIter i = tags.first; i != tags.second; i++) { const reference<ConfigTag>& tag = i->second; if (!stdalgo::string::equalsci(tag->getString("module"), "ldap")) continue; std::string id = tag->getString("id"); ServiceMap::iterator curr = LDAPServices.find(id); if (curr == LDAPServices.end()) { LDAPService* conn = new LDAPService(this, tag); conns[id] = conn; ServerInstance->Modules->AddService(*conn); ServerInstance->Threads.Start(conn); } else { conns.insert(*curr); LDAPServices.erase(curr); } } for (ServiceMap::iterator i = LDAPServices.begin(); i != LDAPServices.end(); ++i) { LDAPService* conn = i->second; ServerInstance->Modules->DelService(*conn); conn->join(); conn->OnNotify(); delete conn; } LDAPServices.swap(conns); } void OnUnloadModule(Module* m) CXX11_OVERRIDE { for (ServiceMap::iterator it = this->LDAPServices.begin(); it != this->LDAPServices.end(); ++it) { LDAPService* s = it->second; s->process_mutex.Lock(); s->LockQueue(); for (unsigned int i = s->queries.size(); i > 0; --i) { LDAPRequest* req = s->queries[i - 1]; LDAPInterface* li = req->inter; if (li->creator == m) { s->queries.erase(s->queries.begin() + i - 1); delete req; } } for (unsigned int i = s->results.size(); i > 0; --i) { LDAPRequest* req = s->results[i - 1]; LDAPInterface* li = req->inter; if (li->creator == m) { s->results.erase(s->results.begin() + i - 1); delete req; } } s->UnlockQueue(); s->process_mutex.Unlock(); } } ~ModuleLDAP() { for (ServiceMap::iterator i = LDAPServices.begin(); i != LDAPServices.end(); ++i) { LDAPService* conn = i->second; conn->join(); conn->OnNotify(); delete conn; } } Version GetVersion() CXX11_OVERRIDE { return Version("Provides LDAP support", VF_VENDOR); } }; int LDAPBind::run() { berval cred; cred.bv_val = strdup(pass.c_str()); cred.bv_len = pass.length(); int i = ldap_sasl_bind_s(service->GetConnection(), who.c_str(), LDAP_SASL_SIMPLE, &cred, NULL, NULL, NULL); free(cred.bv_val); return i; } int LDAPSearch::run() { return ldap_search_ext_s(service->GetConnection(), base.c_str(), searchscope, filter.c_str(), NULL, 0, NULL, NULL, &tv, 0, &message); } int LDAPAdd::run() { LDAPMod** mods = LDAPService::BuildMods(attributes); int i = ldap_add_ext_s(service->GetConnection(), dn.c_str(), mods, NULL, NULL); LDAPService::FreeMods(mods); return i; } int LDAPDel::run() { return ldap_delete_ext_s(service->GetConnection(), dn.c_str(), NULL, NULL); } int LDAPModify::run() { LDAPMod** mods = LDAPService::BuildMods(attributes); int i = ldap_modify_ext_s(service->GetConnection(), base.c_str(), mods, NULL, NULL); LDAPService::FreeMods(mods); return i; } int LDAPCompare::run() { berval cred; cred.bv_val = strdup(val.c_str()); cred.bv_len = val.length(); int ret = ldap_compare_ext_s(service->GetConnection(), dn.c_str(), attr.c_str(), &cred, NULL, NULL); free(cred.bv_val); return ret; } MODULE_INIT(ModuleLDAP) ����������������������������������������������������������������������������������inspircd-3.4.0/src/modules/extra/m_mysql.cpp��������������������������������������������������������0000664�0000000�0000000�00000037135�13554550454�0021123�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * InspIRCd -- Internet Relay Chat Daemon * * Copyright (C) 2009-2010 Daniel De Graaf <danieldg@inspircd.org> * Copyright (C) 2006-2007, 2009 Dennis Friis <peavey@inspircd.org> * Copyright (C) 2006-2009 Craig Edwards <craigedwards@brainbox.cc> * Copyright (C) 2008 Robin Burchell <robin+git@viroteck.net> * * 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/>. */ /// $CompilerFlags: execute("mysql_config --include" "MYSQL_CXXFLAGS") /// $LinkerFlags: execute("mysql_config --libs_r" "MYSQL_LDFLAGS" "-lmysqlclient") /// $PackageInfo: require_system("arch") mariadb-libs /// $PackageInfo: require_system("centos" "6.0" "6.99") mysql-devel /// $PackageInfo: require_system("centos" "7.0") mariadb-devel /// $PackageInfo: require_system("darwin") mysql-connector-c /// $PackageInfo: require_system("debian") libmysqlclient-dev /// $PackageInfo: require_system("ubuntu") libmysqlclient-dev #ifdef __GNUC__ # pragma GCC diagnostic push #endif // Fix warnings about the use of `long long` on C++03. #if defined __clang__ # pragma clang diagnostic ignored "-Wc++11-long-long" #elif defined __GNUC__ # pragma GCC diagnostic ignored "-Wlong-long" #endif #include "inspircd.h" #include <mysql.h> #include "modules/sql.h" #ifdef __GNUC__ # pragma GCC diagnostic pop #endif #ifdef _WIN32 # pragma comment(lib, "libmysql.lib") #endif /* VERSION 3 API: With nonblocking (threaded) requests */ /* THE NONBLOCKING MYSQL API! * * MySQL provides no nonblocking (asyncronous) API of its own, and its developers recommend * that instead, you should thread your program. This is what i've done here to allow for * asyncronous SQL requests via mysql. The way this works is as follows: * * The module spawns a thread via class Thread, and performs its mysql queries in this thread, * using a queue with priorities. There is a mutex on either end which prevents two threads * adjusting the queue at the same time, and crashing the ircd. Every 50 milliseconds, the * worker thread wakes up, and checks if there is a request at the head of its queue. * If there is, it processes this request, blocking the worker thread but leaving the ircd * thread to go about its business as usual. During this period, the ircd thread is able * to insert futher pending requests into the queue. * * Once the processing of a request is complete, it is removed from the incoming queue to * an outgoing queue, and initialized as a 'response'. The worker thread then signals the * ircd thread (via a loopback socket) of the fact a result is available, by sending the * connection ID through the connection. * * The ircd thread then mutexes the queue once more, reads the outbound response off the head * of the queue, and sends it on its way to the original calling module. * * XXX: You might be asking "why doesnt it just send the response from within the worker thread?" * The answer to this is simple. The majority of InspIRCd, and in fact most ircd's are not * threadsafe. This module is designed to be threadsafe and is careful with its use of threads, * however, if we were to call a module's OnRequest even from within a thread which was not the * one the module was originally instantiated upon, there is a chance of all hell breaking loose * if a module is ever put in a re-enterant state (stack corruption could occur, crashes, data * corruption, and worse, so DONT think about it until the day comes when InspIRCd is 100% * gauranteed threadsafe!) */ class SQLConnection; class MySQLresult; class DispatcherThread; struct QQueueItem { SQL::Query* q; std::string query; SQLConnection* c; QQueueItem(SQL::Query* Q, const std::string& S, SQLConnection* C) : q(Q), query(S), c(C) {} }; struct RQueueItem { SQL::Query* q; MySQLresult* r; RQueueItem(SQL::Query* Q, MySQLresult* R) : q(Q), r(R) {} }; typedef insp::flat_map<std::string, SQLConnection*> ConnMap; typedef std::deque<QQueueItem> QueryQueue; typedef std::deque<RQueueItem> ResultQueue; /** MySQL module * */ class ModuleSQL : public Module { public: DispatcherThread* Dispatcher; QueryQueue qq; // MUST HOLD MUTEX ResultQueue rq; // MUST HOLD MUTEX ConnMap connections; // main thread only ModuleSQL(); void init() CXX11_OVERRIDE; ~ModuleSQL(); void ReadConfig(ConfigStatus& status) CXX11_OVERRIDE; void OnUnloadModule(Module* mod) CXX11_OVERRIDE; Version GetVersion() CXX11_OVERRIDE; }; class DispatcherThread : public SocketThread { private: ModuleSQL* const Parent; public: DispatcherThread(ModuleSQL* CreatorModule) : Parent(CreatorModule) { } ~DispatcherThread() { } void Run() CXX11_OVERRIDE; void OnNotify() CXX11_OVERRIDE; }; #if !defined(MYSQL_VERSION_ID) || MYSQL_VERSION_ID<32224 #define mysql_field_count mysql_num_fields #endif /** Represents a mysql result set */ class MySQLresult : public SQL::Result { public: SQL::Error err; int currentrow; int rows; std::vector<std::string> colnames; std::vector<SQL::Row> fieldlists; MySQLresult(MYSQL_RES* res, int affected_rows) : err(SQL::SUCCESS), currentrow(0), rows(0) { if (affected_rows >= 1) { rows = affected_rows; fieldlists.resize(rows); } unsigned int field_count = 0; if (res) { MYSQL_ROW row; int n = 0; while ((row = mysql_fetch_row(res))) { if (fieldlists.size() < (unsigned int)rows+1) { fieldlists.resize(fieldlists.size()+1); } field_count = 0; MYSQL_FIELD *fields = mysql_fetch_fields(res); if(mysql_num_fields(res) == 0) break; if (fields && mysql_num_fields(res)) { colnames.clear(); while (field_count < mysql_num_fields(res)) { std::string a = (fields[field_count].name ? fields[field_count].name : ""); if (row[field_count]) fieldlists[n].push_back(SQL::Field(row[field_count])); else fieldlists[n].push_back(SQL::Field()); colnames.push_back(a); field_count++; } n++; } rows++; } mysql_free_result(res); } } MySQLresult(SQL::Error& e) : err(e) { } int Rows() CXX11_OVERRIDE { return rows; } void GetCols(std::vector<std::string>& result) CXX11_OVERRIDE { result.assign(colnames.begin(), colnames.end()); } bool HasColumn(const std::string& column, size_t& index) CXX11_OVERRIDE { for (size_t i = 0; i < colnames.size(); ++i) { if (colnames[i] == column) { index = i; return true; } } return false; } SQL::Field GetValue(int row, int column) { if ((row >= 0) && (row < rows) && (column >= 0) && (column < (int)fieldlists[row].size())) { return fieldlists[row][column]; } return SQL::Field(); } bool GetRow(SQL::Row& result) CXX11_OVERRIDE { if (currentrow < rows) { result.assign(fieldlists[currentrow].begin(), fieldlists[currentrow].end()); currentrow++; return true; } else { result.clear(); return false; } } }; /** Represents a connection to a mysql database */ class SQLConnection : public SQL::Provider { private: bool EscapeString(SQL::Query* query, const std::string& in, std::string& out) { // In the worst case each character may need to be encoded as using two bytes and one // byte is the NUL terminator. std::vector<char> buffer(in.length() * 2 + 1); // The return value of mysql_escape_string() is either an error or the length of the // encoded string not including the NUL terminator. // // Unfortunately, someone genius decided that mysql_escape_string should return an // unsigned type even though -1 is returned on error so checking whether an error // happened is a bit cursed. unsigned long escapedsize = mysql_escape_string(&buffer[0], in.c_str(), in.length()); if (escapedsize == static_cast<unsigned long>(-1)) { SQL::Error err(SQL::QSEND_FAIL, InspIRCd::Format("%u: %s", mysql_errno(connection), mysql_error(connection))); query->OnError(err); return false; } out.append(&buffer[0], escapedsize); return true; } public: reference<ConfigTag> config; MYSQL *connection; Mutex lock; // This constructor creates an SQLConnection object with the given credentials, but does not connect yet. SQLConnection(Module* p, ConfigTag* tag) : SQL::Provider(p, "SQL/" + tag->getString("id")), config(tag), connection(NULL) { } ~SQLConnection() { Close(); } // This method connects to the database using the credentials supplied to the constructor, and returns // true upon success. bool Connect() { unsigned int timeout = 1; connection = mysql_init(connection); mysql_options(connection,MYSQL_OPT_CONNECT_TIMEOUT,(char*)&timeout); std::string host = config->getString("host"); std::string user = config->getString("user"); std::string pass = config->getString("pass"); std::string dbname = config->getString("name"); unsigned int port = config->getUInt("port", 3306); bool rv = mysql_real_connect(connection, host.c_str(), user.c_str(), pass.c_str(), dbname.c_str(), port, NULL, 0); if (!rv) return rv; // Enable character set settings std::string charset = config->getString("charset"); if ((!charset.empty()) && (mysql_set_character_set(connection, charset.c_str()))) ServerInstance->Logs->Log(MODNAME, LOG_DEFAULT, "WARNING: Could not set character set to \"%s\"", charset.c_str()); std::string initquery; if (config->readString("initialquery", initquery)) { mysql_query(connection,initquery.c_str()); } return true; } ModuleSQL* Parent() { return (ModuleSQL*)(Module*)creator; } MySQLresult* DoBlockingQuery(const std::string& query) { /* Parse the command string and dispatch it to mysql */ if (CheckConnection() && !mysql_real_query(connection, query.data(), query.length())) { /* Successfull query */ MYSQL_RES* res = mysql_use_result(connection); unsigned long rows = mysql_affected_rows(connection); return new MySQLresult(res, rows); } else { /* XXX: See /usr/include/mysql/mysqld_error.h for a list of * possible error numbers and error messages */ SQL::Error e(SQL::QREPLY_FAIL, InspIRCd::Format("%u: %s", mysql_errno(connection), mysql_error(connection))); return new MySQLresult(e); } } bool CheckConnection() { if (!connection || mysql_ping(connection) != 0) return Connect(); return true; } std::string GetError() { return mysql_error(connection); } void Close() { mysql_close(connection); } void Submit(SQL::Query* q, const std::string& qs) CXX11_OVERRIDE { ServerInstance->Logs->Log(MODNAME, LOG_DEBUG, "Executing MySQL query: " + qs); Parent()->Dispatcher->LockQueue(); Parent()->qq.push_back(QQueueItem(q, qs, this)); Parent()->Dispatcher->UnlockQueueWakeup(); } void Submit(SQL::Query* call, const std::string& q, const SQL::ParamList& p) CXX11_OVERRIDE { std::string res; unsigned int param = 0; for(std::string::size_type i = 0; i < q.length(); i++) { if (q[i] != '?') res.push_back(q[i]); else if (param < p.size() && !EscapeString(call, p[param++], res)) return; } Submit(call, res); } void Submit(SQL::Query* call, const std::string& q, const SQL::ParamMap& p) CXX11_OVERRIDE { std::string res; for(std::string::size_type i = 0; i < q.length(); i++) { if (q[i] != '$') res.push_back(q[i]); else { std::string field; i++; while (i < q.length() && isalnum(q[i])) field.push_back(q[i++]); i--; SQL::ParamMap::const_iterator it = p.find(field); if (it != p.end() && !EscapeString(call, it->second, res)) return; } } Submit(call, res); } }; ModuleSQL::ModuleSQL() { Dispatcher = NULL; } void ModuleSQL::init() { if (mysql_library_init(0, NULL, NULL)) throw ModuleException("Unable to initialise the MySQL library!"); Dispatcher = new DispatcherThread(this); ServerInstance->Threads.Start(Dispatcher); } ModuleSQL::~ModuleSQL() { if (Dispatcher) { Dispatcher->join(); Dispatcher->OnNotify(); delete Dispatcher; } for(ConnMap::iterator i = connections.begin(); i != connections.end(); i++) { delete i->second; } mysql_library_end(); } void ModuleSQL::ReadConfig(ConfigStatus& status) { ConnMap conns; ConfigTagList tags = ServerInstance->Config->ConfTags("database"); for(ConfigIter i = tags.first; i != tags.second; i++) { if (!stdalgo::string::equalsci(i->second->getString("module"), "mysql")) continue; std::string id = i->second->getString("id"); ConnMap::iterator curr = connections.find(id); if (curr == connections.end()) { SQLConnection* conn = new SQLConnection(this, i->second); conns.insert(std::make_pair(id, conn)); ServerInstance->Modules->AddService(*conn); } else { conns.insert(*curr); connections.erase(curr); } } // now clean up the deleted databases Dispatcher->LockQueue(); SQL::Error err(SQL::BAD_DBID); for(ConnMap::iterator i = connections.begin(); i != connections.end(); i++) { ServerInstance->Modules->DelService(*i->second); // it might be running a query on this database. Wait for that to complete i->second->lock.Lock(); i->second->lock.Unlock(); // now remove all active queries to this DB for (size_t j = qq.size(); j > 0; j--) { size_t k = j - 1; if (qq[k].c == i->second) { qq[k].q->OnError(err); delete qq[k].q; qq.erase(qq.begin() + k); } } // finally, nuke the connection delete i->second; } Dispatcher->UnlockQueue(); connections.swap(conns); } void ModuleSQL::OnUnloadModule(Module* mod) { SQL::Error err(SQL::BAD_DBID); Dispatcher->LockQueue(); unsigned int i = qq.size(); while (i > 0) { i--; if (qq[i].q->creator == mod) { if (i == 0) { // need to wait until the query is done // (the result will be discarded) qq[i].c->lock.Lock(); qq[i].c->lock.Unlock(); } qq[i].q->OnError(err); delete qq[i].q; qq.erase(qq.begin() + i); } } Dispatcher->UnlockQueue(); // clean up any result queue entries Dispatcher->OnNotify(); } Version ModuleSQL::GetVersion() { return Version("Provides MySQL support", VF_VENDOR); } void DispatcherThread::Run() { this->LockQueue(); while (!this->GetExitFlag()) { if (!Parent->qq.empty()) { QQueueItem i = Parent->qq.front(); i.c->lock.Lock(); this->UnlockQueue(); MySQLresult* res = i.c->DoBlockingQuery(i.query); i.c->lock.Unlock(); /* * At this point, the main thread could be working on: * Rehash - delete i.c out from under us. We don't care about that. * UnloadModule - delete i.q and the qq item. Need to avoid reporting results. */ this->LockQueue(); if (!Parent->qq.empty() && Parent->qq.front().q == i.q) { Parent->qq.pop_front(); Parent->rq.push_back(RQueueItem(i.q, res)); NotifyParent(); } else { // UnloadModule ate the query delete res; } } else { /* We know the queue is empty, we can safely hang this thread until * something happens */ this->WaitForQueue(); } } this->UnlockQueue(); } void DispatcherThread::OnNotify() { // this could unlock during the dispatch, but OnResult isn't expected to take that long this->LockQueue(); for(ResultQueue::iterator i = Parent->rq.begin(); i != Parent->rq.end(); i++) { MySQLresult* res = i->r; if (res->err.code == SQL::SUCCESS) i->q->OnResult(*res); else i->q->OnError(res->err); delete i->q; delete i->r; } Parent->rq.clear(); this->UnlockQueue(); } MODULE_INIT(ModuleSQL) �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/src/modules/extra/m_pgsql.cpp��������������������������������������������������������0000664�0000000�0000000�00000035324�13554550454�0021102�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * InspIRCd -- Internet Relay Chat Daemon * * Copyright (C) 2009-2010 Daniel De Graaf <danieldg@inspircd.org> * Copyright (C) 2006-2007, 2009 Dennis Friis <peavey@inspircd.org> * Copyright (C) 2006-2007, 2009 Craig Edwards <craigedwards@brainbox.cc> * Copyright (C) 2008 Robin Burchell <robin+git@viroteck.net> * Copyright (C) 2008 Thomas Stagner <aquanight@inspircd.org> * Copyright (C) 2006 Oliver Lupton <oliverlupton@gmail.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/>. */ /// $CompilerFlags: -Iexecute("pg_config --includedir" "POSTGRESQL_INCLUDE_DIR") /// $LinkerFlags: -Lexecute("pg_config --libdir" "POSTGRESQL_LIBRARY_DIR") -lpq /// $PackageInfo: require_system("arch") postgresql-libs /// $PackageInfo: require_system("centos") postgresql-devel /// $PackageInfo: require_system("darwin") postgresql /// $PackageInfo: require_system("debian") libpq-dev /// $PackageInfo: require_system("ubuntu") libpq-dev #include "inspircd.h" #include <cstdlib> #include <libpq-fe.h> #include "modules/sql.h" /* SQLConn rewritten by peavey to * use EventHandler instead of * BufferedSocket. This is much neater * and gives total control of destroy * and delete of resources. */ /* Forward declare, so we can have the typedef neatly at the top */ class SQLConn; class ModulePgSQL; typedef insp::flat_map<std::string, SQLConn*> ConnMap; /* CREAD, Connecting and wants read event * CWRITE, Connecting and wants write event * WREAD, Connected/Working and wants read event * WWRITE, Connected/Working and wants write event * RREAD, Resetting and wants read event * RWRITE, Resetting and wants write event */ enum SQLstatus { CREAD, CWRITE, WREAD, WWRITE, RREAD, RWRITE }; class ReconnectTimer : public Timer { private: ModulePgSQL* mod; public: ReconnectTimer(ModulePgSQL* m) : Timer(5, false), mod(m) { } bool Tick(time_t TIME) CXX11_OVERRIDE; }; struct QueueItem { SQL::Query* c; std::string q; QueueItem(SQL::Query* C, const std::string& Q) : c(C), q(Q) {} }; /** PgSQLresult is a subclass of the mostly-pure-virtual class SQLresult. * All SQL providers must create their own subclass and define it's methods using that * database library's data retriveal functions. The aim is to avoid a slow and inefficient process * of converting all data to a common format before it reaches the result structure. This way * data is passes to the module nearly as directly as if it was using the API directly itself. */ class PgSQLresult : public SQL::Result { PGresult* res; int currentrow; int rows; std::vector<std::string> colnames; void getColNames() { colnames.resize(PQnfields(res)); for(unsigned int i=0; i < colnames.size(); i++) { colnames[i] = PQfname(res, i); } } public: PgSQLresult(PGresult* result) : res(result), currentrow(0) { rows = PQntuples(res); if (!rows) rows = ConvToNum<int>(PQcmdTuples(res)); } ~PgSQLresult() { PQclear(res); } int Rows() CXX11_OVERRIDE { return rows; } void GetCols(std::vector<std::string>& result) CXX11_OVERRIDE { if (colnames.empty()) getColNames(); result = colnames; } bool HasColumn(const std::string& column, size_t& index) CXX11_OVERRIDE { if (colnames.empty()) getColNames(); for (size_t i = 0; i < colnames.size(); ++i) { if (colnames[i] == column) { index = i; return true; } } return false; } SQL::Field GetValue(int row, int column) { char* v = PQgetvalue(res, row, column); if (!v || PQgetisnull(res, row, column)) return SQL::Field(); return SQL::Field(std::string(v, PQgetlength(res, row, column))); } bool GetRow(SQL::Row& result) CXX11_OVERRIDE { if (currentrow >= PQntuples(res)) return false; int ncols = PQnfields(res); for(int i = 0; i < ncols; i++) { result.push_back(GetValue(currentrow, i)); } currentrow++; return true; } }; /** SQLConn represents one SQL session. */ class SQLConn : public SQL::Provider, public EventHandler { public: reference<ConfigTag> conf; /* The <database> entry */ std::deque<QueueItem> queue; PGconn* sql; /* PgSQL database connection handle */ SQLstatus status; /* PgSQL database connection status */ QueueItem qinprog; /* If there is currently a query in progress */ SQLConn(Module* Creator, ConfigTag* tag) : SQL::Provider(Creator, "SQL/" + tag->getString("id")), conf(tag), sql(NULL), status(CWRITE), qinprog(NULL, "") { if (!DoConnect()) { ServerInstance->Logs->Log(MODNAME, LOG_DEFAULT, "WARNING: Could not connect to database " + tag->getString("id")); DelayReconnect(); } } CullResult cull() CXX11_OVERRIDE { this->SQL::Provider::cull(); ServerInstance->Modules->DelService(*this); return this->EventHandler::cull(); } ~SQLConn() { SQL::Error err(SQL::BAD_DBID); if (qinprog.c) { qinprog.c->OnError(err); delete qinprog.c; } for(std::deque<QueueItem>::iterator i = queue.begin(); i != queue.end(); i++) { SQL::Query* q = i->c; q->OnError(err); delete q; } } void OnEventHandlerRead() CXX11_OVERRIDE { DoEvent(); } void OnEventHandlerWrite() CXX11_OVERRIDE { DoEvent(); } void OnEventHandlerError(int errornum) CXX11_OVERRIDE { DelayReconnect(); } std::string GetDSN() { std::ostringstream conninfo("connect_timeout = '5'"); std::string item; if (conf->readString("host", item)) conninfo << " host = '" << item << "'"; if (conf->readString("port", item)) conninfo << " port = '" << item << "'"; if (conf->readString("name", item)) conninfo << " dbname = '" << item << "'"; if (conf->readString("user", item)) conninfo << " user = '" << item << "'"; if (conf->readString("pass", item)) conninfo << " password = '" << item << "'"; if (conf->getBool("ssl")) conninfo << " sslmode = 'require'"; else conninfo << " sslmode = 'disable'"; return conninfo.str(); } bool DoConnect() { sql = PQconnectStart(GetDSN().c_str()); if (!sql) return false; if(PQstatus(sql) == CONNECTION_BAD) return false; if(PQsetnonblocking(sql, 1) == -1) return false; /* OK, we've initalised the connection, now to get it hooked into the socket engine * and then start polling it. */ this->fd = PQsocket(sql); if(this->fd <= -1) return false; if (!SocketEngine::AddFd(this, FD_WANT_NO_WRITE | FD_WANT_NO_READ)) { ServerInstance->Logs->Log(MODNAME, LOG_DEBUG, "BUG: Couldn't add pgsql socket to socket engine"); return false; } /* Socket all hooked into the engine, now to tell PgSQL to start connecting */ return DoPoll(); } bool DoPoll() { switch(PQconnectPoll(sql)) { case PGRES_POLLING_WRITING: SocketEngine::ChangeEventMask(this, FD_WANT_POLL_WRITE | FD_WANT_NO_READ); status = CWRITE; return true; case PGRES_POLLING_READING: SocketEngine::ChangeEventMask(this, FD_WANT_POLL_READ | FD_WANT_NO_WRITE); status = CREAD; return true; case PGRES_POLLING_FAILED: return false; case PGRES_POLLING_OK: SocketEngine::ChangeEventMask(this, FD_WANT_POLL_READ | FD_WANT_NO_WRITE); status = WWRITE; DoConnectedPoll(); return true; default: return true; } } void DoConnectedPoll() { restart: while (qinprog.q.empty() && !queue.empty()) { /* There's no query currently in progress, and there's queries in the queue. */ DoQuery(queue.front()); queue.pop_front(); } if (PQconsumeInput(sql)) { if (PQisBusy(sql)) { /* Nothing happens here */ } else if (qinprog.c) { /* Fetch the result.. */ PGresult* result = PQgetResult(sql); /* PgSQL would allow a query string to be sent which has multiple * queries in it, this isn't portable across database backends and * we don't want modules doing it. But just in case we make sure we * drain any results there are and just use the last one. * If the module devs are behaving there will only be one result. */ while (PGresult* temp = PQgetResult(sql)) { PQclear(result); result = temp; } /* ..and the result */ PgSQLresult reply(result); switch(PQresultStatus(result)) { case PGRES_EMPTY_QUERY: case PGRES_BAD_RESPONSE: case PGRES_FATAL_ERROR: { SQL::Error err(SQL::QREPLY_FAIL, PQresultErrorMessage(result)); qinprog.c->OnError(err); break; } default: /* Other values are not errors */ qinprog.c->OnResult(reply); } delete qinprog.c; qinprog = QueueItem(NULL, ""); goto restart; } else { qinprog.q.clear(); } } else { /* I think we'll assume this means the server died...it might not, * but I think that any error serious enough we actually get here * deserves to reconnect [/excuse] * Returning true so the core doesn't try and close the connection. */ DelayReconnect(); } } bool DoResetPoll() { switch(PQresetPoll(sql)) { case PGRES_POLLING_WRITING: SocketEngine::ChangeEventMask(this, FD_WANT_POLL_WRITE | FD_WANT_NO_READ); status = CWRITE; return DoPoll(); case PGRES_POLLING_READING: SocketEngine::ChangeEventMask(this, FD_WANT_POLL_READ | FD_WANT_NO_WRITE); status = CREAD; return true; case PGRES_POLLING_FAILED: return false; case PGRES_POLLING_OK: SocketEngine::ChangeEventMask(this, FD_WANT_POLL_READ | FD_WANT_NO_WRITE); status = WWRITE; DoConnectedPoll(); return true; default: return true; } } void DelayReconnect(); void DoEvent() { if((status == CREAD) || (status == CWRITE)) { DoPoll(); } else if((status == RREAD) || (status == RWRITE)) { DoResetPoll(); } else { DoConnectedPoll(); } } void Submit(SQL::Query *req, const std::string& q) CXX11_OVERRIDE { ServerInstance->Logs->Log(MODNAME, LOG_DEBUG, "Executing PostgreSQL query: " + q); if (qinprog.q.empty()) { DoQuery(QueueItem(req,q)); } else { // wait your turn. queue.push_back(QueueItem(req,q)); } } void Submit(SQL::Query *req, const std::string& q, const SQL::ParamList& p) CXX11_OVERRIDE { std::string res; unsigned int param = 0; for(std::string::size_type i = 0; i < q.length(); i++) { if (q[i] != '?') res.push_back(q[i]); else { if (param < p.size()) { std::string parm = p[param++]; std::vector<char> buffer(parm.length() * 2 + 1); int error; size_t escapedsize = PQescapeStringConn(sql, &buffer[0], parm.data(), parm.length(), &error); if (error) ServerInstance->Logs->Log(MODNAME, LOG_DEBUG, "BUG: Apparently PQescapeStringConn() failed"); res.append(&buffer[0], escapedsize); } } } Submit(req, res); } void Submit(SQL::Query *req, const std::string& q, const SQL::ParamMap& p) CXX11_OVERRIDE { std::string res; for(std::string::size_type i = 0; i < q.length(); i++) { if (q[i] != '$') res.push_back(q[i]); else { std::string field; i++; while (i < q.length() && isalnum(q[i])) field.push_back(q[i++]); i--; SQL::ParamMap::const_iterator it = p.find(field); if (it != p.end()) { std::string parm = it->second; std::vector<char> buffer(parm.length() * 2 + 1); int error; size_t escapedsize = PQescapeStringConn(sql, &buffer[0], parm.data(), parm.length(), &error); if (error) ServerInstance->Logs->Log(MODNAME, LOG_DEBUG, "BUG: Apparently PQescapeStringConn() failed"); res.append(&buffer[0], escapedsize); } } } Submit(req, res); } void DoQuery(const QueueItem& req) { if (status != WREAD && status != WWRITE) { // whoops, not connected... SQL::Error err(SQL::BAD_CONN); req.c->OnError(err); delete req.c; return; } if(PQsendQuery(sql, req.q.c_str())) { qinprog = req; } else { SQL::Error err(SQL::QSEND_FAIL, PQerrorMessage(sql)); req.c->OnError(err); delete req.c; } } void Close() { SocketEngine::DelFd(this); if(sql) { PQfinish(sql); sql = NULL; } } }; class ModulePgSQL : public Module { public: ConnMap connections; ReconnectTimer* retimer; ModulePgSQL() : retimer(NULL) { } ~ModulePgSQL() { delete retimer; ClearAllConnections(); } void ReadConfig(ConfigStatus& status) CXX11_OVERRIDE { ReadConf(); } void ReadConf() { ConnMap conns; ConfigTagList tags = ServerInstance->Config->ConfTags("database"); for(ConfigIter i = tags.first; i != tags.second; i++) { if (!stdalgo::string::equalsci(i->second->getString("module"), "pgsql")) continue; std::string id = i->second->getString("id"); ConnMap::iterator curr = connections.find(id); if (curr == connections.end()) { SQLConn* conn = new SQLConn(this, i->second); conns.insert(std::make_pair(id, conn)); ServerInstance->Modules->AddService(*conn); } else { conns.insert(*curr); connections.erase(curr); } } ClearAllConnections(); conns.swap(connections); } void ClearAllConnections() { for(ConnMap::iterator i = connections.begin(); i != connections.end(); i++) { i->second->cull(); delete i->second; } connections.clear(); } void OnUnloadModule(Module* mod) CXX11_OVERRIDE { SQL::Error err(SQL::BAD_DBID); for(ConnMap::iterator i = connections.begin(); i != connections.end(); i++) { SQLConn* conn = i->second; if (conn->qinprog.c && conn->qinprog.c->creator == mod) { conn->qinprog.c->OnError(err); delete conn->qinprog.c; conn->qinprog.c = NULL; } std::deque<QueueItem>::iterator j = conn->queue.begin(); while (j != conn->queue.end()) { SQL::Query* q = j->c; if (q->creator == mod) { q->OnError(err); delete q; j = conn->queue.erase(j); } else j++; } } } Version GetVersion() CXX11_OVERRIDE { return Version("PostgreSQL Service Provider module for all other m_sql* modules, uses v2 of the SQL API", VF_VENDOR); } }; bool ReconnectTimer::Tick(time_t time) { mod->retimer = NULL; mod->ReadConf(); delete this; return false; } void SQLConn::DelayReconnect() { ModulePgSQL* mod = (ModulePgSQL*)(Module*)creator; ConnMap::iterator it = mod->connections.find(conf->getString("id")); if (it != mod->connections.end()) { mod->connections.erase(it); ServerInstance->GlobalCulls.AddItem((EventHandler*)this); if (!mod->retimer) { mod->retimer = new ReconnectTimer(mod); ServerInstance->Timers.AddTimer(mod->retimer); } } } MODULE_INIT(ModulePgSQL) ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/src/modules/extra/m_regex_pcre.cpp���������������������������������������������������0000664�0000000�0000000�00000004472�13554550454�0022077�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * InspIRCd -- Internet Relay Chat Daemon * * Copyright (C) 2009 Daniel De Graaf <danieldg@inspircd.org> * Copyright (C) 2008 Thomas Stagner <aquanight@inspircd.org> * * This file is part of InspIRCd. InspIRCd is free software: you can * redistribute it and/or modify it under the terms of the GNU General Public * License as published by the Free Software Foundation, version 2. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ /// $CompilerFlags: execute("pcre-config --cflags" "PCRE_CXXFLAGS") /// $LinkerFlags: execute("pcre-config --libs" "PCRE_LDFLAGS" "-lpcre") /// $PackageInfo: require_system("arch") pcre /// $PackageInfo: require_system("centos") pcre-devel /// $PackageInfo: require_system("darwin") pcre /// $PackageInfo: require_system("debian") libpcre3-dev /// $PackageInfo: require_system("ubuntu") libpcre3-dev #include "inspircd.h" #include <pcre.h> #include "modules/regex.h" #ifdef _WIN32 # pragma comment(lib, "libpcre.lib") #endif class PCRERegex : public Regex { pcre* regex; public: PCRERegex(const std::string& rx) : Regex(rx) { const char* error; int erroffset; regex = pcre_compile(rx.c_str(), 0, &error, &erroffset, NULL); if (!regex) { ServerInstance->Logs->Log(MODNAME, LOG_DEBUG, "pcre_compile failed: /%s/ [%d] %s", rx.c_str(), erroffset, error); throw RegexException(rx, error, erroffset); } } ~PCRERegex() { pcre_free(regex); } bool Matches(const std::string& text) CXX11_OVERRIDE { return (pcre_exec(regex, NULL, text.c_str(), text.length(), 0, 0, NULL, 0) >= 0); } }; class PCREFactory : public RegexFactory { public: PCREFactory(Module* m) : RegexFactory(m, "regex/pcre") {} Regex* Create(const std::string& expr) CXX11_OVERRIDE { return new PCRERegex(expr); } }; class ModuleRegexPCRE : public Module { public: PCREFactory ref; ModuleRegexPCRE() : ref(this) { } Version GetVersion() CXX11_OVERRIDE { return Version("Regex Provider Module for PCRE", VF_VENDOR); } }; MODULE_INIT(ModuleRegexPCRE) ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/src/modules/extra/m_regex_posix.cpp��������������������������������������������������0000664�0000000�0000000�00000004471�13554550454�0022307�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * InspIRCd -- Internet Relay Chat Daemon * * Copyright (C) 2009 Daniel De Graaf <danieldg@inspircd.org> * Copyright (C) 2008 Thomas Stagner <aquanight@inspircd.org> * * This file is part of InspIRCd. InspIRCd is free software: you can * redistribute it and/or modify it under the terms of the GNU General Public * License as published by the Free Software Foundation, version 2. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include "inspircd.h" #include "modules/regex.h" #include <sys/types.h> #include <regex.h> class POSIXRegex : public Regex { regex_t regbuf; public: POSIXRegex(const std::string& rx, bool extended) : Regex(rx) { int flags = (extended ? REG_EXTENDED : 0) | REG_NOSUB; int errcode; errcode = regcomp(&regbuf, rx.c_str(), flags); if (errcode) { // Get the error string into a std::string. YUCK this involves at least 2 string copies. std::string error; char* errbuf; size_t sz = regerror(errcode, &regbuf, NULL, 0); errbuf = new char[sz + 1]; memset(errbuf, 0, sz + 1); regerror(errcode, &regbuf, errbuf, sz + 1); error = errbuf; delete[] errbuf; regfree(&regbuf); throw RegexException(rx, error); } } ~POSIXRegex() { regfree(&regbuf); } bool Matches(const std::string& text) CXX11_OVERRIDE { return (regexec(&regbuf, text.c_str(), 0, NULL, 0) == 0); } }; class PosixFactory : public RegexFactory { public: bool extended; PosixFactory(Module* m) : RegexFactory(m, "regex/posix") {} Regex* Create(const std::string& expr) CXX11_OVERRIDE { return new POSIXRegex(expr, extended); } }; class ModuleRegexPOSIX : public Module { PosixFactory ref; public: ModuleRegexPOSIX() : ref(this) { } Version GetVersion() CXX11_OVERRIDE { return Version("Regex Provider Module for POSIX Regular Expressions", VF_VENDOR); } void ReadConfig(ConfigStatus& status) CXX11_OVERRIDE { ref.extended = ServerInstance->Config->ConfValue("posix")->getBool("extended"); } }; MODULE_INIT(ModuleRegexPOSIX) �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/src/modules/extra/m_regex_re2.cpp����������������������������������������������������0000664�0000000�0000000�00000004447�13554550454�0021640�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * InspIRCd -- Internet Relay Chat Daemon * * Copyright (C) 2013 Peter Powell <petpow@saberuk.com> * Copyright (C) 2012 ChrisTX <chris@rev-crew.info> * * 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/>. */ /// $CompilerFlags: find_compiler_flags("re2" "") /// $LinkerFlags: find_linker_flags("re2" "-lre2") /// $PackageInfo: require_system("arch") pkgconf re2 /// $PackageInfo: require_system("darwin") pkg-config re2 /// $PackageInfo: require_system("debian" "8.0") libre2-dev pkg-config /// $PackageInfo: require_system("ubuntu" "15.10") libre2-dev pkg-config #include "inspircd.h" #include "modules/regex.h" #ifdef __GNUC__ # pragma GCC diagnostic push #endif // Fix warnings about the use of `long long` on C++03 and // shadowing on GCC. #if defined __clang__ # pragma clang diagnostic ignored "-Wc++11-long-long" #elif defined __GNUC__ # pragma GCC diagnostic ignored "-Wlong-long" # pragma GCC diagnostic ignored "-Wshadow" #endif #include <re2/re2.h> #ifdef __GNUC__ # pragma GCC diagnostic pop #endif class RE2Regex : public Regex { RE2 regexcl; public: RE2Regex(const std::string& rx) : Regex(rx), regexcl(rx, RE2::Quiet) { if (!regexcl.ok()) { throw RegexException(rx, regexcl.error()); } } bool Matches(const std::string& text) CXX11_OVERRIDE { return RE2::FullMatch(text, regexcl); } }; class RE2Factory : public RegexFactory { public: RE2Factory(Module* m) : RegexFactory(m, "regex/re2") { } Regex* Create(const std::string& expr) CXX11_OVERRIDE { return new RE2Regex(expr); } }; class ModuleRegexRE2 : public Module { RE2Factory ref; public: ModuleRegexRE2() : ref(this) { } Version GetVersion() CXX11_OVERRIDE { return Version("Regex Provider Module for RE2", VF_VENDOR); } }; MODULE_INIT(ModuleRegexRE2) �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/src/modules/extra/m_regex_stdlib.cpp�������������������������������������������������0000664�0000000�0000000�00000005141�13554550454�0022421�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * InspIRCd -- Internet Relay Chat Daemon * * Copyright (C) 2012 ChrisTX <chris@rev-crew.info> * * 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/>. */ /// $CompilerFlags: -std=c++11 #include "inspircd.h" #include "modules/regex.h" #include <regex> class StdRegex : public Regex { std::regex regexcl; public: StdRegex(const std::string& rx, std::regex::flag_type fltype) : Regex(rx) { try{ regexcl.assign(rx, fltype | std::regex::optimize); } catch(std::regex_error rxerr) { throw RegexException(rx, rxerr.what()); } } bool Matches(const std::string& text) CXX11_OVERRIDE { return std::regex_search(text, regexcl); } }; class StdRegexFactory : public RegexFactory { public: std::regex::flag_type regextype; StdRegexFactory(Module* m) : RegexFactory(m, "regex/stdregex") {} Regex* Create(const std::string& expr) CXX11_OVERRIDE { return new StdRegex(expr, regextype); } }; class ModuleRegexStd : public Module { public: StdRegexFactory ref; ModuleRegexStd() : ref(this) { } Version GetVersion() CXX11_OVERRIDE { return Version("Regex Provider Module for std::regex", VF_VENDOR); } void ReadConfig(ConfigStatus& status) CXX11_OVERRIDE { ConfigTag* Conf = ServerInstance->Config->ConfValue("stdregex"); std::string regextype = Conf->getString("type", "ecmascript"); if (stdalgo::string::equalsci(regextype, "bre")) ref.regextype = std::regex::basic; else if (stdalgo::string::equalsci(regextype, "ere")) ref.regextype = std::regex::extended; else if (stdalgo::string::equalsci(regextype, "awk")) ref.regextype = std::regex::awk; else if (stdalgo::string::equalsci(regextype, "grep")) ref.regextype = std::regex::grep; else if (stdalgo::string::equalsci(regextype, "egrep")) ref.regextype = std::regex::egrep; else { if (!stdalgo::string::equalsci(regextype, "ecmascript")) ServerInstance->SNO->WriteToSnoMask('a', "WARNING: Nonexistent regex engine '%s' specified. Falling back to ECMAScript.", regextype.c_str()); ref.regextype = std::regex::ECMAScript; } } }; MODULE_INIT(ModuleRegexStd) �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/src/modules/extra/m_regex_tre.cpp����������������������������������������������������0000664�0000000�0000000�00000004660�13554550454�0021737�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * InspIRCd -- Internet Relay Chat Daemon * * Copyright (C) 2009 Daniel De Graaf <danieldg@inspircd.org> * Copyright (C) 2008 Thomas Stagner <aquanight@inspircd.org> * * This file is part of InspIRCd. InspIRCd is free software: you can * redistribute it and/or modify it under the terms of the GNU General Public * License as published by the Free Software Foundation, version 2. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ /// $CompilerFlags: find_compiler_flags("tre") /// $LinkerFlags: find_linker_flags("tre" "-ltre") /// $PackageInfo: require_system("arch") pkgconf tre /// $PackageInfo: require_system("darwin") pkg-config tre /// $PackageInfo: require_system("debian") libtre-dev pkg-config /// $PackageInfo: require_system("ubuntu") libtre-dev pkg-config #include "inspircd.h" #include "modules/regex.h" #include <sys/types.h> #include <tre/regex.h> class TRERegex : public Regex { regex_t regbuf; public: TRERegex(const std::string& rx) : Regex(rx) { int flags = REG_EXTENDED | REG_NOSUB; int errcode; errcode = regcomp(&regbuf, rx.c_str(), flags); if (errcode) { // Get the error string into a std::string. YUCK this involves at least 2 string copies. std::string error; char* errbuf; size_t sz = regerror(errcode, &regbuf, NULL, 0); errbuf = new char[sz + 1]; memset(errbuf, 0, sz + 1); regerror(errcode, &regbuf, errbuf, sz + 1); error = errbuf; delete[] errbuf; regfree(&regbuf); throw RegexException(rx, error); } } ~TRERegex() { regfree(&regbuf); } bool Matches(const std::string& text) CXX11_OVERRIDE { return (regexec(&regbuf, text.c_str(), 0, NULL, 0) == 0); } }; class TREFactory : public RegexFactory { public: TREFactory(Module* m) : RegexFactory(m, "regex/tre") {} Regex* Create(const std::string& expr) CXX11_OVERRIDE { return new TRERegex(expr); } }; class ModuleRegexTRE : public Module { TREFactory trf; public: ModuleRegexTRE() : trf(this) { } Version GetVersion() CXX11_OVERRIDE { return Version("Regex Provider Module for TRE Regular Expressions", VF_VENDOR); } }; MODULE_INIT(ModuleRegexTRE) ��������������������������������������������������������������������������������inspircd-3.4.0/src/modules/extra/m_sqlite3.cpp������������������������������������������������������0000664�0000000�0000000�00000014677�13554550454�0021350�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * InspIRCd -- Internet Relay Chat Daemon * * Copyright (C) 2009-2010 Daniel De Graaf <danieldg@inspircd.org> * Copyright (C) 2007-2009 Dennis Friis <peavey@inspircd.org> * Copyright (C) 2007, 2009 Craig Edwards <craigedwards@brainbox.cc> * Copyright (C) 2008 Pippijn van Steenhoven <pip88nl@gmail.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/>. */ /// $CompilerFlags: find_compiler_flags("sqlite3") /// $LinkerFlags: find_linker_flags("sqlite3" "-lsqlite3") /// $PackageInfo: require_system("arch") pkgconf sqlite /// $PackageInfo: require_system("centos") pkgconfig sqlite-devel /// $PackageInfo: require_system("darwin") pkg-config sqlite3 /// $PackageInfo: require_system("debian") libsqlite3-dev pkg-config /// $PackageInfo: require_system("ubuntu") libsqlite3-dev pkg-config #include "inspircd.h" #include "modules/sql.h" #ifdef __GNUC__ # pragma GCC diagnostic push #endif // Fix warnings about the use of `long long` on C++03. #if defined __clang__ # pragma clang diagnostic ignored "-Wc++11-long-long" #elif defined __GNUC__ # pragma GCC diagnostic ignored "-Wlong-long" #endif #include <sqlite3.h> #ifdef __GNUC__ # pragma GCC diagnostic pop #endif #ifdef _WIN32 # pragma comment(lib, "sqlite3.lib") #endif class SQLConn; typedef insp::flat_map<std::string, SQLConn*> ConnMap; class SQLite3Result : public SQL::Result { public: int currentrow; int rows; std::vector<std::string> columns; std::vector<SQL::Row> fieldlists; SQLite3Result() : currentrow(0), rows(0) { } int Rows() CXX11_OVERRIDE { return rows; } bool GetRow(SQL::Row& result) CXX11_OVERRIDE { if (currentrow < rows) { result.assign(fieldlists[currentrow].begin(), fieldlists[currentrow].end()); currentrow++; return true; } else { result.clear(); return false; } } void GetCols(std::vector<std::string>& result) CXX11_OVERRIDE { result.assign(columns.begin(), columns.end()); } bool HasColumn(const std::string& column, size_t& index) CXX11_OVERRIDE { for (size_t i = 0; i < columns.size(); ++i) { if (columns[i] == column) { index = i; return true; } } return false; } }; class SQLConn : public SQL::Provider { sqlite3* conn; reference<ConfigTag> config; public: SQLConn(Module* Parent, ConfigTag* tag) : SQL::Provider(Parent, "SQL/" + tag->getString("id")), config(tag) { std::string host = tag->getString("hostname"); if (sqlite3_open_v2(host.c_str(), &conn, SQLITE_OPEN_READWRITE, 0) != SQLITE_OK) { // Even in case of an error conn must be closed sqlite3_close(conn); conn = NULL; ServerInstance->Logs->Log(MODNAME, LOG_DEFAULT, "WARNING: Could not open DB with id: " + tag->getString("id")); } } ~SQLConn() { if (conn) { sqlite3_interrupt(conn); sqlite3_close(conn); } } void Query(SQL::Query* query, const std::string& q) { SQLite3Result res; sqlite3_stmt *stmt; int err = sqlite3_prepare_v2(conn, q.c_str(), q.length(), &stmt, NULL); if (err != SQLITE_OK) { SQL::Error error(SQL::QSEND_FAIL, sqlite3_errmsg(conn)); query->OnError(error); return; } int cols = sqlite3_column_count(stmt); res.columns.resize(cols); for(int i=0; i < cols; i++) { res.columns[i] = sqlite3_column_name(stmt, i); } while (1) { err = sqlite3_step(stmt); if (err == SQLITE_ROW) { // Add the row res.fieldlists.resize(res.rows + 1); res.fieldlists[res.rows].resize(cols); for(int i=0; i < cols; i++) { const char* txt = (const char*)sqlite3_column_text(stmt, i); if (txt) res.fieldlists[res.rows][i] = SQL::Field(txt); } res.rows++; } else if (err == SQLITE_DONE) { query->OnResult(res); break; } else { SQL::Error error(SQL::QREPLY_FAIL, sqlite3_errmsg(conn)); query->OnError(error); break; } } sqlite3_finalize(stmt); } void Submit(SQL::Query* query, const std::string& q) CXX11_OVERRIDE { ServerInstance->Logs->Log(MODNAME, LOG_DEBUG, "Executing SQLite3 query: " + q); Query(query, q); delete query; } void Submit(SQL::Query* query, const std::string& q, const SQL::ParamList& p) CXX11_OVERRIDE { std::string res; unsigned int param = 0; for(std::string::size_type i = 0; i < q.length(); i++) { if (q[i] != '?') res.push_back(q[i]); else { if (param < p.size()) { char* escaped = sqlite3_mprintf("%q", p[param++].c_str()); res.append(escaped); sqlite3_free(escaped); } } } Submit(query, res); } void Submit(SQL::Query* query, const std::string& q, const SQL::ParamMap& p) CXX11_OVERRIDE { std::string res; for(std::string::size_type i = 0; i < q.length(); i++) { if (q[i] != '$') res.push_back(q[i]); else { std::string field; i++; while (i < q.length() && isalnum(q[i])) field.push_back(q[i++]); i--; SQL::ParamMap::const_iterator it = p.find(field); if (it != p.end()) { char* escaped = sqlite3_mprintf("%q", it->second.c_str()); res.append(escaped); sqlite3_free(escaped); } } } Submit(query, res); } }; class ModuleSQLite3 : public Module { ConnMap conns; public: ~ModuleSQLite3() { ClearConns(); } void ClearConns() { for(ConnMap::iterator i = conns.begin(); i != conns.end(); i++) { SQLConn* conn = i->second; ServerInstance->Modules->DelService(*conn); delete conn; } conns.clear(); } void ReadConfig(ConfigStatus& status) CXX11_OVERRIDE { ClearConns(); ConfigTagList tags = ServerInstance->Config->ConfTags("database"); for(ConfigIter i = tags.first; i != tags.second; i++) { if (!stdalgo::string::equalsci(i->second->getString("module"), "sqlite")) continue; SQLConn* conn = new SQLConn(this, i->second); conns.insert(std::make_pair(i->second->getString("id"), conn)); ServerInstance->Modules->AddService(*conn); } } Version GetVersion() CXX11_OVERRIDE { return Version("Provides SQLite3 support", VF_VENDOR); } }; MODULE_INIT(ModuleSQLite3) �����������������������������������������������������������������inspircd-3.4.0/src/modules/extra/m_ssl_gnutls.cpp���������������������������������������������������0000664�0000000�0000000�00000113555�13554550454�0022154�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * InspIRCd -- Internet Relay Chat Daemon * * Copyright (C) 2009-2010 Daniel De Graaf <danieldg@inspircd.org> * Copyright (C) 2008 John Brooks <john.brooks@dereferenced.net> * Copyright (C) 2006-2008 Craig Edwards <craigedwards@brainbox.cc> * Copyright (C) 2007 Dennis Friis <peavey@inspircd.org> * Copyright (C) 2006 Oliver Lupton <oliverlupton@gmail.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/>. */ /// $CompilerFlags: find_compiler_flags("gnutls") /// $CompilerFlags: require_version("gnutls" "1.0" "2.12") execute("libgcrypt-config --cflags" "LIBGCRYPT_CXXFLAGS") /// $LinkerFlags: find_linker_flags("gnutls" "-lgnutls") /// $LinkerFlags: require_version("gnutls" "1.0" "2.12") execute("libgcrypt-config --libs" "LIBGCRYPT_LDFLAGS") /// $PackageInfo: require_system("arch") gnutls pkgconf /// $PackageInfo: require_system("centos") gnutls-devel pkgconfig /// $PackageInfo: require_system("darwin") gnutls pkg-config /// $PackageInfo: require_system("debian") gnutls-bin libgnutls28-dev pkg-config /// $PackageInfo: require_system("ubuntu") gnutls-bin libgnutls-dev pkg-config #include "inspircd.h" #include "modules/ssl.h" #include <memory> #ifdef __GNUC__ # pragma GCC diagnostic push #endif // Fix warnings about the use of commas at end of enumerator lists on C++03. #if defined __clang__ # pragma clang diagnostic ignored "-Wc++11-extensions" #elif defined __GNUC__ # if (__GNUC__ > 4) || ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 8)) # pragma GCC diagnostic ignored "-Wpedantic" # else # pragma GCC diagnostic ignored "-pedantic" # endif #endif #include <gnutls/gnutls.h> #include <gnutls/x509.h> #ifdef __GNUC__ # pragma GCC diagnostic pop #endif // Fix warnings about using std::auto_ptr on C++11 or newer. #pragma GCC diagnostic ignored "-Wdeprecated-declarations" #ifndef GNUTLS_VERSION_NUMBER #define GNUTLS_VERSION_NUMBER LIBGNUTLS_VERSION_NUMBER #define GNUTLS_VERSION LIBGNUTLS_VERSION #endif // Check if the GnuTLS library is at least version major.minor.patch #define INSPIRCD_GNUTLS_HAS_VERSION(major, minor, patch) (GNUTLS_VERSION_NUMBER >= ((major << 16) | (minor << 8) | patch)) #if INSPIRCD_GNUTLS_HAS_VERSION(2, 9, 8) #define GNUTLS_HAS_MAC_GET_ID #include <gnutls/crypto.h> #endif #if INSPIRCD_GNUTLS_HAS_VERSION(2, 12, 0) # define GNUTLS_HAS_RND #else # include <gcrypt.h> #endif #ifdef _WIN32 # pragma comment(lib, "libgnutls-30.lib") #endif // These don't exist in older GnuTLS versions #if INSPIRCD_GNUTLS_HAS_VERSION(2, 1, 7) #define GNUTLS_NEW_PRIO_API #endif enum issl_status { ISSL_NONE, ISSL_HANDSHAKING, ISSL_HANDSHAKEN }; #if INSPIRCD_GNUTLS_HAS_VERSION(2, 12, 0) #define INSPIRCD_GNUTLS_HAS_VECTOR_PUSH #define GNUTLS_NEW_CERT_CALLBACK_API typedef gnutls_retr2_st cert_cb_last_param_type; #else typedef gnutls_retr_st cert_cb_last_param_type; #endif #if INSPIRCD_GNUTLS_HAS_VERSION(3, 3, 5) #define INSPIRCD_GNUTLS_HAS_RECV_PACKET #endif #if INSPIRCD_GNUTLS_HAS_VERSION(2, 99, 0) // The second parameter of gnutls_init() has changed in 2.99.0 from gnutls_connection_end_t to unsigned int // (it became a general flags parameter) and the enum has been deprecated and generates a warning on use. typedef unsigned int inspircd_gnutls_session_init_flags_t; #else typedef gnutls_connection_end_t inspircd_gnutls_session_init_flags_t; #endif #if INSPIRCD_GNUTLS_HAS_VERSION(3, 1, 9) #define INSPIRCD_GNUTLS_HAS_CORK #endif static Module* thismod; class RandGen { public: static void Call(char* buffer, size_t len) { #ifdef GNUTLS_HAS_RND gnutls_rnd(GNUTLS_RND_RANDOM, buffer, len); #else gcry_randomize(buffer, len, GCRY_STRONG_RANDOM); #endif } }; namespace GnuTLS { class Init { public: Init() { gnutls_global_init(); } ~Init() { gnutls_global_deinit(); } }; class Exception : public ModuleException { public: Exception(const std::string& reason) : ModuleException(reason) { } }; void ThrowOnError(int errcode, const char* msg) { if (errcode < 0) { std::string reason = msg; reason.append(" :").append(gnutls_strerror(errcode)); throw Exception(reason); } } /** Used to create a gnutls_datum_t* from a std::string */ class Datum { gnutls_datum_t datum; public: Datum(const std::string& dat) { datum.data = (unsigned char*)dat.data(); datum.size = static_cast<unsigned int>(dat.length()); } const gnutls_datum_t* get() const { return &datum; } }; class Hash { gnutls_digest_algorithm_t hash; public: // Nothing to deallocate, constructor may throw freely Hash(const std::string& hashname) { // As older versions of gnutls can't do this, let's disable it where needed. #ifdef GNUTLS_HAS_MAC_GET_ID // As gnutls_digest_algorithm_t and gnutls_mac_algorithm_t are mapped 1:1, we can do this // There is no gnutls_dig_get_id() at the moment, but it may come later hash = (gnutls_digest_algorithm_t)gnutls_mac_get_id(hashname.c_str()); if (hash == GNUTLS_DIG_UNKNOWN) throw Exception("Unknown hash type " + hashname); // Check if the user is giving us something that is a valid MAC but not digest gnutls_hash_hd_t is_digest; if (gnutls_hash_init(&is_digest, hash) < 0) throw Exception("Unknown hash type " + hashname); gnutls_hash_deinit(is_digest, NULL); #else if (stdalgo::string::equalsci(hashname, "md5")) hash = GNUTLS_DIG_MD5; else if (stdalgo::string::equalsci(hashname, "sha1")) hash = GNUTLS_DIG_SHA1; else if (stdalgo::string::equalsci(hashname, "sha256")) hash = GNUTLS_DIG_SHA256; else throw Exception("Unknown hash type " + hashname); #endif } gnutls_digest_algorithm_t get() const { return hash; } }; class DHParams { gnutls_dh_params_t dh_params; DHParams() { ThrowOnError(gnutls_dh_params_init(&dh_params), "gnutls_dh_params_init() failed"); } public: /** Import */ static std::auto_ptr<DHParams> Import(const std::string& dhstr) { std::auto_ptr<DHParams> dh(new DHParams); int ret = gnutls_dh_params_import_pkcs3(dh->dh_params, Datum(dhstr).get(), GNUTLS_X509_FMT_PEM); ThrowOnError(ret, "Unable to import DH params"); return dh; } ~DHParams() { gnutls_dh_params_deinit(dh_params); } const gnutls_dh_params_t& get() const { return dh_params; } }; class X509Key { /** Ensure that the key is deinited in case the constructor of X509Key throws */ class RAIIKey { public: gnutls_x509_privkey_t key; RAIIKey() { ThrowOnError(gnutls_x509_privkey_init(&key), "gnutls_x509_privkey_init() failed"); } ~RAIIKey() { gnutls_x509_privkey_deinit(key); } } key; public: /** Import */ X509Key(const std::string& keystr) { int ret = gnutls_x509_privkey_import(key.key, Datum(keystr).get(), GNUTLS_X509_FMT_PEM); ThrowOnError(ret, "Unable to import private key"); } gnutls_x509_privkey_t& get() { return key.key; } }; class X509CertList { std::vector<gnutls_x509_crt_t> certs; public: /** Import */ X509CertList(const std::string& certstr) { unsigned int certcount = 3; certs.resize(certcount); Datum datum(certstr); int ret = gnutls_x509_crt_list_import(raw(), &certcount, datum.get(), GNUTLS_X509_FMT_PEM, GNUTLS_X509_CRT_LIST_IMPORT_FAIL_IF_EXCEED); if (ret == GNUTLS_E_SHORT_MEMORY_BUFFER) { // the buffer wasn't big enough to hold all certs but gnutls changed certcount to the number of available certs, // try again with a bigger buffer certs.resize(certcount); ret = gnutls_x509_crt_list_import(raw(), &certcount, datum.get(), GNUTLS_X509_FMT_PEM, GNUTLS_X509_CRT_LIST_IMPORT_FAIL_IF_EXCEED); } ThrowOnError(ret, "Unable to load certificates"); // Resize the vector to the actual number of certs because we rely on its size being correct // when deallocating the certs certs.resize(certcount); } ~X509CertList() { for (std::vector<gnutls_x509_crt_t>::iterator i = certs.begin(); i != certs.end(); ++i) gnutls_x509_crt_deinit(*i); } gnutls_x509_crt_t* raw() { return &certs[0]; } unsigned int size() const { return certs.size(); } }; class X509CRL : public refcountbase { class RAIICRL { public: gnutls_x509_crl_t crl; RAIICRL() { ThrowOnError(gnutls_x509_crl_init(&crl), "gnutls_x509_crl_init() failed"); } ~RAIICRL() { gnutls_x509_crl_deinit(crl); } } crl; public: /** Import */ X509CRL(const std::string& crlstr) { int ret = gnutls_x509_crl_import(get(), Datum(crlstr).get(), GNUTLS_X509_FMT_PEM); ThrowOnError(ret, "Unable to load certificate revocation list"); } gnutls_x509_crl_t& get() { return crl.crl; } }; #ifdef GNUTLS_NEW_PRIO_API class Priority { gnutls_priority_t priority; public: Priority(const std::string& priorities) { // Try to set the priorities for ciphers, kex methods etc. to the user supplied string // If the user did not supply anything then the string is already set to "NORMAL" const char* priocstr = priorities.c_str(); const char* prioerror; int ret = gnutls_priority_init(&priority, priocstr, &prioerror); if (ret < 0) { // gnutls did not understand the user supplied string throw Exception("Unable to initialize priorities to \"" + priorities + "\": " + gnutls_strerror(ret) + " Syntax error at position " + ConvToStr((unsigned int) (prioerror - priocstr))); } } ~Priority() { gnutls_priority_deinit(priority); } void SetupSession(gnutls_session_t sess) { gnutls_priority_set(sess, priority); } static const char* GetDefault() { return "NORMAL:%SERVER_PRECEDENCE:-VERS-SSL3.0"; } static std::string RemoveUnknownTokens(const std::string& prio) { std::string ret; irc::sepstream ss(prio, ':'); for (std::string token; ss.GetToken(token); ) { // Save current position so we can revert later if needed const std::string::size_type prevpos = ret.length(); // Append next token if (!ret.empty()) ret.push_back(':'); ret.append(token); gnutls_priority_t test; if (gnutls_priority_init(&test, ret.c_str(), NULL) < 0) { // The new token broke the priority string, revert to the previously working one ServerInstance->Logs->Log(MODNAME, LOG_DEBUG, "Priority string token not recognized: \"%s\"", token.c_str()); ret.erase(prevpos); } else { // Worked gnutls_priority_deinit(test); } } return ret; } }; #else /** Dummy class, used when gnutls_priority_set() is not available */ class Priority { public: Priority(const std::string& priorities) { if (priorities != GetDefault()) throw Exception("You've set a non-default priority string, but GnuTLS lacks support for it"); } static void SetupSession(gnutls_session_t sess) { // Always set the default priorities gnutls_set_default_priority(sess); } static const char* GetDefault() { return "NORMAL"; } static std::string RemoveUnknownTokens(const std::string& prio) { // We don't do anything here because only NORMAL is accepted return prio; } }; #endif class CertCredentials { /** DH parameters associated with these credentials */ std::auto_ptr<DHParams> dh; protected: gnutls_certificate_credentials_t cred; public: CertCredentials() { ThrowOnError(gnutls_certificate_allocate_credentials(&cred), "Cannot allocate certificate credentials"); } ~CertCredentials() { gnutls_certificate_free_credentials(cred); } /** Associates these credentials with the session */ void SetupSession(gnutls_session_t sess) { gnutls_credentials_set(sess, GNUTLS_CRD_CERTIFICATE, cred); } /** Set the given DH parameters to be used with these credentials */ void SetDH(std::auto_ptr<DHParams>& DH) { dh = DH; gnutls_certificate_set_dh_params(cred, dh->get()); } }; class X509Credentials : public CertCredentials { /** Private key */ X509Key key; /** Certificate list, presented to the peer */ X509CertList certs; /** Trusted CA, may be NULL */ std::auto_ptr<X509CertList> trustedca; /** Certificate revocation list, may be NULL */ std::auto_ptr<X509CRL> crl; static int cert_callback(gnutls_session_t session, const gnutls_datum_t* req_ca_rdn, int nreqs, const gnutls_pk_algorithm_t* sign_algos, int sign_algos_length, cert_cb_last_param_type* st); public: X509Credentials(const std::string& certstr, const std::string& keystr) : key(keystr) , certs(certstr) { // Throwing is ok here, the destructor of Credentials is called in that case int ret = gnutls_certificate_set_x509_key(cred, certs.raw(), certs.size(), key.get()); ThrowOnError(ret, "Unable to set cert/key pair"); #ifdef GNUTLS_NEW_CERT_CALLBACK_API gnutls_certificate_set_retrieve_function(cred, cert_callback); #else gnutls_certificate_client_set_retrieve_function(cred, cert_callback); #endif } /** Sets the trusted CA and the certificate revocation list * to use when verifying certificates */ void SetCA(std::auto_ptr<X509CertList>& certlist, std::auto_ptr<X509CRL>& CRL) { // Do nothing if certlist is NULL if (certlist.get()) { int ret = gnutls_certificate_set_x509_trust(cred, certlist->raw(), certlist->size()); ThrowOnError(ret, "gnutls_certificate_set_x509_trust() failed"); if (CRL.get()) { ret = gnutls_certificate_set_x509_crl(cred, &CRL->get(), 1); ThrowOnError(ret, "gnutls_certificate_set_x509_crl() failed"); } trustedca = certlist; crl = CRL; } } }; class DataReader { int retval; #ifdef INSPIRCD_GNUTLS_HAS_RECV_PACKET gnutls_packet_t packet; public: DataReader(gnutls_session_t sess) { // Using the packet API avoids the final copy of the data which GnuTLS does if we supply // our own buffer. Instead, we get the buffer containing the data from GnuTLS and copy it // to the recvq directly from there in appendto(). retval = gnutls_record_recv_packet(sess, &packet); } void appendto(std::string& recvq) { // Copy data from GnuTLS buffers to recvq gnutls_datum_t datum; gnutls_packet_get(packet, &datum, NULL); recvq.append(reinterpret_cast<const char*>(datum.data), datum.size); gnutls_packet_deinit(packet); } #else char* const buffer; public: DataReader(gnutls_session_t sess) : buffer(ServerInstance->GetReadBuffer()) { // Read data from GnuTLS buffers into ReadBuffer retval = gnutls_record_recv(sess, buffer, ServerInstance->Config->NetBufferSize); } void appendto(std::string& recvq) { // Copy data from ReadBuffer to recvq recvq.append(buffer, retval); } #endif int ret() const { return retval; } }; class Profile { /** Name of this profile */ const std::string name; /** X509 certificate(s) and key */ X509Credentials x509cred; /** The minimum length in bits for the DH prime to be accepted as a client */ unsigned int min_dh_bits; /** Hashing algorithm to use when generating certificate fingerprints */ Hash hash; /** Priorities for ciphers, compression methods, etc. */ Priority priority; /** Rough max size of records to send */ const unsigned int outrecsize; /** True to request a client certificate as a server */ const bool requestclientcert; static std::string ReadFile(const std::string& filename) { FileReader reader(filename); std::string ret = reader.GetString(); if (ret.empty()) throw Exception("Cannot read file " + filename); return ret; } static std::string GetPrioStr(const std::string& profilename, ConfigTag* tag) { // Use default priority string if this tag does not specify one std::string priostr = GnuTLS::Priority::GetDefault(); bool found = tag->readString("priority", priostr); // If the prio string isn't set in the config don't be strict about the default one because it doesn't work on all versions of GnuTLS if (!tag->getBool("strictpriority", found)) { std::string stripped = GnuTLS::Priority::RemoveUnknownTokens(priostr); if (stripped.empty()) { // Stripping failed, act as if a prio string wasn't set stripped = GnuTLS::Priority::RemoveUnknownTokens(GnuTLS::Priority::GetDefault()); ServerInstance->Logs->Log(MODNAME, LOG_DEFAULT, "Priority string for profile \"%s\" contains unknown tokens and stripping it didn't yield a working one either, falling back to \"%s\"", profilename.c_str(), stripped.c_str()); } else if ((found) && (stripped != priostr)) { // Prio string was set in the config and we ended up with something that works but different ServerInstance->Logs->Log(MODNAME, LOG_DEFAULT, "Priority string for profile \"%s\" contains unknown tokens, stripped to \"%s\"", profilename.c_str(), stripped.c_str()); } priostr.swap(stripped); } return priostr; } public: struct Config { std::string name; std::auto_ptr<X509CertList> ca; std::auto_ptr<X509CRL> crl; std::string certstr; std::string keystr; std::auto_ptr<DHParams> dh; std::string priostr; unsigned int mindh; std::string hashstr; unsigned int outrecsize; bool requestclientcert; Config(const std::string& profilename, ConfigTag* tag) : name(profilename) , certstr(ReadFile(tag->getString("certfile", "cert.pem"))) , keystr(ReadFile(tag->getString("keyfile", "key.pem"))) , dh(DHParams::Import(ReadFile(tag->getString("dhfile", "dhparams.pem")))) , priostr(GetPrioStr(profilename, tag)) , mindh(tag->getUInt("mindhbits", 1024)) , hashstr(tag->getString("hash", "md5")) , requestclientcert(tag->getBool("requestclientcert", true)) { // Load trusted CA and revocation list, if set std::string filename = tag->getString("cafile"); if (!filename.empty()) { ca.reset(new X509CertList(ReadFile(filename))); filename = tag->getString("crlfile"); if (!filename.empty()) crl.reset(new X509CRL(ReadFile(filename))); } #ifdef INSPIRCD_GNUTLS_HAS_CORK // If cork support is available outrecsize represents the (rough) max amount of data we give GnuTLS while corked outrecsize = tag->getUInt("outrecsize", 2048, 512); #else outrecsize = tag->getUInt("outrecsize", 2048, 512, 16384); #endif } }; Profile(Config& config) : name(config.name) , x509cred(config.certstr, config.keystr) , min_dh_bits(config.mindh) , hash(config.hashstr) , priority(config.priostr) , outrecsize(config.outrecsize) , requestclientcert(config.requestclientcert) { x509cred.SetDH(config.dh); x509cred.SetCA(config.ca, config.crl); } /** Set up the given session with the settings in this profile */ void SetupSession(gnutls_session_t sess) { priority.SetupSession(sess); x509cred.SetupSession(sess); gnutls_dh_set_prime_bits(sess, min_dh_bits); // Request client certificate if enabled and we are a server, no-op if we're a client if (requestclientcert) gnutls_certificate_server_set_request(sess, GNUTLS_CERT_REQUEST); } const std::string& GetName() const { return name; } X509Credentials& GetX509Credentials() { return x509cred; } gnutls_digest_algorithm_t GetHash() const { return hash.get(); } unsigned int GetOutgoingRecordSize() const { return outrecsize; } }; } class GnuTLSIOHook : public SSLIOHook { private: gnutls_session_t sess; issl_status status; #ifdef INSPIRCD_GNUTLS_HAS_CORK size_t gbuffersize; #endif void CloseSession() { if (this->sess) { gnutls_bye(this->sess, GNUTLS_SHUT_WR); gnutls_deinit(this->sess); } sess = NULL; certificate = NULL; status = ISSL_NONE; } // Returns 1 if handshake succeeded, 0 if it is still in progress, -1 if it failed int Handshake(StreamSocket* user) { int ret = gnutls_handshake(this->sess); if (ret < 0) { if(ret == GNUTLS_E_AGAIN || ret == GNUTLS_E_INTERRUPTED) { // Handshake needs resuming later, read() or write() would have blocked. this->status = ISSL_HANDSHAKING; if (gnutls_record_get_direction(this->sess) == 0) { // gnutls_handshake() wants to read() again. SocketEngine::ChangeEventMask(user, FD_WANT_POLL_READ | FD_WANT_NO_WRITE); } else { // gnutls_handshake() wants to write() again. SocketEngine::ChangeEventMask(user, FD_WANT_NO_READ | FD_WANT_SINGLE_WRITE); } return 0; } else { user->SetError("Handshake Failed - " + std::string(gnutls_strerror(ret))); CloseSession(); return -1; } } else { // Change the seesion state this->status = ISSL_HANDSHAKEN; VerifyCertificate(); // Finish writing, if any left SocketEngine::ChangeEventMask(user, FD_WANT_POLL_READ | FD_WANT_NO_WRITE | FD_ADD_TRIAL_WRITE); return 1; } } void VerifyCertificate() { unsigned int certstatus; const gnutls_datum_t* cert_list; int ret; unsigned int cert_list_size; gnutls_x509_crt_t cert; char str[512]; unsigned char digest[512]; size_t digest_size = sizeof(digest); size_t name_size = sizeof(str); ssl_cert* certinfo = new ssl_cert; this->certificate = certinfo; /* This verification function uses the trusted CAs in the credentials * structure. So you must have installed one or more CA certificates. */ ret = gnutls_certificate_verify_peers2(this->sess, &certstatus); if (ret < 0) { certinfo->error = std::string(gnutls_strerror(ret)); return; } certinfo->invalid = (certstatus & GNUTLS_CERT_INVALID); certinfo->unknownsigner = (certstatus & GNUTLS_CERT_SIGNER_NOT_FOUND); certinfo->revoked = (certstatus & GNUTLS_CERT_REVOKED); certinfo->trusted = !(certstatus & GNUTLS_CERT_SIGNER_NOT_CA); /* Up to here the process is the same for X.509 certificates and * OpenPGP keys. From now on X.509 certificates are assumed. This can * be easily extended to work with openpgp keys as well. */ if (gnutls_certificate_type_get(this->sess) != GNUTLS_CRT_X509) { certinfo->error = "No X509 keys sent"; return; } ret = gnutls_x509_crt_init(&cert); if (ret < 0) { certinfo->error = gnutls_strerror(ret); return; } cert_list_size = 0; cert_list = gnutls_certificate_get_peers(this->sess, &cert_list_size); if (cert_list == NULL) { certinfo->error = "No certificate was found"; goto info_done_dealloc; } /* This is not a real world example, since we only check the first * certificate in the given chain. */ ret = gnutls_x509_crt_import(cert, &cert_list[0], GNUTLS_X509_FMT_DER); if (ret < 0) { certinfo->error = gnutls_strerror(ret); goto info_done_dealloc; } if (gnutls_x509_crt_get_dn(cert, str, &name_size) == 0) { std::string& dn = certinfo->dn; dn = str; // Make sure there are no chars in the string that we consider invalid if (dn.find_first_of("\r\n") != std::string::npos) dn.clear(); } name_size = sizeof(str); if (gnutls_x509_crt_get_issuer_dn(cert, str, &name_size) == 0) { std::string& issuer = certinfo->issuer; issuer = str; if (issuer.find_first_of("\r\n") != std::string::npos) issuer.clear(); } if ((ret = gnutls_x509_crt_get_fingerprint(cert, GetProfile().GetHash(), digest, &digest_size)) < 0) { certinfo->error = gnutls_strerror(ret); } else { certinfo->fingerprint = BinToHex(digest, digest_size); } /* Beware here we do not check for errors. */ if ((gnutls_x509_crt_get_expiration_time(cert) < ServerInstance->Time()) || (gnutls_x509_crt_get_activation_time(cert) > ServerInstance->Time())) { certinfo->error = "Not activated, or expired certificate"; } info_done_dealloc: gnutls_x509_crt_deinit(cert); } // Returns 1 if application I/O should proceed, 0 if it must wait for the underlying protocol to progress, -1 on fatal error int PrepareIO(StreamSocket* sock) { if (status == ISSL_HANDSHAKEN) return 1; else if (status == ISSL_HANDSHAKING) { // The handshake isn't finished, try to finish it return Handshake(sock); } CloseSession(); sock->SetError("No SSL session"); return -1; } #ifdef INSPIRCD_GNUTLS_HAS_CORK int FlushBuffer(StreamSocket* sock) { // If GnuTLS has some data buffered, write it if (gbuffersize) return HandleWriteRet(sock, gnutls_record_uncork(this->sess, 0)); return 1; } #endif int HandleWriteRet(StreamSocket* sock, int ret) { if (ret > 0) { #ifdef INSPIRCD_GNUTLS_HAS_CORK gbuffersize -= ret; if (gbuffersize) { SocketEngine::ChangeEventMask(sock, FD_WANT_SINGLE_WRITE); return 0; } #endif return ret; } else if (ret == GNUTLS_E_AGAIN || ret == GNUTLS_E_INTERRUPTED || ret == 0) { SocketEngine::ChangeEventMask(sock, FD_WANT_SINGLE_WRITE); return 0; } else // (ret < 0) { sock->SetError(gnutls_strerror(ret)); CloseSession(); return -1; } } static const char* UnknownIfNULL(const char* str) { return str ? str : "UNKNOWN"; } static ssize_t gnutls_pull_wrapper(gnutls_transport_ptr_t session_wrap, void* buffer, size_t size) { StreamSocket* sock = reinterpret_cast<StreamSocket*>(session_wrap); #ifdef _WIN32 GnuTLSIOHook* session = static_cast<GnuTLSIOHook*>(sock->GetModHook(thismod)); #endif if (sock->GetEventMask() & FD_READ_WILL_BLOCK) { #ifdef _WIN32 gnutls_transport_set_errno(session->sess, EAGAIN); #else errno = EAGAIN; #endif return -1; } int rv = SocketEngine::Recv(sock, reinterpret_cast<char *>(buffer), size, 0); #ifdef _WIN32 if (rv < 0) { /* Windows doesn't use errno, but gnutls does, so check SocketEngine::IgnoreError() * and then set errno appropriately. * The gnutls library may also have a different errno variable than us, see * gnutls_transport_set_errno(3). */ gnutls_transport_set_errno(session->sess, SocketEngine::IgnoreError() ? EAGAIN : errno); } #endif if (rv < (int)size) SocketEngine::ChangeEventMask(sock, FD_READ_WILL_BLOCK); return rv; } #ifdef INSPIRCD_GNUTLS_HAS_VECTOR_PUSH static ssize_t VectorPush(gnutls_transport_ptr_t transportptr, const giovec_t* iov, int iovcnt) { StreamSocket* sock = reinterpret_cast<StreamSocket*>(transportptr); #ifdef _WIN32 GnuTLSIOHook* session = static_cast<GnuTLSIOHook*>(sock->GetModHook(thismod)); #endif if (sock->GetEventMask() & FD_WRITE_WILL_BLOCK) { #ifdef _WIN32 gnutls_transport_set_errno(session->sess, EAGAIN); #else errno = EAGAIN; #endif return -1; } // Cast the giovec_t to iovec not to IOVector so the correct function is called on Windows int ret = SocketEngine::WriteV(sock, reinterpret_cast<const iovec*>(iov), iovcnt); #ifdef _WIN32 // See the function above for more info about the usage of gnutls_transport_set_errno() on Windows if (ret < 0) gnutls_transport_set_errno(session->sess, SocketEngine::IgnoreError() ? EAGAIN : errno); #endif int size = 0; for (int i = 0; i < iovcnt; i++) size += iov[i].iov_len; if (ret < size) SocketEngine::ChangeEventMask(sock, FD_WRITE_WILL_BLOCK); return ret; } #else // INSPIRCD_GNUTLS_HAS_VECTOR_PUSH static ssize_t gnutls_push_wrapper(gnutls_transport_ptr_t session_wrap, const void* buffer, size_t size) { StreamSocket* sock = reinterpret_cast<StreamSocket*>(session_wrap); #ifdef _WIN32 GnuTLSIOHook* session = static_cast<GnuTLSIOHook*>(sock->GetModHook(thismod)); #endif if (sock->GetEventMask() & FD_WRITE_WILL_BLOCK) { #ifdef _WIN32 gnutls_transport_set_errno(session->sess, EAGAIN); #else errno = EAGAIN; #endif return -1; } int rv = SocketEngine::Send(sock, reinterpret_cast<const char *>(buffer), size, 0); #ifdef _WIN32 if (rv < 0) { /* Windows doesn't use errno, but gnutls does, so check SocketEngine::IgnoreError() * and then set errno appropriately. * The gnutls library may also have a different errno variable than us, see * gnutls_transport_set_errno(3). */ gnutls_transport_set_errno(session->sess, SocketEngine::IgnoreError() ? EAGAIN : errno); } #endif if (rv < (int)size) SocketEngine::ChangeEventMask(sock, FD_WRITE_WILL_BLOCK); return rv; } #endif // INSPIRCD_GNUTLS_HAS_VECTOR_PUSH public: GnuTLSIOHook(IOHookProvider* hookprov, StreamSocket* sock, inspircd_gnutls_session_init_flags_t flags) : SSLIOHook(hookprov) , sess(NULL) , status(ISSL_NONE) #ifdef INSPIRCD_GNUTLS_HAS_CORK , gbuffersize(0) #endif { gnutls_init(&sess, flags); gnutls_transport_set_ptr(sess, reinterpret_cast<gnutls_transport_ptr_t>(sock)); #ifdef INSPIRCD_GNUTLS_HAS_VECTOR_PUSH gnutls_transport_set_vec_push_function(sess, VectorPush); #else gnutls_transport_set_push_function(sess, gnutls_push_wrapper); #endif gnutls_transport_set_pull_function(sess, gnutls_pull_wrapper); GetProfile().SetupSession(sess); sock->AddIOHook(this); Handshake(sock); } void OnStreamSocketClose(StreamSocket* user) CXX11_OVERRIDE { CloseSession(); } int OnStreamSocketRead(StreamSocket* user, std::string& recvq) CXX11_OVERRIDE { // Finish handshake if needed int prepret = PrepareIO(user); if (prepret <= 0) return prepret; // If we resumed the handshake then this->status will be ISSL_HANDSHAKEN. { GnuTLS::DataReader reader(sess); int ret = reader.ret(); if (ret > 0) { reader.appendto(recvq); // Schedule a read if there is still data in the GnuTLS buffer if (gnutls_record_check_pending(sess) > 0) SocketEngine::ChangeEventMask(user, FD_ADD_TRIAL_READ); return 1; } else if (ret == GNUTLS_E_AGAIN || ret == GNUTLS_E_INTERRUPTED) { return 0; } else if (ret == 0) { user->SetError("Connection closed"); CloseSession(); return -1; } else { user->SetError(gnutls_strerror(ret)); CloseSession(); return -1; } } } int OnStreamSocketWrite(StreamSocket* user, StreamSocket::SendQueue& sendq) CXX11_OVERRIDE { // Finish handshake if needed int prepret = PrepareIO(user); if (prepret <= 0) return prepret; // Session is ready for transferring application data #ifdef INSPIRCD_GNUTLS_HAS_CORK while (true) { // If there is something in the GnuTLS buffer try to send() it int ret = FlushBuffer(user); if (ret <= 0) return ret; // Couldn't flush entire buffer, retry later (or close on error) // GnuTLS buffer is empty, if the sendq is empty as well then break to set FD_WANT_NO_WRITE if (sendq.empty()) break; // GnuTLS buffer is empty but sendq is not, begin sending data from the sendq gnutls_record_cork(this->sess); while ((!sendq.empty()) && (gbuffersize < GetProfile().GetOutgoingRecordSize())) { const StreamSocket::SendQueue::Element& elem = sendq.front(); gbuffersize += elem.length(); ret = gnutls_record_send(this->sess, elem.data(), elem.length()); if (ret < 0) { CloseSession(); return -1; } sendq.pop_front(); } } #else int ret = 0; while (!sendq.empty()) { FlattenSendQueue(sendq, GetProfile().GetOutgoingRecordSize()); const StreamSocket::SendQueue::Element& buffer = sendq.front(); ret = HandleWriteRet(user, gnutls_record_send(this->sess, buffer.data(), buffer.length())); if (ret <= 0) return ret; else if (ret < (int)buffer.length()) { sendq.erase_front(ret); SocketEngine::ChangeEventMask(user, FD_WANT_SINGLE_WRITE); return 0; } // Wrote entire record, continue sending sendq.pop_front(); } #endif SocketEngine::ChangeEventMask(user, FD_WANT_NO_WRITE); return 1; } void GetCiphersuite(std::string& out) const CXX11_OVERRIDE { if (!IsHandshakeDone()) return; out.append(UnknownIfNULL(gnutls_protocol_get_name(gnutls_protocol_get_version(sess)))).push_back('-'); out.append(UnknownIfNULL(gnutls_kx_get_name(gnutls_kx_get(sess)))).push_back('-'); out.append(UnknownIfNULL(gnutls_cipher_get_name(gnutls_cipher_get(sess)))).push_back('-'); out.append(UnknownIfNULL(gnutls_mac_get_name(gnutls_mac_get(sess)))); } bool GetServerName(std::string& out) const CXX11_OVERRIDE { std::vector<char> nameBuffer; size_t nameLength = 0; unsigned int nameType = GNUTLS_NAME_DNS; // First, determine the size of the hostname. if (gnutls_server_name_get(sess, &nameBuffer[0], &nameLength, &nameType, 0) != GNUTLS_E_SHORT_MEMORY_BUFFER) return false; // Then retrieve the hostname. nameBuffer.resize(nameLength); if (gnutls_server_name_get(sess, &nameBuffer[0], &nameLength, &nameType, 0) != GNUTLS_E_SUCCESS) return false; out.append(&nameBuffer[0]); return true; } GnuTLS::Profile& GetProfile(); bool IsHandshakeDone() const { return (status == ISSL_HANDSHAKEN); } }; int GnuTLS::X509Credentials::cert_callback(gnutls_session_t sess, const gnutls_datum_t* req_ca_rdn, int nreqs, const gnutls_pk_algorithm_t* sign_algos, int sign_algos_length, cert_cb_last_param_type* st) { #ifndef GNUTLS_NEW_CERT_CALLBACK_API st->type = GNUTLS_CRT_X509; #else st->cert_type = GNUTLS_CRT_X509; st->key_type = GNUTLS_PRIVKEY_X509; #endif StreamSocket* sock = reinterpret_cast<StreamSocket*>(gnutls_transport_get_ptr(sess)); GnuTLS::X509Credentials& cred = static_cast<GnuTLSIOHook*>(sock->GetModHook(thismod))->GetProfile().GetX509Credentials(); st->ncerts = cred.certs.size(); st->cert.x509 = cred.certs.raw(); st->key.x509 = cred.key.get(); st->deinit_all = 0; return 0; } class GnuTLSIOHookProvider : public IOHookProvider { GnuTLS::Profile profile; public: GnuTLSIOHookProvider(Module* mod, GnuTLS::Profile::Config& config) : IOHookProvider(mod, "ssl/" + config.name, IOHookProvider::IOH_SSL) , profile(config) { ServerInstance->Modules->AddService(*this); } ~GnuTLSIOHookProvider() { ServerInstance->Modules->DelService(*this); } void OnAccept(StreamSocket* sock, irc::sockets::sockaddrs* client, irc::sockets::sockaddrs* server) CXX11_OVERRIDE { new GnuTLSIOHook(this, sock, GNUTLS_SERVER); } void OnConnect(StreamSocket* sock) CXX11_OVERRIDE { new GnuTLSIOHook(this, sock, GNUTLS_CLIENT); } GnuTLS::Profile& GetProfile() { return profile; } }; GnuTLS::Profile& GnuTLSIOHook::GetProfile() { IOHookProvider* hookprov = prov; return static_cast<GnuTLSIOHookProvider*>(hookprov)->GetProfile(); } class ModuleSSLGnuTLS : public Module { typedef std::vector<reference<GnuTLSIOHookProvider> > ProfileList; // First member of the class, gets constructed first and destructed last GnuTLS::Init libinit; ProfileList profiles; void ReadProfiles() { // First, store all profiles in a new, temporary container. If no problems occur, swap the two // containers; this way if something goes wrong we can go back and continue using the current profiles, // avoiding unpleasant situations where no new SSL connections are possible. ProfileList newprofiles; ConfigTagList tags = ServerInstance->Config->ConfTags("sslprofile"); if (tags.first == tags.second) { // No <sslprofile> tags found, create a profile named "gnutls" from settings in the <gnutls> block const std::string defname = "gnutls"; ConfigTag* tag = ServerInstance->Config->ConfValue(defname); ServerInstance->Logs->Log(MODNAME, LOG_DEFAULT, "No <sslprofile> tags found; using settings from the <gnutls> tag"); try { GnuTLS::Profile::Config profileconfig(defname, tag); newprofiles.push_back(new GnuTLSIOHookProvider(this, profileconfig)); } catch (CoreException& ex) { throw ModuleException("Error while initializing the default SSL profile - " + ex.GetReason()); } } for (ConfigIter i = tags.first; i != tags.second; ++i) { ConfigTag* tag = i->second; if (!stdalgo::string::equalsci(tag->getString("provider"), "gnutls")) continue; std::string name = tag->getString("name"); if (name.empty()) { ServerInstance->Logs->Log(MODNAME, LOG_DEFAULT, "Ignoring <sslprofile> tag without name at " + tag->getTagLocation()); continue; } reference<GnuTLSIOHookProvider> prov; try { GnuTLS::Profile::Config profileconfig(name, tag); prov = new GnuTLSIOHookProvider(this, profileconfig); } catch (CoreException& ex) { throw ModuleException("Error while initializing SSL profile \"" + name + "\" at " + tag->getTagLocation() + " - " + ex.GetReason()); } newprofiles.push_back(prov); } // New profiles are ok, begin using them // Old profiles are deleted when their refcount drops to zero for (ProfileList::iterator i = profiles.begin(); i != profiles.end(); ++i) { GnuTLSIOHookProvider& prov = **i; ServerInstance->Modules.DelService(prov); } profiles.swap(newprofiles); } public: ModuleSSLGnuTLS() { #ifndef GNUTLS_HAS_RND gcry_control (GCRYCTL_INITIALIZATION_FINISHED, 0); #endif thismod = this; } void init() CXX11_OVERRIDE { ServerInstance->Logs->Log(MODNAME, LOG_DEFAULT, "GnuTLS lib version %s module was compiled for " GNUTLS_VERSION, gnutls_check_version(NULL)); ReadProfiles(); ServerInstance->GenRandom = RandGen::Call; } void OnModuleRehash(User* user, const std::string &param) CXX11_OVERRIDE { if(param != "ssl") return; try { ReadProfiles(); } catch (ModuleException& ex) { ServerInstance->Logs->Log(MODNAME, LOG_DEFAULT, ex.GetReason() + " Not applying settings."); } } ~ModuleSSLGnuTLS() { ServerInstance->GenRandom = &InspIRCd::DefaultGenRandom; } void OnCleanup(ExtensionItem::ExtensibleType type, Extensible* item) CXX11_OVERRIDE { if (type == ExtensionItem::EXT_USER) { LocalUser* user = IS_LOCAL(static_cast<User*>(item)); if ((user) && (user->eh.GetModHook(this))) { // User is using SSL, they're a local user, and they're using one of *our* SSL ports. // Potentially there could be multiple SSL modules loaded at once on different ports. ServerInstance->Users->QuitUser(user, "SSL module unloading"); } } } Version GetVersion() CXX11_OVERRIDE { return Version("Provides SSL support via GnuTLS", VF_VENDOR); } ModResult OnCheckReady(LocalUser* user) CXX11_OVERRIDE { const GnuTLSIOHook* const iohook = static_cast<GnuTLSIOHook*>(user->eh.GetModHook(this)); if ((iohook) && (!iohook->IsHandshakeDone())) return MOD_RES_DENY; return MOD_RES_PASSTHRU; } }; MODULE_INIT(ModuleSSLGnuTLS) ���������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/src/modules/extra/m_ssl_mbedtls.cpp��������������������������������������������������0000664�0000000�0000000�00000062161�13554550454�0022266�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * InspIRCd -- Internet Relay Chat Daemon * * Copyright (C) 2016 Attila Molnar <attilamolnar@hush.com> * * This file is part of InspIRCd. InspIRCd is free software: you can * redistribute it and/or modify it under the terms of the GNU General Public * License as published by the Free Software Foundation, version 2. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ /// $LinkerFlags: -lmbedtls /// $PackageInfo: require_system("arch") mbedtls /// $PackageInfo: require_system("darwin") mbedtls /// $PackageInfo: require_system("debian" "9.0") libmbedtls-dev /// $PackageInfo: require_system("ubuntu" "16.04") libmbedtls-dev #include "inspircd.h" #include "modules/ssl.h" #include <mbedtls/ctr_drbg.h> #include <mbedtls/dhm.h> #include <mbedtls/ecp.h> #include <mbedtls/entropy.h> #include <mbedtls/error.h> #include <mbedtls/md.h> #include <mbedtls/pk.h> #include <mbedtls/ssl.h> #include <mbedtls/ssl_ciphersuites.h> #include <mbedtls/version.h> #include <mbedtls/x509.h> #include <mbedtls/x509_crt.h> #include <mbedtls/x509_crl.h> #ifdef INSPIRCD_MBEDTLS_LIBRARY_DEBUG #include <mbedtls/debug.h> #endif namespace mbedTLS { class Exception : public ModuleException { public: Exception(const std::string& reason) : ModuleException(reason) { } }; std::string ErrorToString(int errcode) { char buf[256]; mbedtls_strerror(errcode, buf, sizeof(buf)); return buf; } void ThrowOnError(int errcode, const char* msg) { if (errcode != 0) { std::string reason = msg; reason.append(" :").append(ErrorToString(errcode)); throw Exception(reason); } } template <typename T, void (*init)(T*), void (*deinit)(T*)> class RAIIObj { T obj; public: RAIIObj() { init(&obj); } ~RAIIObj() { deinit(&obj); } T* get() { return &obj; } const T* get() const { return &obj; } }; typedef RAIIObj<mbedtls_entropy_context, mbedtls_entropy_init, mbedtls_entropy_free> Entropy; class CTRDRBG : private RAIIObj<mbedtls_ctr_drbg_context, mbedtls_ctr_drbg_init, mbedtls_ctr_drbg_free> { public: bool Seed(Entropy& entropy) { return (mbedtls_ctr_drbg_seed(get(), mbedtls_entropy_func, entropy.get(), NULL, 0) == 0); } void SetupConf(mbedtls_ssl_config* conf) { mbedtls_ssl_conf_rng(conf, mbedtls_ctr_drbg_random, get()); } }; class DHParams : public RAIIObj<mbedtls_dhm_context, mbedtls_dhm_init, mbedtls_dhm_free> { public: void set(const std::string& dhstr) { // Last parameter is buffer size, must include the terminating null int ret = mbedtls_dhm_parse_dhm(get(), reinterpret_cast<const unsigned char*>(dhstr.c_str()), dhstr.size()+1); ThrowOnError(ret, "Unable to import DH params"); } }; class X509Key : public RAIIObj<mbedtls_pk_context, mbedtls_pk_init, mbedtls_pk_free> { public: /** Import */ X509Key(const std::string& keystr) { int ret = mbedtls_pk_parse_key(get(), reinterpret_cast<const unsigned char*>(keystr.c_str()), keystr.size()+1, NULL, 0); ThrowOnError(ret, "Unable to import private key"); } }; class Ciphersuites { std::vector<int> list; public: Ciphersuites(const std::string& str) { // mbedTLS uses the ciphersuite format "TLS-ECDHE-RSA-WITH-AES-128-GCM-SHA256" internally. // This is a bit verbose, so we make life a bit simpler for admins by not requiring them to supply the static parts. irc::sepstream ss(str, ':'); for (std::string token; ss.GetToken(token); ) { // Prepend "TLS-" if not there if (token.compare(0, 4, "TLS-", 4)) token.insert(0, "TLS-"); const int id = mbedtls_ssl_get_ciphersuite_id(token.c_str()); if (!id) throw Exception("Unknown ciphersuite " + token); list.push_back(id); } list.push_back(0); } const int* get() const { return &list.front(); } bool empty() const { return (list.size() <= 1); } }; class Curves { std::vector<mbedtls_ecp_group_id> list; public: Curves(const std::string& str) { irc::sepstream ss(str, ':'); for (std::string token; ss.GetToken(token); ) { const mbedtls_ecp_curve_info* curve = mbedtls_ecp_curve_info_from_name(token.c_str()); if (!curve) throw Exception("Unknown curve " + token); list.push_back(curve->grp_id); } list.push_back(MBEDTLS_ECP_DP_NONE); } const mbedtls_ecp_group_id* get() const { return &list.front(); } bool empty() const { return (list.size() <= 1); } }; class X509CertList : public RAIIObj<mbedtls_x509_crt, mbedtls_x509_crt_init, mbedtls_x509_crt_free> { public: /** Import or create empty */ X509CertList(const std::string& certstr, bool allowempty = false) { if ((allowempty) && (certstr.empty())) return; int ret = mbedtls_x509_crt_parse(get(), reinterpret_cast<const unsigned char*>(certstr.c_str()), certstr.size()+1); ThrowOnError(ret, "Unable to load certificates"); } bool empty() const { return (get()->raw.p != NULL); } }; class X509CRL : public RAIIObj<mbedtls_x509_crl, mbedtls_x509_crl_init, mbedtls_x509_crl_free> { public: X509CRL(const std::string& crlstr) { if (crlstr.empty()) return; int ret = mbedtls_x509_crl_parse(get(), reinterpret_cast<const unsigned char*>(crlstr.c_str()), crlstr.size()+1); ThrowOnError(ret, "Unable to load CRL"); } }; class X509Credentials { /** Private key */ X509Key key; /** Certificate list, presented to the peer */ X509CertList certs; public: X509Credentials(const std::string& certstr, const std::string& keystr) : key(keystr) , certs(certstr) { // Verify that one of the certs match the private key bool found = false; for (mbedtls_x509_crt* cert = certs.get(); cert; cert = cert->next) { if (mbedtls_pk_check_pair(&cert->pk, key.get()) == 0) { found = true; break; } } if (!found) throw Exception("Public/private key pair does not match"); } mbedtls_pk_context* getkey() { return key.get(); } mbedtls_x509_crt* getcerts() { return certs.get(); } }; class Context { mbedtls_ssl_config conf; #ifdef INSPIRCD_MBEDTLS_LIBRARY_DEBUG static void DebugLogFunc(void* userptr, int level, const char* file, int line, const char* msg) { // Remove trailing \n size_t len = strlen(msg); if ((len > 0) && (msg[len-1] == '\n')) len--; ServerInstance->Logs->Log(MODNAME, LOG_DEBUG, "%s:%d %.*s", file, line, len, msg); } #endif public: Context(CTRDRBG& ctrdrbg, unsigned int endpoint) { mbedtls_ssl_config_init(&conf); #ifdef INSPIRCD_MBEDTLS_LIBRARY_DEBUG mbedtls_debug_set_threshold(INT_MAX); mbedtls_ssl_conf_dbg(&conf, DebugLogFunc, NULL); #endif // TODO: check ret of mbedtls_ssl_config_defaults mbedtls_ssl_config_defaults(&conf, endpoint, MBEDTLS_SSL_TRANSPORT_STREAM, MBEDTLS_SSL_PRESET_DEFAULT); ctrdrbg.SetupConf(&conf); } ~Context() { mbedtls_ssl_config_free(&conf); } void SetMinDHBits(unsigned int mindh) { mbedtls_ssl_conf_dhm_min_bitlen(&conf, mindh); } void SetDHParams(DHParams& dh) { mbedtls_ssl_conf_dh_param_ctx(&conf, dh.get()); } void SetX509CertAndKey(X509Credentials& x509cred) { mbedtls_ssl_conf_own_cert(&conf, x509cred.getcerts(), x509cred.getkey()); } void SetCiphersuites(const Ciphersuites& ciphersuites) { mbedtls_ssl_conf_ciphersuites(&conf, ciphersuites.get()); } void SetCurves(const Curves& curves) { mbedtls_ssl_conf_curves(&conf, curves.get()); } void SetVersion(int minver, int maxver) { // SSL v3 support cannot be enabled if (minver) mbedtls_ssl_conf_min_version(&conf, MBEDTLS_SSL_MAJOR_VERSION_3, minver); if (maxver) mbedtls_ssl_conf_max_version(&conf, MBEDTLS_SSL_MAJOR_VERSION_3, maxver); } void SetCA(X509CertList& certs, X509CRL& crl) { mbedtls_ssl_conf_ca_chain(&conf, certs.get(), crl.get()); } void SetOptionalVerifyCert() { mbedtls_ssl_conf_authmode(&conf, MBEDTLS_SSL_VERIFY_OPTIONAL); } const mbedtls_ssl_config* GetConf() const { return &conf; } }; class Hash { const mbedtls_md_info_t* md; /** Buffer where cert hashes are written temporarily */ mutable std::vector<unsigned char> buf; public: Hash(std::string hashstr) { std::transform(hashstr.begin(), hashstr.end(), hashstr.begin(), ::toupper); md = mbedtls_md_info_from_string(hashstr.c_str()); if (!md) throw Exception("Unknown hash: " + hashstr); buf.resize(mbedtls_md_get_size(md)); } std::string hash(const unsigned char* input, size_t length) const { mbedtls_md(md, input, length, &buf.front()); return BinToHex(&buf.front(), buf.size()); } }; class Profile { /** Name of this profile */ const std::string name; X509Credentials x509cred; /** Ciphersuites to use */ Ciphersuites ciphersuites; /** Curves accepted for use in ECDHE and in the peer's end-entity certificate */ Curves curves; Context serverctx; Context clientctx; DHParams dhparams; X509CertList cacerts; X509CRL crl; /** Hashing algorithm to use when generating certificate fingerprints */ Hash hash; /** Rough max size of records to send */ const unsigned int outrecsize; public: struct Config { const std::string name; CTRDRBG& ctrdrbg; const std::string certstr; const std::string keystr; const std::string dhstr; const std::string ciphersuitestr; const std::string curvestr; const unsigned int mindh; const std::string hashstr; std::string crlstr; std::string castr; const int minver; const int maxver; const unsigned int outrecsize; const bool requestclientcert; Config(const std::string& profilename, ConfigTag* tag, CTRDRBG& ctr_drbg) : name(profilename) , ctrdrbg(ctr_drbg) , certstr(ReadFile(tag->getString("certfile", "cert.pem"))) , keystr(ReadFile(tag->getString("keyfile", "key.pem"))) , dhstr(ReadFile(tag->getString("dhfile", "dhparams.pem"))) , ciphersuitestr(tag->getString("ciphersuites")) , curvestr(tag->getString("curves")) , mindh(tag->getUInt("mindhbits", 2048)) , hashstr(tag->getString("hash", "sha256")) , castr(tag->getString("cafile")) , minver(tag->getUInt("minver", 0)) , maxver(tag->getUInt("maxver", 0)) , outrecsize(tag->getUInt("outrecsize", 2048, 512, 16384)) , requestclientcert(tag->getBool("requestclientcert", true)) { if (!castr.empty()) { castr = ReadFile(castr); crlstr = tag->getString("crlfile"); if (!crlstr.empty()) crlstr = ReadFile(crlstr); } } }; Profile(Config& config) : name(config.name) , x509cred(config.certstr, config.keystr) , ciphersuites(config.ciphersuitestr) , curves(config.curvestr) , serverctx(config.ctrdrbg, MBEDTLS_SSL_IS_SERVER) , clientctx(config.ctrdrbg, MBEDTLS_SSL_IS_CLIENT) , cacerts(config.castr, true) , crl(config.crlstr) , hash(config.hashstr) , outrecsize(config.outrecsize) { serverctx.SetX509CertAndKey(x509cred); clientctx.SetX509CertAndKey(x509cred); clientctx.SetMinDHBits(config.mindh); if (!ciphersuites.empty()) { serverctx.SetCiphersuites(ciphersuites); clientctx.SetCiphersuites(ciphersuites); } if (!curves.empty()) { serverctx.SetCurves(curves); clientctx.SetCurves(curves); } serverctx.SetVersion(config.minver, config.maxver); clientctx.SetVersion(config.minver, config.maxver); if (!config.dhstr.empty()) { dhparams.set(config.dhstr); serverctx.SetDHParams(dhparams); } clientctx.SetOptionalVerifyCert(); clientctx.SetCA(cacerts, crl); // The default for servers is to not request a client certificate from the peer if (config.requestclientcert) { serverctx.SetOptionalVerifyCert(); serverctx.SetCA(cacerts, crl); } } static std::string ReadFile(const std::string& filename) { FileReader reader(filename); std::string ret = reader.GetString(); if (ret.empty()) throw Exception("Cannot read file " + filename); return ret; } /** Set up the given session with the settings in this profile */ void SetupClientSession(mbedtls_ssl_context* sess) { mbedtls_ssl_setup(sess, clientctx.GetConf()); } void SetupServerSession(mbedtls_ssl_context* sess) { mbedtls_ssl_setup(sess, serverctx.GetConf()); } const std::string& GetName() const { return name; } X509Credentials& GetX509Credentials() { return x509cred; } unsigned int GetOutgoingRecordSize() const { return outrecsize; } const Hash& GetHash() const { return hash; } }; } class mbedTLSIOHook : public SSLIOHook { enum Status { ISSL_NONE, ISSL_HANDSHAKING, ISSL_HANDSHAKEN }; mbedtls_ssl_context sess; Status status; void CloseSession() { if (status == ISSL_NONE) return; mbedtls_ssl_close_notify(&sess); mbedtls_ssl_free(&sess); certificate = NULL; status = ISSL_NONE; } // Returns 1 if handshake succeeded, 0 if it is still in progress, -1 if it failed int Handshake(StreamSocket* sock) { int ret = mbedtls_ssl_handshake(&sess); if (ret == 0) { // Change the seesion state this->status = ISSL_HANDSHAKEN; VerifyCertificate(); // Finish writing, if any left SocketEngine::ChangeEventMask(sock, FD_WANT_POLL_READ | FD_WANT_NO_WRITE | FD_ADD_TRIAL_WRITE); return 1; } this->status = ISSL_HANDSHAKING; if (ret == MBEDTLS_ERR_SSL_WANT_READ) { SocketEngine::ChangeEventMask(sock, FD_WANT_POLL_READ | FD_WANT_NO_WRITE); return 0; } else if (ret == MBEDTLS_ERR_SSL_WANT_WRITE) { SocketEngine::ChangeEventMask(sock, FD_WANT_NO_READ | FD_WANT_SINGLE_WRITE); return 0; } sock->SetError("Handshake Failed - " + mbedTLS::ErrorToString(ret)); CloseSession(); return -1; } // Returns 1 if application I/O should proceed, 0 if it must wait for the underlying protocol to progress, -1 on fatal error int PrepareIO(StreamSocket* sock) { if (status == ISSL_HANDSHAKEN) return 1; else if (status == ISSL_HANDSHAKING) { // The handshake isn't finished, try to finish it return Handshake(sock); } CloseSession(); sock->SetError("No SSL session"); return -1; } void VerifyCertificate() { this->certificate = new ssl_cert; const mbedtls_x509_crt* const cert = mbedtls_ssl_get_peer_cert(&sess); if (!cert) { certificate->error = "No client certificate sent"; return; } // If there is a certificate we can always generate a fingerprint certificate->fingerprint = GetProfile().GetHash().hash(cert->raw.p, cert->raw.len); // At this point mbedTLS verified the cert already, we just need to check the results const uint32_t flags = mbedtls_ssl_get_verify_result(&sess); if (flags == 0xFFFFFFFF) { certificate->error = "Internal error during verification"; return; } if (flags == 0) { // Verification succeeded certificate->trusted = true; } else { // Verification failed certificate->trusted = false; if ((flags & MBEDTLS_X509_BADCERT_EXPIRED) || (flags & MBEDTLS_X509_BADCERT_FUTURE)) certificate->error = "Not activated, or expired certificate"; } certificate->unknownsigner = (flags & MBEDTLS_X509_BADCERT_NOT_TRUSTED); certificate->revoked = (flags & MBEDTLS_X509_BADCERT_REVOKED); certificate->invalid = ((flags & MBEDTLS_X509_BADCERT_BAD_KEY) || (flags & MBEDTLS_X509_BADCERT_BAD_MD) || (flags & MBEDTLS_X509_BADCERT_BAD_PK)); GetDNString(&cert->subject, certificate->dn); GetDNString(&cert->issuer, certificate->issuer); } static void GetDNString(const mbedtls_x509_name* x509name, std::string& out) { char buf[512]; const int ret = mbedtls_x509_dn_gets(buf, sizeof(buf), x509name); if (ret <= 0) return; out.assign(buf, ret); } static int Pull(void* userptr, unsigned char* buffer, size_t size) { StreamSocket* const sock = reinterpret_cast<StreamSocket*>(userptr); if (sock->GetEventMask() & FD_READ_WILL_BLOCK) return MBEDTLS_ERR_SSL_WANT_READ; const int ret = SocketEngine::Recv(sock, reinterpret_cast<char*>(buffer), size, 0); if (ret < (int)size) { SocketEngine::ChangeEventMask(sock, FD_READ_WILL_BLOCK); if ((ret == -1) && (SocketEngine::IgnoreError())) return MBEDTLS_ERR_SSL_WANT_READ; } return ret; } static int Push(void* userptr, const unsigned char* buffer, size_t size) { StreamSocket* const sock = reinterpret_cast<StreamSocket*>(userptr); if (sock->GetEventMask() & FD_WRITE_WILL_BLOCK) return MBEDTLS_ERR_SSL_WANT_WRITE; const int ret = SocketEngine::Send(sock, buffer, size, 0); if (ret < (int)size) { SocketEngine::ChangeEventMask(sock, FD_WRITE_WILL_BLOCK); if ((ret == -1) && (SocketEngine::IgnoreError())) return MBEDTLS_ERR_SSL_WANT_WRITE; } return ret; } public: mbedTLSIOHook(IOHookProvider* hookprov, StreamSocket* sock, bool isserver) : SSLIOHook(hookprov) , status(ISSL_NONE) { mbedtls_ssl_init(&sess); if (isserver) GetProfile().SetupServerSession(&sess); else GetProfile().SetupClientSession(&sess); mbedtls_ssl_set_bio(&sess, reinterpret_cast<void*>(sock), Push, Pull, NULL); sock->AddIOHook(this); Handshake(sock); } void OnStreamSocketClose(StreamSocket* sock) CXX11_OVERRIDE { CloseSession(); } int OnStreamSocketRead(StreamSocket* sock, std::string& recvq) CXX11_OVERRIDE { // Finish handshake if needed int prepret = PrepareIO(sock); if (prepret <= 0) return prepret; // If we resumed the handshake then this->status will be ISSL_HANDSHAKEN. char* const readbuf = ServerInstance->GetReadBuffer(); const size_t readbufsize = ServerInstance->Config->NetBufferSize; int ret = mbedtls_ssl_read(&sess, reinterpret_cast<unsigned char*>(readbuf), readbufsize); if (ret > 0) { recvq.append(readbuf, ret); // Schedule a read if there is still data in the mbedTLS buffer if (mbedtls_ssl_get_bytes_avail(&sess) > 0) SocketEngine::ChangeEventMask(sock, FD_ADD_TRIAL_READ); return 1; } else if (ret == MBEDTLS_ERR_SSL_WANT_READ) { SocketEngine::ChangeEventMask(sock, FD_WANT_POLL_READ); return 0; } else if (ret == MBEDTLS_ERR_SSL_WANT_WRITE) { SocketEngine::ChangeEventMask(sock, FD_WANT_NO_READ | FD_WANT_SINGLE_WRITE); return 0; } else if (ret == 0) { sock->SetError("Connection closed"); CloseSession(); return -1; } else // error or MBEDTLS_ERR_SSL_CLIENT_RECONNECT which we treat as an error { sock->SetError(mbedTLS::ErrorToString(ret)); CloseSession(); return -1; } } int OnStreamSocketWrite(StreamSocket* sock, StreamSocket::SendQueue& sendq) CXX11_OVERRIDE { // Finish handshake if needed int prepret = PrepareIO(sock); if (prepret <= 0) return prepret; // Session is ready for transferring application data while (!sendq.empty()) { FlattenSendQueue(sendq, GetProfile().GetOutgoingRecordSize()); const StreamSocket::SendQueue::Element& buffer = sendq.front(); int ret = mbedtls_ssl_write(&sess, reinterpret_cast<const unsigned char*>(buffer.data()), buffer.length()); if (ret == (int)buffer.length()) { // Wrote entire record, continue sending sendq.pop_front(); } else if (ret > 0) { sendq.erase_front(ret); SocketEngine::ChangeEventMask(sock, FD_WANT_SINGLE_WRITE); return 0; } else if (ret == 0) { sock->SetError("Connection closed"); CloseSession(); return -1; } else if (ret == MBEDTLS_ERR_SSL_WANT_WRITE) { SocketEngine::ChangeEventMask(sock, FD_WANT_SINGLE_WRITE); return 0; } else if (ret == MBEDTLS_ERR_SSL_WANT_READ) { SocketEngine::ChangeEventMask(sock, FD_WANT_POLL_READ); return 0; } else { sock->SetError(mbedTLS::ErrorToString(ret)); CloseSession(); return -1; } } SocketEngine::ChangeEventMask(sock, FD_WANT_NO_WRITE); return 1; } void GetCiphersuite(std::string& out) const CXX11_OVERRIDE { if (!IsHandshakeDone()) return; out.append(mbedtls_ssl_get_version(&sess)).push_back('-'); // All mbedTLS ciphersuite names currently begin with "TLS-" which provides no useful information so skip it, but be prepared if it changes const char* const ciphersuitestr = mbedtls_ssl_get_ciphersuite(&sess); const char prefix[] = "TLS-"; unsigned int skip = sizeof(prefix)-1; if (strncmp(ciphersuitestr, prefix, sizeof(prefix)-1)) skip = 0; out.append(ciphersuitestr + skip); } bool GetServerName(std::string& out) const CXX11_OVERRIDE { // TODO: Implement SNI support. return false; } mbedTLS::Profile& GetProfile(); bool IsHandshakeDone() const { return (status == ISSL_HANDSHAKEN); } }; class mbedTLSIOHookProvider : public IOHookProvider { mbedTLS::Profile profile; public: mbedTLSIOHookProvider(Module* mod, mbedTLS::Profile::Config& config) : IOHookProvider(mod, "ssl/" + config.name, IOHookProvider::IOH_SSL) , profile(config) { ServerInstance->Modules->AddService(*this); } ~mbedTLSIOHookProvider() { ServerInstance->Modules->DelService(*this); } void OnAccept(StreamSocket* sock, irc::sockets::sockaddrs* client, irc::sockets::sockaddrs* server) CXX11_OVERRIDE { new mbedTLSIOHook(this, sock, true); } void OnConnect(StreamSocket* sock) CXX11_OVERRIDE { new mbedTLSIOHook(this, sock, false); } mbedTLS::Profile& GetProfile() { return profile; } }; mbedTLS::Profile& mbedTLSIOHook::GetProfile() { IOHookProvider* hookprov = prov; return static_cast<mbedTLSIOHookProvider*>(hookprov)->GetProfile(); } class ModuleSSLmbedTLS : public Module { typedef std::vector<reference<mbedTLSIOHookProvider> > ProfileList; mbedTLS::Entropy entropy; mbedTLS::CTRDRBG ctr_drbg; ProfileList profiles; void ReadProfiles() { // First, store all profiles in a new, temporary container. If no problems occur, swap the two // containers; this way if something goes wrong we can go back and continue using the current profiles, // avoiding unpleasant situations where no new SSL connections are possible. ProfileList newprofiles; ConfigTagList tags = ServerInstance->Config->ConfTags("sslprofile"); if (tags.first == tags.second) { // No <sslprofile> tags found, create a profile named "mbedtls" from settings in the <mbedtls> block const std::string defname = "mbedtls"; ConfigTag* tag = ServerInstance->Config->ConfValue(defname); ServerInstance->Logs->Log(MODNAME, LOG_DEFAULT, "No <sslprofile> tags found; using settings from the <mbedtls> tag"); try { mbedTLS::Profile::Config profileconfig(defname, tag, ctr_drbg); newprofiles.push_back(new mbedTLSIOHookProvider(this, profileconfig)); } catch (CoreException& ex) { throw ModuleException("Error while initializing the default SSL profile - " + ex.GetReason()); } } for (ConfigIter i = tags.first; i != tags.second; ++i) { ConfigTag* tag = i->second; if (!stdalgo::string::equalsci(tag->getString("provider"), "mbedtls")) continue; std::string name = tag->getString("name"); if (name.empty()) { ServerInstance->Logs->Log(MODNAME, LOG_DEFAULT, "Ignoring <sslprofile> tag without name at " + tag->getTagLocation()); continue; } reference<mbedTLSIOHookProvider> prov; try { mbedTLS::Profile::Config profileconfig(name, tag, ctr_drbg); prov = new mbedTLSIOHookProvider(this, profileconfig); } catch (CoreException& ex) { throw ModuleException("Error while initializing SSL profile \"" + name + "\" at " + tag->getTagLocation() + " - " + ex.GetReason()); } newprofiles.push_back(prov); } // New profiles are ok, begin using them // Old profiles are deleted when their refcount drops to zero for (ProfileList::iterator i = profiles.begin(); i != profiles.end(); ++i) { mbedTLSIOHookProvider& prov = **i; ServerInstance->Modules.DelService(prov); } profiles.swap(newprofiles); } public: void init() CXX11_OVERRIDE { char verbuf[16]; // Should be at least 9 bytes in size mbedtls_version_get_string(verbuf); ServerInstance->Logs->Log(MODNAME, LOG_DEFAULT, "mbedTLS lib version %s module was compiled for " MBEDTLS_VERSION_STRING, verbuf); if (!ctr_drbg.Seed(entropy)) throw ModuleException("CTR DRBG seed failed"); ReadProfiles(); } void OnModuleRehash(User* user, const std::string &param) CXX11_OVERRIDE { if (param != "ssl") return; try { ReadProfiles(); } catch (ModuleException& ex) { ServerInstance->Logs->Log(MODNAME, LOG_DEFAULT, ex.GetReason() + " Not applying settings."); } } void OnCleanup(ExtensionItem::ExtensibleType type, Extensible* item) CXX11_OVERRIDE { if (type != ExtensionItem::EXT_USER) return; LocalUser* user = IS_LOCAL(static_cast<User*>(item)); if ((user) && (user->eh.GetModHook(this))) { // User is using SSL, they're a local user, and they're using our IOHook. // Potentially there could be multiple SSL modules loaded at once on different ports. ServerInstance->Users.QuitUser(user, "SSL module unloading"); } } ModResult OnCheckReady(LocalUser* user) CXX11_OVERRIDE { const mbedTLSIOHook* const iohook = static_cast<mbedTLSIOHook*>(user->eh.GetModHook(this)); if ((iohook) && (!iohook->IsHandshakeDone())) return MOD_RES_DENY; return MOD_RES_PASSTHRU; } Version GetVersion() CXX11_OVERRIDE { return Version("Provides SSL support via mbedTLS (PolarSSL)", VF_VENDOR); } }; MODULE_INIT(ModuleSSLmbedTLS) ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/src/modules/extra/m_ssl_openssl.cpp��������������������������������������������������0000664�0000000�0000000�00000071273�13554550454�0022323�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * InspIRCd -- Internet Relay Chat Daemon * * Copyright (C) 2009-2010 Daniel De Graaf <danieldg@inspircd.org> * Copyright (C) 2008 Pippijn van Steenhoven <pip88nl@gmail.com> * Copyright (C) 2006-2008 Craig Edwards <craigedwards@brainbox.cc> * Copyright (C) 2008 Thomas Stagner <aquanight@inspircd.org> * Copyright (C) 2007 Dennis Friis <peavey@inspircd.org> * Copyright (C) 2006 Oliver Lupton <oliverlupton@gmail.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/>. */ /// $CompilerFlags: find_compiler_flags("openssl") /// $LinkerFlags: find_linker_flags("openssl" "-lssl -lcrypto") /// $PackageInfo: require_system("arch") openssl pkgconf /// $PackageInfo: require_system("centos") openssl-devel pkgconfig /// $PackageInfo: require_system("darwin") openssl pkg-config /// $PackageInfo: require_system("debian") libssl-dev openssl pkg-config /// $PackageInfo: require_system("ubuntu") libssl-dev openssl pkg-config #include "inspircd.h" #include "iohook.h" #include "modules/ssl.h" #ifdef __GNUC__ # pragma GCC diagnostic push #endif // Ignore OpenSSL deprecation warnings on OS X Lion and newer. #if defined __APPLE__ # pragma GCC diagnostic ignored "-Wdeprecated-declarations" #endif // Fix warnings about the use of `long long` on C++03. #if defined __clang__ # pragma clang diagnostic ignored "-Wc++11-long-long" #elif defined __GNUC__ # pragma GCC diagnostic ignored "-Wlong-long" #endif #include <openssl/ssl.h> #include <openssl/err.h> #include <openssl/dh.h> #ifdef __GNUC__ # pragma GCC diagnostic pop #endif #ifdef _WIN32 # pragma comment(lib, "ssleay32.lib") # pragma comment(lib, "libeay32.lib") #endif // Compatibility layer to allow OpenSSL 1.0 to use the 1.1 API. #if ((defined LIBRESSL_VERSION_NUMBER) || (OPENSSL_VERSION_NUMBER < 0x10100000L)) // BIO is opaque in OpenSSL 1.1 but the access API does not exist in 1.0. # define BIO_get_data(BIO) BIO->ptr # define BIO_set_data(BIO, VALUE) BIO->ptr = VALUE; # define BIO_set_init(BIO, VALUE) BIO->init = VALUE; // These functions have been renamed in OpenSSL 1.1. # define OpenSSL_version SSLeay_version # define X509_getm_notAfter X509_get_notAfter # define X509_getm_notBefore X509_get_notBefore # define OPENSSL_init_ssl(OPTIONS, SETTINGS) \ SSL_library_init(); \ SSL_load_error_strings(); // These macros have been renamed in OpenSSL 1.1. # define OPENSSL_VERSION SSLEAY_VERSION #else # define INSPIRCD_OPENSSL_OPAQUE_BIO #endif enum issl_status { ISSL_NONE, ISSL_HANDSHAKING, ISSL_OPEN }; static bool SelfSigned = false; static int exdataindex; char* get_error() { return ERR_error_string(ERR_get_error(), NULL); } static int OnVerify(int preverify_ok, X509_STORE_CTX* ctx); static void StaticSSLInfoCallback(const SSL* ssl, int where, int rc); namespace OpenSSL { class Exception : public ModuleException { public: Exception(const std::string& reason) : ModuleException(reason) { } }; class DHParams { DH* dh; public: DHParams(const std::string& filename) { BIO* dhpfile = BIO_new_file(filename.c_str(), "r"); if (dhpfile == NULL) throw Exception("Couldn't open DH file " + filename); dh = PEM_read_bio_DHparams(dhpfile, NULL, NULL, NULL); BIO_free(dhpfile); if (!dh) throw Exception("Couldn't read DH params from file " + filename); } ~DHParams() { DH_free(dh); } DH* get() { return dh; } }; class Context { SSL_CTX* const ctx; long ctx_options; public: Context(SSL_CTX* context) : ctx(context) { // Sane default options for OpenSSL see https://www.openssl.org/docs/ssl/SSL_CTX_set_options.html // and when choosing a cipher, use the server's preferences instead of the client preferences. long opts = SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3 | SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION | SSL_OP_CIPHER_SERVER_PREFERENCE | SSL_OP_SINGLE_DH_USE; // Only turn options on if they exist #ifdef SSL_OP_SINGLE_ECDH_USE opts |= SSL_OP_SINGLE_ECDH_USE; #endif #ifdef SSL_OP_NO_TICKET opts |= SSL_OP_NO_TICKET; #endif ctx_options = SSL_CTX_set_options(ctx, opts); long mode = SSL_MODE_ENABLE_PARTIAL_WRITE | SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER; #ifdef SSL_MODE_RELEASE_BUFFERS mode |= SSL_MODE_RELEASE_BUFFERS; #endif SSL_CTX_set_mode(ctx, mode); SSL_CTX_set_verify(ctx, SSL_VERIFY_NONE, NULL); SSL_CTX_set_session_cache_mode(ctx, SSL_SESS_CACHE_OFF); SSL_CTX_set_info_callback(ctx, StaticSSLInfoCallback); } ~Context() { SSL_CTX_free(ctx); } bool SetDH(DHParams& dh) { ERR_clear_error(); return (SSL_CTX_set_tmp_dh(ctx, dh.get()) >= 0); } #ifndef OPENSSL_NO_ECDH void SetECDH(const std::string& curvename) { int nid = OBJ_sn2nid(curvename.c_str()); if (nid == 0) throw Exception("Unknown curve: " + curvename); EC_KEY* eckey = EC_KEY_new_by_curve_name(nid); if (!eckey) throw Exception("Unable to create EC key object"); ERR_clear_error(); bool ret = (SSL_CTX_set_tmp_ecdh(ctx, eckey) >= 0); EC_KEY_free(eckey); if (!ret) throw Exception("Couldn't set ECDH parameters"); } #endif bool SetCiphers(const std::string& ciphers) { ERR_clear_error(); return SSL_CTX_set_cipher_list(ctx, ciphers.c_str()); } bool SetCerts(const std::string& filename) { ERR_clear_error(); return SSL_CTX_use_certificate_chain_file(ctx, filename.c_str()); } bool SetPrivateKey(const std::string& filename) { ERR_clear_error(); return SSL_CTX_use_PrivateKey_file(ctx, filename.c_str(), SSL_FILETYPE_PEM); } bool SetCA(const std::string& filename) { ERR_clear_error(); return SSL_CTX_load_verify_locations(ctx, filename.c_str(), 0); } void SetCRL(const std::string& crlfile, const std::string& crlpath, const std::string& crlmode) { if (crlfile.empty() && crlpath.empty()) return; /* Set CRL mode */ unsigned long crlflags = X509_V_FLAG_CRL_CHECK; if (stdalgo::string::equalsci(crlmode, "chain")) { crlflags |= X509_V_FLAG_CRL_CHECK_ALL; } else if (!stdalgo::string::equalsci(crlmode, "leaf")) { throw ModuleException("Unknown mode '" + crlmode + "'; expected either 'chain' (default) or 'leaf'"); } /* Load CRL files */ X509_STORE* store = SSL_CTX_get_cert_store(ctx); if (!store) { throw ModuleException("Unable to get X509_STORE from SSL context; this should never happen"); } ERR_clear_error(); if (!X509_STORE_load_locations(store, crlfile.empty() ? NULL : crlfile.c_str(), crlpath.empty() ? NULL : crlpath.c_str())) { int err = ERR_get_error(); throw ModuleException("Unable to load CRL file '" + crlfile + "' or CRL path '" + crlpath + "': '" + (err ? ERR_error_string(err, NULL) : "unknown") + "'"); } /* Set CRL mode */ if (X509_STORE_set_flags(store, crlflags) != 1) { throw ModuleException("Unable to set X509 CRL flags"); } } long GetDefaultContextOptions() const { return ctx_options; } long SetRawContextOptions(long setoptions, long clearoptions) { // Clear everything SSL_CTX_clear_options(ctx, SSL_CTX_get_options(ctx)); // Set the default options and what is in the conf SSL_CTX_set_options(ctx, ctx_options | setoptions); return SSL_CTX_clear_options(ctx, clearoptions); } void SetVerifyCert() { SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER | SSL_VERIFY_CLIENT_ONCE, OnVerify); } SSL* CreateServerSession() { SSL* sess = SSL_new(ctx); SSL_set_accept_state(sess); // Act as server return sess; } SSL* CreateClientSession() { SSL* sess = SSL_new(ctx); SSL_set_connect_state(sess); // Act as client return sess; } }; class Profile { /** Name of this profile */ const std::string name; /** DH parameters in use */ DHParams dh; /** OpenSSL makes us have two contexts, one for servers and one for clients */ Context ctx; Context clictx; /** Digest to use when generating fingerprints */ const EVP_MD* digest; /** Last error, set by error_callback() */ std::string lasterr; /** True if renegotiations are allowed, false if not */ const bool allowrenego; /** Rough max size of records to send */ const unsigned int outrecsize; static int error_callback(const char* str, size_t len, void* u) { Profile* profile = reinterpret_cast<Profile*>(u); profile->lasterr = std::string(str, len - 1); return 0; } /** Set raw OpenSSL context (SSL_CTX) options from a config tag * @param ctxname Name of the context, client or server * @param tag Config tag defining this profile * @param context Context object to manipulate */ void SetContextOptions(const std::string& ctxname, ConfigTag* tag, Context& context) { long setoptions = tag->getInt(ctxname + "setoptions", 0); long clearoptions = tag->getInt(ctxname + "clearoptions", 0); #ifdef SSL_OP_NO_COMPRESSION // Disable compression by default if (!tag->getBool("compression", false)) setoptions |= SSL_OP_NO_COMPRESSION; #endif // Disable TLSv1.0 by default. if (!tag->getBool("tlsv1", false)) setoptions |= SSL_OP_NO_TLSv1; #ifdef SSL_OP_NO_TLSv1_1 // Enable TLSv1.1 by default. if (!tag->getBool("tlsv11", true)) setoptions |= SSL_OP_NO_TLSv1_1; #endif #ifdef SSL_OP_NO_TLSv1_2 // Enable TLSv1.2 by default. if (!tag->getBool("tlsv12", true)) setoptions |= SSL_OP_NO_TLSv1_2; #endif if (!setoptions && !clearoptions) return; // Nothing to do ServerInstance->Logs->Log(MODNAME, LOG_DEBUG, "Setting %s %s context options, default: %ld set: %ld clear: %ld", name.c_str(), ctxname.c_str(), ctx.GetDefaultContextOptions(), setoptions, clearoptions); long final = context.SetRawContextOptions(setoptions, clearoptions); ServerInstance->Logs->Log(MODNAME, LOG_DEFAULT, "%s %s context options: %ld", name.c_str(), ctxname.c_str(), final); } public: Profile(const std::string& profilename, ConfigTag* tag) : name(profilename) , dh(ServerInstance->Config->Paths.PrependConfig(tag->getString("dhfile", "dhparams.pem"))) , ctx(SSL_CTX_new(SSLv23_server_method())) , clictx(SSL_CTX_new(SSLv23_client_method())) , allowrenego(tag->getBool("renegotiation")) // Disallow by default , outrecsize(tag->getUInt("outrecsize", 2048, 512, 16384)) { if ((!ctx.SetDH(dh)) || (!clictx.SetDH(dh))) throw Exception("Couldn't set DH parameters"); std::string hash = tag->getString("hash", "md5"); digest = EVP_get_digestbyname(hash.c_str()); if (digest == NULL) throw Exception("Unknown hash type " + hash); std::string ciphers = tag->getString("ciphers"); if (!ciphers.empty()) { if ((!ctx.SetCiphers(ciphers)) || (!clictx.SetCiphers(ciphers))) { ERR_print_errors_cb(error_callback, this); throw Exception("Can't set cipher list to \"" + ciphers + "\" " + lasterr); } } #ifndef OPENSSL_NO_ECDH std::string curvename = tag->getString("ecdhcurve", "prime256v1"); if (!curvename.empty()) ctx.SetECDH(curvename); #endif SetContextOptions("server", tag, ctx); SetContextOptions("client", tag, clictx); /* Load our keys and certificates * NOTE: OpenSSL's error logging API sucks, don't blame us for this clusterfuck. */ std::string filename = ServerInstance->Config->Paths.PrependConfig(tag->getString("certfile", "cert.pem")); if ((!ctx.SetCerts(filename)) || (!clictx.SetCerts(filename))) { ERR_print_errors_cb(error_callback, this); throw Exception("Can't read certificate file: " + lasterr); } filename = ServerInstance->Config->Paths.PrependConfig(tag->getString("keyfile", "key.pem")); if ((!ctx.SetPrivateKey(filename)) || (!clictx.SetPrivateKey(filename))) { ERR_print_errors_cb(error_callback, this); throw Exception("Can't read key file: " + lasterr); } // Load the CAs we trust filename = ServerInstance->Config->Paths.PrependConfig(tag->getString("cafile", "ca.pem")); if ((!ctx.SetCA(filename)) || (!clictx.SetCA(filename))) { ERR_print_errors_cb(error_callback, this); ServerInstance->Logs->Log(MODNAME, LOG_DEFAULT, "Can't read CA list from %s. This is only a problem if you want to verify client certificates, otherwise it's safe to ignore this message. Error: %s", filename.c_str(), lasterr.c_str()); } // Load the CRLs. std::string crlfile = tag->getString("crlfile"); std::string crlpath = tag->getString("crlpath"); std::string crlmode = tag->getString("crlmode", "chain"); ctx.SetCRL(crlfile, crlpath, crlmode); clictx.SetVerifyCert(); if (tag->getBool("requestclientcert", true)) ctx.SetVerifyCert(); } const std::string& GetName() const { return name; } SSL* CreateServerSession() { return ctx.CreateServerSession(); } SSL* CreateClientSession() { return clictx.CreateClientSession(); } const EVP_MD* GetDigest() { return digest; } bool AllowRenegotiation() const { return allowrenego; } unsigned int GetOutgoingRecordSize() const { return outrecsize; } }; namespace BIOMethod { static int create(BIO* bio) { BIO_set_init(bio, 1); return 1; } static int destroy(BIO* bio) { // XXX: Dummy function to avoid a memory leak in OpenSSL. // The memory leak happens in BIO_free() (bio_lib.c) when the destroy func of the BIO is NULL. // This is fixed in OpenSSL but some distros still ship the unpatched version hence we provide this workaround. return 1; } static long ctrl(BIO* bio, int cmd, long num, void* ptr) { if (cmd == BIO_CTRL_FLUSH) return 1; return 0; } static int read(BIO* bio, char* buf, int len); static int write(BIO* bio, const char* buf, int len); #ifdef INSPIRCD_OPENSSL_OPAQUE_BIO static BIO_METHOD* alloc() { BIO_METHOD* meth = BIO_meth_new(100 | BIO_TYPE_SOURCE_SINK, "inspircd"); BIO_meth_set_write(meth, OpenSSL::BIOMethod::write); BIO_meth_set_read(meth, OpenSSL::BIOMethod::read); BIO_meth_set_ctrl(meth, OpenSSL::BIOMethod::ctrl); BIO_meth_set_create(meth, OpenSSL::BIOMethod::create); BIO_meth_set_destroy(meth, OpenSSL::BIOMethod::destroy); return meth; } #endif } } // BIO_METHOD is opaque in OpenSSL 1.1 so we can't do this. // See OpenSSL::BIOMethod::alloc for the new method. #ifndef INSPIRCD_OPENSSL_OPAQUE_BIO static BIO_METHOD biomethods = { (100 | BIO_TYPE_SOURCE_SINK), "inspircd", OpenSSL::BIOMethod::write, OpenSSL::BIOMethod::read, NULL, // puts NULL, // gets OpenSSL::BIOMethod::ctrl, OpenSSL::BIOMethod::create, OpenSSL::BIOMethod::destroy, // destroy, does nothing, see function body for more info NULL // callback_ctrl }; #else static BIO_METHOD* biomethods; #endif static int OnVerify(int preverify_ok, X509_STORE_CTX *ctx) { /* XXX: This will allow self signed certificates. * In the future if we want an option to not allow this, * we can just return preverify_ok here, and openssl * will boot off self-signed and invalid peer certs. */ int ve = X509_STORE_CTX_get_error(ctx); SelfSigned = (ve == X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT); return 1; } class OpenSSLIOHook : public SSLIOHook { private: SSL* sess; issl_status status; bool data_to_write; // Returns 1 if handshake succeeded, 0 if it is still in progress, -1 if it failed int Handshake(StreamSocket* user) { ERR_clear_error(); int ret = SSL_do_handshake(sess); if (ret < 0) { int err = SSL_get_error(sess, ret); if (err == SSL_ERROR_WANT_READ) { SocketEngine::ChangeEventMask(user, FD_WANT_POLL_READ | FD_WANT_NO_WRITE); this->status = ISSL_HANDSHAKING; return 0; } else if (err == SSL_ERROR_WANT_WRITE) { SocketEngine::ChangeEventMask(user, FD_WANT_NO_READ | FD_WANT_SINGLE_WRITE); this->status = ISSL_HANDSHAKING; return 0; } else { CloseSession(); return -1; } } else if (ret > 0) { // Handshake complete. VerifyCertificate(); status = ISSL_OPEN; SocketEngine::ChangeEventMask(user, FD_WANT_POLL_READ | FD_WANT_NO_WRITE | FD_ADD_TRIAL_WRITE); return 1; } else if (ret == 0) { CloseSession(); } return -1; } void CloseSession() { if (sess) { SSL_shutdown(sess); SSL_free(sess); } sess = NULL; certificate = NULL; status = ISSL_NONE; } void VerifyCertificate() { X509* cert; ssl_cert* certinfo = new ssl_cert; this->certificate = certinfo; unsigned int n; unsigned char md[EVP_MAX_MD_SIZE]; cert = SSL_get_peer_certificate(sess); if (!cert) { certinfo->error = "Could not get peer certificate: "+std::string(get_error()); return; } certinfo->invalid = (SSL_get_verify_result(sess) != X509_V_OK); if (!SelfSigned) { certinfo->unknownsigner = false; certinfo->trusted = true; } else { certinfo->unknownsigner = true; certinfo->trusted = false; } char buf[512]; X509_NAME_oneline(X509_get_subject_name(cert), buf, sizeof(buf)); certinfo->dn = buf; // Make sure there are no chars in the string that we consider invalid if (certinfo->dn.find_first_of("\r\n") != std::string::npos) certinfo->dn.clear(); X509_NAME_oneline(X509_get_issuer_name(cert), buf, sizeof(buf)); certinfo->issuer = buf; if (certinfo->issuer.find_first_of("\r\n") != std::string::npos) certinfo->issuer.clear(); if (!X509_digest(cert, GetProfile().GetDigest(), md, &n)) { certinfo->error = "Out of memory generating fingerprint"; } else { certinfo->fingerprint = BinToHex(md, n); } if ((ASN1_UTCTIME_cmp_time_t(X509_getm_notAfter(cert), ServerInstance->Time()) == -1) || (ASN1_UTCTIME_cmp_time_t(X509_getm_notBefore(cert), ServerInstance->Time()) == 0)) { certinfo->error = "Not activated, or expired certificate"; } X509_free(cert); } void SSLInfoCallback(int where, int rc) { if ((where & SSL_CB_HANDSHAKE_START) && (status == ISSL_OPEN)) { if (GetProfile().AllowRenegotiation()) return; // The other side is trying to renegotiate, kill the connection and change status // to ISSL_NONE so CheckRenego() closes the session status = ISSL_NONE; BIO* bio = SSL_get_rbio(sess); EventHandler* eh = static_cast<StreamSocket*>(BIO_get_data(bio)); SocketEngine::Shutdown(eh, 2); } } bool CheckRenego(StreamSocket* sock) { if (status != ISSL_NONE) return true; ServerInstance->Logs->Log(MODNAME, LOG_DEBUG, "Session %p killed, attempted to renegotiate", (void*)sess); CloseSession(); sock->SetError("Renegotiation is not allowed"); return false; } // Returns 1 if application I/O should proceed, 0 if it must wait for the underlying protocol to progress, -1 on fatal error int PrepareIO(StreamSocket* sock) { if (status == ISSL_OPEN) return 1; else if (status == ISSL_HANDSHAKING) { // The handshake isn't finished, try to finish it return Handshake(sock); } CloseSession(); return -1; } // Calls our private SSLInfoCallback() friend void StaticSSLInfoCallback(const SSL* ssl, int where, int rc); public: OpenSSLIOHook(IOHookProvider* hookprov, StreamSocket* sock, SSL* session) : SSLIOHook(hookprov) , sess(session) , status(ISSL_NONE) , data_to_write(false) { // Create BIO instance and store a pointer to the socket in it which will be used by the read and write functions #ifdef INSPIRCD_OPENSSL_OPAQUE_BIO BIO* bio = BIO_new(biomethods); #else BIO* bio = BIO_new(&biomethods); #endif BIO_set_data(bio, sock); SSL_set_bio(sess, bio, bio); SSL_set_ex_data(sess, exdataindex, this); sock->AddIOHook(this); Handshake(sock); } void OnStreamSocketClose(StreamSocket* user) CXX11_OVERRIDE { CloseSession(); } int OnStreamSocketRead(StreamSocket* user, std::string& recvq) CXX11_OVERRIDE { // Finish handshake if needed int prepret = PrepareIO(user); if (prepret <= 0) return prepret; // If we resumed the handshake then this->status will be ISSL_OPEN { ERR_clear_error(); char* buffer = ServerInstance->GetReadBuffer(); size_t bufsiz = ServerInstance->Config->NetBufferSize; int ret = SSL_read(sess, buffer, bufsiz); if (!CheckRenego(user)) return -1; 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(sess) > 0) mask |= FD_ADD_TRIAL_READ; if (data_to_write) mask |= FD_WANT_POLL_READ | FD_WANT_SINGLE_WRITE; if (mask != 0) SocketEngine::ChangeEventMask(user, mask); return 1; } else if (ret == 0) { // Client closed connection. CloseSession(); user->SetError("Connection closed"); return -1; } else // if (ret < 0) { int err = SSL_get_error(sess, ret); if (err == SSL_ERROR_WANT_READ) { SocketEngine::ChangeEventMask(user, FD_WANT_POLL_READ); return 0; } else if (err == SSL_ERROR_WANT_WRITE) { SocketEngine::ChangeEventMask(user, FD_WANT_NO_READ | FD_WANT_SINGLE_WRITE); return 0; } else { CloseSession(); return -1; } } } } int OnStreamSocketWrite(StreamSocket* user, StreamSocket::SendQueue& sendq) CXX11_OVERRIDE { // Finish handshake if needed int prepret = PrepareIO(user); if (prepret <= 0) return prepret; data_to_write = true; // Session is ready for transferring application data while (!sendq.empty()) { ERR_clear_error(); FlattenSendQueue(sendq, GetProfile().GetOutgoingRecordSize()); const StreamSocket::SendQueue::Element& buffer = sendq.front(); int ret = SSL_write(sess, buffer.data(), buffer.size()); if (!CheckRenego(user)) return -1; if (ret == (int)buffer.length()) { // Wrote entire record, continue sending sendq.pop_front(); } else if (ret > 0) { sendq.erase_front(ret); SocketEngine::ChangeEventMask(user, FD_WANT_SINGLE_WRITE); return 0; } else if (ret == 0) { CloseSession(); return -1; } else // if (ret < 0) { int err = SSL_get_error(sess, ret); if (err == SSL_ERROR_WANT_WRITE) { SocketEngine::ChangeEventMask(user, FD_WANT_SINGLE_WRITE); return 0; } else if (err == SSL_ERROR_WANT_READ) { SocketEngine::ChangeEventMask(user, FD_WANT_POLL_READ); return 0; } else { CloseSession(); return -1; } } } data_to_write = false; SocketEngine::ChangeEventMask(user, FD_WANT_POLL_READ | FD_WANT_NO_WRITE); return 1; } void GetCiphersuite(std::string& out) const CXX11_OVERRIDE { if (!IsHandshakeDone()) return; out.append(SSL_get_version(sess)).push_back('-'); out.append(SSL_get_cipher(sess)); } bool GetServerName(std::string& out) const CXX11_OVERRIDE { const char* name = SSL_get_servername(sess, TLSEXT_NAMETYPE_host_name); if (!name) return false; out.append(name); return true; } bool IsHandshakeDone() const { return (status == ISSL_OPEN); } OpenSSL::Profile& GetProfile(); }; static void StaticSSLInfoCallback(const SSL* ssl, int where, int rc) { OpenSSLIOHook* hook = static_cast<OpenSSLIOHook*>(SSL_get_ex_data(ssl, exdataindex)); hook->SSLInfoCallback(where, rc); } static int OpenSSL::BIOMethod::write(BIO* bio, const char* buffer, int size) { BIO_clear_retry_flags(bio); StreamSocket* sock = static_cast<StreamSocket*>(BIO_get_data(bio)); if (sock->GetEventMask() & FD_WRITE_WILL_BLOCK) { // Writes blocked earlier, don't retry syscall BIO_set_retry_write(bio); return -1; } int ret = SocketEngine::Send(sock, buffer, size, 0); if ((ret < size) && ((ret > 0) || (SocketEngine::IgnoreError()))) { // Blocked, set retry flag for OpenSSL SocketEngine::ChangeEventMask(sock, FD_WRITE_WILL_BLOCK); BIO_set_retry_write(bio); } return ret; } static int OpenSSL::BIOMethod::read(BIO* bio, char* buffer, int size) { BIO_clear_retry_flags(bio); StreamSocket* sock = static_cast<StreamSocket*>(BIO_get_data(bio)); if (sock->GetEventMask() & FD_READ_WILL_BLOCK) { // Reads blocked earlier, don't retry syscall BIO_set_retry_read(bio); return -1; } int ret = SocketEngine::Recv(sock, buffer, size, 0); if ((ret < size) && ((ret > 0) || (SocketEngine::IgnoreError()))) { // Blocked, set retry flag for OpenSSL SocketEngine::ChangeEventMask(sock, FD_READ_WILL_BLOCK); BIO_set_retry_read(bio); } return ret; } class OpenSSLIOHookProvider : public IOHookProvider { OpenSSL::Profile profile; public: OpenSSLIOHookProvider(Module* mod, const std::string& profilename, ConfigTag* tag) : IOHookProvider(mod, "ssl/" + profilename, IOHookProvider::IOH_SSL) , profile(profilename, tag) { ServerInstance->Modules->AddService(*this); } ~OpenSSLIOHookProvider() { ServerInstance->Modules->DelService(*this); } void OnAccept(StreamSocket* sock, irc::sockets::sockaddrs* client, irc::sockets::sockaddrs* server) CXX11_OVERRIDE { new OpenSSLIOHook(this, sock, profile.CreateServerSession()); } void OnConnect(StreamSocket* sock) CXX11_OVERRIDE { new OpenSSLIOHook(this, sock, profile.CreateClientSession()); } OpenSSL::Profile& GetProfile() { return profile; } }; OpenSSL::Profile& OpenSSLIOHook::GetProfile() { IOHookProvider* hookprov = prov; return static_cast<OpenSSLIOHookProvider*>(hookprov)->GetProfile(); } class ModuleSSLOpenSSL : public Module { typedef std::vector<reference<OpenSSLIOHookProvider> > ProfileList; ProfileList profiles; void ReadProfiles() { ProfileList newprofiles; ConfigTagList tags = ServerInstance->Config->ConfTags("sslprofile"); if (tags.first == tags.second) { // Create a default profile named "openssl" const std::string defname = "openssl"; ConfigTag* tag = ServerInstance->Config->ConfValue(defname); ServerInstance->Logs->Log(MODNAME, LOG_DEFAULT, "No <sslprofile> tags found, using settings from the <openssl> tag"); try { newprofiles.push_back(new OpenSSLIOHookProvider(this, defname, tag)); } catch (OpenSSL::Exception& ex) { throw ModuleException("Error while initializing the default SSL profile - " + ex.GetReason()); } } for (ConfigIter i = tags.first; i != tags.second; ++i) { ConfigTag* tag = i->second; if (!stdalgo::string::equalsci(tag->getString("provider"), "openssl")) continue; std::string name = tag->getString("name"); if (name.empty()) { ServerInstance->Logs->Log(MODNAME, LOG_DEFAULT, "Ignoring <sslprofile> tag without name at " + tag->getTagLocation()); continue; } reference<OpenSSLIOHookProvider> prov; try { prov = new OpenSSLIOHookProvider(this, name, tag); } catch (CoreException& ex) { throw ModuleException("Error while initializing SSL profile \"" + name + "\" at " + tag->getTagLocation() + " - " + ex.GetReason()); } newprofiles.push_back(prov); } for (ProfileList::iterator i = profiles.begin(); i != profiles.end(); ++i) { OpenSSLIOHookProvider& prov = **i; ServerInstance->Modules.DelService(prov); } profiles.swap(newprofiles); } public: ModuleSSLOpenSSL() { // Initialize OpenSSL OPENSSL_init_ssl(0, NULL); #ifdef INSPIRCD_OPENSSL_OPAQUE_BIO biomethods = OpenSSL::BIOMethod::alloc(); } ~ModuleSSLOpenSSL() { BIO_meth_free(biomethods); #endif } void init() CXX11_OVERRIDE { ServerInstance->Logs->Log(MODNAME, LOG_DEFAULT, "OpenSSL lib version \"%s\" module was compiled for \"" OPENSSL_VERSION_TEXT "\"", OpenSSL_version(OPENSSL_VERSION)); // Register application specific data char exdatastr[] = "inspircd"; exdataindex = SSL_get_ex_new_index(0, exdatastr, NULL, NULL, NULL); if (exdataindex < 0) throw ModuleException("Failed to register application specific data"); ReadProfiles(); } void OnModuleRehash(User* user, const std::string &param) CXX11_OVERRIDE { if (param != "ssl") return; try { ReadProfiles(); } catch (ModuleException& ex) { ServerInstance->Logs->Log(MODNAME, LOG_DEFAULT, ex.GetReason() + " Not applying settings."); } } void OnCleanup(ExtensionItem::ExtensibleType type, Extensible* item) CXX11_OVERRIDE { if (type == ExtensionItem::EXT_USER) { LocalUser* user = IS_LOCAL((User*)item); if ((user) && (user->eh.GetModHook(this))) { // User is using SSL, they're a local user, and they're using one of *our* SSL ports. // Potentially there could be multiple SSL modules loaded at once on different ports. ServerInstance->Users->QuitUser(user, "SSL module unloading"); } } } ModResult OnCheckReady(LocalUser* user) CXX11_OVERRIDE { const OpenSSLIOHook* const iohook = static_cast<OpenSSLIOHook*>(user->eh.GetModHook(this)); if ((iohook) && (!iohook->IsHandshakeDone())) return MOD_RES_DENY; return MOD_RES_PASSTHRU; } Version GetVersion() CXX11_OVERRIDE { return Version("Provides SSL support via OpenSSL", VF_VENDOR); } }; MODULE_INIT(ModuleSSLOpenSSL) �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/src/modules/extra/m_sslrehashsignal.cpp����������������������������������������������0000664�0000000�0000000�00000003052�13554550454�0023137�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * InspIRCd -- Internet Relay Chat Daemon * * Copyright (C) 2018 Peter Powell <petpow@saberuk.com> * Copyright (C) 2016 Attila Molnar <attilamolnar@hush.com> * * This file is part of InspIRCd. InspIRCd is free software: you can * redistribute it and/or modify it under the terms of the GNU General Public * License as published by the Free Software Foundation, version 2. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include "inspircd.h" static volatile sig_atomic_t signaled; class ModuleSSLRehashSignal : public Module { private: static void SignalHandler(int) { signaled = 1; } public: ~ModuleSSLRehashSignal() { signal(SIGUSR1, SIG_IGN); } void init() { signal(SIGUSR1, SignalHandler); } void OnBackgroundTimer(time_t) { if (!signaled) return; const std::string feedbackmsg = "Got SIGUSR1, reloading SSL credentials"; ServerInstance->SNO->WriteGlobalSno('a', feedbackmsg); ServerInstance->Logs->Log(MODNAME, LOG_DEFAULT, feedbackmsg); const std::string str = "ssl"; FOREACH_MOD(OnModuleRehash, (NULL, str)); signaled = 0; } Version GetVersion() { return Version("Reloads SSL credentials on SIGUSR1", VF_VENDOR); } }; MODULE_INIT(ModuleSSLRehashSignal) ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/src/modules/m_abbreviation.cpp�������������������������������������������������������0000664�0000000�0000000�00000005127�13554550454�0021274�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * InspIRCd -- Internet Relay Chat Daemon * * Copyright (C) 2008 Craig Edwards <craigedwards@brainbox.cc> * * This file is part of InspIRCd. InspIRCd is free software: you can * redistribute it and/or modify it under the terms of the GNU General Public * License as published by the Free Software Foundation, version 2. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include "inspircd.h" enum { // InspIRCd-specific. ERR_AMBIGUOUSCOMMAND = 420 }; class ModuleAbbreviation : public Module { public: void Prioritize() CXX11_OVERRIDE { ServerInstance->Modules->SetPriority(this, I_OnPreCommand, PRIORITY_FIRST); } Version GetVersion() CXX11_OVERRIDE { return Version("Provides the ability to abbreviate commands a-la BBC BASIC keywords", VF_VENDOR); } ModResult OnPreCommand(std::string& command, CommandBase::Params& parameters, LocalUser* user, bool validated) CXX11_OVERRIDE { /* Command is already validated, has a length of 0, or last character is not a . */ if (validated || command.empty() || *command.rbegin() != '.') return MOD_RES_PASSTHRU; /* Look for any command that starts with the same characters, if it does, replace the command string with it */ size_t clen = command.length() - 1; std::string foundcommand, matchlist; bool foundmatch = false; const CommandParser::CommandMap& commands = ServerInstance->Parser.GetCommands(); for (CommandParser::CommandMap::const_iterator n = commands.begin(); n != commands.end(); ++n) { if (!command.compare(0, clen, n->first, 0, clen)) { if (matchlist.length() > 450) { user->WriteNumeric(ERR_AMBIGUOUSCOMMAND, "Ambiguous abbreviation and too many possible matches."); return MOD_RES_DENY; } if (!foundmatch) { /* Found the command */ foundcommand = n->first; foundmatch = true; } else matchlist.append(" ").append(n->first); } } /* Ambiguous command, list the matches */ if (!matchlist.empty()) { user->WriteNumeric(ERR_AMBIGUOUSCOMMAND, InspIRCd::Format("Ambiguous abbreviation, possible matches: %s%s", foundcommand.c_str(), matchlist.c_str())); return MOD_RES_DENY; } if (!foundcommand.empty()) { command = foundcommand; } return MOD_RES_PASSTHRU; } }; MODULE_INIT(ModuleAbbreviation) �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/src/modules/m_alias.cpp��������������������������������������������������������������0000664�0000000�0000000�00000025333�13554550454�0017721�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * InspIRCd -- Internet Relay Chat Daemon * * Copyright (C) 2009 Daniel De Graaf <danieldg@inspircd.org> * Copyright (C) 2005, 2009 Robin Burchell <robin+git@viroteck.net> * Copyright (C) 2004-2007, 2009 Craig Edwards <craigedwards@brainbox.cc> * Copyright (C) 2007 Dennis Friis <peavey@inspircd.org> * * This file is part of InspIRCd. InspIRCd is free software: you can * redistribute it and/or modify it under the terms of the GNU General Public * License as published by the Free Software Foundation, version 2. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include "inspircd.h" /** An alias definition */ class Alias { public: /** The text of the alias command */ std::string AliasedCommand; /** Text to replace with */ std::string ReplaceFormat; /** Nickname required to perform alias */ std::string RequiredNick; /** Alias requires ulined server */ bool ULineOnly; /** Requires oper? */ bool OperOnly; /* whether or not it may be executed via fantasy (default OFF) */ bool ChannelCommand; /* whether or not it may be executed via /command (default ON) */ bool UserCommand; /** Format that must be matched for use */ std::string format; /** Strip color codes before match? */ bool StripColor; }; class ModuleAlias : public Module { std::string fprefix; /* We cant use a map, there may be multiple aliases with the same name. * We can, however, use a fancy invention: the multimap. Maps a key to one or more values. * -- w00t */ typedef insp::flat_multimap<std::string, Alias, irc::insensitive_swo> AliasMap; AliasMap Aliases; /* whether or not +B users are allowed to use fantasy commands */ bool AllowBots; UserModeReference botmode; // Whether we are actively executing an alias. bool active; public: void ReadConfig(ConfigStatus& status) CXX11_OVERRIDE { AliasMap newAliases; ConfigTagList tags = ServerInstance->Config->ConfTags("alias"); for(ConfigIter i = tags.first; i != tags.second; ++i) { ConfigTag* tag = i->second; Alias a; a.AliasedCommand = tag->getString("text"); if (a.AliasedCommand.empty()) throw ModuleException("<alias:text> is empty! at " + tag->getTagLocation()); tag->readString("replace", a.ReplaceFormat, true); if (a.ReplaceFormat.empty()) throw ModuleException("<alias:replace> is empty! at " + tag->getTagLocation()); a.RequiredNick = tag->getString("requires"); a.ULineOnly = tag->getBool("uline"); a.ChannelCommand = tag->getBool("channelcommand", false); a.UserCommand = tag->getBool("usercommand", true); a.OperOnly = tag->getBool("operonly"); a.format = tag->getString("format"); a.StripColor = tag->getBool("stripcolor"); std::transform(a.AliasedCommand.begin(), a.AliasedCommand.end(), a.AliasedCommand.begin(), ::toupper); newAliases.insert(std::make_pair(a.AliasedCommand, a)); } ConfigTag* fantasy = ServerInstance->Config->ConfValue("fantasy"); AllowBots = fantasy->getBool("allowbots", false); fprefix = fantasy->getString("prefix", "!", 1, ServerInstance->Config->Limits.MaxLine); Aliases.swap(newAliases); } ModuleAlias() : botmode(this, "bot") , active(false) { } Version GetVersion() CXX11_OVERRIDE { return Version("Provides aliases of commands", VF_VENDOR); } std::string GetVar(std::string varname, const std::string &original_line) { irc::spacesepstream ss(original_line); varname.erase(varname.begin()); int index = *(varname.begin()) - 48; varname.erase(varname.begin()); bool everything_after = (varname == "-"); std::string word; for (int j = 0; j < index; j++) ss.GetToken(word); if (everything_after) { std::string more; while (ss.GetToken(more)) { word.append(" "); word.append(more); } } return word; } std::string CreateRFCMessage(const std::string& command, CommandBase::Params& parameters) { std::string message(command); for (CommandBase::Params::const_iterator iter = parameters.begin(); iter != parameters.end();) { const std::string& parameter = *iter++; message.push_back(' '); if (iter == parameters.end() && (parameter.empty() || parameter.find(' ') != std::string::npos)) message.push_back(':'); message.append(parameter); } return message; } ModResult OnPreCommand(std::string& command, CommandBase::Params& parameters, LocalUser* user, bool validated) CXX11_OVERRIDE { /* If theyre not registered yet, we dont want * to know. */ if (user->registered != REG_ALL) return MOD_RES_PASSTHRU; /* We dont have any commands looking like this? Stop processing. */ std::pair<AliasMap::iterator, AliasMap::iterator> iters = Aliases.equal_range(command); if (iters.first == iters.second) return MOD_RES_PASSTHRU; /* The parameters for the command in their original form, with the command stripped off */ std::string original_line = CreateRFCMessage(command, parameters); std::string compare(original_line, command.length()); while (*(compare.c_str()) == ' ') compare.erase(compare.begin()); for (AliasMap::iterator i = iters.first; i != iters.second; ++i) { if (i->second.UserCommand) { if (DoAlias(user, NULL, &(i->second), compare, original_line)) { return MOD_RES_DENY; } } } // If we made it here, no aliases actually matched. return MOD_RES_PASSTHRU; } ModResult OnUserPreMessage(User* user, const MessageTarget& target, MessageDetails& details) CXX11_OVERRIDE { // Don't echo anything which is caused by an alias. if (active) details.echo = false; return MOD_RES_PASSTHRU; } void OnUserPostMessage(User* user, const MessageTarget& target, const MessageDetails& details) CXX11_OVERRIDE { if ((target.type != MessageTarget::TYPE_CHANNEL) || (details.type != MSG_PRIVMSG)) { return; } // fcommands are only for local users. Spanningtree will send them back out as their original cmd. if (!IS_LOCAL(user)) { return; } /* Stop here if the user is +B and allowbot is set to no. */ if (!AllowBots && user->IsModeSet(botmode)) { return; } Channel *c = target.Get<Channel>(); std::string scommand; // text is like "!moo cows bite me", we want "!moo" first irc::spacesepstream ss(details.text); ss.GetToken(scommand); if (scommand.size() <= fprefix.size()) { return; // wtfbbq } // we don't want to touch non-fantasy stuff if (scommand.compare(0, fprefix.size(), fprefix) != 0) { return; } // nor do we give a shit about the prefix scommand.erase(0, fprefix.size()); std::pair<AliasMap::iterator, AliasMap::iterator> iters = Aliases.equal_range(scommand); if (iters.first == iters.second) return; /* The parameters for the command in their original form, with the command stripped off */ std::string compare(details.text, scommand.length() + fprefix.size()); while (*(compare.c_str()) == ' ') compare.erase(compare.begin()); for (AliasMap::iterator i = iters.first; i != iters.second; ++i) { if (i->second.ChannelCommand) { // We use substr here to remove the fantasy prefix if (DoAlias(user, c, &(i->second), compare, details.text.substr(fprefix.size()))) return; } } } int DoAlias(User *user, Channel *c, Alias *a, const std::string& compare, const std::string& safe) { std::string stripped(compare); if (a->StripColor) InspIRCd::StripColor(stripped); /* Does it match the pattern? */ if (!a->format.empty()) { if (!InspIRCd::Match(stripped, a->format)) return 0; } if ((a->OperOnly) && (!user->IsOper())) return 0; if (!a->RequiredNick.empty()) { User* u = ServerInstance->FindNick(a->RequiredNick); if (!u) { user->WriteNumeric(ERR_NOSUCHNICK, a->RequiredNick, "is currently unavailable. Please try again later."); return 1; } if ((a->ULineOnly) && (!u->server->IsULine())) { ServerInstance->SNO->WriteToSnoMask('a', "NOTICE -- Service "+a->RequiredNick+" required by alias "+a->AliasedCommand+" is not on a U-lined server, possibly underhanded antics detected!"); user->WriteNumeric(ERR_NOSUCHNICK, a->RequiredNick, "is not a network service! Please inform a server operator as soon as possible."); return 1; } } /* Now, search and replace in a copy of the original_line, replacing $1 through $9 and $1- etc */ std::string::size_type crlf = a->ReplaceFormat.find('\n'); if (crlf == std::string::npos) { DoCommand(a->ReplaceFormat, user, c, safe, a); return 1; } else { irc::sepstream commands(a->ReplaceFormat, '\n'); std::string scommand; while (commands.GetToken(scommand)) { DoCommand(scommand, user, c, safe, a); } return 1; } } void DoCommand(const std::string& newline, User* user, Channel *chan, const std::string &original_line, Alias* a) { std::string result; result.reserve(newline.length()); for (unsigned int i = 0; i < newline.length(); i++) { char c = newline[i]; if ((c == '$') && (i + 1 < newline.length())) { if (isdigit(newline[i+1])) { size_t len = ((i + 2 < newline.length()) && (newline[i+2] == '-')) ? 3 : 2; std::string var = newline.substr(i, len); result.append(GetVar(var, original_line)); i += len - 1; } else if (!newline.compare(i, 5, "$nick", 5)) { result.append(user->nick); i += 4; } else if (!newline.compare(i, 5, "$host", 5)) { result.append(user->GetRealHost()); i += 4; } else if (!newline.compare(i, 5, "$chan", 5)) { if (chan) result.append(chan->name); i += 4; } else if (!newline.compare(i, 6, "$ident", 6)) { result.append(user->ident); i += 5; } else if (!newline.compare(i, 6, "$vhost", 6)) { result.append(user->GetDisplayedHost()); i += 5; } else if (!newline.compare(i, 12, "$requirement", 12)) { result.append(a->RequiredNick); i += 11; } else result.push_back(c); } else result.push_back(c); } irc::tokenstream ss(result); CommandBase::Params pars; std::string command, token; ss.GetMiddle(command); while (ss.GetTrailing(token)) { pars.push_back(token); } active = true; ServerInstance->Parser.CallHandler(command, pars, user); active = false; } void Prioritize() CXX11_OVERRIDE { // Prioritise after spanningtree so that channel aliases show the alias before the effects. Module* linkmod = ServerInstance->Modules->Find("m_spanningtree.so"); ServerInstance->Modules->SetPriority(this, I_OnUserPostMessage, PRIORITY_AFTER, linkmod); } }; MODULE_INIT(ModuleAlias) �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/src/modules/m_allowinvite.cpp��������������������������������������������������������0000664�0000000�0000000�00000003354�13554550454�0021164�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * InspIRCd -- Internet Relay Chat Daemon * * Copyright (C) 2008 Robin Burchell <robin+git@viroteck.net> * * 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 "inspircd.h" class ModuleAllowInvite : public Module { SimpleChannelModeHandler ni; public: ModuleAllowInvite() : ni(this, "allowinvite", 'A') { } void On005Numeric(std::map<std::string, std::string>& tokens) CXX11_OVERRIDE { tokens["EXTBAN"].push_back('A'); } ModResult OnUserPreInvite(User* user,User* dest,Channel* channel, time_t timeout) CXX11_OVERRIDE { if (IS_LOCAL(user)) { ModResult res = channel->GetExtBanStatus(user, 'A'); if (res == MOD_RES_DENY) { // Matching extban, explicitly deny /invite user->WriteNumeric(ERR_CHANOPRIVSNEEDED, channel->name, "You are banned from using INVITE"); return res; } if (channel->IsModeSet(ni) || res == MOD_RES_ALLOW) { // Explicitly allow /invite return MOD_RES_ALLOW; } } return MOD_RES_PASSTHRU; } Version GetVersion() CXX11_OVERRIDE { return Version("Provides channel mode +A to allow /INVITE freely on a channel, and extban 'A' to deny specific users it", VF_VENDOR); } }; MODULE_INIT(ModuleAllowInvite) ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/src/modules/m_alltime.cpp������������������������������������������������������������0000664�0000000�0000000�00000003533�13554550454�0020255�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * InspIRCd -- Internet Relay Chat Daemon * * Copyright (C) 2007 Dennis Friis <peavey@inspircd.org> * Copyright (C) 2007 Robin Burchell <robin+git@viroteck.net> * Copyright (C) 2006 John Brooks <john.brooks@dereferenced.net> * * 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 "inspircd.h" class CommandAlltime : public Command { public: CommandAlltime(Module* Creator) : Command(Creator, "ALLTIME", 0) { flags_needed = 'o'; } CmdResult Handle(User* user, const Params& parameters) CXX11_OVERRIDE { const std::string fmtdate = InspIRCd::TimeString(ServerInstance->Time(), "%Y-%m-%d %H:%M:%S", true); std::string msg = "System time is " + fmtdate + " (" + ConvToStr(ServerInstance->Time()) + ") on " + ServerInstance->Config->ServerName; user->WriteRemoteNotice(msg); /* we want this routed out! */ return CMD_SUCCESS; } RouteDescriptor GetRouting(User* user, const Params& parameters) CXX11_OVERRIDE { return ROUTE_OPT_BCAST; } }; class Modulealltime : public Module { CommandAlltime mycommand; public: Modulealltime() : mycommand(this) { } Version GetVersion() CXX11_OVERRIDE { return Version("Provides the ALLTIME command, displays timestamps from all servers connected to the network", VF_OPTCOMMON | VF_VENDOR); } }; MODULE_INIT(Modulealltime) ���������������������������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/src/modules/m_anticaps.cpp�����������������������������������������������������������0000664�0000000�0000000�00000020072�13554550454�0020425�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * InspIRCd -- Internet Relay Chat Daemon * * Copyright (C) 2017 Peter Powell <petpow@saberuk.com> * * This file is part of InspIRCd. InspIRCd is free software: you can * redistribute it and/or modify it under the terms of the GNU General Public * License as published by the Free Software Foundation, version 2. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include "inspircd.h" #include "modules/exemption.h" enum AntiCapsMethod { ACM_BAN, ACM_BLOCK, ACM_MUTE, ACM_KICK, ACM_KICK_BAN }; class AntiCapsSettings { public: const AntiCapsMethod method; const uint16_t minlen; const uint8_t percent; AntiCapsSettings(const AntiCapsMethod& Method, const uint16_t& MinLen, const uint8_t& Percent) : method(Method) , minlen(MinLen) , percent(Percent) { } }; class AntiCapsMode : public ParamMode<AntiCapsMode, SimpleExtItem<AntiCapsSettings> > { private: bool ParseMethod(irc::sepstream& stream, AntiCapsMethod& method) { std::string methodstr; if (!stream.GetToken(methodstr)) return false; if (irc::equals(methodstr, "ban")) method = ACM_BAN; else if (irc::equals(methodstr, "block")) method = ACM_BLOCK; else if (irc::equals(methodstr, "mute")) method = ACM_MUTE; else if (irc::equals(methodstr, "kick")) method = ACM_KICK; else if (irc::equals(methodstr, "kickban")) method = ACM_KICK_BAN; else return false; return true; } bool ParseMinimumLength(irc::sepstream& stream, uint16_t& minlen) { std::string minlenstr; if (!stream.GetToken(minlenstr)) return false; uint16_t result = ConvToNum<uint16_t>(minlenstr); if (result < 1 || result > ServerInstance->Config->Limits.MaxLine) return false; minlen = result; return true; } bool ParsePercent(irc::sepstream& stream, uint8_t& percent) { std::string percentstr; if (!stream.GetToken(percentstr)) return false; uint8_t result = ConvToNum<uint8_t>(percentstr); if (result < 1 || result > 100) return false; percent = result; return true; } public: AntiCapsMode(Module* Creator) : ParamMode<AntiCapsMode, SimpleExtItem<AntiCapsSettings> >(Creator, "anticaps", 'B') { syntax = "{ban|block|mute|kick|kickban}:<minlen>:<percent>"; } ModeAction OnSet(User* source, Channel* channel, std::string& parameter) CXX11_OVERRIDE { irc::sepstream stream(parameter, ':'); AntiCapsMethod method; uint16_t minlen; uint8_t percent; // Attempt to parse the method. if (!ParseMethod(stream, method) || !ParseMinimumLength(stream, minlen) || !ParsePercent(stream, percent)) { source->WriteNumeric(Numerics::InvalidModeParameter(channel, this, parameter)); return MODEACTION_DENY; } ext.set(channel, new AntiCapsSettings(method, minlen, percent)); return MODEACTION_ALLOW; } void SerializeParam(Channel* chan, const AntiCapsSettings* acs, std::string& out) { switch (acs->method) { case ACM_BAN: out.append("ban"); break; case ACM_BLOCK: out.append("block"); break; case ACM_MUTE: out.append("mute"); break; case ACM_KICK: out.append("kick"); break; case ACM_KICK_BAN: out.append("kickban"); break; default: out.append("unknown~"); out.append(ConvToStr(acs->method)); break; } out.push_back(':'); out.append(ConvToStr(acs->minlen)); out.push_back(':'); out.append(ConvNumeric(acs->percent)); } }; class ModuleAntiCaps : public Module { private: CheckExemption::EventProvider exemptionprov; std::bitset<UCHAR_MAX> uppercase; std::bitset<UCHAR_MAX> lowercase; AntiCapsMode mode; void CreateBan(Channel* channel, User* user, bool mute) { std::string banmask(mute ? "m:" : ""); banmask.append("*!*@"); banmask.append(user->GetDisplayedHost()); Modes::ChangeList changelist; changelist.push_add(ServerInstance->Modes->FindMode('b', MODETYPE_CHANNEL), banmask); ServerInstance->Modes->Process(ServerInstance->FakeClient, channel, NULL, changelist); } void InformUser(Channel* channel, User* user, const std::string& message) { user->WriteNumeric(ERR_CANNOTSENDTOCHAN, channel->name, message + " and was blocked."); } public: ModuleAntiCaps() : exemptionprov(this) , mode(this) { } void ReadConfig(ConfigStatus&) CXX11_OVERRIDE { ConfigTag* tag = ServerInstance->Config->ConfValue("anticaps"); uppercase.reset(); const std::string upper = tag->getString("uppercase", "ABCDEFGHIJKLMNOPQRSTUVWXYZ"); for (std::string::const_iterator iter = upper.begin(); iter != upper.end(); ++iter) uppercase.set(static_cast<unsigned char>(*iter)); lowercase.reset(); const std::string lower = tag->getString("lowercase", "abcdefghijklmnopqrstuvwxyz"); for (std::string::const_iterator iter = lower.begin(); iter != lower.end(); ++iter) lowercase.set(static_cast<unsigned char>(*iter)); } ModResult OnUserPreMessage(User* user, const MessageTarget& target, MessageDetails& details) CXX11_OVERRIDE { // We only want to operate on messages from local users. if (!IS_LOCAL(user)) return MOD_RES_PASSTHRU; // The mode can only be applied to channels. if (target.type != MessageTarget::TYPE_CHANNEL) return MOD_RES_PASSTHRU; // We only act if the channel has the mode set. Channel* channel = target.Get<Channel>(); if (!channel->IsModeSet(&mode)) return MOD_RES_PASSTHRU; // If the user is exempt from anticaps then we don't need // to do anything else. ModResult result = CheckExemption::Call(exemptionprov, user, channel, "anticaps"); if (result == MOD_RES_ALLOW) return MOD_RES_PASSTHRU; // If the message is a CTCP then we skip it unless it is // an ACTION in which case we just check against the body. std::string ctcpname; std::string msgbody(details.text); if (details.IsCTCP(ctcpname, msgbody)) { // If the CTCP is not an action then skip it. if (!irc::equals(ctcpname, "ACTION")) return MOD_RES_PASSTHRU; } // Retrieve the anticaps config. This should never be // null but its better to be safe than sorry. AntiCapsSettings* config = mode.ext.get(channel); if (!config) return MOD_RES_PASSTHRU; // If the message is shorter than the minimum length then // we don't need to do anything else. size_t length = msgbody.length(); if (length < config->minlen) return MOD_RES_PASSTHRU; // Count the characters to see how many upper case and // ignored (non upper or lower) characters there are. size_t upper = 0; for (std::string::const_iterator iter = msgbody.begin(); iter != msgbody.end(); ++iter) { unsigned char chr = static_cast<unsigned char>(*iter); if (uppercase.test(chr)) upper += 1; else if (!lowercase.test(chr)) length -= 1; } // If the message was entirely symbols then the message // can't contain any upper case letters. if (length == 0) return MOD_RES_PASSTHRU; // Calculate the percentage. double percent = round((upper * 100) / length); if (percent < config->percent) return MOD_RES_PASSTHRU; const std::string message = InspIRCd::Format("Your message exceeded the %d%% upper case character threshold for %s", config->percent, channel->name.c_str()); switch (config->method) { case ACM_BAN: InformUser(channel, user, message); CreateBan(channel, user, false); break; case ACM_BLOCK: InformUser(channel, user, message); break; case ACM_MUTE: InformUser(channel, user, message); CreateBan(channel, user, true); break; case ACM_KICK: channel->KickUser(ServerInstance->FakeClient, user, message); break; case ACM_KICK_BAN: CreateBan(channel, user, false); channel->KickUser(ServerInstance->FakeClient, user, message); break; } return MOD_RES_DENY; } Version GetVersion() CXX11_OVERRIDE { return Version("Provides support for punishing users that send capitalised messages", VF_COMMON|VF_VENDOR); } }; MODULE_INIT(ModuleAntiCaps) ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/src/modules/m_auditorium.cpp���������������������������������������������������������0000664�0000000�0000000�00000014352�13554550454�0021011�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * InspIRCd -- Internet Relay Chat Daemon * * Copyright (C) 2009-2010 Daniel De Graaf <danieldg@inspircd.org> * Copyright (C) 2007-2008 Craig Edwards <craigedwards@brainbox.cc> * Copyright (C) 2007 Dennis Friis <peavey@inspircd.org> * Copyright (C) 2007 Robin Burchell <robin+git@viroteck.net> * * 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 "inspircd.h" #include "modules/exemption.h" #include "modules/names.h" #include "modules/who.h" class AuditoriumMode : public SimpleChannelModeHandler { public: AuditoriumMode(Module* Creator) : SimpleChannelModeHandler(Creator, "auditorium", 'u') { ranktoset = ranktounset = OP_VALUE; } }; class ModuleAuditorium; namespace { /** Hook handler for join client protocol events. * This allows us to block join protocol events completely, including all associated messages (e.g. MODE, away-notify AWAY). * This is not the same as OnUserJoin() because that runs only when a real join happens but this runs also when a module * such as delayjoin or hostcycle generates a join. */ class JoinHook : public ClientProtocol::EventHook { ModuleAuditorium* const parentmod; bool active; public: JoinHook(ModuleAuditorium* mod); void OnEventInit(const ClientProtocol::Event& ev) CXX11_OVERRIDE; ModResult OnPreEventSend(LocalUser* user, const ClientProtocol::Event& ev, ClientProtocol::MessageList& messagelist) CXX11_OVERRIDE; }; } class ModuleAuditorium : public Module , public Names::EventListener , public Who::EventListener { CheckExemption::EventProvider exemptionprov; AuditoriumMode aum; bool OpsVisible; bool OpsCanSee; bool OperCanSee; JoinHook joinhook; public: ModuleAuditorium() : Names::EventListener(this) , Who::EventListener(this) , exemptionprov(this) , aum(this) , joinhook(this) { } void ReadConfig(ConfigStatus& status) CXX11_OVERRIDE { ConfigTag* tag = ServerInstance->Config->ConfValue("auditorium"); OpsVisible = tag->getBool("opvisible"); OpsCanSee = tag->getBool("opcansee"); OperCanSee = tag->getBool("opercansee", true); } Version GetVersion() CXX11_OVERRIDE { return Version("Provides channel mode +u, auditorium channels where nobody can see others joining and parting or the nick list", VF_VENDOR); } /* Can they be seen by everyone? */ bool IsVisible(Membership* memb) { if (!memb->chan->IsModeSet(&aum)) return true; ModResult res = CheckExemption::Call(exemptionprov, memb->user, memb->chan, "auditorium-vis"); return res.check(OpsVisible && memb->getRank() >= OP_VALUE); } /* Can they see this specific membership? */ bool CanSee(User* issuer, Membership* memb) { // If user is oper and operoverride is on, don't touch the list if (OperCanSee && issuer->HasPrivPermission("channels/auspex")) return true; // You can always see yourself if (issuer == memb->user) return true; // Can you see the list by permission? ModResult res = CheckExemption::Call(exemptionprov, issuer, memb->chan, "auditorium-see"); if (res.check(OpsCanSee && memb->chan->GetPrefixValue(issuer) >= OP_VALUE)) return true; return false; } ModResult OnNamesListItem(LocalUser* issuer, Membership* memb, std::string& prefixes, std::string& nick) CXX11_OVERRIDE { if (IsVisible(memb)) return MOD_RES_PASSTHRU; if (CanSee(issuer, memb)) return MOD_RES_PASSTHRU; // Don't display this user in the NAMES list return MOD_RES_DENY; } /** Build CUList for showing this join/part/kick */ void BuildExcept(Membership* memb, CUList& excepts) { if (IsVisible(memb)) return; const Channel::MemberMap& users = memb->chan->GetUsers(); for (Channel::MemberMap::const_iterator i = users.begin(); i != users.end(); ++i) { if (IS_LOCAL(i->first) && !CanSee(i->first, memb)) excepts.insert(i->first); } } void OnUserPart(Membership* memb, std::string &partmessage, CUList& excepts) CXX11_OVERRIDE { BuildExcept(memb, excepts); } void OnUserKick(User* source, Membership* memb, const std::string &reason, CUList& excepts) CXX11_OVERRIDE { BuildExcept(memb, excepts); } void OnBuildNeighborList(User* source, IncludeChanList& include, std::map<User*, bool>& exception) CXX11_OVERRIDE { for (IncludeChanList::iterator i = include.begin(); i != include.end(); ) { Membership* memb = *i; if (IsVisible(memb)) { ++i; continue; } // this channel should not be considered when listing my neighbors i = include.erase(i); // however, that might hide me from ops that can see me... const Channel::MemberMap& users = memb->chan->GetUsers(); for(Channel::MemberMap::const_iterator j = users.begin(); j != users.end(); ++j) { if (IS_LOCAL(j->first) && CanSee(j->first, memb)) exception[j->first] = true; } } } ModResult OnWhoLine(const Who::Request& request, LocalUser* source, User* user, Membership* memb, Numeric::Numeric& numeric) CXX11_OVERRIDE { if (!memb) return MOD_RES_PASSTHRU; if (IsVisible(memb)) return MOD_RES_PASSTHRU; if (CanSee(source, memb)) return MOD_RES_PASSTHRU; return MOD_RES_DENY; } }; JoinHook::JoinHook(ModuleAuditorium* mod) : ClientProtocol::EventHook(mod, "JOIN", 10) , parentmod(mod) { } void JoinHook::OnEventInit(const ClientProtocol::Event& ev) { const ClientProtocol::Events::Join& join = static_cast<const ClientProtocol::Events::Join&>(ev); active = !parentmod->IsVisible(join.GetMember()); } ModResult JoinHook::OnPreEventSend(LocalUser* user, const ClientProtocol::Event& ev, ClientProtocol::MessageList& messagelist) { if (!active) return MOD_RES_PASSTHRU; const ClientProtocol::Events::Join& join = static_cast<const ClientProtocol::Events::Join&>(ev); return ((parentmod->CanSee(user, join.GetMember())) ? MOD_RES_PASSTHRU : MOD_RES_DENY); } MODULE_INIT(ModuleAuditorium) ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/src/modules/m_autoop.cpp�������������������������������������������������������������0000664�0000000�0000000�00000006674�13554550454�0020146�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * InspIRCd -- Internet Relay Chat Daemon * * Copyright (C) 2011 Jackmcbarn <jackmcbarn@jackmcbarn.no-ip.org> * Copyright (C) 2010 Daniel De Graaf <danieldg@inspircd.org> * * This file is part of InspIRCd. InspIRCd is free software: you can * redistribute it and/or modify it under the terms of the GNU General Public * License as published by the Free Software Foundation, version 2. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include "inspircd.h" #include "listmode.h" /** Handles +w channel mode */ class AutoOpList : public ListModeBase { public: AutoOpList(Module* Creator) : ListModeBase(Creator, "autoop", 'w', "End of Channel Access List", 910, 911, true) { ranktoset = ranktounset = OP_VALUE; syntax = "<prefix>:<mask>"; tidy = false; } PrefixMode* FindMode(const std::string& mid) { if (mid.length() == 1) return ServerInstance->Modes->FindPrefixMode(mid[0]); ModeHandler* mh = ServerInstance->Modes->FindMode(mid, MODETYPE_CHANNEL); return mh ? mh->IsPrefixMode() : NULL; } ModResult AccessCheck(User* source, Channel* channel, std::string &parameter, bool adding) CXX11_OVERRIDE { std::string::size_type pos = parameter.find(':'); if (pos == 0 || pos == std::string::npos) return adding ? MOD_RES_DENY : MOD_RES_PASSTHRU; unsigned int mylevel = channel->GetPrefixValue(source); std::string mid(parameter, 0, pos); PrefixMode* mh = FindMode(mid); if (adding && !mh) { source->WriteNumeric(ERR_UNKNOWNMODE, mid, InspIRCd::Format("Cannot find prefix mode '%s' for autoop", mid.c_str())); return MOD_RES_DENY; } else if (!mh) return MOD_RES_PASSTHRU; std::string dummy; if (mh->AccessCheck(source, channel, dummy, true) == MOD_RES_DENY) return MOD_RES_DENY; if (mh->GetLevelRequired(adding) > mylevel) { source->WriteNumeric(ERR_CHANOPRIVSNEEDED, channel->name, InspIRCd::Format("You must be able to %s mode %c (%s) to %s an autoop containing it", adding ? "set" : "unset", mh->GetModeChar(), mh->name.c_str(), adding ? "add" : "remove")); return MOD_RES_DENY; } return MOD_RES_PASSTHRU; } }; class ModuleAutoOp : public Module { AutoOpList mh; public: ModuleAutoOp() : mh(this) { } void OnPostJoin(Membership *memb) CXX11_OVERRIDE { if (!IS_LOCAL(memb->user)) return; ListModeBase::ModeList* list = mh.GetList(memb->chan); if (list) { Modes::ChangeList changelist; for (ListModeBase::ModeList::iterator it = list->begin(); it != list->end(); it++) { std::string::size_type colon = it->mask.find(':'); if (colon == std::string::npos) continue; if (memb->chan->CheckBan(memb->user, it->mask.substr(colon+1))) { PrefixMode* given = mh.FindMode(it->mask.substr(0, colon)); if (given) changelist.push_add(given, memb->user->nick); } } ServerInstance->Modes->Process(ServerInstance->FakeClient, memb->chan, NULL, changelist); } } void ReadConfig(ConfigStatus& status) CXX11_OVERRIDE { mh.DoRehash(); } Version GetVersion() CXX11_OVERRIDE { return Version("Provides channel mode +w, basic channel access controls", VF_VENDOR); } }; MODULE_INIT(ModuleAutoOp) ��������������������������������������������������������������������inspircd-3.4.0/src/modules/m_banexception.cpp�������������������������������������������������������0000664�0000000�0000000�00000006201�13554550454�0021300�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * InspIRCd -- Internet Relay Chat Daemon * * Copyright (C) 2009 Daniel De Graaf <danieldg@inspircd.org> * Copyright (C) 2006-2008 Craig Edwards <craigedwards@brainbox.cc> * Copyright (C) 2007-2008 Robin Burchell <robin+git@viroteck.net> * Copyright (C) 2007 Dennis Friis <peavey@inspircd.org> * Copyright (C) 2006 Oliver Lupton <oliverlupton@gmail.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 "inspircd.h" #include "listmode.h" /* Written by Om<om@inspircd.org>, April 2005. */ /* Rewritten to use the listmode utility by Om, December 2005 */ /* Adapted from m_exception, which was originally based on m_chanprotect and m_silence */ // The +e channel mode takes a nick!ident@host, glob patterns allowed, // and if a user matches an entry on the +e list then they can join the channel, overriding any (+b) bans set on them // Now supports CIDR and IP addresses -- Brain /** Handles +e channel mode */ class BanException : public ListModeBase { public: BanException(Module* Creator) : ListModeBase(Creator, "banexception", 'e', "End of Channel Exception List", 348, 349, true) { syntax = "<mask>"; } }; class ModuleBanException : public Module { BanException be; public: ModuleBanException() : be(this) { } void On005Numeric(std::map<std::string, std::string>& tokens) CXX11_OVERRIDE { tokens["EXCEPTS"] = ConvToStr(be.GetModeChar()); } ModResult OnExtBanCheck(User *user, Channel *chan, char type) CXX11_OVERRIDE { ListModeBase::ModeList* list = be.GetList(chan); if (!list) return MOD_RES_PASSTHRU; for (ListModeBase::ModeList::iterator it = list->begin(); it != list->end(); it++) { if (it->mask.length() <= 2 || it->mask[0] != type || it->mask[1] != ':') continue; if (chan->CheckBan(user, it->mask.substr(2))) { // They match an entry on the list, so let them pass this. return MOD_RES_ALLOW; } } return MOD_RES_PASSTHRU; } ModResult OnCheckChannelBan(User* user, Channel* chan) CXX11_OVERRIDE { ListModeBase::ModeList* list = be.GetList(chan); if (!list) { // No list, proceed normally return MOD_RES_PASSTHRU; } for (ListModeBase::ModeList::iterator it = list->begin(); it != list->end(); it++) { if (chan->CheckBan(user, it->mask)) { // They match an entry on the list, so let them in. return MOD_RES_ALLOW; } } return MOD_RES_PASSTHRU; } void ReadConfig(ConfigStatus& status) CXX11_OVERRIDE { be.DoRehash(); } Version GetVersion() CXX11_OVERRIDE { return Version("Provides channel mode +e, ban exceptions", VF_VENDOR); } }; MODULE_INIT(ModuleBanException) �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/src/modules/m_banredirect.cpp��������������������������������������������������������0000664�0000000�0000000�00000024703�13554550454�0021112�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * InspIRCd -- Internet Relay Chat Daemon * * Copyright (C) 2009 Daniel De Graaf <danieldg@inspircd.org> * Copyright (C) 2007, 2009 Robin Burchell <robin+git@viroteck.net> * Copyright (C) 2008 Pippijn van Steenhoven <pip88nl@gmail.com> * Copyright (C) 2007 Dennis Friis <peavey@inspircd.org> * Copyright (C) 2007 Craig Edwards <craigedwards@brainbox.cc> * Copyright (C) 2007 Oliver Lupton <oliverlupton@gmail.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 "inspircd.h" #include "listmode.h" /* Originally written by Om, January 2009 */ class BanRedirectEntry { public: std::string targetchan; std::string banmask; BanRedirectEntry(const std::string &target = "", const std::string &mask = "") : targetchan(target), banmask(mask) { } }; typedef std::vector<BanRedirectEntry> BanRedirectList; class BanRedirect : public ModeWatcher { ChanModeReference ban; public: SimpleExtItem<BanRedirectList> extItem; BanRedirect(Module* parent) : ModeWatcher(parent, "ban", MODETYPE_CHANNEL) , ban(parent, "ban") , extItem("banredirect", ExtensionItem::EXT_CHANNEL, parent) { } bool BeforeMode(User* source, User* dest, Channel* channel, std::string& param, bool adding) CXX11_OVERRIDE { /* nick!ident@host -> nick!ident@host * nick!ident@host#chan -> nick!ident@host#chan * nick@host#chan -> nick!*@host#chan * nick!ident#chan -> nick!ident@*#chan * nick#chan -> nick!*@*#chan */ if ((channel) && !param.empty()) { BanRedirectList* redirects; std::string mask[4]; enum { NICK, IDENT, HOST, CHAN } current = NICK; std::string::iterator start_pos = param.begin(); if (param.length() >= 2 && param[1] == ':') return true; if (param.find('#') == std::string::npos) return true; ListModeBase* banlm = static_cast<ListModeBase*>(*ban); unsigned int maxbans = banlm->GetLimit(channel); ListModeBase::ModeList* list = banlm->GetList(channel); if ((list) && (adding) && (maxbans <= list->size())) { source->WriteNumeric(ERR_BANLISTFULL, channel->name, banlm->GetModeChar(), InspIRCd::Format("Channel ban list for %s is full (maximum entries for this channel is %u)", channel->name.c_str(), maxbans)); return false; } for(std::string::iterator curr = start_pos; curr != param.end(); curr++) { switch(*curr) { case '!': if (current != NICK) break; mask[current].assign(start_pos, curr); current = IDENT; start_pos = curr+1; break; case '@': if (current != IDENT) break; mask[current].assign(start_pos, curr); current = HOST; start_pos = curr+1; break; case '#': if (current == CHAN) break; mask[current].assign(start_pos, curr); current = CHAN; start_pos = curr; break; } } if(mask[current].empty()) { mask[current].assign(start_pos, param.end()); } /* nick@host wants to be changed to *!nick@host rather than nick!*@host... */ if(mask[NICK].length() && mask[HOST].length() && mask[IDENT].empty()) { /* std::string::swap() is fast - it runs in constant time */ mask[NICK].swap(mask[IDENT]); } if (!mask[NICK].empty() && mask[IDENT].empty() && mask[HOST].empty()) { if (mask[NICK].find('.') != std::string::npos || mask[NICK].find(':') != std::string::npos) { mask[NICK].swap(mask[HOST]); } } for(int i = 0; i < 3; i++) { if(mask[i].empty()) { mask[i].assign("*"); } } param.assign(mask[NICK]).append(1, '!').append(mask[IDENT]).append(1, '@').append(mask[HOST]); if(mask[CHAN].length()) { if (adding && IS_LOCAL(source)) { if (!ServerInstance->IsChannel(mask[CHAN])) { source->WriteNumeric(ERR_NOSUCHCHANNEL, channel->name, InspIRCd::Format("Invalid channel name in redirection (%s)", mask[CHAN].c_str())); return false; } Channel *c = ServerInstance->FindChan(mask[CHAN]); if (!c) { source->WriteNumeric(690, InspIRCd::Format("Target channel %s must exist to be set as a redirect.", mask[CHAN].c_str())); return false; } else if (adding && c->GetPrefixValue(source) < OP_VALUE) { source->WriteNumeric(690, InspIRCd::Format("You must be opped on %s to set it as a redirect.", mask[CHAN].c_str())); return false; } if (irc::equals(channel->name, mask[CHAN])) { source->WriteNumeric(690, channel->name, "You cannot set a ban redirection to the channel the ban is on"); return false; } } if(adding) { /* It's a properly valid redirecting ban, and we're adding it */ redirects = extItem.get(channel); if (!redirects) { redirects = new BanRedirectList; extItem.set(channel, redirects); } else { for (BanRedirectList::iterator redir = redirects->begin(); redir != redirects->end(); ++redir) { // Mimic the functionality used when removing the mode if (irc::equals(redir->targetchan, mask[CHAN]) && irc::equals(redir->banmask, param)) { // Make sure the +b handler will still set the right ban param.append(mask[CHAN]); // Silently ignore the duplicate and don't set metadata // This still allows channel ops to set/unset a redirect ban to clear "ghost" redirects return true; } } } /* Here 'param' doesn't have the channel on it yet */ redirects->push_back(BanRedirectEntry(mask[CHAN], param)); /* Now it does */ param.append(mask[CHAN]); } else { /* Removing a ban, if there's no extensible there are no redirecting bans and we're fine. */ redirects = extItem.get(channel); if (redirects) { /* But there were, so we need to remove the matching one if there is one */ for(BanRedirectList::iterator redir = redirects->begin(); redir != redirects->end(); redir++) { if ((irc::equals(redir->targetchan, mask[CHAN])) && (irc::equals(redir->banmask, param))) { redirects->erase(redir); if(redirects->empty()) { extItem.unset(channel); } break; } } } /* Append the channel so the default +b handler can remove the entry too */ param.append(mask[CHAN]); } } } return true; } }; class ModuleBanRedirect : public Module { BanRedirect re; bool nofollow; ChanModeReference limitmode; ChanModeReference redirectmode; public: ModuleBanRedirect() : re(this) , nofollow(false) , limitmode(this, "limit") , redirectmode(this, "redirect") { } void OnCleanup(ExtensionItem::ExtensibleType type, Extensible* item) CXX11_OVERRIDE { if (type == ExtensionItem::EXT_CHANNEL) { Channel* chan = static_cast<Channel*>(item); BanRedirectList* redirects = re.extItem.get(chan); if(redirects) { ModeHandler* ban = ServerInstance->Modes->FindMode('b', MODETYPE_CHANNEL); Modes::ChangeList changelist; for(BanRedirectList::iterator i = redirects->begin(); i != redirects->end(); i++) changelist.push_remove(ban, i->targetchan.insert(0, i->banmask)); for(BanRedirectList::iterator i = redirects->begin(); i != redirects->end(); i++) changelist.push_add(ban, i->banmask); ServerInstance->Modes->Process(ServerInstance->FakeClient, chan, NULL, changelist, ModeParser::MODE_LOCALONLY); } } } ModResult OnUserPreJoin(LocalUser* user, Channel* chan, const std::string& cname, std::string& privs, const std::string& keygiven) CXX11_OVERRIDE { if (chan) { BanRedirectList* redirects = re.extItem.get(chan); if (redirects) { /* We actually had some ban redirects to check */ /* This was replaced with user->MakeHostIP() when I had a snprintf(), but MakeHostIP() doesn't seem to add the nick. * Maybe we should have a GetFullIPHost() or something to match GetFullHost() and GetFullRealHost? */ ModResult result; FIRST_MOD_RESULT(OnCheckChannelBan, result, (user, chan)); if (result == MOD_RES_ALLOW) { // they have a ban exception return MOD_RES_PASSTHRU; } std::string ipmask(user->nick); ipmask.append(1, '!').append(user->MakeHostIP()); for(BanRedirectList::iterator redir = redirects->begin(); redir != redirects->end(); redir++) { if(InspIRCd::Match(user->GetFullRealHost(), redir->banmask) || InspIRCd::Match(user->GetFullHost(), redir->banmask) || InspIRCd::MatchCIDR(ipmask, redir->banmask)) { /* This prevents recursion when a user sets multiple ban redirects in a chain * (thanks Potter) * * If we're here and nofollow is true then we're already redirecting this user * and there's a redirecting ban set on this channel that matches him, too. * Deny both joins. */ if (nofollow) return MOD_RES_DENY; /* tell them they're banned and are being transferred */ Channel* destchan = ServerInstance->FindChan(redir->targetchan); std::string destlimit; if (destchan) destlimit = destchan->GetModeParameter(limitmode); if(destchan && destchan->IsModeSet(redirectmode) && !destlimit.empty() && (destchan->GetUserCounter() >= ConvToNum<size_t>(destlimit))) { user->WriteNumeric(ERR_BANNEDFROMCHAN, chan->name, "Cannot join channel (you're banned)"); return MOD_RES_DENY; } else { user->WriteNumeric(ERR_BANNEDFROMCHAN, chan->name, "Cannot join channel (you're banned)"); user->WriteNumeric(470, chan->name, redir->targetchan, "You are banned from this channel, so you are automatically being transferred to the redirected channel."); nofollow = true; Channel::JoinUser(user, redir->targetchan); nofollow = false; return MOD_RES_DENY; } } } } } return MOD_RES_PASSTHRU; } Version GetVersion() CXX11_OVERRIDE { return Version("Allows an extended ban (+b) syntax redirecting banned users to another channel", VF_COMMON|VF_VENDOR); } }; MODULE_INIT(ModuleBanRedirect) �������������������������������������������������������������inspircd-3.4.0/src/modules/m_bcrypt.cpp�������������������������������������������������������������0000664�0000000�0000000�00000004551�13554550454�0020132�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * InspIRCd -- Internet Relay Chat Daemon * * Copyright (C) 2013 Daniel Vassdal <shutter@canternet.org> * * This file is part of InspIRCd. InspIRCd is free software: you can * redistribute it and/or modify it under the terms of the GNU General Public * License as published by the Free Software Foundation, version 2. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ /// $CompilerFlags: -Ivendor_directory("bcrypt") #include "inspircd.h" #include "modules/hash.h" #include <crypt_blowfish.c> class BCryptProvider : public HashProvider { private: std::string Salt() { char entropy[16]; for (unsigned int i = 0; i < sizeof(entropy); ++i) entropy[i] = ServerInstance->GenRandomInt(0xFF); char salt[32]; if (!_crypt_gensalt_blowfish_rn("$2a$", rounds, entropy, sizeof(entropy), salt, sizeof(salt))) throw ModuleException("Could not generate salt - this should never happen"); return salt; } public: unsigned int rounds; std::string Generate(const std::string& data, const std::string& salt) { char hash[64]; _crypt_blowfish_rn(data.c_str(), salt.c_str(), hash, sizeof(hash)); return hash; } std::string GenerateRaw(const std::string& data) CXX11_OVERRIDE { return Generate(data, Salt()); } bool Compare(const std::string& input, const std::string& hash) CXX11_OVERRIDE { std::string ret = Generate(input, hash); if (ret.empty()) return false; if (ret == hash) return true; return false; } std::string ToPrintable(const std::string& raw) CXX11_OVERRIDE { return raw; } BCryptProvider(Module* parent) : HashProvider(parent, "bcrypt", 60) , rounds(10) { } }; class ModuleBCrypt : public Module { BCryptProvider bcrypt; public: ModuleBCrypt() : bcrypt(this) { } void ReadConfig(ConfigStatus& status) CXX11_OVERRIDE { ConfigTag* conf = ServerInstance->Config->ConfValue("bcrypt"); bcrypt.rounds = conf->getUInt("rounds", 10, 1); } Version GetVersion() CXX11_OVERRIDE { return Version("Implements bcrypt hashing", VF_VENDOR); } }; MODULE_INIT(ModuleBCrypt) �������������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/src/modules/m_blockamsg.cpp����������������������������������������������������������0000664�0000000�0000000�00000012262�13554550454�0020567�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * InspIRCd -- Internet Relay Chat Daemon * * Copyright (C) 2009 Daniel De Graaf <danieldg@inspircd.org> * Copyright (C) 2008 Pippijn van Steenhoven <pip88nl@gmail.com> * Copyright (C) 2007 Dennis Friis <peavey@inspircd.org> * Copyright (C) 2007 Robin Burchell <robin+git@viroteck.net> * Copyright (C) 2006-2007 Oliver Lupton <oliverlupton@gmail.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 "inspircd.h" enum BlockAction { IBLOCK_KILL, IBLOCK_KILLOPERS, IBLOCK_NOTICE, IBLOCK_NOTICEOPERS, IBLOCK_SILENT }; /* IBLOCK_NOTICE - Send a notice to the user informing them of what happened. * IBLOCK_NOTICEOPERS - Send a notice to the user informing them and send an oper notice. * IBLOCK_SILENT - Generate no output, silently drop messages. * IBLOCK_KILL - Kill the user with the reason "Global message (/amsg or /ame) detected". * IBLOCK_KILLOPERS - As above, but send an oper notice as well. This is the default. */ /** Holds a blocked message's details */ class BlockedMessage { public: std::string message; std::string target; time_t sent; BlockedMessage(const std::string& msg, const std::string& tgt, time_t when) : message(msg), target(tgt), sent(when) { } }; class ModuleBlockAmsg : public Module { unsigned int ForgetDelay; BlockAction action; SimpleExtItem<BlockedMessage> blockamsg; public: ModuleBlockAmsg() : blockamsg("blockamsg", ExtensionItem::EXT_USER, this) { } Version GetVersion() CXX11_OVERRIDE { return Version("Attempt to block /amsg or /ame, at least some of the irritating client scripts", VF_VENDOR); } void ReadConfig(ConfigStatus& status) CXX11_OVERRIDE { ConfigTag* tag = ServerInstance->Config->ConfValue("blockamsg"); ForgetDelay = tag->getDuration("delay", 3); std::string act = tag->getString("action"); if (stdalgo::string::equalsci(act, "notice")) action = IBLOCK_NOTICE; else if (stdalgo::string::equalsci(act, "noticeopers")) action = IBLOCK_NOTICEOPERS; else if (stdalgo::string::equalsci(act, "silent")) action = IBLOCK_SILENT; else if (stdalgo::string::equalsci(act, "kill")) action = IBLOCK_KILL; else action = IBLOCK_KILLOPERS; } ModResult OnPreCommand(std::string& command, CommandBase::Params& parameters, LocalUser* user, bool validated) CXX11_OVERRIDE { // Don't do anything with unregistered users if (user->registered != REG_ALL) return MOD_RES_PASSTHRU; if ((validated) && (parameters.size() >= 2) && ((command == "PRIVMSG") || (command == "NOTICE"))) { // parameters[0] is the target list, count how many channels are there unsigned int targets = 0; // Is the first target a channel? if (*parameters[0].c_str() == '#') targets = 1; for (const char* c = parameters[0].c_str(); *c; c++) { if ((*c == ',') && (*(c+1) == '#')) targets++; } /* targets should now contain the number of channel targets the msg/notice was pointed at. * If the msg/notice was a PM there should be no channel targets and 'targets' should = 0. * We don't want to block PMs so... */ if (targets == 0) return MOD_RES_PASSTHRU; // Check that this message wasn't already sent within a few seconds. BlockedMessage* m = blockamsg.get(user); // If the message is identical and within the time. // We check the target is *not* identical, that'd straying into the realms of flood control. Which isn't what we're doing... // OR // The number of target channels is equal to the number of channels the sender is on..a little suspicious. // Check it's more than 1 too, or else users on one channel would have fun. if ((m && (m->message == parameters[1]) && (!irc::equals(m->target, parameters[0])) && ForgetDelay && (m->sent >= ServerInstance->Time()-ForgetDelay)) || ((targets > 1) && (targets == user->chans.size()))) { // Block it... if (action == IBLOCK_KILLOPERS || action == IBLOCK_NOTICEOPERS) ServerInstance->SNO->WriteToSnoMask('a', "%s had an /amsg or /ame blocked", user->nick.c_str()); if (action == IBLOCK_KILL || action == IBLOCK_KILLOPERS) ServerInstance->Users->QuitUser(user, "Attempted to global message (/amsg or /ame)"); else if (action == IBLOCK_NOTICE || action == IBLOCK_NOTICEOPERS) user->WriteNotice("Global message (/amsg or /ame) blocked"); return MOD_RES_DENY; } if (m) { // If there's already a BlockedMessage allocated, use it. m->message = parameters[1]; m->target = parameters[0]; m->sent = ServerInstance->Time(); } else { m = new BlockedMessage(parameters[1], parameters[0], ServerInstance->Time()); blockamsg.set(user, m); } } return MOD_RES_PASSTHRU; } }; MODULE_INIT(ModuleBlockAmsg) ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/src/modules/m_blockcaps.cpp����������������������������������������������������������0000664�0000000�0000000�00000010307�13554550454�0020564�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * InspIRCd -- Internet Relay Chat Daemon * * Copyright (C) 2006, 2008 Craig Edwards <craigedwards@brainbox.cc> * Copyright (C) 2006-2007 Dennis Friis <peavey@inspircd.org> * Copyright (C) 2007 Robin Burchell <robin+git@viroteck.net> * Copyright (C) 2006 Oliver Lupton <oliverlupton@gmail.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 "inspircd.h" #include "modules/exemption.h" class ModuleBlockCAPS : public Module { CheckExemption::EventProvider exemptionprov; SimpleChannelModeHandler bc; unsigned int percent; unsigned int minlen; std::bitset<UCHAR_MAX> lowercase; std::bitset<UCHAR_MAX> uppercase; public: ModuleBlockCAPS() : exemptionprov(this) , bc(this, "blockcaps", 'B') { } void On005Numeric(std::map<std::string, std::string>& tokens) CXX11_OVERRIDE { tokens["EXTBAN"].push_back('B'); } ModResult OnUserPreMessage(User* user, const MessageTarget& target, MessageDetails& details) CXX11_OVERRIDE { if (target.type == MessageTarget::TYPE_CHANNEL) { if (!IS_LOCAL(user)) return MOD_RES_PASSTHRU; Channel* c = target.Get<Channel>(); ModResult res = CheckExemption::Call(exemptionprov, user, c, "blockcaps"); if (res == MOD_RES_ALLOW) return MOD_RES_PASSTHRU; if (!c->GetExtBanStatus(user, 'B').check(!c->IsModeSet(bc))) { // If the message is a CTCP then we skip it unless it is // an ACTION in which case we just check against the body. std::string ctcpname; std::string message(details.text); if (details.IsCTCP(ctcpname, message)) { // If the CTCP is not an action then skip it. if (!irc::equals(ctcpname, "ACTION")) return MOD_RES_PASSTHRU; } // If the message is shorter than the minimum length // then we don't need to do anything else. size_t length = message.length(); if (length < minlen) return MOD_RES_PASSTHRU; // Count the characters to see how many upper case and // ignored (non upper or lower) characters there are. size_t upper = 0; for (std::string::const_iterator iter = message.begin(); iter != message.end(); ++iter) { unsigned char chr = static_cast<unsigned char>(*iter); if (uppercase.test(chr)) upper += 1; else if (!lowercase.test(chr)) length -= 1; } // Calculate the percentage which is upper case. If the // message was entirely symbols then it can't contain // any upper case letters. if (length > 0 && round((upper * 100) / length) >= percent) { user->WriteNumeric(ERR_CANNOTSENDTOCHAN, c->name, InspIRCd::Format("Your message cannot contain %d%% or more capital letters if it's longer than %d characters", percent, minlen)); return MOD_RES_DENY; } } } return MOD_RES_PASSTHRU; } void ReadConfig(ConfigStatus& status) CXX11_OVERRIDE { ConfigTag* tag = ServerInstance->Config->ConfValue("blockcaps"); percent = tag->getUInt("percent", 100, 1, 100); minlen = tag->getUInt("minlen", 1, 1, ServerInstance->Config->Limits.MaxLine); lowercase.reset(); const std::string lower = tag->getString("lowercase", "abcdefghijklmnopqrstuvwxyz"); for (std::string::const_iterator iter = lower.begin(); iter != lower.end(); ++iter) lowercase.set(static_cast<unsigned char>(*iter)); uppercase.reset(); const std::string upper = tag->getString("uppercase", tag->getString("capsmap", "ABCDEFGHIJKLMNOPQRSTUVWXYZ")); for (std::string::const_iterator iter = upper.begin(); iter != upper.end(); ++iter) uppercase.set(static_cast<unsigned char>(*iter)); } Version GetVersion() CXX11_OVERRIDE { return Version("Provides support to block all-CAPS channel messages and notices", VF_VENDOR); } }; MODULE_INIT(ModuleBlockCAPS) �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/src/modules/m_blockcolor.cpp���������������������������������������������������������0000664�0000000�0000000�00000004452�13554550454�0020760�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * InspIRCd -- Internet Relay Chat Daemon * * Copyright (C) 2004-2006, 2008 Craig Edwards <craigedwards@brainbox.cc> * Copyright (C) 2008 Thomas Stagner <aquanight@inspircd.org> * Copyright (C) 2007 Dennis Friis <peavey@inspircd.org> * Copyright (C) 2005, 2007 Robin Burchell <robin+git@viroteck.net> * Copyright (C) 2006 Oliver Lupton <oliverlupton@gmail.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 "inspircd.h" #include "modules/exemption.h" class ModuleBlockColor : public Module { CheckExemption::EventProvider exemptionprov; SimpleChannelModeHandler bc; public: ModuleBlockColor() : exemptionprov(this) , bc(this, "blockcolor", 'c') { } void On005Numeric(std::map<std::string, std::string>& tokens) CXX11_OVERRIDE { tokens["EXTBAN"].push_back('c'); } ModResult OnUserPreMessage(User* user, const MessageTarget& target, MessageDetails& details) CXX11_OVERRIDE { if ((target.type == MessageTarget::TYPE_CHANNEL) && (IS_LOCAL(user))) { Channel* c = target.Get<Channel>(); ModResult res = CheckExemption::Call(exemptionprov, user, c, "blockcolor"); if (res == MOD_RES_ALLOW) return MOD_RES_PASSTHRU; if (!c->GetExtBanStatus(user, 'c').check(!c->IsModeSet(bc))) { for (std::string::iterator i = details.text.begin(); i != details.text.end(); i++) { // Block all control codes except \001 for CTCP if ((*i >= 0) && (*i < 32) && (*i != 1)) { user->WriteNumeric(ERR_CANNOTSENDTOCHAN, c->name, "Can't send colors to channel (+c is set)"); return MOD_RES_DENY; } } } } return MOD_RES_PASSTHRU; } Version GetVersion() CXX11_OVERRIDE { return Version("Provides channel mode +c to block color",VF_VENDOR); } }; MODULE_INIT(ModuleBlockColor) ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/src/modules/m_botmode.cpp������������������������������������������������������������0000664�0000000�0000000�00000004210�13554550454�0020250�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * InspIRCd -- Internet Relay Chat Daemon * * Copyright (C) 2004, 2008 Craig Edwards <craigedwards@brainbox.cc> * Copyright (C) 2007 Dennis Friis <peavey@inspircd.org> * Copyright (C) 2007 Robin Burchell <robin+git@viroteck.net> * * 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 "inspircd.h" #include "modules/cap.h" #include "modules/whois.h" enum { // From UnrealIRCd. RPL_WHOISBOT = 335 }; class BotTag : public ClientProtocol::MessageTagProvider { private: SimpleUserModeHandler& botmode; Cap::Reference ctctagcap; public: BotTag(Module* mod, SimpleUserModeHandler& bm) : ClientProtocol::MessageTagProvider(mod) , botmode(bm) , ctctagcap(mod, "message-tags") { } void OnPopulateTags(ClientProtocol::Message& msg) CXX11_OVERRIDE { User* const user = msg.GetSourceUser(); if (user && user->IsModeSet(botmode)) msg.AddTag("inspircd.org/bot", this, ""); } bool ShouldSendTag(LocalUser* user, const ClientProtocol::MessageTagData& tagdata) CXX11_OVERRIDE { return ctctagcap.get(user); } }; class ModuleBotMode : public Module, public Whois::EventListener { private: SimpleUserModeHandler bm; BotTag tag; public: ModuleBotMode() : Whois::EventListener(this) , bm(this, "bot", 'B') , tag(this, bm) { } Version GetVersion() CXX11_OVERRIDE { return Version("Provides user mode +B to mark the user as a bot",VF_VENDOR); } void OnWhois(Whois::Context& whois) CXX11_OVERRIDE { if (whois.GetTarget()->IsModeSet(bm)) { whois.SendLine(RPL_WHOISBOT, "is a bot on " + ServerInstance->Config->Network); } } }; MODULE_INIT(ModuleBotMode) ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/src/modules/m_callerid.cpp�����������������������������������������������������������0000664�0000000�0000000�00000032631�13554550454�0020406�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * InspIRCd -- Internet Relay Chat Daemon * * Copyright (C) 2009 Daniel De Graaf <danieldg@inspircd.org> * Copyright (C) 2008-2009 Robin Burchell <robin+git@viroteck.net> * Copyright (C) 2008 Thomas Stagner <aquanight@inspircd.org> * Copyright (C) 2008 Craig Edwards <craigedwards@brainbox.cc> * * This file is part of InspIRCd. InspIRCd is free software: you can * redistribute it and/or modify it under the terms of the GNU General Public * License as published by the Free Software Foundation, version 2. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include "inspircd.h" #include "modules/callerid.h" #include "modules/ctctags.h" enum { RPL_ACCEPTLIST = 281, RPL_ENDOFACCEPT = 282, ERR_ACCEPTFULL = 456, ERR_ACCEPTEXIST = 457, ERR_ACCEPTNOT = 458, ERR_TARGUMODEG = 716, RPL_TARGNOTIFY = 717, RPL_UMODEGMSG = 718 }; class callerid_data { public: typedef insp::flat_set<User*> UserSet; typedef std::vector<callerid_data*> CallerIdDataSet; time_t lastnotify; /** Users I accept messages from */ UserSet accepting; /** Users who list me as accepted */ CallerIdDataSet wholistsme; callerid_data() : lastnotify(0) { } std::string ToString(bool human) const { std::ostringstream oss; oss << lastnotify; for (UserSet::const_iterator i = accepting.begin(); i != accepting.end(); ++i) { User* u = *i; // Encode UIDs. oss << "," << (human ? u->nick : u->uuid); } return oss.str(); } }; struct CallerIDExtInfo : public ExtensionItem { CallerIDExtInfo(Module* parent) : ExtensionItem("callerid_data", ExtensionItem::EXT_USER, parent) { } std::string ToHuman(const Extensible* container, void* item) const CXX11_OVERRIDE { callerid_data* dat = static_cast<callerid_data*>(item); return dat->ToString(true); } std::string ToInternal(const Extensible* container, void* item) const CXX11_OVERRIDE { callerid_data* dat = static_cast<callerid_data*>(item); return dat->ToString(false); } void FromInternal(Extensible* container, const std::string& value) CXX11_OVERRIDE { void* old = get_raw(container); if (old) this->free(NULL, old); callerid_data* dat = new callerid_data; set_raw(container, dat); irc::commasepstream s(value); std::string tok; if (s.GetToken(tok)) dat->lastnotify = ConvToNum<time_t>(tok); while (s.GetToken(tok)) { User *u = ServerInstance->FindNick(tok); if ((u) && (u->registered == REG_ALL) && (!u->quitting)) { if (dat->accepting.insert(u).second) { callerid_data* other = this->get(u, true); other->wholistsme.push_back(dat); } } } } callerid_data* get(User* user, bool create) { callerid_data* dat = static_cast<callerid_data*>(get_raw(user)); if (create && !dat) { dat = new callerid_data; set_raw(user, dat); } return dat; } void free(Extensible* container, void* item) CXX11_OVERRIDE { callerid_data* dat = static_cast<callerid_data*>(item); // We need to walk the list of users on our accept list, and remove ourselves from their wholistsme. for (callerid_data::UserSet::iterator it = dat->accepting.begin(); it != dat->accepting.end(); ++it) { callerid_data *targ = this->get(*it, false); if (!targ) { ServerInstance->Logs->Log(MODNAME, LOG_DEFAULT, "ERROR: Inconsistency detected in callerid state, please report (1)"); continue; // shouldn't happen, but oh well. } if (!stdalgo::vector::swaperase(targ->wholistsme, dat)) ServerInstance->Logs->Log(MODNAME, LOG_DEFAULT, "ERROR: Inconsistency detected in callerid state, please report (2)"); } delete dat; } }; class CommandAccept : public Command { /** Pair: first is the target, second is true to add, false to remove */ typedef std::pair<User*, bool> ACCEPTAction; static ACCEPTAction GetTargetAndAction(std::string& tok, User* cmdfrom = NULL) { bool remove = (tok[0] == '-'); if ((remove) || (tok[0] == '+')) tok.erase(tok.begin()); User* target; if (!cmdfrom || !IS_LOCAL(cmdfrom)) target = ServerInstance->FindNick(tok); else target = ServerInstance->FindNickOnly(tok); if ((!target) || (target->registered != REG_ALL) || (target->quitting)) target = NULL; return std::make_pair(target, !remove); } public: CallerIDExtInfo extInfo; unsigned int maxaccepts; CommandAccept(Module* Creator) : Command(Creator, "ACCEPT", 1), extInfo(Creator) { allow_empty_last_param = false; syntax = "*|(+|-)<nick>[,(+|-)<nick>]+"; TRANSLATE1(TR_CUSTOM); } void EncodeParameter(std::string& parameter, unsigned int index) CXX11_OVERRIDE { // Send lists as-is (part of 2.0 compat) if (parameter.find(',') != std::string::npos) return; // Convert a (+|-)<nick> into a [-]<uuid> ACCEPTAction action = GetTargetAndAction(parameter); if (!action.first) return; parameter = (action.second ? "" : "-") + action.first->uuid; } /** Will take any number of nicks (up to MaxTargets), which can be seperated by commas. * - in front of any nick removes, and an * lists. This effectively means you can do: * /accept nick1,nick2,nick3,* * to add 3 nicks and then show your list */ CmdResult Handle(User* user, const Params& parameters) CXX11_OVERRIDE { if (CommandParser::LoopCall(user, this, parameters, 0)) return CMD_SUCCESS; /* Even if callerid mode is not set, we let them manage their ACCEPT list so that if they go +g they can * have a list already setup. */ if (parameters[0] == "*") { ListAccept(user); return CMD_SUCCESS; } std::string tok = parameters[0]; ACCEPTAction action = GetTargetAndAction(tok, user); if (!action.first) { user->WriteNumeric(Numerics::NoSuchNick(tok)); return CMD_FAILURE; } if ((!IS_LOCAL(user)) && (!IS_LOCAL(action.first))) // Neither source nor target is local, forward the command to the server of target return CMD_SUCCESS; // The second item in the pair is true if the first char is a '+' (or nothing), false if it's a '-' if (action.second) return (AddAccept(user, action.first) ? CMD_SUCCESS : CMD_FAILURE); else return (RemoveAccept(user, action.first) ? CMD_SUCCESS : CMD_FAILURE); } RouteDescriptor GetRouting(User* user, const Params& parameters) CXX11_OVERRIDE { // There is a list in parameters[0] in two cases: // Either when the source is remote, this happens because 2.0 servers send comma seperated uuid lists, // we don't split those but broadcast them, as before. // // Or if the source is local then LoopCall() runs OnPostCommand() after each entry in the list, // meaning the linking module has sent an ACCEPT already for each entry in the list to the // appropiate server and the ACCEPT with the list of nicks (this) doesn't need to be sent anywhere. if ((!IS_LOCAL(user)) && (parameters[0].find(',') != std::string::npos)) return ROUTE_BROADCAST; // Find the target std::string targetstring = parameters[0]; ACCEPTAction action = GetTargetAndAction(targetstring, user); if (!action.first) // Target is a "*" or source is local and the target is a list of nicks return ROUTE_LOCALONLY; // Route to the server of the target return ROUTE_UNICAST(action.first->server); } void ListAccept(User* user) { callerid_data* dat = extInfo.get(user, false); if (dat) { for (callerid_data::UserSet::iterator i = dat->accepting.begin(); i != dat->accepting.end(); ++i) user->WriteNumeric(RPL_ACCEPTLIST, (*i)->nick); } user->WriteNumeric(RPL_ENDOFACCEPT, "End of ACCEPT list"); } bool AddAccept(User* user, User* whotoadd) { // Add this user to my accept list first, so look me up.. callerid_data* dat = extInfo.get(user, true); if (dat->accepting.size() >= maxaccepts) { user->WriteNumeric(ERR_ACCEPTFULL, InspIRCd::Format("Accept list is full (limit is %d)", maxaccepts)); return false; } if (!dat->accepting.insert(whotoadd).second) { user->WriteNumeric(ERR_ACCEPTEXIST, whotoadd->nick, "is already on your accept list"); return false; } // Now, look them up, and add me to their list callerid_data *targ = extInfo.get(whotoadd, true); targ->wholistsme.push_back(dat); user->WriteNotice(whotoadd->nick + " is now on your accept list"); return true; } bool RemoveAccept(User* user, User* whotoremove) { // Remove them from my list, so look up my list.. callerid_data* dat = extInfo.get(user, false); if (!dat) { user->WriteNumeric(ERR_ACCEPTNOT, whotoremove->nick, "is not on your accept list"); return false; } if (!dat->accepting.erase(whotoremove)) { user->WriteNumeric(ERR_ACCEPTNOT, whotoremove->nick, "is not on your accept list"); return false; } // Look up their list to remove me. callerid_data *dat2 = extInfo.get(whotoremove, false); if (!dat2) { // How the fuck is this possible. ServerInstance->Logs->Log(MODNAME, LOG_DEFAULT, "ERROR: Inconsistency detected in callerid state, please report (3)"); return false; } if (!stdalgo::vector::swaperase(dat2->wholistsme, dat)) ServerInstance->Logs->Log(MODNAME, LOG_DEFAULT, "ERROR: Inconsistency detected in callerid state, please report (4)"); user->WriteNotice(whotoremove->nick + " is no longer on your accept list"); return true; } }; class CallerIDAPIImpl : public CallerID::APIBase { private: CallerIDExtInfo& ext; public: CallerIDAPIImpl(Module* Creator, CallerIDExtInfo& Ext) : CallerID::APIBase(Creator) , ext(Ext) { } bool IsOnAcceptList(User* source, User* target) CXX11_OVERRIDE { callerid_data* dat = ext.get(target, true); return dat->accepting.count(source); } }; class ModuleCallerID : public Module , public CTCTags::EventListener { CommandAccept cmd; CallerIDAPIImpl api; SimpleUserModeHandler myumode; // Configuration variables: bool tracknick; // Allow ACCEPT entries to update with nick changes. unsigned int notify_cooldown; // Seconds between notifications. /** Removes a user from all accept lists * @param who The user to remove from accepts */ void RemoveFromAllAccepts(User* who) { // First, find the list of people who have me on accept callerid_data *userdata = cmd.extInfo.get(who, false); if (!userdata) return; // Iterate over the list of people who accept me, and remove all entries for (callerid_data::CallerIdDataSet::iterator it = userdata->wholistsme.begin(); it != userdata->wholistsme.end(); ++it) { callerid_data *dat = *(it); // Find me on their callerid list if (!dat->accepting.erase(who)) ServerInstance->Logs->Log(MODNAME, LOG_DEFAULT, "ERROR: Inconsistency detected in callerid state, please report (5)"); } userdata->wholistsme.clear(); } public: ModuleCallerID() : CTCTags::EventListener(this) , cmd(this) , api(this, cmd.extInfo) , myumode(this, "callerid", 'g') { } Version GetVersion() CXX11_OVERRIDE { return Version("Implementation of callerid, provides user mode +g and the ACCEPT command", VF_COMMON | VF_VENDOR); } void On005Numeric(std::map<std::string, std::string>& tokens) CXX11_OVERRIDE { tokens["ACCEPT"] = ConvToStr(cmd.maxaccepts); tokens["CALLERID"] = ConvToStr(myumode.GetModeChar()); } ModResult HandleMessage(User* user, const MessageTarget& target) { if (!IS_LOCAL(user) || target.type != MessageTarget::TYPE_USER) return MOD_RES_PASSTHRU; User* dest = target.Get<User>(); if (!dest->IsModeSet(myumode) || (user == dest)) return MOD_RES_PASSTHRU; if (user->HasPrivPermission("users/ignore-callerid")) return MOD_RES_PASSTHRU; callerid_data* dat = cmd.extInfo.get(dest, true); if (!dat->accepting.count(user)) { time_t now = ServerInstance->Time(); /* +g and *not* accepted */ user->WriteNumeric(ERR_TARGUMODEG, dest->nick, "is in +g mode (server-side ignore)."); if (now > (dat->lastnotify + (time_t)notify_cooldown)) { user->WriteNumeric(RPL_TARGNOTIFY, dest->nick, "has been informed that you messaged them."); dest->WriteRemoteNumeric(RPL_UMODEGMSG, user->nick, InspIRCd::Format("%s@%s", user->ident.c_str(), user->GetDisplayedHost().c_str()), InspIRCd::Format("is messaging you, and you have user mode +g set. Use /ACCEPT +%s to allow.", user->nick.c_str())); dat->lastnotify = now; } return MOD_RES_DENY; } return MOD_RES_PASSTHRU; } ModResult OnUserPreMessage(User* user, const MessageTarget& target, MessageDetails& details) CXX11_OVERRIDE { return HandleMessage(user, target); } ModResult OnUserPreTagMessage(User* user, const MessageTarget& target, CTCTags::TagMessageDetails& details) CXX11_OVERRIDE { return HandleMessage(user, target); } void OnUserPostNick(User* user, const std::string& oldnick) CXX11_OVERRIDE { if (!tracknick) RemoveFromAllAccepts(user); } void OnUserQuit(User* user, const std::string& message, const std::string& oper_message) CXX11_OVERRIDE { RemoveFromAllAccepts(user); } void ReadConfig(ConfigStatus& status) CXX11_OVERRIDE { ConfigTag* tag = ServerInstance->Config->ConfValue("callerid"); cmd.maxaccepts = tag->getUInt("maxaccepts", 30); tracknick = tag->getBool("tracknick"); notify_cooldown = tag->getDuration("cooldown", 60); } void Prioritize() CXX11_OVERRIDE { // Want to be after modules like silence or services_account ServerInstance->Modules->SetPriority(this, I_OnUserPreMessage, PRIORITY_LAST); } }; MODULE_INIT(ModuleCallerID) �������������������������������������������������������������������������������������������������������inspircd-3.4.0/src/modules/m_cap.cpp����������������������������������������������������������������0000664�0000000�0000000�00000030524�13554550454�0017371�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * InspIRCd -- Internet Relay Chat Daemon * * Copyright (C) 2015 Attila Molnar <attilamolnar@hush.com> * * This file is part of InspIRCd. InspIRCd is free software: you can * redistribute it and/or modify it under the terms of the GNU General Public * License as published by the Free Software Foundation, version 2. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include "inspircd.h" #include "modules/reload.h" #include "modules/cap.h" enum { // From IRCv3 capability-negotiation-3.1. ERR_INVALIDCAPCMD = 410 }; namespace Cap { class ManagerImpl; } static Cap::ManagerImpl* managerimpl; class Cap::ManagerImpl : public Cap::Manager, public ReloadModule::EventListener { /** Stores the cap state of a module being reloaded */ struct CapModData { struct Data { std::string name; std::vector<std::string> users; Data(Capability* cap) : name(cap->GetName()) { } }; std::vector<Data> caps; }; typedef insp::flat_map<std::string, Capability*, irc::insensitive_swo> CapMap; ExtItem capext; CapMap caps; Events::ModuleEventProvider& evprov; static bool CanRequest(LocalUser* user, Ext usercaps, Capability* cap, bool adding) { const bool hascap = ((usercaps & cap->GetMask()) != 0); if (hascap == adding) return true; return cap->OnRequest(user, adding); } Capability::Bit AllocateBit() const { Capability::Bit used = 0; for (CapMap::const_iterator i = caps.begin(); i != caps.end(); ++i) { Capability* cap = i->second; used |= cap->GetMask(); } for (unsigned int i = 0; i < MAX_CAPS; i++) { Capability::Bit bit = (1 << i); if (!(used & bit)) return bit; } throw ModuleException("Too many caps"); } void OnReloadModuleSave(Module* mod, ReloadModule::CustomData& cd) CXX11_OVERRIDE { ServerInstance->Logs->Log(MODNAME, LOG_DEBUG, "OnReloadModuleSave()"); if (mod == creator) return; CapModData* capmoddata = new CapModData; cd.add(this, capmoddata); for (CapMap::iterator i = caps.begin(); i != caps.end(); ++i) { Capability* cap = i->second; // Only save users of caps that belong to the module being reloaded if (cap->creator != mod) continue; ServerInstance->Logs->Log(MODNAME, LOG_DEBUG, "Module being reloaded implements cap %s, saving cap users", cap->GetName().c_str()); capmoddata->caps.push_back(CapModData::Data(cap)); CapModData::Data& capdata = capmoddata->caps.back(); // Populate list with uuids of users who are using the cap const UserManager::LocalList& list = ServerInstance->Users.GetLocalUsers(); for (UserManager::LocalList::const_iterator j = list.begin(); j != list.end(); ++j) { LocalUser* user = *j; if (cap->get(user)) capdata.users.push_back(user->uuid); } } } void OnReloadModuleRestore(Module* mod, void* data) CXX11_OVERRIDE { CapModData* capmoddata = static_cast<CapModData*>(data); for (std::vector<CapModData::Data>::const_iterator i = capmoddata->caps.begin(); i != capmoddata->caps.end(); ++i) { const CapModData::Data& capdata = *i; Capability* cap = ManagerImpl::Find(capdata.name); if (!cap) { ServerInstance->Logs->Log(MODNAME, LOG_DEBUG, "Cap %s is no longer available after reload", capdata.name.c_str()); continue; } // Set back the cap for all users who were using it before the reload for (std::vector<std::string>::const_iterator j = capdata.users.begin(); j != capdata.users.end(); ++j) { const std::string& uuid = *j; User* user = ServerInstance->FindUUID(uuid); if (!user) { ServerInstance->Logs->Log(MODNAME, LOG_DEBUG, "User %s is gone when trying to restore cap %s", uuid.c_str(), capdata.name.c_str()); continue; } cap->set(user, true); } } delete capmoddata; } public: ManagerImpl(Module* mod, Events::ModuleEventProvider& evprovref) : Cap::Manager(mod) , ReloadModule::EventListener(mod) , capext(mod) , evprov(evprovref) { managerimpl = this; } ~ManagerImpl() { for (CapMap::iterator i = caps.begin(); i != caps.end(); ++i) { Capability* cap = i->second; cap->Unregister(); } } void AddCap(Cap::Capability* cap) CXX11_OVERRIDE { // No-op if the cap is already registered. // This allows modules to call SetActive() on a cap without checking if it's active first. if (cap->IsRegistered()) return; ServerInstance->Logs->Log(MODNAME, LOG_DEBUG, "Registering cap %s", cap->GetName().c_str()); cap->bit = AllocateBit(); cap->extitem = &capext; caps.insert(std::make_pair(cap->GetName(), cap)); ServerInstance->Modules.AddReferent("cap/" + cap->GetName(), cap); FOREACH_MOD_CUSTOM(evprov, Cap::EventListener, OnCapAddDel, (cap, true)); } void DelCap(Cap::Capability* cap) CXX11_OVERRIDE { // No-op if the cap is not registered, see AddCap() above if (!cap->IsRegistered()) return; ServerInstance->Logs->Log(MODNAME, LOG_DEBUG, "Unregistering cap %s", cap->GetName().c_str()); // Fire the event first so modules can still see who is using the cap which is being unregistered FOREACH_MOD_CUSTOM(evprov, Cap::EventListener, OnCapAddDel, (cap, false)); // Turn off the cap for all users const UserManager::LocalList& list = ServerInstance->Users.GetLocalUsers(); for (UserManager::LocalList::const_iterator i = list.begin(); i != list.end(); ++i) { LocalUser* user = *i; cap->set(user, false); } ServerInstance->Modules.DelReferent(cap); cap->Unregister(); caps.erase(cap->GetName()); } Capability* Find(const std::string& capname) const CXX11_OVERRIDE { CapMap::const_iterator it = caps.find(capname); if (it != caps.end()) return it->second; return NULL; } void NotifyValueChange(Capability* cap) CXX11_OVERRIDE { ServerInstance->Logs->Log(MODNAME, LOG_DEBUG, "Cap %s changed value", cap->GetName().c_str()); FOREACH_MOD_CUSTOM(evprov, Cap::EventListener, OnCapValueChange, (cap)); } Protocol GetProtocol(LocalUser* user) const { return ((capext.get(user) & CAP_302_BIT) ? CAP_302 : CAP_LEGACY); } void Set302Protocol(LocalUser* user) { capext.set(user, capext.get(user) | CAP_302_BIT); } bool HandleReq(LocalUser* user, const std::string& reqlist) { Ext usercaps = capext.get(user); irc::spacesepstream ss(reqlist); for (std::string capname; ss.GetToken(capname); ) { bool remove = (capname[0] == '-'); if (remove) capname.erase(capname.begin()); Capability* cap = ManagerImpl::Find(capname); if ((!cap) || (!CanRequest(user, usercaps, cap, !remove))) return false; if (remove) usercaps = cap->DelFromMask(usercaps); else usercaps = cap->AddToMask(usercaps); } capext.set(user, usercaps); return true; } void HandleList(std::string& out, LocalUser* user, bool show_all, bool show_values, bool minus_prefix = false) const { Ext show_caps = (show_all ? ~0 : capext.get(user)); for (CapMap::const_iterator i = caps.begin(); i != caps.end(); ++i) { Capability* cap = i->second; if (!(show_caps & cap->GetMask())) continue; if ((show_all) && (!cap->OnList(user))) continue; if (minus_prefix) out.push_back('-'); out.append(cap->GetName()); if (show_values) { const std::string* capvalue = cap->GetValue(user); if ((capvalue) && (!capvalue->empty()) && (capvalue->find(' ') == std::string::npos)) { out.push_back('='); out.append(*capvalue, 0, MAX_VALUE_LENGTH); } } out.push_back(' '); } } void HandleClear(LocalUser* user, std::string& result) { HandleList(result, user, false, false, true); capext.unset(user); } }; namespace { std::string SerializeCaps(const Extensible* container, void* item, bool human) { // XXX: Cast away the const because IS_LOCAL() doesn't handle it LocalUser* user = IS_LOCAL(const_cast<User*>(static_cast<const User*>(container))); if (!user) return std::string(); // List requested caps std::string ret; managerimpl->HandleList(ret, user, false, false); // Serialize cap protocol version. If building a human-readable string append a new token, otherwise append only a single character indicating the version. Cap::Protocol protocol = managerimpl->GetProtocol(user); if (human) ret.append("capversion=3."); else if (!ret.empty()) ret.erase(ret.length()-1); if (protocol == Cap::CAP_302) ret.push_back('2'); else ret.push_back('1'); return ret; } } Cap::ExtItem::ExtItem(Module* mod) : LocalIntExt("caps", ExtensionItem::EXT_USER, mod) { } std::string Cap::ExtItem::ToHuman(const Extensible* container, void* item) const { return SerializeCaps(container, item, true); } std::string Cap::ExtItem::ToInternal(const Extensible* container, void* item) const { return SerializeCaps(container, item, false); } void Cap::ExtItem::FromInternal(Extensible* container, const std::string& value) { LocalUser* user = IS_LOCAL(static_cast<User*>(container)); if (!user) return; // Can't happen // Process the cap protocol version which is a single character at the end of the serialized string const char verchar = *value.rbegin(); if (verchar == '2') managerimpl->Set302Protocol(user); // Remove the version indicator from the string passed to HandleReq std::string caplist(value, 0, value.size()-1); managerimpl->HandleReq(user, caplist); } class CapMessage : public Cap::MessageBase { public: CapMessage(LocalUser* user, const std::string& subcmd, const std::string& result) : Cap::MessageBase(subcmd) { SetUser(user); PushParamRef(result); } }; class CommandCap : public SplitCommand { Events::ModuleEventProvider evprov; Cap::ManagerImpl manager; ClientProtocol::EventProvider protoevprov; void DisplayResult(LocalUser* user, const std::string& subcmd, std::string& result) { if (*result.rbegin() == ' ') result.erase(result.end()-1); DisplayResult2(user, subcmd, result); } void DisplayResult2(LocalUser* user, const std::string& subcmd, const std::string& result) { CapMessage msg(user, subcmd, result); ClientProtocol::Event ev(protoevprov, msg); user->Send(ev); } public: LocalIntExt holdext; CommandCap(Module* mod) : SplitCommand(mod, "CAP", 1) , evprov(mod, "event/cap") , manager(mod, evprov) , protoevprov(mod, name) , holdext("cap_hold", ExtensionItem::EXT_USER, mod) { works_before_reg = true; } CmdResult HandleLocal(LocalUser* user, const Params& parameters) CXX11_OVERRIDE { if (user->registered != REG_ALL) holdext.set(user, 1); std::string subcommand(parameters[0].length(), ' '); std::transform(parameters[0].begin(), parameters[0].end(), subcommand.begin(), ::toupper); if (subcommand == "REQ") { if (parameters.size() < 2) return CMD_FAILURE; const std::string replysubcmd = (manager.HandleReq(user, parameters[1]) ? "ACK" : "NAK"); DisplayResult2(user, replysubcmd, parameters[1]); } else if (subcommand == "END") { holdext.unset(user); } else if ((subcommand == "LS") || (subcommand == "LIST")) { Cap::Protocol capversion = Cap::CAP_LEGACY; const bool is_ls = (subcommand.length() == 2); if ((is_ls) && (parameters.size() > 1)) { unsigned int version = ConvToNum<unsigned int>(parameters[1]); if (version >= 302) { capversion = Cap::CAP_302; manager.Set302Protocol(user); } } std::string result; // Show values only if supports v3.2 and doing LS manager.HandleList(result, user, is_ls, ((is_ls) && (capversion != Cap::CAP_LEGACY))); DisplayResult(user, subcommand, result); } else if ((subcommand == "CLEAR") && (manager.GetProtocol(user) == Cap::CAP_LEGACY)) { std::string result; manager.HandleClear(user, result); DisplayResult(user, "ACK", result); } else { user->WriteNumeric(ERR_INVALIDCAPCMD, subcommand.empty() ? "*" : subcommand, "Invalid CAP subcommand"); return CMD_FAILURE; } return CMD_SUCCESS; } }; class ModuleCap : public Module { CommandCap cmd; public: ModuleCap() : cmd(this) { } ModResult OnCheckReady(LocalUser* user) CXX11_OVERRIDE { return (cmd.holdext.get(user) ? MOD_RES_DENY : MOD_RES_PASSTHRU); } Version GetVersion() CXX11_OVERRIDE { return Version("Provides support for CAP capability negotiation", VF_VENDOR); } }; MODULE_INIT(ModuleCap) ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/src/modules/m_cban.cpp���������������������������������������������������������������0000664�0000000�0000000�00000013011�13554550454�0017521�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * InspIRCd -- Internet Relay Chat Daemon * * Copyright (C) 2007-2008 Dennis Friis <peavey@inspircd.org> * Copyright (C) 2005-2008 Robin Burchell <robin+git@viroteck.net> * Copyright (C) 2005-2006 Craig Edwards <craigedwards@brainbox.cc> * Copyright (C) 2006 Oliver Lupton <oliverlupton@gmail.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 "inspircd.h" #include "xline.h" #include "modules/stats.h" enum { // InspIRCd-specific. ERR_BADCHANNEL = 926 }; /** Holds a CBAN item */ class CBan : public XLine { private: std::string matchtext; public: CBan(time_t s_time, unsigned long d, const std::string& src, const std::string& re, const std::string& ch) : XLine(s_time, d, src, re, "CBAN") , matchtext(ch) { } // XXX I shouldn't have to define this bool Matches(User* u) CXX11_OVERRIDE { return false; } bool Matches(const std::string& s) CXX11_OVERRIDE { return irc::equals(matchtext, s); } const std::string& Displayable() CXX11_OVERRIDE { return matchtext; } }; /** An XLineFactory specialized to generate cban pointers */ class CBanFactory : public XLineFactory { public: CBanFactory() : XLineFactory("CBAN") { } /** Generate a CBAN */ XLine* Generate(time_t set_time, unsigned long duration, const std::string& source, const std::string& reason, const std::string& xline_specific_mask) CXX11_OVERRIDE { return new CBan(set_time, duration, source, reason, xline_specific_mask); } bool AutoApplyToUserList(XLine* x) CXX11_OVERRIDE { return false; // No, we apply to channels. } }; /** Handle /CBAN */ class CommandCBan : public Command { public: CommandCBan(Module* Creator) : Command(Creator, "CBAN", 1, 3) { flags_needed = 'o'; this->syntax = "<channel> [<duration> [:<reason>]]"; } CmdResult Handle(User* user, const Params& parameters) CXX11_OVERRIDE { /* syntax: CBAN #channel time :reason goes here */ /* 'time' is a human-readable timestring, like 2d3h2s. */ if (parameters.size() == 1) { std::string reason; if (ServerInstance->XLines->DelLine(parameters[0].c_str(), "CBAN", reason, user)) { ServerInstance->SNO->WriteGlobalSno('x', "%s removed CBan on %s: %s", user->nick.c_str(), parameters[0].c_str(), reason.c_str()); } else { user->WriteNotice("*** CBan " + parameters[0] + " not found on the list."); return CMD_FAILURE; } } else { // Adding - XXX todo make this respect <insane> tag perhaps.. unsigned long duration; if (!InspIRCd::Duration(parameters[1], duration)) { user->WriteNotice("*** Invalid duration for CBan."); return CMD_FAILURE; } const char *reason = (parameters.size() > 2) ? parameters[2].c_str() : "No reason supplied"; CBan* r = new CBan(ServerInstance->Time(), duration, user->nick.c_str(), reason, parameters[0].c_str()); if (ServerInstance->XLines->AddLine(r, user)) { if (!duration) { ServerInstance->SNO->WriteGlobalSno('x', "%s added permanent CBan for %s: %s", user->nick.c_str(), parameters[0].c_str(), reason); } else { ServerInstance->SNO->WriteGlobalSno('x', "%s added timed CBan for %s, expires in %s (on %s): %s", user->nick.c_str(), parameters[0].c_str(), InspIRCd::DurationString(duration).c_str(), InspIRCd::TimeString(ServerInstance->Time() + duration).c_str(), reason); } } else { delete r; user->WriteNotice("*** CBan for " + parameters[0] + " already exists"); return CMD_FAILURE; } } return CMD_SUCCESS; } RouteDescriptor GetRouting(User* user, const Params& parameters) CXX11_OVERRIDE { if (IS_LOCAL(user)) return ROUTE_LOCALONLY; // spanningtree will send ADDLINE return ROUTE_BROADCAST; } }; class ModuleCBan : public Module, public Stats::EventListener { CommandCBan mycommand; CBanFactory f; public: ModuleCBan() : Stats::EventListener(this) , mycommand(this) { } void init() CXX11_OVERRIDE { ServerInstance->XLines->RegisterFactory(&f); } ~ModuleCBan() { ServerInstance->XLines->DelAll("CBAN"); ServerInstance->XLines->UnregisterFactory(&f); } ModResult OnStats(Stats::Context& stats) CXX11_OVERRIDE { if (stats.GetSymbol() != 'C') return MOD_RES_PASSTHRU; ServerInstance->XLines->InvokeStats("CBAN", 210, stats); return MOD_RES_DENY; } ModResult OnUserPreJoin(LocalUser* user, Channel* chan, const std::string& cname, std::string& privs, const std::string& keygiven) CXX11_OVERRIDE { XLine *rl = ServerInstance->XLines->MatchesLine("CBAN", cname); if (rl) { // Channel is banned. user->WriteNumeric(ERR_BADCHANNEL, cname, InspIRCd::Format("Channel %s is CBANed: %s", cname.c_str(), rl->reason.c_str())); ServerInstance->SNO->WriteGlobalSno('a', "%s tried to join %s which is CBANed (%s)", user->nick.c_str(), cname.c_str(), rl->reason.c_str()); return MOD_RES_DENY; } return MOD_RES_PASSTHRU; } Version GetVersion() CXX11_OVERRIDE { return Version("Provides the CBAN command, like Q-lines, but for channels", VF_COMMON | VF_VENDOR); } }; MODULE_INIT(ModuleCBan) �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/src/modules/m_censor.cpp�������������������������������������������������������������0000664�0000000�0000000�00000007133�13554550454�0020117�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * InspIRCd -- Internet Relay Chat Daemon * * Copyright (C) 2009 Daniel De Graaf <danieldg@inspircd.org> * Copyright (C) 2004, 2008-2009 Craig Edwards <craigedwards@brainbox.cc> * Copyright (C) 2007 Dennis Friis <peavey@inspircd.org> * Copyright (C) 2005, 2007 Robin Burchell <robin+git@viroteck.net> * * 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 "inspircd.h" #include "modules/exemption.h" typedef insp::flat_map<std::string, std::string, irc::insensitive_swo> censor_t; class ModuleCensor : public Module { CheckExemption::EventProvider exemptionprov; censor_t censors; SimpleUserModeHandler cu; SimpleChannelModeHandler cc; public: ModuleCensor() : exemptionprov(this) , cu(this, "u_censor", 'G') , cc(this, "censor", 'G') { } // format of a config entry is <badword text="shit" replace="poo"> ModResult OnUserPreMessage(User* user, const MessageTarget& target, MessageDetails& details) CXX11_OVERRIDE { if (!IS_LOCAL(user)) return MOD_RES_PASSTHRU; int numeric = 0; const char* targetname = NULL; switch (target.type) { case MessageTarget::TYPE_USER: { User* targuser = target.Get<User>(); if (!targuser->IsModeSet(cu)) return MOD_RES_PASSTHRU; numeric = ERR_CANTSENDTOUSER; targetname = targuser->nick.c_str(); break; } case MessageTarget::TYPE_CHANNEL: { Channel* targchan = target.Get<Channel>(); if (!targchan->IsModeSet(cc)) return MOD_RES_PASSTHRU; ModResult result = CheckExemption::Call(exemptionprov, user, targchan, "censor"); if (result == MOD_RES_ALLOW) return MOD_RES_PASSTHRU; numeric = ERR_CANNOTSENDTOCHAN; targetname = targchan->name.c_str(); break; } default: return MOD_RES_PASSTHRU; } for (censor_t::iterator index = censors.begin(); index != censors.end(); index++) { size_t censorpos; while ((censorpos = irc::find(details.text, index->first)) != std::string::npos) { if (index->second.empty()) { user->WriteNumeric(numeric, targetname, "Your message contained a censored word (" + index->first + "), and was blocked"); return MOD_RES_DENY; } details.text.replace(censorpos, index->first.size(), index->second); } } return MOD_RES_PASSTHRU; } void ReadConfig(ConfigStatus& status) CXX11_OVERRIDE { /* * reload our config file on rehash - we must destroy and re-allocate the classes * to call the constructor again and re-read our data. */ censor_t newcensors; ConfigTagList badwords = ServerInstance->Config->ConfTags("badword"); for (ConfigIter i = badwords.first; i != badwords.second; ++i) { ConfigTag* tag = i->second; const std::string text = tag->getString("text"); if (text.empty()) throw ModuleException("<badword:text> is empty! at " + tag->getTagLocation()); const std::string replace = tag->getString("replace"); newcensors[text] = replace; } censors.swap(newcensors); } Version GetVersion() CXX11_OVERRIDE { return Version("Provides user and channel mode +G", VF_VENDOR); } }; MODULE_INIT(ModuleCensor) �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/src/modules/m_cgiirc.cpp�������������������������������������������������������������0000664�0000000�0000000�00000034732�13554550454�0020073�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * InspIRCd -- Internet Relay Chat Daemon * * Copyright (C) 2009-2010 Daniel De Graaf <danieldg@inspircd.org> * Copyright (C) 2007-2008 John Brooks <john.brooks@dereferenced.net> * Copyright (C) 2008 Pippijn van Steenhoven <pip88nl@gmail.com> * Copyright (C) 2006-2008 Craig Edwards <craigedwards@brainbox.cc> * Copyright (C) 2007 Robin Burchell <robin+git@viroteck.net> * Copyright (C) 2007 Dennis Friis <peavey@inspircd.org> * Copyright (C) 2006 Oliver Lupton <oliverlupton@gmail.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 "inspircd.h" #include "modules/ssl.h" #include "modules/webirc.h" #include "modules/whois.h" enum { // InspIRCd-specific. RPL_WHOISGATEWAY = 350 }; // Encapsulates information about an ident host. class IdentHost { private: std::string hostmask; std::string newident; public: IdentHost(const std::string& mask, const std::string& ident) : hostmask(mask) , newident(ident) { } const std::string& GetIdent() const { return newident; } bool Matches(LocalUser* user) const { if (!InspIRCd::Match(user->GetRealHost(), hostmask, ascii_case_insensitive_map)) return false; return InspIRCd::MatchCIDR(user->GetIPString(), hostmask, ascii_case_insensitive_map); } }; // Encapsulates information about a WebIRC host. class WebIRCHost { private: std::string hostmask; std::string fingerprint; std::string password; std::string passhash; public: WebIRCHost(const std::string& mask, const std::string& fp, const std::string& pass, const std::string& hash) : hostmask(mask) , fingerprint(fp) , password(pass) , passhash(hash) { } bool Matches(LocalUser* user, const std::string& pass, UserCertificateAPI& sslapi) const { // Did the user send a valid password? if (!password.empty() && !ServerInstance->PassCompare(user, password, pass, passhash)) return false; // Does the user have a valid fingerprint? const std::string fp = sslapi ? sslapi->GetFingerprint(user) : ""; if (!fingerprint.empty() && !InspIRCd::TimingSafeCompare(fp, fingerprint)) return false; // Does the user's hostname match our hostmask? if (InspIRCd::Match(user->GetRealHost(), hostmask, ascii_case_insensitive_map)) return true; // Does the user's IP address match our hostmask? return InspIRCd::MatchCIDR(user->GetIPString(), hostmask, ascii_case_insensitive_map); } }; /* * WEBIRC * This is used for the webirc method of CGIIRC auth, and is (really) the best way to do these things. * Syntax: WEBIRC password gateway hostname ip * Where password is a shared key, gateway is the name of the WebIRC gateway and version (e.g. cgiirc), hostname * is the resolved host of the client issuing the command and IP is the real IP of the client. * * How it works: * To tie in with the rest of cgiirc module, and to avoid race conditions, /webirc is only processed locally * and simply sets metadata on the user, which is later decoded on full connect to give something meaningful. */ class CommandWebIRC : public SplitCommand { public: std::vector<WebIRCHost> hosts; bool notify; StringExtItem gateway; StringExtItem realhost; StringExtItem realip; UserCertificateAPI sslapi; Events::ModuleEventProvider webircevprov; CommandWebIRC(Module* Creator) : SplitCommand(Creator, "WEBIRC", 4) , gateway("cgiirc_gateway", ExtensionItem::EXT_USER, Creator) , realhost("cgiirc_realhost", ExtensionItem::EXT_USER, Creator) , realip("cgiirc_realip", ExtensionItem::EXT_USER, Creator) , sslapi(Creator) , webircevprov(Creator, "event/webirc") { allow_empty_last_param = false; works_before_reg = true; this->syntax = "<password> <gateway> <hostname> <ip> [<flags>]"; } CmdResult HandleLocal(LocalUser* user, const Params& parameters) CXX11_OVERRIDE { if (user->registered == REG_ALL || realhost.get(user)) return CMD_FAILURE; for (std::vector<WebIRCHost>::const_iterator iter = hosts.begin(); iter != hosts.end(); ++iter) { // If we don't match the host then skip to the next host. if (!iter->Matches(user, parameters[0], sslapi)) continue; irc::sockets::sockaddrs ipaddr; if (!irc::sockets::aptosa(parameters[3], user->client_sa.port(), ipaddr)) { WriteLog("Connecting user %s (%s) tried to use WEBIRC but gave an invalid IP address.", user->uuid.c_str(), user->GetIPString().c_str()); ServerInstance->Users->QuitUser(user, "WEBIRC: IP address is invalid: " + parameters[3]); return CMD_FAILURE; } // The user matched a WebIRC block! gateway.set(user, parameters[1]); realhost.set(user, user->GetRealHost()); realip.set(user, user->GetIPString()); WriteLog("Connecting user %s is using a WebIRC gateway; changing their IP from %s to %s.", user->uuid.c_str(), user->GetIPString().c_str(), parameters[3].c_str()); // If we have custom flags then deal with them. WebIRC::FlagMap flags; const bool hasflags = (parameters.size() > 4); if (hasflags) { // Parse the flags. irc::spacesepstream flagstream(parameters[4]); for (std::string flag; flagstream.GetToken(flag); ) { // Does this flag have a value? const size_t separator = flag.find('='); if (separator == std::string::npos) { flags[flag]; continue; } // The flag has a value! const std::string key = flag.substr(0, separator); const std::string value = flag.substr(separator + 1); flags[key] = value; } } // Inform modules about the WebIRC attempt. FOREACH_MOD_CUSTOM(webircevprov, WebIRC::EventListener, OnWebIRCAuth, (user, (hasflags ? &flags : NULL))); // Set the IP address sent via WEBIRC. We ignore the hostname and lookup // instead do our own DNS lookups because of unreliable gateways. user->SetClientIP(ipaddr); return CMD_SUCCESS; } WriteLog("Connecting user %s (%s) tried to use WEBIRC but didn't match any configured WebIRC hosts.", user->uuid.c_str(), user->GetIPString().c_str()); ServerInstance->Users->QuitUser(user, "WEBIRC: you don't match any configured WebIRC hosts."); return CMD_FAILURE; } void WriteLog(const char* message, ...) CUSTOM_PRINTF(2, 3) { std::string buffer; VAFORMAT(buffer, message, message); // If we are sending a snotice then the message will already be // written to the logfile. if (notify) ServerInstance->SNO->WriteGlobalSno('w', buffer); else ServerInstance->Logs->Log(MODNAME, LOG_DEFAULT, buffer); } }; class ModuleCgiIRC : public Module , public WebIRC::EventListener , public Whois::EventListener { private: CommandWebIRC cmd; std::vector<IdentHost> hosts; static bool ParseIdent(LocalUser* user, irc::sockets::sockaddrs& out) { const char* ident = NULL; if (user->ident.length() == 8) { // The ident is an IPv4 address encoded in hexadecimal with two characters // per address segment. ident = user->ident.c_str(); } else if (user->ident.length() == 9 && user->ident[0] == '~') { // The same as above but m_ident got to this user before we did. Strip the // ident prefix and continue as normal. ident = user->ident.c_str() + 1; } else { // The user either does not have an IPv4 in their ident or the gateway server // is also running an identd. In the latter case there isn't really a lot we // can do so we just assume that the client in question is not connecting via // an ident gateway. return false; } // Try to convert the IP address to a string. If this fails then the user // does not have an IPv4 address in their ident. errno = 0; unsigned long address = strtoul(ident, NULL, 16); if (errno) return false; out.in4.sin_family = AF_INET; out.in4.sin_addr.s_addr = htonl(address); return true; } public: ModuleCgiIRC() : WebIRC::EventListener(this) , Whois::EventListener(this) , cmd(this) { } void init() CXX11_OVERRIDE { ServerInstance->SNO->EnableSnomask('w', "CGIIRC"); } void ReadConfig(ConfigStatus& status) CXX11_OVERRIDE { std::vector<IdentHost> identhosts; std::vector<WebIRCHost> webirchosts; ConfigTagList tags = ServerInstance->Config->ConfTags("cgihost"); for (ConfigIter i = tags.first; i != tags.second; ++i) { ConfigTag* tag = i->second; // Ensure that we have the <cgihost:mask> parameter. const std::string mask = tag->getString("mask"); if (mask.empty()) throw ModuleException("<cgihost:mask> is a mandatory field, at " + tag->getTagLocation()); // Determine what lookup type this host uses. const std::string type = tag->getString("type"); if (stdalgo::string::equalsci(type, "ident")) { // The IP address should be looked up from the hex IP address. const std::string newident = tag->getString("newident", "gateway", ServerInstance->IsIdent); identhosts.push_back(IdentHost(mask, newident)); } else if (stdalgo::string::equalsci(type, "webirc")) { // The IP address will be received via the WEBIRC command. const std::string fingerprint = tag->getString("fingerprint"); const std::string password = tag->getString("password"); // WebIRC blocks require a password. if (fingerprint.empty() && password.empty()) throw ModuleException("When using <cgihost type=\"webirc\"> either the fingerprint or password field is required, at " + tag->getTagLocation()); webirchosts.push_back(WebIRCHost(mask, fingerprint, password, tag->getString("hash"))); } else { throw ModuleException(type + " is an invalid <cgihost:mask> type, at " + tag->getTagLocation()); } } // The host configuration was valid so we can apply it. hosts.swap(identhosts); cmd.hosts.swap(webirchosts); // Do we send an oper notice when a m_cgiirc client has their IP changed? cmd.notify = ServerInstance->Config->ConfValue("cgiirc")->getBool("opernotice", true); } ModResult OnSetConnectClass(LocalUser* user, ConnectClass* myclass) CXX11_OVERRIDE { // If <connect:webirc> is not set then we have nothing to do. const std::string webirc = myclass->config->getString("webirc"); if (webirc.empty()) return MOD_RES_PASSTHRU; // If the user is not connecting via a WebIRC gateway then they // cannot match this connect class. const std::string* gateway = cmd.gateway.get(user); if (!gateway) return MOD_RES_DENY; // If the gateway matches the <connect:webirc> constraint then // allow the check to continue. Otherwise, reject it. return InspIRCd::Match(*gateway, webirc) ? MOD_RES_PASSTHRU : MOD_RES_DENY; } ModResult OnUserRegister(LocalUser* user) CXX11_OVERRIDE { // There is no need to check for gateways if one is already being used. if (cmd.realhost.get(user)) return MOD_RES_PASSTHRU; for (std::vector<IdentHost>::const_iterator iter = hosts.begin(); iter != hosts.end(); ++iter) { // If we don't match the host then skip to the next host. if (!iter->Matches(user)) continue; // We have matched an <cgihost> block! Try to parse the encoded IPv4 address // out of the ident. irc::sockets::sockaddrs address(user->client_sa); if (!ParseIdent(user, address)) return MOD_RES_PASSTHRU; // Store the hostname and IP of the gateway for later use. cmd.realhost.set(user, user->GetRealHost()); cmd.realip.set(user, user->GetIPString()); const std::string& newident = iter->GetIdent(); cmd.WriteLog("Connecting user %s is using an ident gateway; changing their IP from %s to %s and their ident from %s to %s.", user->uuid.c_str(), user->GetIPString().c_str(), address.addr().c_str(), user->ident.c_str(), newident.c_str()); user->ChangeIdent(newident); user->SetClientIP(address); break; } return MOD_RES_PASSTHRU; } void OnWebIRCAuth(LocalUser* user, const WebIRC::FlagMap* flags) CXX11_OVERRIDE { // We are only interested in connection flags. If none have been // given then we have nothing to do. if (!flags) return; WebIRC::FlagMap::const_iterator cport = flags->find("remote-port"); if (cport != flags->end()) { // If we can't parse the port then just give up. uint16_t port = ConvToNum<uint16_t>(cport->second); if (port) { switch (user->client_sa.family()) { case AF_INET: user->client_sa.in4.sin_port = htons(port); break; case AF_INET6: user->client_sa.in6.sin6_port = htons(port); break; default: // If we have reached this point then we have encountered a bug. ServerInstance->Logs->Log(MODNAME, LOG_DEBUG, "BUG: OnWebIRCAuth(%s): socket type %d is unknown!", user->uuid.c_str(), user->client_sa.family()); return; } } } WebIRC::FlagMap::const_iterator sport = flags->find("local-port"); if (sport != flags->end()) { // If we can't parse the port then just give up. uint16_t port = ConvToNum<uint16_t>(sport->second); if (port) { switch (user->server_sa.family()) { case AF_INET: user->server_sa.in4.sin_port = htons(port); break; case AF_INET6: user->server_sa.in6.sin6_port = htons(port); break; default: // If we have reached this point then we have encountered a bug. ServerInstance->Logs->Log(MODNAME, LOG_DEBUG, "BUG: OnWebIRCAuth(%s): socket type %d is unknown!", user->uuid.c_str(), user->server_sa.family()); return; } } } } void OnWhois(Whois::Context& whois) CXX11_OVERRIDE { if (!whois.IsSelfWhois() && !whois.GetSource()->HasPrivPermission("users/auspex")) return; // If these fields are not set then the client is not using a gateway. const std::string* realhost = cmd.realhost.get(whois.GetTarget()); const std::string* realip = cmd.realip.get(whois.GetTarget()); if (!realhost || !realip) return; const std::string* gateway = cmd.gateway.get(whois.GetTarget()); if (gateway) whois.SendLine(RPL_WHOISGATEWAY, *realhost, *realip, "is connected via the " + *gateway + " WebIRC gateway"); else whois.SendLine(RPL_WHOISGATEWAY, *realhost, *realip, "is connected via an ident gateway"); } Version GetVersion() CXX11_OVERRIDE { return Version("Enables forwarding the real IP address of a user from a gateway to the IRC server", VF_VENDOR); } }; MODULE_INIT(ModuleCgiIRC) ��������������������������������������inspircd-3.4.0/src/modules/m_chancreate.cpp���������������������������������������������������������0000664�0000000�0000000�00000002740�13554550454�0020722�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * InspIRCd -- Internet Relay Chat Daemon * * Copyright (C) 2007 Dennis Friis <peavey@inspircd.org> * Copyright (C) 2007 Robin Burchell <robin+git@viroteck.net> * Copyright (C) 2007 John Brooks <john.brooks@dereferenced.net> * * 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 "inspircd.h" class ModuleChanCreate : public Module { public: void init() CXX11_OVERRIDE { ServerInstance->SNO->EnableSnomask('j', "CHANCREATE"); } Version GetVersion() CXX11_OVERRIDE { return Version("Provides snomasks 'j' and 'J', to which notices about newly created channels are sent", VF_VENDOR); } void OnUserJoin(Membership* memb, bool sync, bool created, CUList& except) CXX11_OVERRIDE { if ((created) && (IS_LOCAL(memb->user))) { ServerInstance->SNO->WriteGlobalSno('j', "Channel %s created by %s", memb->chan->name.c_str(), memb->user->GetFullRealHost().c_str()); } } }; MODULE_INIT(ModuleChanCreate) ��������������������������������inspircd-3.4.0/src/modules/m_chanfilter.cpp���������������������������������������������������������0000664�0000000�0000000�00000011466�13554550454�0020751�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * InspIRCd -- Internet Relay Chat Daemon * * Copyright (C) 2009 Daniel De Graaf <danieldg@inspircd.org> * Copyright (C) 2008 Pippijn van Steenhoven <pip88nl@gmail.com> * Copyright (C) 2007 Robin Burchell <robin+git@viroteck.net> * Copyright (C) 2007 Dennis Friis <peavey@inspircd.org> * Copyright (C) 2006 Oliver Lupton <oliverlupton@gmail.com> * Copyright (C) 2005 Craig McLure <craig@chatspike.net> * Copyright (C) 2005 Craig Edwards <craigedwards@brainbox.cc> * * This file is part of InspIRCd. InspIRCd is free software: you can * redistribute it and/or modify it under the terms of the GNU General Public * License as published by the Free Software Foundation, version 2. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include "inspircd.h" #include "listmode.h" #include "modules/exemption.h" /** Handles channel mode +g */ class ChanFilter : public ListModeBase { public: unsigned long maxlen; ChanFilter(Module* Creator) : ListModeBase(Creator, "filter", 'g', "End of channel spamfilter list", 941, 940, false) { syntax = "<pattern>"; } bool ValidateParam(User* user, Channel* chan, std::string& word) CXX11_OVERRIDE { if (word.length() > maxlen) { user->WriteNumeric(Numerics::InvalidModeParameter(chan, this, word, "Word is too long for the spamfilter list.")); return false; } return true; } }; class ModuleChanFilter : public Module { CheckExemption::EventProvider exemptionprov; ChanFilter cf; bool hidemask; bool notifyuser; ChanFilter::ListItem* Match(User* user, Channel* chan, const std::string& text) { ModResult res = CheckExemption::Call(exemptionprov, user, chan, "filter"); if (!IS_LOCAL(user) || res == MOD_RES_ALLOW) return NULL; ListModeBase::ModeList* list = cf.GetList(chan); if (!list) return NULL; for (ListModeBase::ModeList::iterator i = list->begin(); i != list->end(); i++) { if (InspIRCd::Match(text, i->mask)) return &*i; } return NULL; } public: ModuleChanFilter() : exemptionprov(this) , cf(this) { } void ReadConfig(ConfigStatus& status) CXX11_OVERRIDE { ConfigTag* tag = ServerInstance->Config->ConfValue("chanfilter"); hidemask = tag->getBool("hidemask"); cf.maxlen = tag->getUInt("maxlen", 35, 10, ModeParser::MODE_PARAM_MAX); notifyuser = tag->getBool("notifyuser", true); cf.DoRehash(); } void OnUserPart(Membership* memb, std::string& partmessage, CUList& except_list) CXX11_OVERRIDE { if (!memb) return; User* user = memb->user; Channel* chan = memb->chan; ChanFilter::ListItem* match = Match(user, chan, partmessage); if (!match) return; // Match() checks the user is local, we can assume from here LocalUser* luser = IS_LOCAL(user); std::string oldreason(partmessage); partmessage = "Reason filtered"; if (!notifyuser) { // Send fake part ClientProtocol::Messages::Part partmsg(memb, oldreason); ClientProtocol::Event ev(ServerInstance->GetRFCEvents().part, partmsg); luser->Send(ev); // Don't send the user the changed message except_list.insert(user); return; } if (hidemask) user->WriteNumeric(ERR_CANNOTSENDTOCHAN, chan->name, "Cannot send to channel (your part message contained a censored word)"); else user->WriteNumeric(ERR_CANNOTSENDTOCHAN, chan->name, "Cannot send to channel (your part message contained a censored word: " + match->mask + ")"); } ModResult OnUserPreMessage(User* user, const MessageTarget& target, MessageDetails& details) CXX11_OVERRIDE { if (target.type != MessageTarget::TYPE_CHANNEL) return MOD_RES_PASSTHRU; Channel* chan = target.Get<Channel>(); ChanFilter::ListItem* match = Match(user, chan, details.text); if (match) { if (!notifyuser) { details.echo_original = true; return MOD_RES_DENY; } if (hidemask) user->WriteNumeric(ERR_CANNOTSENDTOCHAN, chan->name, "Cannot send to channel (your message contained a censored word)"); else user->WriteNumeric(ERR_CANNOTSENDTOCHAN, chan->name, "Cannot send to channel (your message contained a censored word: " + match->mask + ")"); return MOD_RES_DENY; } return MOD_RES_PASSTHRU; } Version GetVersion() CXX11_OVERRIDE { // We don't send any link data if the length is 35 for compatibility with the 2.0 branch. std::string maxfilterlen; if (cf.maxlen != 35) maxfilterlen.assign(ConvToStr(cf.maxlen)); return Version("Provides channel-specific censor lists (like mode +G but varies from channel to channel)", VF_VENDOR, maxfilterlen); } }; MODULE_INIT(ModuleChanFilter) ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/src/modules/m_chanhistory.cpp��������������������������������������������������������0000664�0000000�0000000�00000014026�13554550454�0021160�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * InspIRCd -- Internet Relay Chat Daemon * * 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 * 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 "inspircd.h" #include "modules/ircv3_servertime.h" #include "modules/ircv3_batch.h" #include "modules/server.h" struct HistoryItem { time_t ts; std::string text; std::string sourcemask; HistoryItem(User* source, const std::string& Text) : ts(ServerInstance->Time()) , text(Text) , sourcemask(source->GetFullHost()) { } }; struct HistoryList { std::deque<HistoryItem> lines; unsigned int maxlen; unsigned int maxtime; HistoryList(unsigned int len, unsigned int time) : maxlen(len) , maxtime(time) { } }; class HistoryMode : public ParamMode<HistoryMode, SimpleExtItem<HistoryList> > { public: unsigned int maxlines; HistoryMode(Module* Creator) : ParamMode<HistoryMode, SimpleExtItem<HistoryList> >(Creator, "history", 'H') { syntax = "<max-messages>:<max-duration>"; } ModeAction OnSet(User* source, Channel* channel, std::string& parameter) CXX11_OVERRIDE { std::string::size_type colon = parameter.find(':'); if (colon == std::string::npos) { source->WriteNumeric(Numerics::InvalidModeParameter(channel, this, parameter)); return MODEACTION_DENY; } std::string duration(parameter, colon+1); if ((IS_LOCAL(source)) && ((duration.length() > 10) || (!InspIRCd::IsValidDuration(duration)))) { source->WriteNumeric(Numerics::InvalidModeParameter(channel, this, parameter)); return MODEACTION_DENY; } unsigned int len = ConvToNum<unsigned int>(parameter.substr(0, colon)); unsigned long time; if (!InspIRCd::Duration(duration, time) || len == 0 || (len > maxlines && IS_LOCAL(source))) { source->WriteNumeric(Numerics::InvalidModeParameter(channel, this, parameter)); return MODEACTION_DENY; } if (len > maxlines) len = maxlines; HistoryList* history = ext.get(channel); if (history) { // Shrink the list if the new line number limit is lower than the old one if (len < history->lines.size()) history->lines.erase(history->lines.begin(), history->lines.begin() + (history->lines.size() - len)); history->maxlen = len; history->maxtime = time; } else { ext.set(channel, new HistoryList(len, time)); } return MODEACTION_ALLOW; } void SerializeParam(Channel* chan, const HistoryList* history, std::string& out) { out.append(ConvToStr(history->maxlen)); out.append(":"); out.append(InspIRCd::DurationString(history->maxtime)); } }; class ModuleChanHistory : public Module , public ServerProtocol::BroadcastEventListener { private: HistoryMode m; bool sendnotice; UserModeReference botmode; bool dobots; IRCv3::Batch::CapReference batchcap; IRCv3::Batch::API batchmanager; IRCv3::Batch::Batch batch; IRCv3::ServerTime::API servertimemanager; void SendHistory(LocalUser* user, Channel* channel, HistoryList* list, time_t mintime) { if (batchmanager) { batchmanager->Start(batch); batch.GetBatchStartMessage().PushParamRef(channel->name); } for(std::deque<HistoryItem>::iterator i = list->lines.begin(); i != list->lines.end(); ++i) { const HistoryItem& item = *i; if (item.ts >= mintime) { ClientProtocol::Messages::Privmsg msg(ClientProtocol::Messages::Privmsg::nocopy, item.sourcemask, channel, item.text); if (servertimemanager) servertimemanager->Set(msg, item.ts); batch.AddToBatch(msg); user->Send(ServerInstance->GetRFCEvents().privmsg, msg); } } if (batchmanager) batchmanager->End(batch); } public: ModuleChanHistory() : ServerProtocol::BroadcastEventListener(this) , m(this) , botmode(this, "bot") , batchcap(this) , batchmanager(this) , batch("chathistory") , servertimemanager(this) { } void ReadConfig(ConfigStatus& status) CXX11_OVERRIDE { ConfigTag* tag = ServerInstance->Config->ConfValue("chanhistory"); m.maxlines = tag->getUInt("maxlines", 50, 1); sendnotice = tag->getBool("notice", true); dobots = tag->getBool("bots", true); } ModResult OnBroadcastMessage(Channel* channel, const Server* server) CXX11_OVERRIDE { return channel->IsModeSet(m) ? MOD_RES_ALLOW : MOD_RES_PASSTHRU; } void OnUserPostMessage(User* user, const MessageTarget& target, const MessageDetails& details) CXX11_OVERRIDE { if ((target.type == MessageTarget::TYPE_CHANNEL) && (target.status == 0) && (details.type == MSG_PRIVMSG)) { Channel* c = target.Get<Channel>(); HistoryList* list = m.ext.get(c); if (list) { list->lines.push_back(HistoryItem(user, details.text)); if (list->lines.size() > list->maxlen) list->lines.pop_front(); } } } void OnPostJoin(Membership* memb) CXX11_OVERRIDE { LocalUser* localuser = IS_LOCAL(memb->user); if (!localuser) return; if (memb->user->IsModeSet(botmode) && !dobots) return; HistoryList* list = m.ext.get(memb->chan); if (!list) return; if ((sendnotice) && (!batchcap.get(localuser))) { std::string message("Replaying up to " + ConvToStr(list->maxlen) + " lines of pre-join history"); if (list->maxtime > 0) message.append(" spanning up to " + InspIRCd::DurationString(list->maxtime)); memb->WriteNotice(message); } time_t mintime = 0; if (list->maxtime) mintime = ServerInstance->Time() - list->maxtime; SendHistory(localuser, memb->chan, list, mintime); } Version GetVersion() CXX11_OVERRIDE { return Version("Provides channel mode +H, allows for the channel message history to be replayed on join", VF_VENDOR); } }; MODULE_INIT(ModuleChanHistory) ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/src/modules/m_chanlog.cpp������������������������������������������������������������0000664�0000000�0000000�00000005265�13554550454�0020245�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * InspIRCd -- Internet Relay Chat Daemon * * Copyright (C) 2008 Robin Burchell <robin+git@viroteck.net> * Copyright (C) 2008 Thomas Stagner <aquanight@inspircd.org> * * This file is part of InspIRCd. InspIRCd is free software: you can * redistribute it and/or modify it under the terms of the GNU General Public * License as published by the Free Software Foundation, version 2. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include "inspircd.h" class ModuleChanLog : public Module { /* * Multimap so people can redirect a snomask to multiple channels. */ typedef insp::flat_multimap<char, std::string> ChanLogTargets; ChanLogTargets logstreams; public: void ReadConfig(ConfigStatus& status) CXX11_OVERRIDE { std::string snomasks; std::string channel; ChanLogTargets newlogs; ConfigTagList tags = ServerInstance->Config->ConfTags("chanlog"); for (ConfigIter i = tags.first; i != tags.second; ++i) { channel = i->second->getString("channel"); snomasks = i->second->getString("snomasks"); if (channel.empty() || snomasks.empty()) { throw ModuleException("Malformed chanlog tag at " + i->second->getTagLocation()); } for (std::string::const_iterator it = snomasks.begin(); it != snomasks.end(); it++) { newlogs.insert(std::make_pair(*it, channel)); ServerInstance->Logs->Log(MODNAME, LOG_DEFAULT, "Logging %c to %s", *it, channel.c_str()); } } logstreams.swap(newlogs); } ModResult OnSendSnotice(char &sno, std::string &desc, const std::string &msg) CXX11_OVERRIDE { std::pair<ChanLogTargets::const_iterator, ChanLogTargets::const_iterator> itpair = logstreams.equal_range(sno); if (itpair.first == itpair.second) return MOD_RES_PASSTHRU; const std::string snotice = "\002" + desc + "\002: " + msg; for (ChanLogTargets::const_iterator it = itpair.first; it != itpair.second; ++it) { Channel *c = ServerInstance->FindChan(it->second); if (c) { ClientProtocol::Messages::Privmsg privmsg(ClientProtocol::Messages::Privmsg::nocopy, ServerInstance->Config->ServerName, c, snotice); c->Write(ServerInstance->GetRFCEvents().privmsg, privmsg); ServerInstance->PI->SendMessage(c, 0, snotice); } } return MOD_RES_PASSTHRU; } Version GetVersion() CXX11_OVERRIDE { return Version("Logs snomask output to channel(s)", VF_VENDOR); } }; MODULE_INIT(ModuleChanLog) �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/src/modules/m_channames.cpp����������������������������������������������������������0000664�0000000�0000000�00000010035�13554550454�0020556�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * InspIRCd -- Internet Relay Chat Daemon * * 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 * 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 "inspircd.h" static std::bitset<256> allowedmap; class NewIsChannelHandler { public: static bool Call(const std::string&); }; bool NewIsChannelHandler::Call(const std::string& channame) { if (channame.empty() || channame.length() > ServerInstance->Config->Limits.ChanMax || channame[0] != '#') return false; for (std::string::const_iterator c = channame.begin(); c != channame.end(); ++c) { unsigned int i = *c & 0xFF; if (!allowedmap[i]) return false; } return true; } class ModuleChannelNames : public Module { TR1NS::function<bool(const std::string&)> rememberer; bool badchan; ChanModeReference permchannelmode; public: ModuleChannelNames() : rememberer(ServerInstance->IsChannel) , badchan(false) , permchannelmode(this, "permanent") { } void init() CXX11_OVERRIDE { ServerInstance->IsChannel = NewIsChannelHandler::Call; } void ValidateChans() { Modes::ChangeList removepermchan; badchan = true; const chan_hash& chans = ServerInstance->GetChans(); for (chan_hash::const_iterator i = chans.begin(); i != chans.end(); ) { Channel* c = i->second; // Move iterator before we begin kicking ++i; if (ServerInstance->IsChannel(c->name)) continue; // The name of this channel is still valid if (c->IsModeSet(permchannelmode) && c->GetUserCounter()) { removepermchan.clear(); removepermchan.push_remove(*permchannelmode); ServerInstance->Modes->Process(ServerInstance->FakeClient, c, NULL, removepermchan); } Channel::MemberMap& users = c->userlist; for (Channel::MemberMap::iterator j = users.begin(); j != users.end(); ) { if (IS_LOCAL(j->first)) { // KickUser invalidates the iterator Channel::MemberMap::iterator it = j++; c->KickUser(ServerInstance->FakeClient, it, "Channel name no longer valid"); } else ++j; } } badchan = false; } void ReadConfig(ConfigStatus& status) CXX11_OVERRIDE { ConfigTag* tag = ServerInstance->Config->ConfValue("channames"); std::string denyToken = tag->getString("denyrange"); std::string allowToken = tag->getString("allowrange"); if (!denyToken.compare(0, 2, "0-")) denyToken[0] = '1'; if (!allowToken.compare(0, 2, "0-")) allowToken[0] = '1'; allowedmap.set(); irc::portparser denyrange(denyToken, false); int denyno = -1; while (0 != (denyno = denyrange.GetToken())) allowedmap[denyno & 0xFF] = false; irc::portparser allowrange(allowToken, false); int allowno = -1; while (0 != (allowno = allowrange.GetToken())) allowedmap[allowno & 0xFF] = true; allowedmap[0x07] = false; // BEL allowedmap[0x20] = false; // ' ' allowedmap[0x2C] = false; // ',' ValidateChans(); } void OnUserKick(User* source, Membership* memb, const std::string &reason, CUList& except_list) CXX11_OVERRIDE { if (badchan) { const Channel::MemberMap& users = memb->chan->GetUsers(); for (Channel::MemberMap::const_iterator i = users.begin(); i != users.end(); ++i) if (i->first != memb->user) except_list.insert(i->first); } } CullResult cull() CXX11_OVERRIDE { ServerInstance->IsChannel = rememberer; ValidateChans(); return Module::cull(); } Version GetVersion() CXX11_OVERRIDE { return Version("Implements config tags which allow changing characters allowed in channel names", VF_VENDOR); } }; MODULE_INIT(ModuleChannelNames) ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/src/modules/m_channelban.cpp���������������������������������������������������������0000664�0000000�0000000�00000003512�13554550454�0020714�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * InspIRCd -- Internet Relay Chat Daemon * * Copyright (C) 2009 Daniel De Graaf <danieldg@inspircd.org> * Copyright (C) 2008 Robin Burchell <robin+git@viroteck.net> * * 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 "inspircd.h" class ModuleBadChannelExtban : public Module { public: Version GetVersion() CXX11_OVERRIDE { return Version("Provides extban 'j', ban users that are present in another channel, and optionally on their status there", VF_OPTCOMMON|VF_VENDOR); } ModResult OnCheckBan(User *user, Channel *c, const std::string& mask) CXX11_OVERRIDE { if ((mask.length() > 2) && (mask[0] == 'j') && (mask[1] == ':')) { std::string rm(mask, 2); char status = 0; const PrefixMode* const mh = ServerInstance->Modes->FindPrefix(rm[0]); if (mh) { rm.assign(mask, 3, std::string::npos); status = mh->GetModeChar(); } for (User::ChanList::iterator i = user->chans.begin(); i != user->chans.end(); i++) { if (InspIRCd::Match((*i)->chan->name, rm)) { if ((!status) || ((*i)->HasMode(mh))) return MOD_RES_DENY; } } } return MOD_RES_PASSTHRU; } void On005Numeric(std::map<std::string, std::string>& tokens) CXX11_OVERRIDE { tokens["EXTBAN"].push_back('j'); } }; MODULE_INIT(ModuleBadChannelExtban) ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/src/modules/m_check.cpp��������������������������������������������������������������0000664�0000000�0000000�00000023075�13554550454�0017706�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * InspIRCd -- Internet Relay Chat Daemon * * Copyright (C) 2009-2010 Daniel De Graaf <danieldg@inspircd.org> * Copyright (C) 2007 Dennis Friis <peavey@inspircd.org> * Copyright (C) 2006-2007 Robin Burchell <robin+git@viroteck.net> * Copyright (C) 2006 Craig Edwards <craigedwards@brainbox.cc> * * This file is part of InspIRCd. InspIRCd is free software: you can * redistribute it and/or modify it under the terms of the GNU General Public * License as published by the Free Software Foundation, version 2. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include "inspircd.h" #include "listmode.h" enum { RPL_CHECK = 802 }; class CheckContext { private: User* const user; const std::string& target; std::string FormatTime(time_t ts) { std::string timestr(InspIRCd::TimeString(ts, "%Y-%m-%d %H:%M:%S UTC (", true)); timestr.append(ConvToStr(ts)); timestr.push_back(')'); return timestr; } public: CheckContext(User* u, const std::string& targetstr) : user(u) , target(targetstr) { Write("START", target); } ~CheckContext() { Write("END", target); } void Write(const std::string& type, const std::string& text) { user->WriteRemoteNumeric(RPL_CHECK, type, text); } void Write(const std::string& type, time_t ts) { user->WriteRemoteNumeric(RPL_CHECK, type, FormatTime(ts)); } User* GetUser() const { return user; } void DumpListMode(ListModeBase* mode, Channel* chan) { const ListModeBase::ModeList* list = mode->GetList(chan); if (!list) return; for (ListModeBase::ModeList::const_iterator i = list->begin(); i != list->end(); ++i) { CheckContext::List listmode(*this, "listmode"); listmode.Add(ConvToStr(mode->GetModeChar())); listmode.Add(i->mask); listmode.Add(i->setter); listmode.Add(FormatTime(i->time)); listmode.Flush(); } } void DumpExt(Extensible* ext) { CheckContext::List extlist(*this, "metadata"); for(Extensible::ExtensibleStore::const_iterator i = ext->GetExtList().begin(); i != ext->GetExtList().end(); ++i) { ExtensionItem* item = i->first; std::string value = item->ToHuman(ext, i->second); if (!value.empty()) Write("meta:" + item->name, value); else if (!item->name.empty()) extlist.Add(item->name); } extlist.Flush(); } class List : public Numeric::GenericBuilder<' ', false, Numeric::WriteRemoteNumericSink> { public: List(CheckContext& context, const char* checktype) : Numeric::GenericBuilder<' ', false, Numeric::WriteRemoteNumericSink>(Numeric::WriteRemoteNumericSink(context.GetUser()), RPL_CHECK, false, (IS_LOCAL(context.GetUser()) ? context.GetUser()->nick.length() : ServerInstance->Config->Limits.NickMax) + strlen(checktype) + 1) { GetNumeric().push(checktype).push(std::string()); } }; }; /** Handle /CHECK */ class CommandCheck : public Command { UserModeReference snomaskmode; std::string GetSnomasks(User* user) { std::string ret; if (snomaskmode) ret = snomaskmode->GetUserParameter(user); if (ret.empty()) ret = "+"; return ret; } static std::string GetAllowedOperOnlyModes(LocalUser* user, ModeType modetype) { std::string ret; const ModeParser::ModeHandlerMap& modes = ServerInstance->Modes.GetModes(modetype); for (ModeParser::ModeHandlerMap::const_iterator i = modes.begin(); i != modes.end(); ++i) { const ModeHandler* const mh = i->second; if ((mh->NeedsOper()) && (user->HasModePermission(mh))) ret.push_back(mh->GetModeChar()); } return ret; } public: CommandCheck(Module* parent) : Command(parent,"CHECK", 1) , snomaskmode(parent, "snomask") { flags_needed = 'o'; syntax = "<nick>|<ipmask>|<hostmask>|<channel> [<servername>]"; } CmdResult Handle(User* user, const Params& parameters) CXX11_OVERRIDE { if (parameters.size() > 1 && !irc::equals(parameters[1], ServerInstance->Config->ServerName)) return CMD_SUCCESS; User *targuser; Channel *targchan; std::string chliststr; targuser = ServerInstance->FindNick(parameters[0]); targchan = ServerInstance->FindChan(parameters[0]); /* * Syntax of a /check reply: * :server.name 802 target START <target> * :server.name 802 target <field> :<value> * :server.name 802 target END <target> */ // Constructor sends START, destructor sends END CheckContext context(user, parameters[0]); if (targuser) { LocalUser* loctarg = IS_LOCAL(targuser); /* /check on a user */ context.Write("nuh", targuser->GetFullHost()); context.Write("realnuh", targuser->GetFullRealHost()); context.Write("realname", targuser->GetRealName()); context.Write("modes", targuser->GetModeLetters()); context.Write("snomasks", GetSnomasks(targuser)); context.Write("server", targuser->server->GetName()); context.Write("uid", targuser->uuid); context.Write("signon", targuser->signon); context.Write("nickts", targuser->age); if (loctarg) context.Write("lastmsg", loctarg->idle_lastmsg); if (targuser->IsAway()) { /* user is away */ context.Write("awaytime", targuser->awaytime); context.Write("awaymsg", targuser->awaymsg); } if (targuser->IsOper()) { OperInfo* oper = targuser->oper; /* user is an oper of type ____ */ context.Write("opertype", oper->name); if (loctarg) { context.Write("chanmodeperms", GetAllowedOperOnlyModes(loctarg, MODETYPE_CHANNEL)); context.Write("usermodeperms", GetAllowedOperOnlyModes(loctarg, MODETYPE_USER)); context.Write("commandperms", oper->AllowedOperCommands.ToString()); context.Write("permissions", oper->AllowedPrivs.ToString()); } } if (loctarg) { context.Write("clientaddr", loctarg->client_sa.str()); context.Write("serveraddr", loctarg->server_sa.str()); std::string classname = loctarg->GetClass()->name; if (!classname.empty()) context.Write("connectclass", classname); } else context.Write("onip", targuser->GetIPString()); CheckContext::List chanlist(context, "onchans"); for (User::ChanList::iterator i = targuser->chans.begin(); i != targuser->chans.end(); i++) { Membership* memb = *i; Channel* c = memb->chan; char prefix = memb->GetPrefixChar(); if (prefix) chliststr.push_back(prefix); chliststr.append(c->name); chanlist.Add(chliststr); chliststr.clear(); } chanlist.Flush(); context.DumpExt(targuser); } else if (targchan) { /* /check on a channel */ context.Write("createdat", targchan->age); if (!targchan->topic.empty()) { /* there is a topic, assume topic related information exists */ context.Write("topic", targchan->topic); context.Write("topic_setby", targchan->setby); context.Write("topic_setat", targchan->topicset); } context.Write("modes", targchan->ChanModes(true)); context.Write("membercount", ConvToStr(targchan->GetUserCounter())); /* now the ugly bit, spool current members of a channel. :| */ const Channel::MemberMap& ulist = targchan->GetUsers(); /* note that unlike /names, we do NOT check +i vs in the channel */ for (Channel::MemberMap::const_iterator i = ulist.begin(); i != ulist.end(); ++i) { /* * Unlike Asuka, I define a clone as coming from the same host. --w00t */ const UserManager::CloneCounts& clonecount = ServerInstance->Users->GetCloneCounts(i->first); context.Write("member", InspIRCd::Format("%u %s%s (%s)", clonecount.global, i->second->GetAllPrefixChars().c_str(), i->first->GetFullHost().c_str(), i->first->GetRealName().c_str())); } const ModeParser::ListModeList& listmodes = ServerInstance->Modes->GetListModes(); for (ModeParser::ListModeList::const_iterator i = listmodes.begin(); i != listmodes.end(); ++i) context.DumpListMode(*i, targchan); context.DumpExt(targchan); } else { /* /check on an IP address, or something that doesn't exist */ long x = 0; /* hostname or other */ const user_hash& users = ServerInstance->Users->GetUsers(); for (user_hash::const_iterator a = users.begin(); a != users.end(); ++a) { if (InspIRCd::Match(a->second->GetRealHost(), parameters[0], ascii_case_insensitive_map) || InspIRCd::Match(a->second->GetDisplayedHost(), parameters[0], ascii_case_insensitive_map)) { /* host or vhost matches mask */ context.Write("match", ConvToStr(++x) + " " + a->second->GetFullRealHost() + " " + a->second->GetIPString() + " " + a->second->GetRealName()); } /* IP address */ else if (InspIRCd::MatchCIDR(a->second->GetIPString(), parameters[0])) { /* same IP. */ context.Write("match", ConvToStr(++x) + " " + a->second->GetFullRealHost() + " " + a->second->GetIPString() + " " + a->second->GetRealName()); } } context.Write("matches", ConvToStr(x)); } // END is sent by the CheckContext destructor return CMD_SUCCESS; } RouteDescriptor GetRouting(User* user, const Params& parameters) CXX11_OVERRIDE { if ((parameters.size() > 1) && (parameters[1].find('.') != std::string::npos)) return ROUTE_OPT_UCAST(parameters[1]); return ROUTE_LOCALONLY; } }; class ModuleCheck : public Module { CommandCheck mycommand; public: ModuleCheck() : mycommand(this) { } Version GetVersion() CXX11_OVERRIDE { return Version("Provides the CHECK command to view user, channel, IP address or hostname information", VF_VENDOR|VF_OPTCOMMON); } }; MODULE_INIT(ModuleCheck) �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/src/modules/m_chghost.cpp������������������������������������������������������������0000664�0000000�0000000�00000005767�13554550454�0020300�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * InspIRCd -- Internet Relay Chat Daemon * * Copyright (C) 2007 Dennis Friis <peavey@inspircd.org> * Copyright (C) 2007 Robin Burchell <robin+git@viroteck.net> * Copyright (C) 2004-2006 Craig Edwards <craigedwards@brainbox.cc> * * This file is part of InspIRCd. InspIRCd is free software: you can * redistribute it and/or modify it under the terms of the GNU General Public * License as published by the Free Software Foundation, version 2. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include "inspircd.h" /** Handle /CHGHOST */ class CommandChghost : public Command { public: std::bitset<UCHAR_MAX> hostmap; CommandChghost(Module* Creator) : Command(Creator,"CHGHOST", 2) { allow_empty_last_param = false; flags_needed = 'o'; syntax = "<nick> <host>"; TRANSLATE2(TR_NICK, TR_TEXT); } CmdResult Handle(User* user, const Params& parameters) CXX11_OVERRIDE { if (parameters[1].length() > ServerInstance->Config->Limits.MaxHost) { user->WriteNotice("*** CHGHOST: Host too long"); return CMD_FAILURE; } for (std::string::const_iterator x = parameters[1].begin(); x != parameters[1].end(); x++) { if (!hostmap.test(static_cast<unsigned char>(*x))) { user->WriteNotice("*** CHGHOST: Invalid characters in hostname"); return CMD_FAILURE; } } User* dest = ServerInstance->FindNick(parameters[0]); // Allow services to change the host of unregistered users if ((!dest) || ((dest->registered != REG_ALL) && (!user->server->IsULine()))) { user->WriteNumeric(Numerics::NoSuchNick(parameters[0])); return CMD_FAILURE; } if (IS_LOCAL(dest)) { if ((dest->ChangeDisplayedHost(parameters[1])) && (!user->server->IsULine())) { // fix by brain - ulines set hosts silently ServerInstance->SNO->WriteGlobalSno('a', user->nick+" used CHGHOST to make the displayed host of "+dest->nick+" become "+dest->GetDisplayedHost()); } } return CMD_SUCCESS; } RouteDescriptor GetRouting(User* user, const Params& parameters) CXX11_OVERRIDE { return ROUTE_OPT_UCAST(parameters[0]); } }; class ModuleChgHost : public Module { CommandChghost cmd; public: ModuleChgHost() : cmd(this) { } void ReadConfig(ConfigStatus& status) CXX11_OVERRIDE { std::string hmap = ServerInstance->Config->ConfValue("hostname")->getString("charmap", "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz.-_/0123456789"); cmd.hostmap.reset(); for (std::string::iterator n = hmap.begin(); n != hmap.end(); n++) cmd.hostmap.set(static_cast<unsigned char>(*n)); } Version GetVersion() CXX11_OVERRIDE { return Version("Provides the CHGHOST command", VF_OPTCOMMON | VF_VENDOR); } }; MODULE_INIT(ModuleChgHost) ���������inspircd-3.4.0/src/modules/m_chgident.cpp�����������������������������������������������������������0000664�0000000�0000000�00000004633�13554550454�0020415�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * InspIRCd -- Internet Relay Chat Daemon * * Copyright (C) 2009 Daniel De Graaf <danieldg@inspircd.org> * Copyright (C) 2007 Dennis Friis <peavey@inspircd.org> * Copyright (C) 2007 Robin Burchell <robin+git@viroteck.net> * Copyright (C) 2006 Oliver Lupton <oliverlupton@gmail.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 "inspircd.h" /** Handle /CHGIDENT */ class CommandChgident : public Command { public: CommandChgident(Module* Creator) : Command(Creator,"CHGIDENT", 2) { allow_empty_last_param = false; flags_needed = 'o'; syntax = "<nick> <ident>"; TRANSLATE2(TR_NICK, TR_TEXT); } CmdResult Handle(User* user, const Params& parameters) CXX11_OVERRIDE { User* dest = ServerInstance->FindNick(parameters[0]); if ((!dest) || (dest->registered != REG_ALL)) { user->WriteNumeric(Numerics::NoSuchNick(parameters[0])); return CMD_FAILURE; } if (parameters[1].length() > ServerInstance->Config->Limits.IdentMax) { user->WriteNotice("*** CHGIDENT: Ident is too long"); return CMD_FAILURE; } if (!ServerInstance->IsIdent(parameters[1])) { user->WriteNotice("*** CHGIDENT: Invalid characters in ident"); return CMD_FAILURE; } if (IS_LOCAL(dest)) { dest->ChangeIdent(parameters[1]); if (!user->server->IsULine()) ServerInstance->SNO->WriteGlobalSno('a', "%s used CHGIDENT to change %s's ident to '%s'", user->nick.c_str(), dest->nick.c_str(), dest->ident.c_str()); } return CMD_SUCCESS; } RouteDescriptor GetRouting(User* user, const Params& parameters) CXX11_OVERRIDE { return ROUTE_OPT_UCAST(parameters[0]); } }; class ModuleChgIdent : public Module { CommandChgident cmd; public: ModuleChgIdent() : cmd(this) { } Version GetVersion() CXX11_OVERRIDE { return Version("Provides the CHGIDENT command", VF_OPTCOMMON | VF_VENDOR); } }; MODULE_INIT(ModuleChgIdent) �����������������������������������������������������������������������������������������������������inspircd-3.4.0/src/modules/m_chgname.cpp������������������������������������������������������������0000664�0000000�0000000�00000004364�13554550454�0020233�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * InspIRCd -- Internet Relay Chat Daemon * * Copyright (C) 2007 Dennis Friis <peavey@inspircd.org> * Copyright (C) 2007 Robin Burchell <robin+git@viroteck.net> * * 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 "inspircd.h" /** Handle /CHGNAME */ class CommandChgname : public Command { public: CommandChgname(Module* Creator) : Command(Creator,"CHGNAME", 2, 2) { allow_empty_last_param = false; flags_needed = 'o'; syntax = "<nick> :<realname>"; TRANSLATE2(TR_NICK, TR_TEXT); } CmdResult Handle(User* user, const Params& parameters) CXX11_OVERRIDE { User* dest = ServerInstance->FindNick(parameters[0]); if ((!dest) || (dest->registered != REG_ALL)) { user->WriteNumeric(Numerics::NoSuchNick(parameters[0])); return CMD_FAILURE; } if (parameters[1].empty()) { user->WriteNotice("*** CHGNAME: Real name must be specified"); return CMD_FAILURE; } if (parameters[1].length() > ServerInstance->Config->Limits.MaxReal) { user->WriteNotice("*** CHGNAME: Real name is too long"); return CMD_FAILURE; } if (IS_LOCAL(dest)) { dest->ChangeRealName(parameters[1]); ServerInstance->SNO->WriteGlobalSno('a', "%s used CHGNAME to change %s's real name to '%s'", user->nick.c_str(), dest->nick.c_str(), dest->GetRealName().c_str()); } return CMD_SUCCESS; } RouteDescriptor GetRouting(User* user, const Params& parameters) CXX11_OVERRIDE { return ROUTE_OPT_UCAST(parameters[0]); } }; class ModuleChgName : public Module { CommandChgname cmd; public: ModuleChgName() : cmd(this) { } Version GetVersion() CXX11_OVERRIDE { return Version("Provides the CHGNAME command", VF_OPTCOMMON | VF_VENDOR); } }; MODULE_INIT(ModuleChgName) ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/src/modules/m_classban.cpp�����������������������������������������������������������0000664�0000000�0000000�00000002631�13554550454�0020412�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * InspIRCd -- Internet Relay Chat Daemon * * Copyright (C) 2016 Johanna Abrahamsson <johanna-a@mjao.org> * * This file is part of InspIRCd. InspIRCd is free software: you can * redistribute it and/or modify it under the terms of the GNU General Public * License as published by the Free Software Foundation, version 2. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include "inspircd.h" class ModuleClassBan : public Module { public: ModResult OnCheckBan(User* user, Channel* c, const std::string& mask) CXX11_OVERRIDE { LocalUser* localUser = IS_LOCAL(user); if ((localUser) && (mask.length() > 2) && (mask[0] == 'n') && (mask[1] == ':')) { if (InspIRCd::Match(localUser->GetClass()->name, mask.substr(2))) return MOD_RES_DENY; } return MOD_RES_PASSTHRU; } void On005Numeric(std::map<std::string, std::string>& tokens) CXX11_OVERRIDE { tokens["EXTBAN"].push_back('n'); } Version GetVersion() CXX11_OVERRIDE { return Version("Provides extban 'n', connection class bans", VF_VENDOR | VF_OPTCOMMON); } }; MODULE_INIT(ModuleClassBan) �������������������������������������������������������������������������������������������������������inspircd-3.4.0/src/modules/m_clearchan.cpp����������������������������������������������������������0000664�0000000�0000000�00000014606�13554550454�0020551�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * InspIRCd -- Internet Relay Chat Daemon * * Copyright (C) 2014 Attila Molnar <attilamolnar@hush.com> * * This file is part of InspIRCd. InspIRCd is free software: you can * redistribute it and/or modify it under the terms of the GNU General Public * License as published by the Free Software Foundation, version 2. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include "inspircd.h" #include "xline.h" class CommandClearChan : public Command { public: Channel* activechan; CommandClearChan(Module* Creator) : Command(Creator, "CLEARCHAN", 1, 3) { syntax = "<channel> [KILL|KICK|G|Z] [:<reason>]"; flags_needed = 'o'; // Stop the linking mod from forwarding ENCAP'd CLEARCHAN commands, see below why force_manual_route = true; } CmdResult Handle(User* user, const Params& parameters) CXX11_OVERRIDE { Channel* chan = activechan = ServerInstance->FindChan(parameters[0]); if (!chan) { user->WriteNotice("The channel " + parameters[0] + " does not exist."); return CMD_FAILURE; } // See what method the oper wants to use, default to KILL std::string method("KILL"); if (parameters.size() > 1) { method = parameters[1]; std::transform(method.begin(), method.end(), method.begin(), ::toupper); } XLineFactory* xlf = NULL; bool kick = (method == "KICK"); if ((!kick) && (method != "KILL")) { if ((method != "Z") && (method != "G")) { user->WriteNotice("Invalid method for clearing " + chan->name); return CMD_FAILURE; } xlf = ServerInstance->XLines->GetFactory(method); if (!xlf) return CMD_FAILURE; } const std::string reason = parameters.size() > 2 ? parameters.back() : "Clearing " + chan->name; if (!user->server->IsSilentULine()) ServerInstance->SNO->WriteToSnoMask((IS_LOCAL(user) ? 'a' : 'A'), user->nick + " has cleared \002" + chan->name + "\002 (" + method + "): " + reason); user->WriteNotice("Clearing \002" + chan->name + "\002 (" + method + "): " + reason); { // Route this command manually so it is sent before the QUITs we are about to generate. // The idea is that by the time our QUITs reach the next hop, it has already removed all their // clients from the channel, meaning victims on other servers won't see the victims on this // server quitting. CommandBase::Params eparams; eparams.push_back(chan->name); eparams.push_back(method); eparams.push_back(":"); eparams.back().append(reason); ServerInstance->PI->BroadcastEncap(this->name, eparams, user, user); } // Attach to the appropriate hook so we're able to hide the QUIT/KICK messages Implementation hook = (kick ? I_OnUserKick : I_OnBuildNeighborList); ServerInstance->Modules->Attach(hook, creator); std::string mask; // Now remove all local non-opers from the channel Channel::MemberMap& users = chan->userlist; for (Channel::MemberMap::iterator i = users.begin(); i != users.end(); ) { User* curr = i->first; const Channel::MemberMap::iterator currit = i; ++i; if (!IS_LOCAL(curr) || curr->IsOper()) continue; // If kicking users, remove them and skip the QuitUser() if (kick) { chan->KickUser(ServerInstance->FakeClient, currit, reason); continue; } // If we are banning users then create the XLine and add it if (xlf) { XLine* xline; try { mask = ((method[0] == 'Z') ? curr->GetIPString() : "*@" + curr->GetRealHost()); xline = xlf->Generate(ServerInstance->Time(), 60*60, user->nick, reason, mask); } catch (ModuleException&) { // Nothing, move on to the next user continue; } if (!ServerInstance->XLines->AddLine(xline, user)) delete xline; } ServerInstance->Users->QuitUser(curr, reason); } ServerInstance->Modules->Detach(hook, creator); if (xlf) ServerInstance->XLines->ApplyLines(); return CMD_SUCCESS; } }; class ModuleClearChan : public Module { CommandClearChan cmd; public: ModuleClearChan() : cmd(this) { } void init() CXX11_OVERRIDE { // Only attached while we are working; don't react to events otherwise ServerInstance->Modules->DetachAll(this); } void OnBuildNeighborList(User* source, IncludeChanList& include, std::map<User*, bool>& exception) CXX11_OVERRIDE { bool found = false; for (IncludeChanList::iterator i = include.begin(); i != include.end(); ++i) { if ((*i)->chan == cmd.activechan) { // Don't show the QUIT to anyone in the channel by default include.erase(i); found = true; break; } } const Channel::MemberMap& users = cmd.activechan->GetUsers(); for (Channel::MemberMap::const_iterator i = users.begin(); i != users.end(); ++i) { LocalUser* curr = IS_LOCAL(i->first); if (!curr) continue; if (curr->IsOper()) { // If another module has removed the channel we're working on from the list of channels // to consider for sending the QUIT to then don't add exceptions for opers, because the // module before us doesn't want them to see it or added the exceptions already. // If there is a value for this oper in excepts already, this won't overwrite it. if (found) exception.insert(std::make_pair(curr, true)); continue; } else if (!include.empty() && curr->chans.size() > 1) { // This is a victim and potentially has another common channel with the user quitting, // add a negative exception overwriting the previous value, if any. exception[curr] = false; } } } void OnUserKick(User* source, Membership* memb, const std::string& reason, CUList& excepts) CXX11_OVERRIDE { // Hide the KICK from all non-opers User* leaving = memb->user; const Channel::MemberMap& users = memb->chan->GetUsers(); for (Channel::MemberMap::const_iterator i = users.begin(); i != users.end(); ++i) { User* curr = i->first; if ((IS_LOCAL(curr)) && (!curr->IsOper()) && (curr != leaving)) excepts.insert(curr); } } Version GetVersion() CXX11_OVERRIDE { return Version("Provides the CLEARCHAN command that allows opers to masskick, masskill or mass G/Z-line users on a channel", VF_VENDOR|VF_OPTCOMMON); } }; MODULE_INIT(ModuleClearChan) ��������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/src/modules/m_cloaking.cpp�����������������������������������������������������������0000664�0000000�0000000�00000036751�13554550454�0020425�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * InspIRCd -- Internet Relay Chat Daemon * * Copyright (C) 2009-2010 Daniel De Graaf <danieldg@inspircd.org> * Copyright (C) 2006-2008 Robin Burchell <robin+git@viroteck.net> * Copyright (C) 2008 Pippijn van Steenhoven <pip88nl@gmail.com> * Copyright (C) 2003-2008 Craig Edwards <craigedwards@brainbox.cc> * Copyright (C) 2007 John Brooks <john.brooks@dereferenced.net> * Copyright (C) 2007 Dennis Friis <peavey@inspircd.org> * Copyright (C) 2006 Oliver Lupton <oliverlupton@gmail.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 "inspircd.h" #include "modules/hash.h" enum CloakMode { /** 2.0 cloak of "half" of the hostname plus the full IP hash */ MODE_HALF_CLOAK, /** 2.0 cloak of IP hash, split at 2 common CIDR range points */ MODE_OPAQUE }; // lowercase-only encoding similar to base64, used for hash output static const char base32[] = "0123456789abcdefghijklmnopqrstuv"; // The minimum length of a cloak key. static const size_t minkeylen = 30; struct CloakInfo { // The method used for cloaking users. CloakMode mode; // The number of parts of the hostname shown when using half cloaking. unsigned int domainparts; // Whether to ignore the case of a hostname when cloaking it. bool ignorecase; // The secret used for generating cloaks. std::string key; // The prefix for cloaks (e.g. MyNet-). std::string prefix; // The suffix for IP cloaks (e.g. .IP). std::string suffix; CloakInfo(CloakMode Mode, const std::string& Key, const std::string& Prefix, const std::string& Suffix, bool IgnoreCase, unsigned int DomainParts = 0) : mode(Mode) , domainparts(DomainParts) , ignorecase(IgnoreCase) , key(Key) , prefix(Prefix) , suffix(Suffix) { } }; typedef std::vector<std::string> CloakList; /** Handles user mode +x */ class CloakUser : public ModeHandler { public: bool active; SimpleExtItem<CloakList> ext; std::string debounce_uid; time_t debounce_ts; int debounce_count; CloakUser(Module* source) : ModeHandler(source, "cloak", 'x', PARAM_NONE, MODETYPE_USER) , active(false) , ext("cloaked_host", ExtensionItem::EXT_USER, source) , debounce_ts(0) , debounce_count(0) { } ModeAction OnModeChange(User* source, User* dest, Channel* channel, std::string& parameter, bool adding) CXX11_OVERRIDE { LocalUser* user = IS_LOCAL(dest); /* For remote clients, we don't take any action, we just allow it. * The local server where they are will set their cloak instead. * This is fine, as we will receive it later. */ if (!user) { // Remote setters broadcast mode before host while local setters do the opposite, so this takes that into account active = IS_LOCAL(source) ? adding : !adding; dest->SetMode(this, adding); return MODEACTION_ALLOW; } if (user->uuid == debounce_uid && debounce_ts == ServerInstance->Time()) { // prevent spamming using /mode user +x-x+x-x+x-x if (++debounce_count > 2) return MODEACTION_DENY; } else { debounce_uid = user->uuid; debounce_count = 1; debounce_ts = ServerInstance->Time(); } if (adding == user->IsModeSet(this)) return MODEACTION_DENY; /* don't allow this user to spam modechanges */ if (source == dest) user->CommandFloodPenalty += 5000; if (adding) { // assume this is more correct if (user->registered != REG_ALL && user->GetRealHost() != user->GetDisplayedHost()) return MODEACTION_DENY; CloakList* cloaks = ext.get(user); if (!cloaks) { /* Force creation of missing cloak */ creator->OnUserConnect(user); cloaks = ext.get(user); } // If we have a cloak then set the hostname. if (cloaks && !cloaks->empty()) { user->ChangeDisplayedHost(cloaks->front()); user->SetMode(this, true); return MODEACTION_ALLOW; } else return MODEACTION_DENY; } else { /* User is removing the mode, so restore their real host * and make it match the displayed one. */ user->SetMode(this, false); user->ChangeDisplayedHost(user->GetRealHost().c_str()); return MODEACTION_ALLOW; } } }; class CommandCloak : public Command { public: CommandCloak(Module* Creator) : Command(Creator, "CLOAK", 1) { flags_needed = 'o'; syntax = "<host>"; } CmdResult Handle(User* user, const Params& parameters) CXX11_OVERRIDE; }; class ModuleCloaking : public Module { public: CloakUser cu; CommandCloak ck; std::vector<CloakInfo> cloaks; dynamic_reference<HashProvider> Hash; ModuleCloaking() : cu(this) , ck(this) , Hash(this, "hash/md5") { } /** Takes a domain name and retrieves the subdomain which should be visible. * This is usually the last \p domainparts labels but if not enough are * present then all but the most specific label are used. If the domain name * consists of one label only then none are used. * * Here are some examples for how domain names will be shortened assuming * \p domainparts is set to the default of 3. * * "this.is.an.example.com" => ".an.example.com" * "an.example.com" => ".example.com" * "example.com" => ".com" * "localhost" => "" * * @param host The hostname to cloak. * @param domainparts The number of domain labels that should be visible. * @return The visible segment of the hostname. */ std::string VisibleDomainParts(const std::string& host, unsigned int domainparts) { // The position at which we found the last dot. std::string::const_reverse_iterator dotpos; // The number of dots we have seen so far. unsigned int seendots = 0; for (std::string::const_reverse_iterator iter = host.rbegin(); iter != host.rend(); ++iter) { if (*iter != '.') continue; // We have found a dot! dotpos = iter; seendots += 1; // Do we have enough segments to stop? if (seendots >= domainparts) break; } // We only returns a domain part if more than one label is // present. See above for a full explanation. if (!seendots) return ""; return std::string(dotpos.base() - 1, host.end()); } /** * 2.0-style cloaking function * @param item The item to cloak (part of an IP or hostname) * @param id A unique ID for this type of item (to make it unique if the item matches) * @param len The length of the output. Maximum for MD5 is 16 characters. */ std::string SegmentCloak(const CloakInfo& info, const std::string& item, char id, size_t len) { std::string input; input.reserve(info.key.length() + 3 + item.length()); input.append(1, id); input.append(info.key); input.append(1, '\0'); // null does not terminate a C++ string if (info.ignorecase) std::transform(item.begin(), item.end(), std::back_inserter(input), ::tolower); else input.append(item); std::string rv = Hash->GenerateRaw(input).substr(0,len); for(size_t i = 0; i < len; i++) { // this discards 3 bits per byte. We have an // overabundance of bits in the hash output, doesn't // matter which ones we are discarding. rv[i] = base32[rv[i] & 0x1F]; } return rv; } std::string SegmentIP(const CloakInfo& info, const irc::sockets::sockaddrs& ip, bool full) { std::string bindata; size_t hop1, hop2, hop3; size_t len1, len2; std::string rv; if (ip.family() == AF_INET6) { bindata = std::string((const char*)ip.in6.sin6_addr.s6_addr, 16); hop1 = 8; hop2 = 6; hop3 = 4; len1 = 6; len2 = 4; // pfx s1.s2.s3. (xxxx.xxxx or s4) sfx // 6 4 4 9/6 rv.reserve(info.prefix.length() + 26 + info.suffix.length()); } else { bindata = std::string((const char*)&ip.in4.sin_addr, 4); hop1 = 3; hop2 = 0; hop3 = 2; len1 = len2 = 3; // pfx s1.s2. (xxx.xxx or s3) sfx rv.reserve(info.prefix.length() + 15 + info.suffix.length()); } rv.append(info.prefix); rv.append(SegmentCloak(info, bindata, 10, len1)); rv.append(1, '.'); bindata.erase(hop1); rv.append(SegmentCloak(info, bindata, 11, len2)); if (hop2) { rv.append(1, '.'); bindata.erase(hop2); rv.append(SegmentCloak(info, bindata, 12, len2)); } if (full) { rv.append(1, '.'); bindata.erase(hop3); rv.append(SegmentCloak(info, bindata, 13, 6)); rv.append(info.suffix); } else { if (ip.family() == AF_INET6) { rv.append(InspIRCd::Format(".%02x%02x.%02x%02x%s", ip.in6.sin6_addr.s6_addr[2], ip.in6.sin6_addr.s6_addr[3], ip.in6.sin6_addr.s6_addr[0], ip.in6.sin6_addr.s6_addr[1], info.suffix.c_str())); } else { const unsigned char* ip4 = (const unsigned char*)&ip.in4.sin_addr; rv.append(InspIRCd::Format(".%d.%d%s", ip4[1], ip4[0], info.suffix.c_str())); } } return rv; } ModResult OnCheckBan(User* user, Channel* chan, const std::string& mask) CXX11_OVERRIDE { LocalUser* lu = IS_LOCAL(user); if (!lu) return MOD_RES_PASSTHRU; // Force the creation of cloaks if not already set. OnUserConnect(lu); // If the user has no cloaks (i.e. UNIX socket) then we do nothing here. CloakList* cloaklist = cu.ext.get(user); if (!cloaklist || cloaklist->empty()) return MOD_RES_PASSTHRU; // Check if they have a cloaked host but are not using it. for (CloakList::const_iterator iter = cloaklist->begin(); iter != cloaklist->end(); ++iter) { const std::string& cloak = *iter; if (cloak != user->GetDisplayedHost()) { const std::string cloakMask = user->nick + "!" + user->ident + "@" + cloak; if (InspIRCd::Match(cloakMask, mask)) return MOD_RES_DENY; } } return MOD_RES_PASSTHRU; } void Prioritize() CXX11_OVERRIDE { /* Needs to be after m_banexception etc. */ ServerInstance->Modules->SetPriority(this, I_OnCheckBan, PRIORITY_LAST); } // this unsets umode +x on every host change. If we are actually doing a +x // mode change, we will call SetMode back to true AFTER the host change is done. void OnChangeHost(User* u, const std::string& host) CXX11_OVERRIDE { if (u->IsModeSet(cu) && !cu.active) { u->SetMode(cu, false); LocalUser* luser = IS_LOCAL(u); if (!luser) return; Modes::ChangeList modechangelist; modechangelist.push_remove(&cu); ClientProtocol::Events::Mode modeevent(ServerInstance->FakeClient, NULL, u, modechangelist); luser->Send(modeevent); } cu.active = false; } Version GetVersion() CXX11_OVERRIDE { std::string testcloak = "broken"; if (Hash && !cloaks.empty()) { const CloakInfo& info = cloaks.front(); switch (info.mode) { case MODE_HALF_CLOAK: // Use old cloaking verification to stay compatible with 2.0 // But verify domainparts and ignorecase when use 3.0-only features if (info.domainparts == 3 && !info.ignorecase) testcloak = info.prefix + SegmentCloak(info, "*", 3, 8) + info.suffix; else { irc::sockets::sockaddrs sa; testcloak = GenCloak(info, sa, "", testcloak + ConvToStr(info.domainparts)) + (info.ignorecase ? "-ci" : ""); } break; case MODE_OPAQUE: testcloak = info.prefix + SegmentCloak(info, "*", 4, 8) + info.suffix + (info.ignorecase ? "-ci" : ""); } } return Version("Provides masking of user hostnames", VF_COMMON|VF_VENDOR, testcloak); } void ReadConfig(ConfigStatus& status) CXX11_OVERRIDE { ConfigTagList tags = ServerInstance->Config->ConfTags("cloak"); if (tags.first == tags.second) throw ModuleException("You have loaded the cloaking module but not configured any <cloak> tags!"); std::vector<CloakInfo> newcloaks; for (ConfigIter i = tags.first; i != tags.second; ++i) { ConfigTag* tag = i->second; // Ensure that we have the <cloak:key> parameter. const std::string key = tag->getString("key"); if (key.empty()) throw ModuleException("You have not defined a cloaking key. Define <cloak:key> as a " + ConvToStr(minkeylen) + "+ character network-wide secret, at " + tag->getTagLocation()); // If we are the first cloak method then mandate a strong key. if (i == tags.first && key.length() < minkeylen) throw ModuleException("Your cloaking key is not secure. It should be at least " + ConvToStr(minkeylen) + " characters long, at " + tag->getTagLocation()); const bool ignorecase = tag->getBool("ignorecase"); const std::string mode = tag->getString("mode"); const std::string prefix = tag->getString("prefix"); const std::string suffix = tag->getString("suffix", ".IP"); if (stdalgo::string::equalsci(mode, "half")) { unsigned int domainparts = tag->getUInt("domainparts", 3, 1, 10); newcloaks.push_back(CloakInfo(MODE_HALF_CLOAK, key, prefix, suffix, ignorecase, domainparts)); } else if (stdalgo::string::equalsci(mode, "full")) newcloaks.push_back(CloakInfo(MODE_OPAQUE, key, prefix, suffix, ignorecase)); else throw ModuleException(mode + " is an invalid value for <cloak:mode>; acceptable values are 'half' and 'full', at " + tag->getTagLocation()); } // The cloak configuration was valid so we can apply it. cloaks.swap(newcloaks); } std::string GenCloak(const CloakInfo& info, const irc::sockets::sockaddrs& ip, const std::string& ipstr, const std::string& host) { std::string chost; irc::sockets::sockaddrs hostip; bool host_is_ip = irc::sockets::aptosa(host, ip.port(), hostip) && hostip == ip; switch (info.mode) { case MODE_HALF_CLOAK: { if (!host_is_ip) chost = info.prefix + SegmentCloak(info, host, 1, 6) + VisibleDomainParts(host, info.domainparts); if (chost.empty() || chost.length() > 50) chost = SegmentIP(info, ip, false); break; } case MODE_OPAQUE: default: chost = SegmentIP(info, ip, true); } return chost; } void OnSetUserIP(LocalUser* user) CXX11_OVERRIDE { // Connecting users are handled in OnUserConnect not here. if (user->registered != REG_ALL) return; // Remove the cloaks and generate new ones. cu.ext.unset(user); OnUserConnect(user); // If a user is using a cloak then update it. if (user->IsModeSet(cu)) { CloakList* cloaklist = cu.ext.get(user); user->ChangeDisplayedHost(cloaklist->front()); } } void OnUserConnect(LocalUser* dest) CXX11_OVERRIDE { if (cu.ext.get(dest)) return; // TODO: decide how we are going to cloak AF_UNIX hostnames. if (dest->client_sa.family() != AF_INET && dest->client_sa.family() != AF_INET6) return; CloakList cloaklist; for (std::vector<CloakInfo>::const_iterator iter = cloaks.begin(); iter != cloaks.end(); ++iter) cloaklist.push_back(GenCloak(*iter, dest->client_sa, dest->GetIPString(), dest->GetRealHost())); cu.ext.set(dest, cloaklist); } }; CmdResult CommandCloak::Handle(User* user, const Params& parameters) { ModuleCloaking* mod = (ModuleCloaking*)(Module*)creator; // If we're cloaking an IP address we pass it in the IP field too. irc::sockets::sockaddrs sa; const char* ipaddr = irc::sockets::aptosa(parameters[0], 0, sa) ? parameters[0].c_str() : ""; unsigned int id = 0; for (std::vector<CloakInfo>::const_iterator iter = mod->cloaks.begin(); iter != mod->cloaks.end(); ++iter) { const std::string cloak = mod->GenCloak(*iter, sa, ipaddr, parameters[0]); user->WriteNotice(InspIRCd::Format("*** Cloak #%u for %s is %s", ++id, parameters[0].c_str(), cloak.c_str())); } return CMD_SUCCESS; } MODULE_INIT(ModuleCloaking) �����������������������inspircd-3.4.0/src/modules/m_clones.cpp�������������������������������������������������������������0000664�0000000�0000000�00000005220�13554550454�0020104�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * InspIRCd -- Internet Relay Chat Daemon * * Copyright (C) 2007 Dennis Friis <peavey@inspircd.org> * Copyright (C) 2007 Robin Burchell <robin+git@viroteck.net> * Copyright (C) 2007 Craig Edwards <craigedwards@brainbox.cc> * * This file is part of InspIRCd. InspIRCd is free software: you can * redistribute it and/or modify it under the terms of the GNU General Public * License as published by the Free Software Foundation, version 2. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include "inspircd.h" #include "modules/ircv3_batch.h" enum { // InspIRCd-specific. RPL_CLONES = 399 }; class CommandClones : public SplitCommand { private: IRCv3::Batch::API batchmanager; IRCv3::Batch::Batch batch; public: CommandClones(Module* Creator) : SplitCommand(Creator,"CLONES", 1) , batchmanager(Creator) , batch("inspircd.org/clones") { flags_needed = 'o'; syntax = "<limit>"; } CmdResult HandleLocal(LocalUser* user, const Params& parameters) CXX11_OVERRIDE { unsigned int limit = ConvToNum<unsigned int>(parameters[0]); // Syntax of a CLONES reply: // :irc.example.com BATCH +<id> inspircd.org/clones :<min-count> // @batch=<id> :irc.example.com 399 <client> <local-count> <remote-count> <cidr-mask> /// :irc.example.com BATCH :-<id> if (batchmanager) { batchmanager->Start(batch); batch.GetBatchStartMessage().PushParam(ConvToStr(limit)); } const UserManager::CloneMap& clonemap = ServerInstance->Users->GetCloneMap(); for (UserManager::CloneMap::const_iterator i = clonemap.begin(); i != clonemap.end(); ++i) { const UserManager::CloneCounts& counts = i->second; if (counts.global < limit) continue; Numeric::Numeric numeric(RPL_CLONES); numeric.push(counts.local); numeric.push(counts.global); numeric.push(i->first.str()); ClientProtocol::Messages::Numeric numericmsg(numeric, user); batch.AddToBatch(numericmsg); user->Send(ServerInstance->GetRFCEvents().numeric, numericmsg); } if (batchmanager) batchmanager->End(batch); return CMD_SUCCESS; } }; class ModuleClones : public Module { public: CommandClones cmd; public: ModuleClones() : cmd(this) { } Version GetVersion() CXX11_OVERRIDE { return Version("Provides the CLONES command to retrieve information on clones", VF_VENDOR); } }; MODULE_INIT(ModuleClones) ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/src/modules/m_commonchans.cpp��������������������������������������������������������0000664�0000000�0000000�00000004153�13554550454�0021132�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * InspIRCd -- Internet Relay Chat Daemon * * Copyright (C) 2019 Peter Powell <petpow@saberuk.com> * Copyright (C) 2007 Craig Edwards <craigedwards@brainbox.cc> * * This file is part of InspIRCd. InspIRCd is free software: you can * redistribute it and/or modify it under the terms of the GNU General Public * License as published by the Free Software Foundation, version 2. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include "inspircd.h" #include "modules/ctctags.h" class ModuleCommonChans : public CTCTags::EventListener , public Module { private: SimpleUserModeHandler mode; ModResult HandleMessage(User* user, const MessageTarget& target) { if (target.type != MessageTarget::TYPE_USER) return MOD_RES_PASSTHRU; User* targuser = target.Get<User>(); if (!targuser->IsModeSet(mode) || user->SharesChannelWith(targuser)) return MOD_RES_PASSTHRU; if (user->HasPrivPermission("users/ignore-commonchans") || user->server->IsULine()) return MOD_RES_PASSTHRU; user->WriteNumeric(ERR_CANTSENDTOUSER, targuser->nick, "You are not permitted to send private messages to this user (+c is set)"); return MOD_RES_DENY; } public: ModuleCommonChans() : CTCTags::EventListener(this) , mode(this, "deaf_commonchan", 'c') { } Version GetVersion() CXX11_OVERRIDE { return Version("Provides user mode +c, requires users to share a common channel with you to private message you", VF_VENDOR); } ModResult OnUserPreMessage(User* user, const MessageTarget& target, MessageDetails& details) CXX11_OVERRIDE { return HandleMessage(user, target); } ModResult OnUserPreTagMessage(User* user, const MessageTarget& target, CTCTags::TagMessageDetails& details) CXX11_OVERRIDE { return HandleMessage(user, target); } }; MODULE_INIT(ModuleCommonChans) ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/src/modules/m_conn_join.cpp����������������������������������������������������������0000664�0000000�0000000�00000005600�13554550454�0020577�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * InspIRCd -- Internet Relay Chat Daemon * * Copyright (C) 2010 Daniel De Graaf <danieldg@inspircd.org> * Copyright (C) 2007 Dennis Friis <peavey@inspircd.org> * Copyright (C) 2007 Robin Burchell <robin+git@viroteck.net> * Copyright (C) 2007 Craig Edwards <craigedwards@brainbox.cc> * * This file is part of InspIRCd. InspIRCd is free software: you can * redistribute it and/or modify it under the terms of the GNU General Public * License as published by the Free Software Foundation, version 2. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include "inspircd.h" static void JoinChannels(LocalUser* u, const std::string& chanlist) { irc::commasepstream chans(chanlist); std::string chan; while (chans.GetToken(chan)) { if (ServerInstance->IsChannel(chan)) Channel::JoinUser(u, chan); } } class JoinTimer : public Timer { private: LocalUser* const user; const std::string channels; SimpleExtItem<JoinTimer>& ext; public: JoinTimer(LocalUser* u, SimpleExtItem<JoinTimer>& ex, const std::string& chans, unsigned int delay) : Timer(delay, false) , user(u), channels(chans), ext(ex) { ServerInstance->Timers.AddTimer(this); } bool Tick(time_t time) CXX11_OVERRIDE { if (user->chans.empty()) JoinChannels(user, channels); ext.unset(user); return false; } }; class ModuleConnJoin : public Module { SimpleExtItem<JoinTimer> ext; std::string defchans; unsigned int defdelay; public: ModuleConnJoin() : ext("join_timer", ExtensionItem::EXT_USER, this) { } void ReadConfig(ConfigStatus& status) CXX11_OVERRIDE { ConfigTag* tag = ServerInstance->Config->ConfValue("autojoin"); defchans = tag->getString("channel"); defdelay = tag->getDuration("delay", 0, 0, 60*15); } void Prioritize() CXX11_OVERRIDE { ServerInstance->Modules->SetPriority(this, I_OnPostConnect, PRIORITY_LAST); } Version GetVersion() CXX11_OVERRIDE { return Version("Forces users to join the specified channel(s) on connect", VF_VENDOR); } void OnPostConnect(User* user) CXX11_OVERRIDE { LocalUser* localuser = IS_LOCAL(user); if (!localuser) return; std::string chanlist = localuser->GetClass()->config->getString("autojoin"); unsigned int chandelay = localuser->GetClass()->config->getDuration("autojoindelay", 0, 0, 60*15); if (chanlist.empty()) { if (defchans.empty()) return; chanlist = defchans; chandelay = defdelay; } if (!chandelay) JoinChannels(localuser, chanlist); else ext.set(localuser, new JoinTimer(localuser, ext, chanlist, chandelay)); } }; MODULE_INIT(ModuleConnJoin) ��������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/src/modules/m_conn_umodes.cpp��������������������������������������������������������0000664�0000000�0000000�00000003144�13554550454�0021135�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * InspIRCd -- Internet Relay Chat Daemon * * Copyright (C) 2009 Daniel De Graaf <danieldg@inspircd.org> * Copyright (C) 2007 Dennis Friis <peavey@inspircd.org> * Copyright (C) 2007 Robin Burchell <robin+git@viroteck.net> * Copyright (C) 2006 Craig Edwards <craigedwards@brainbox.cc> * * This file is part of InspIRCd. InspIRCd is free software: you can * redistribute it and/or modify it under the terms of the GNU General Public * License as published by the Free Software Foundation, version 2. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include "inspircd.h" class ModuleModesOnConnect : public Module { public: Version GetVersion() CXX11_OVERRIDE { return Version("Sets (and unsets) modes on users when they connect", VF_VENDOR); } void OnUserConnect(LocalUser* user) CXX11_OVERRIDE { ConfigTag* tag = user->MyClass->config; std::string ThisModes = tag->getString("modes"); if (!ThisModes.empty()) { std::string buf; irc::spacesepstream ss(ThisModes); CommandBase::Params modes; modes.push_back(user->nick); // split ThisUserModes into modes and mode params while (ss.GetToken(buf)) modes.push_back(buf); ServerInstance->Parser.CallHandler("MODE", modes, user); } } }; MODULE_INIT(ModuleModesOnConnect) ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/src/modules/m_conn_waitpong.cpp������������������������������������������������������0000664�0000000�0000000�00000005343�13554550454�0021474�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * InspIRCd -- Internet Relay Chat Daemon * * Copyright (C) 2009 Daniel De Graaf <danieldg@inspircd.org> * Copyright (C) 2008 Pippijn van Steenhoven <pip88nl@gmail.com> * Copyright (C) 2007 Dennis Friis <peavey@inspircd.org> * Copyright (C) 2007 Robin Burchell <robin+git@viroteck.net> * Copyright (C) 2006-2007 Oliver Lupton <oliverlupton@gmail.com> * Copyright (C) 2006 Craig Edwards <craigedwards@brainbox.cc> * * This file is part of InspIRCd. InspIRCd is free software: you can * redistribute it and/or modify it under the terms of the GNU General Public * License as published by the Free Software Foundation, version 2. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include "inspircd.h" class ModuleWaitPong : public Module { bool sendsnotice; bool killonbadreply; LocalStringExt ext; public: ModuleWaitPong() : ext("waitpong_pingstr", ExtensionItem::EXT_USER, this) { } void ReadConfig(ConfigStatus& status) CXX11_OVERRIDE { ConfigTag* tag = ServerInstance->Config->ConfValue("waitpong"); sendsnotice = tag->getBool("sendsnotice", true); killonbadreply = tag->getBool("killonbadreply", true); } ModResult OnUserRegister(LocalUser* user) CXX11_OVERRIDE { std::string pingrpl = ServerInstance->GenRandomStr(10); { ClientProtocol::Messages::Ping pingmsg(pingrpl); user->Send(ServerInstance->GetRFCEvents().ping, pingmsg); } if(sendsnotice) user->WriteNotice("*** If you are having problems connecting due to registration timeouts type /quote PONG " + pingrpl + " or /raw PONG " + pingrpl + " now."); ext.set(user, pingrpl); return MOD_RES_PASSTHRU; } ModResult OnPreCommand(std::string& command, CommandBase::Params& parameters, LocalUser* user, bool validated) CXX11_OVERRIDE { if (command == "PONG") { std::string* pingrpl = ext.get(user); if (pingrpl) { if (!parameters.empty() && *pingrpl == parameters[0]) { ext.unset(user); return MOD_RES_DENY; } else { if(killonbadreply) ServerInstance->Users->QuitUser(user, "Incorrect ping reply for registration"); return MOD_RES_DENY; } } } return MOD_RES_PASSTHRU; } ModResult OnCheckReady(LocalUser* user) CXX11_OVERRIDE { return ext.get(user) ? MOD_RES_DENY : MOD_RES_PASSTHRU; } Version GetVersion() CXX11_OVERRIDE { return Version("Require pong prior to registration", VF_VENDOR); } }; MODULE_INIT(ModuleWaitPong) ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/src/modules/m_connectban.cpp���������������������������������������������������������0000664�0000000�0000000�00000007654�13554550454�0020750�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * InspIRCd -- Internet Relay Chat Daemon * * Copyright (C) 2008 Robin Burchell <robin+git@viroteck.net> * * 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 "inspircd.h" #include "xline.h" #include "modules/webirc.h" class ModuleConnectBan : public Module , public WebIRC::EventListener { typedef std::map<irc::sockets::cidr_mask, unsigned int> ConnectMap; ConnectMap connects; unsigned int threshold; unsigned int banduration; unsigned int ipv4_cidr; unsigned int ipv6_cidr; std::string banmessage; unsigned char GetRange(LocalUser* user) { int family = user->client_sa.family(); switch (family) { case AF_INET: return ipv4_cidr; case AF_INET6: return ipv6_cidr; case AF_UNIX: // Ranges for UNIX sockets are ignored entirely. return 0; } // If we have reached this point then we have encountered a bug. ServerInstance->Logs->Log(MODNAME, LOG_DEBUG, "BUG: ModuleConnectBan::GetRange(): socket type %d is unknown!", family); return 0; } public: ModuleConnectBan() : WebIRC::EventListener(this) { } Version GetVersion() CXX11_OVERRIDE { return Version("Throttles the connections of IP ranges who try to connect flood", VF_VENDOR); } void ReadConfig(ConfigStatus& status) CXX11_OVERRIDE { ConfigTag* tag = ServerInstance->Config->ConfValue("connectban"); ipv4_cidr = tag->getUInt("ipv4cidr", 32, 1, 32); ipv6_cidr = tag->getUInt("ipv6cidr", 128, 1, 128); threshold = tag->getUInt("threshold", 10, 1); banduration = tag->getDuration("duration", 10*60, 1); banmessage = tag->getString("banmessage", "Your IP range has been attempting to connect too many times in too short a duration. Wait a while, and you will be able to connect."); } void OnWebIRCAuth(LocalUser* user, const WebIRC::FlagMap* flags) CXX11_OVERRIDE { if (user->exempt) return; // HACK: Lower the connection attempts for the gateway IP address. The user // will be rechecked for connect spamming shortly after when their IP address // is changed and OnSetUserIP is called. irc::sockets::cidr_mask mask(user->client_sa, GetRange(user)); ConnectMap::iterator iter = connects.find(mask); if (iter != connects.end() && iter->second) iter->second--; } void OnSetUserIP(LocalUser* u) CXX11_OVERRIDE { if (u->exempt) return; irc::sockets::cidr_mask mask(u->client_sa, GetRange(u)); ConnectMap::iterator i = connects.find(mask); if (i != connects.end()) { i->second++; if (i->second >= threshold) { // Create Z-line for set duration. ZLine* zl = new ZLine(ServerInstance->Time(), banduration, ServerInstance->Config->ServerName, banmessage, mask.str()); if (!ServerInstance->XLines->AddLine(zl, NULL)) { delete zl; return; } ServerInstance->XLines->ApplyLines(); std::string maskstr = mask.str(); ServerInstance->SNO->WriteGlobalSno('x', "Z-line added by module m_connectban on %s to expire in %s (on %s): Connect flooding", maskstr.c_str(), InspIRCd::DurationString(zl->duration).c_str(), InspIRCd::TimeString(zl->expiry).c_str()); ServerInstance->SNO->WriteGlobalSno('a', "Connect flooding from IP range %s (%d)", maskstr.c_str(), threshold); connects.erase(i); } } else { connects[mask] = 1; } } void OnGarbageCollect() CXX11_OVERRIDE { ServerInstance->Logs->Log(MODNAME, LOG_DEBUG, "Clearing map."); connects.clear(); } }; MODULE_INIT(ModuleConnectBan) ������������������������������������������������������������������������������������inspircd-3.4.0/src/modules/m_connflood.cpp����������������������������������������������������������0000664�0000000�0000000�00000005402�13554550454�0020604�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * InspIRCd -- Internet Relay Chat Daemon * * Copyright (C) 2007 Dennis Friis <peavey@inspircd.org> * Copyright (C) 2007 Robin Burchell <robin+git@viroteck.net> * Copyright (C) 2006 Craig Edwards <craigedwards@brainbox.cc> * * This file is part of InspIRCd. InspIRCd is free software: you can * redistribute it and/or modify it under the terms of the GNU General Public * License as published by the Free Software Foundation, version 2. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include "inspircd.h" class ModuleConnFlood : public Module { unsigned int seconds; unsigned int timeout; unsigned int boot_wait; unsigned int conns; unsigned int maxconns; bool throttled; time_t first; std::string quitmsg; public: ModuleConnFlood() : conns(0), throttled(false) { } Version GetVersion() CXX11_OVERRIDE { return Version("Connection throttle", VF_VENDOR); } void ReadConfig(ConfigStatus& status) CXX11_OVERRIDE { /* read configuration variables */ ConfigTag* tag = ServerInstance->Config->ConfValue("connflood"); /* throttle configuration */ seconds = tag->getDuration("period", tag->getDuration("seconds", 30)); maxconns = tag->getUInt("maxconns", 3); timeout = tag->getDuration("timeout", 30); quitmsg = tag->getString("quitmsg"); /* seconds to wait when the server just booted */ boot_wait = tag->getDuration("bootwait", 60*2); first = ServerInstance->Time(); } ModResult OnUserRegister(LocalUser* user) CXX11_OVERRIDE { if (user->exempt) return MOD_RES_PASSTHRU; time_t next = ServerInstance->Time(); if ((ServerInstance->startup_time + boot_wait) > next) return MOD_RES_PASSTHRU; /* time difference between first and latest connection */ time_t tdiff = next - first; /* increase connection count */ conns++; if (throttled) { if (tdiff > seconds + timeout) { /* expire throttle */ throttled = false; ServerInstance->SNO->WriteGlobalSno('a', "Connection throttle deactivated"); return MOD_RES_PASSTHRU; } ServerInstance->Users->QuitUser(user, quitmsg); return MOD_RES_DENY; } if (tdiff <= seconds) { if (conns >= maxconns) { throttled = true; ServerInstance->SNO->WriteGlobalSno('a', "Connection throttle activated"); ServerInstance->Users->QuitUser(user, quitmsg); return MOD_RES_DENY; } } else { conns = 1; first = next; } return MOD_RES_PASSTHRU; } }; MODULE_INIT(ModuleConnFlood) ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/src/modules/m_customprefix.cpp�������������������������������������������������������0000664�0000000�0000000�00000007755�13554550454�0021370�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * InspIRCd -- Internet Relay Chat Daemon * * Copyright (C) 2010 Daniel De Graaf <danieldg@inspircd.org> * * This file is part of InspIRCd. InspIRCd is free software: you can * redistribute it and/or modify it under the terms of the GNU General Public * License as published by the Free Software Foundation, version 2. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include "inspircd.h" class CustomPrefixMode : public PrefixMode { public: reference<ConfigTag> tag; CustomPrefixMode(Module* parent, const std::string& Name, char Letter, char Prefix, ConfigTag* Tag) : PrefixMode(parent, Name, Letter, 0, Prefix) , tag(Tag) { unsigned long rank = tag->getUInt("rank", 0, 0, UINT_MAX); unsigned long setrank = tag->getUInt("ranktoset", prefixrank, rank, UINT_MAX); unsigned long unsetrank = tag->getUInt("ranktounset", setrank, setrank, UINT_MAX); bool depriv = tag->getBool("depriv", true); this->Update(rank, setrank, unsetrank, depriv); ServerInstance->Logs->Log(MODNAME, LOG_DEBUG, "Created the %s prefix: letter=%c prefix=%c rank=%u ranktoset=%u ranktounset=%i depriv=%d", name.c_str(), GetModeChar(), GetPrefix(), GetPrefixRank(), GetLevelRequired(true), GetLevelRequired(false), CanSelfRemove()); } }; class ModuleCustomPrefix : public Module { std::vector<CustomPrefixMode*> modes; public: void init() CXX11_OVERRIDE { ConfigTagList tags = ServerInstance->Config->ConfTags("customprefix"); for (ConfigIter iter = tags.first; iter != tags.second; ++iter) { ConfigTag* tag = iter->second; const std::string name = tag->getString("name"); if (name.empty()) throw ModuleException("<customprefix:name> must be specified at " + tag->getTagLocation()); if (tag->getBool("change")) { ModeHandler* mh = ServerInstance->Modes->FindMode(name, MODETYPE_CHANNEL); if (!mh) throw ModuleException("<customprefix:change> specified for a nonexistent mode at " + tag->getTagLocation()); PrefixMode* pm = mh->IsPrefixMode(); if (!pm) throw ModuleException("<customprefix:change> specified for a non-prefix mode at " + tag->getTagLocation()); unsigned long rank = tag->getUInt("rank", pm->GetPrefixRank(), 0, UINT_MAX); unsigned long setrank = tag->getUInt("ranktoset", pm->GetLevelRequired(true), rank, UINT_MAX); unsigned long unsetrank = tag->getUInt("ranktounset", pm->GetLevelRequired(false), setrank, UINT_MAX); bool depriv = tag->getBool("depriv", pm->CanSelfRemove()); pm->Update(rank, setrank, unsetrank, depriv); ServerInstance->Logs->Log(MODNAME, LOG_DEBUG, "Changed the %s prefix: depriv=%u rank=%u ranktoset=%u ranktounset=%u", pm->name.c_str(), pm->CanSelfRemove(), pm->GetPrefixRank(), pm->GetLevelRequired(true), pm->GetLevelRequired(false)); continue; } const std::string letter = tag->getString("letter"); if (letter.length() != 1) throw ModuleException("<customprefix:letter> must be set to a mode character at " + tag->getTagLocation()); const std::string prefix = tag->getString("prefix"); if (prefix.length() != 1) throw ModuleException("<customprefix:prefix> must be set to a mode prefix at " + tag->getTagLocation()); try { CustomPrefixMode* mh = new CustomPrefixMode(this, name, letter[0], prefix[0], tag); modes.push_back(mh); ServerInstance->Modules->AddService(*mh); } catch (ModuleException& e) { throw ModuleException(e.GetReason() + " (while creating mode from " + tag->getTagLocation() + ")"); } } } ~ModuleCustomPrefix() { stdalgo::delete_all(modes); } Version GetVersion() CXX11_OVERRIDE { return Version("Provides custom prefix channel modes", VF_VENDOR); } }; MODULE_INIT(ModuleCustomPrefix) �������������������inspircd-3.4.0/src/modules/m_customtitle.cpp��������������������������������������������������������0000664�0000000�0000000�00000011074�13554550454�0021201�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * InspIRCd -- Internet Relay Chat Daemon * * Copyright (C) 2009 Daniel De Graaf <danieldg@inspircd.org> * Copyright (C) 2008 Pippijn van Steenhoven <pip88nl@gmail.com> * Copyright (C) 2007 Dennis Friis <peavey@inspircd.org> * * This file is part of InspIRCd. InspIRCd is free software: you can * redistribute it and/or modify it under the terms of the GNU General Public * License as published by the Free Software Foundation, version 2. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include "inspircd.h" #include "modules/whois.h" enum { // From UnrealIRCd. RPL_WHOISSPECIAL = 320 }; struct CustomTitle { const std::string name; const std::string password; const std::string hash; const std::string host; const std::string title; const std::string vhost; CustomTitle(const std::string& n, const std::string& p, const std::string& h, const std::string& hst, const std::string& t, const std::string& v) : name(n) , password(p) , hash(h) , host(hst) , title(t) , vhost(v) { } bool MatchUser(User* user) const { const std::string userHost = user->ident + "@" + user->GetRealHost(); const std::string userIP = user->ident + "@" + user->GetIPString(); return InspIRCd::MatchMask(host, userHost, userIP); } bool CheckPass(User* user, const std::string& pass) const { return ServerInstance->PassCompare(user, password, pass, hash); } }; typedef std::multimap<std::string, CustomTitle> CustomVhostMap; typedef std::pair<CustomVhostMap::iterator, CustomVhostMap::iterator> MatchingConfigs; /** Handle /TITLE */ class CommandTitle : public Command { public: StringExtItem ctitle; CustomVhostMap configs; CommandTitle(Module* Creator) : Command(Creator,"TITLE", 2), ctitle("ctitle", ExtensionItem::EXT_USER, Creator) { syntax = "<username> <password>"; } CmdResult Handle(User* user, const Params& parameters) CXX11_OVERRIDE { MatchingConfigs matching = configs.equal_range(parameters[0]); for (MatchingConfigs::first_type i = matching.first; i != matching.second; ++i) { CustomTitle config = i->second; if (config.MatchUser(user) && config.CheckPass(user, parameters[1])) { ctitle.set(user, config.title); ServerInstance->PI->SendMetaData(user, "ctitle", config.title); if (!config.vhost.empty()) user->ChangeDisplayedHost(config.vhost); user->WriteNotice("Custom title set to '" + config.title + "'"); return CMD_SUCCESS; } } user->WriteNotice("Invalid title credentials"); return CMD_SUCCESS; } }; class ModuleCustomTitle : public Module, public Whois::LineEventListener { CommandTitle cmd; public: ModuleCustomTitle() : Whois::LineEventListener(this) , cmd(this) { } void ReadConfig(ConfigStatus& status) CXX11_OVERRIDE { ConfigTagList tags = ServerInstance->Config->ConfTags("title"); CustomVhostMap newtitles; for (ConfigIter i = tags.first; i != tags.second; ++i) { reference<ConfigTag> tag = i->second; std::string name = tag->getString("name", "", 1); if (name.empty()) throw ModuleException("<title:name> is empty at " + tag->getTagLocation()); std::string pass = tag->getString("password"); if (pass.empty()) throw ModuleException("<title:password> is empty at " + tag->getTagLocation()); std::string hash = tag->getString("hash"); std::string host = tag->getString("host", "*@*"); std::string title = tag->getString("title"); std::string vhost = tag->getString("vhost"); CustomTitle config(name, pass, hash, host, title, vhost); newtitles.insert(std::make_pair(name, config)); } cmd.configs.swap(newtitles); } // :kenny.chatspike.net 320 Brain Azhrarn :is getting paid to play games. ModResult OnWhoisLine(Whois::Context& whois, Numeric::Numeric& numeric) CXX11_OVERRIDE { /* We use this and not OnWhois because this triggers for remote, too */ if (numeric.GetNumeric() == 312) { /* Insert our numeric before 312 */ const std::string* ctitle = cmd.ctitle.get(whois.GetTarget()); if (ctitle) { whois.SendLine(RPL_WHOISSPECIAL, ctitle); } } /* Don't block anything */ return MOD_RES_PASSTHRU; } Version GetVersion() CXX11_OVERRIDE { return Version("Provides the TITLE command, custom titles for users", VF_OPTCOMMON | VF_VENDOR); } }; MODULE_INIT(ModuleCustomTitle) ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/src/modules/m_cycle.cpp��������������������������������������������������������������0000664�0000000�0000000�00000004324�13554550454�0017724�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * InspIRCd -- Internet Relay Chat Daemon * * Copyright (C) 2007 Dennis Friis <peavey@inspircd.org> * Copyright (C) 2007 Robin Burchell <robin+git@viroteck.net> * * 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 "inspircd.h" /** Handle /CYCLE */ class CommandCycle : public SplitCommand { public: CommandCycle(Module* Creator) : SplitCommand(Creator, "CYCLE", 1) { Penalty = 3; syntax = "<channel> [:<reason>]"; } CmdResult HandleLocal(LocalUser* user, const Params& parameters) CXX11_OVERRIDE { Channel* channel = ServerInstance->FindChan(parameters[0]); std::string reason = "Cycling"; if (parameters.size() > 1) { /* reason provided, use it */ reason = reason + ": " + parameters[1]; } if (!channel) { user->WriteNumeric(Numerics::NoSuchChannel(parameters[0])); return CMD_FAILURE; } if (channel->HasUser(user)) { if (channel->GetPrefixValue(user) < VOICE_VALUE && channel->IsBanned(user)) { // User is banned, send an error and don't cycle them user->WriteNotice("*** You may not cycle, as you are banned on channel " + channel->name); return CMD_FAILURE; } channel->PartUser(user, reason); Channel::JoinUser(user, parameters[0], true); return CMD_SUCCESS; } else { user->WriteNumeric(ERR_NOTONCHANNEL, channel->name, "You're not on that channel"); } return CMD_FAILURE; } }; class ModuleCycle : public Module { CommandCycle cmd; public: ModuleCycle() : cmd(this) { } Version GetVersion() CXX11_OVERRIDE { return Version("Provides the CYCLE command, acts as a server-side HOP command to part and rejoin a channel", VF_VENDOR); } }; MODULE_INIT(ModuleCycle) ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/src/modules/m_dccallow.cpp�����������������������������������������������������������0000664�0000000�0000000�00000037773�13554550454�0020433�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * InspIRCd -- Internet Relay Chat Daemon * * Copyright (C) 2009 Daniel De Graaf <danieldg@inspircd.org> * Copyright (C) 2008 John Brooks <john.brooks@dereferenced.net> * Copyright (C) 2008 Pippijn van Steenhoven <pip88nl@gmail.com> * Copyright (C) 2006-2008 Craig Edwards <craigedwards@brainbox.cc> * Copyright (C) 2007-2008 Robin Burchell <robin+git@viroteck.net> * Copyright (C) 2007 Dennis Friis <peavey@inspircd.org> * Copyright (C) 2006 Jamie ??? <???@???> * * 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 "inspircd.h" enum { // From ircd-ratbox. RPL_HELPSTART = 704, RPL_HELPTXT = 705, RPL_ENDOFHELP = 706, // InspIRCd-specific? RPL_DCCALLOWSTART = 990, RPL_DCCALLOWLIST = 991, RPL_DCCALLOWEND = 992, RPL_DCCALLOWTIMED = 993, RPL_DCCALLOWPERMANENT = 994, RPL_DCCALLOWREMOVED = 995, ERR_DCCALLOWINVALID = 996, RPL_DCCALLOWEXPIRED = 997, ERR_UNKNOWNDCCALLOWCMD = 998 }; static const char* const helptext[] = { "You may allow DCCs from specific users by specifying a", "DCC allow for the user you want to receive DCCs from.", "For example, to allow the user Brain to send you inspircd.exe", "you would type:", "/DCCALLOW +Brain", "Brain would then be able to send you files. They would have to", "resend the file again if the server gave them an error message", "before you added them to your DCCALLOW list.", "DCCALLOW entries will be temporary. If you want to add", "them to your DCCALLOW list until you leave IRC, type:", "/DCCALLOW +Brain 0", "To remove the user from your DCCALLOW list, type:", "/DCCALLOW -Brain", "To see the users in your DCCALLOW list, type:", "/DCCALLOW LIST", "NOTE: If the user leaves IRC or changes their nickname", " they will be removed from your DCCALLOW list.", " Your DCCALLOW list will be deleted when you leave IRC." }; class BannedFileList { public: std::string filemask; std::string action; }; class DCCAllow { public: std::string nickname; std::string hostmask; time_t set_on; unsigned long length; DCCAllow() { } DCCAllow(const std::string& nick, const std::string& hm, time_t so, unsigned long ln) : nickname(nick) , hostmask(hm) , set_on(so) , length(ln) { } }; typedef std::vector<User *> userlist; userlist ul; typedef std::vector<DCCAllow> dccallowlist; dccallowlist* dl; typedef std::vector<BannedFileList> bannedfilelist; bannedfilelist bfl; class DCCAllowExt : public SimpleExtItem<dccallowlist> { public: unsigned int maxentries; DCCAllowExt(Module* Creator) : SimpleExtItem<dccallowlist>("dccallow", ExtensionItem::EXT_USER, Creator) { } void FromInternal(Extensible* container, const std::string& value) CXX11_OVERRIDE { LocalUser* user = IS_LOCAL(static_cast<User*>(container)); if (!user) return; // Remove the old list and create a new one. unset(user); dccallowlist* list = new dccallowlist(); irc::spacesepstream ts(value); while (!ts.StreamEnd()) { // Check we have space for another entry. if (list->size() >= maxentries) { ServerInstance->Logs->Log(MODNAME, LOG_DEBUG, "Oversized DCC allow list received for %s: %s", user->uuid.c_str(), value.c_str()); delete list; return; } // Extract the fields. DCCAllow dccallow; if (!ts.GetToken(dccallow.nickname) || !ts.GetToken(dccallow.hostmask) || !ts.GetNumericToken(dccallow.set_on) || !ts.GetNumericToken(dccallow.length)) { ServerInstance->Logs->Log(MODNAME, LOG_DEBUG, "Malformed DCC allow list received for %s: %s", user->uuid.c_str(), value.c_str()); delete list; return; } // Store the DCC allow entry. list->push_back(dccallow); } } std::string ToInternal(const Extensible* container, void* item) const CXX11_OVERRIDE { dccallowlist* list = static_cast<dccallowlist*>(item); std::string buf; for (dccallowlist::const_iterator iter = list->begin(); iter != list->end(); ++iter) { if (iter != list->begin()) buf.push_back(' '); buf.append(iter->nickname); buf.push_back(' '); buf.append(iter->hostmask); buf.push_back(' '); buf.append(ConvToStr(iter->set_on)); buf.push_back(' '); buf.append(ConvToStr(iter->length)); } return buf; } }; class CommandDccallow : public Command { public: DCCAllowExt& ext; unsigned long defaultlength; CommandDccallow(Module* parent, DCCAllowExt& Ext) : Command(parent, "DCCALLOW", 0) , ext(Ext) { syntax = "[(+|-)<nick> [<time>]]|[LIST|HELP]"; /* XXX we need to fix this so it can work with translation stuff (i.e. move +- into a seperate param */ } CmdResult Handle(User* user, const Params& parameters) CXX11_OVERRIDE { /* syntax: DCCALLOW [(+|-)<nick> [<time>]]|[LIST|HELP] */ if (!parameters.size()) { // display current DCCALLOW list DisplayDCCAllowList(user); return CMD_FAILURE; } else if (parameters.size() > 0) { char action = *parameters[0].c_str(); // if they didn't specify an action, this is probably a command if (action != '+' && action != '-') { if (!strcasecmp(parameters[0].c_str(), "LIST")) { // list current DCCALLOW list DisplayDCCAllowList(user); return CMD_FAILURE; } else if (!strcasecmp(parameters[0].c_str(), "HELP")) { // display help DisplayHelp(user); return CMD_FAILURE; } else { user->WriteNumeric(ERR_UNKNOWNDCCALLOWCMD, "DCCALLOW command not understood. For help on DCCALLOW, type /DCCALLOW HELP"); return CMD_FAILURE; } } std::string nick(parameters[0], 1); User *target = ServerInstance->FindNickOnly(nick); if ((target) && (!target->quitting) && (target->registered == REG_ALL)) { if (action == '-') { // check if it contains any entries dl = ext.get(user); if (dl) { for (dccallowlist::iterator i = dl->begin(); i != dl->end(); ++i) { // search through list if (i->nickname == target->nick) { dl->erase(i); user->WriteNumeric(RPL_DCCALLOWREMOVED, user->nick, InspIRCd::Format("Removed %s from your DCCALLOW list", target->nick.c_str())); break; } } } } else if (action == '+') { if (target == user) { user->WriteNumeric(ERR_DCCALLOWINVALID, user->nick, "You cannot add yourself to your own DCCALLOW list!"); return CMD_FAILURE; } dl = ext.get(user); if (!dl) { dl = new dccallowlist; ext.set(user, dl); // add this user to the userlist ul.push_back(user); } if (dl->size() >= ext.maxentries) { user->WriteNumeric(ERR_DCCALLOWINVALID, user->nick, "Too many nicks on DCCALLOW list"); return CMD_FAILURE; } for (dccallowlist::const_iterator k = dl->begin(); k != dl->end(); ++k) { if (k->nickname == target->nick) { user->WriteNumeric(ERR_DCCALLOWINVALID, user->nick, InspIRCd::Format("%s is already on your DCCALLOW list", target->nick.c_str())); return CMD_FAILURE; } } std::string mask = target->nick+"!"+target->ident+"@"+target->GetDisplayedHost(); unsigned long length; if (parameters.size() < 2) { length = defaultlength; } else if (!InspIRCd::IsValidDuration(parameters[1])) { user->WriteNumeric(ERR_DCCALLOWINVALID, user->nick, InspIRCd::Format("%s is not a valid DCCALLOW duration", parameters[1].c_str())); return CMD_FAILURE; } else { if (!InspIRCd::Duration(parameters[1], length)) { user->WriteNotice("*** Invalid duration for DCC allow"); return CMD_FAILURE; } } if (!InspIRCd::IsValidMask(mask)) { return CMD_FAILURE; } dl->push_back(DCCAllow(target->nick, mask, ServerInstance->Time(), length)); if (length > 0) { user->WriteNumeric(RPL_DCCALLOWTIMED, user->nick, InspIRCd::Format("Added %s to DCCALLOW list for %s", target->nick.c_str(), InspIRCd::DurationString(length).c_str())); } else { user->WriteNumeric(RPL_DCCALLOWPERMANENT, user->nick, InspIRCd::Format("Added %s to DCCALLOW list for this session", target->nick.c_str())); } /* route it. */ return CMD_SUCCESS; } } else { // nick doesn't exist user->WriteNumeric(Numerics::NoSuchNick(nick)); return CMD_FAILURE; } } return CMD_FAILURE; } RouteDescriptor GetRouting(User* user, const Params& parameters) CXX11_OVERRIDE { return ROUTE_BROADCAST; } void DisplayHelp(User* user) { user->WriteNumeric(RPL_HELPSTART, "*", "DCCALLOW [(+|-)<nick> [<time>]]|[LIST|HELP]"); for (size_t i = 0; i < sizeof(helptext)/sizeof(helptext[0]); i++) user->WriteNumeric(RPL_HELPTXT, "*", helptext[i]); user->WriteNumeric(RPL_ENDOFHELP, "*", "End of DCCALLOW HELP"); LocalUser* localuser = IS_LOCAL(user); if (localuser) localuser->CommandFloodPenalty += 4000; } void DisplayDCCAllowList(User* user) { // display current DCCALLOW list user->WriteNumeric(RPL_DCCALLOWSTART, "Users on your DCCALLOW list:"); dl = ext.get(user); if (dl) { for (dccallowlist::const_iterator c = dl->begin(); c != dl->end(); ++c) { user->WriteNumeric(RPL_DCCALLOWLIST, user->nick, InspIRCd::Format("%s (%s)", c->nickname.c_str(), c->hostmask.c_str())); } } user->WriteNumeric(RPL_DCCALLOWEND, "End of DCCALLOW list"); } }; class ModuleDCCAllow : public Module { DCCAllowExt ext; CommandDccallow cmd; bool blockchat; std::string defaultaction; public: ModuleDCCAllow() : ext(this) , cmd(this, ext) , blockchat(false) { } void OnUserQuit(User* user, const std::string &reason, const std::string &oper_message) CXX11_OVERRIDE { dccallowlist* udl = ext.get(user); // remove their DCCALLOW list if they have one if (udl) stdalgo::erase(ul, user); // remove them from any DCCALLOW lists // they are currently on RemoveNick(user); } void OnUserPostNick(User* user, const std::string &oldnick) CXX11_OVERRIDE { RemoveNick(user); } ModResult OnUserPreMessage(User* user, const MessageTarget& target, MessageDetails& details) CXX11_OVERRIDE { if (!IS_LOCAL(user)) return MOD_RES_PASSTHRU; if (target.type == MessageTarget::TYPE_USER) { User* u = target.Get<User>(); /* Always allow a user to dcc themselves (although... why?) */ if (user == u) return MOD_RES_PASSTHRU; if ((details.text.length()) && (details.text[0] == '\1')) { Expire(); // :jamie!jamie@test-D4457903BA652E0F.silverdream.org PRIVMSG eimaj :DCC SEND m_dnsbl.cpp 3232235786 52650 9676 // :jamie!jamie@test-D4457903BA652E0F.silverdream.org PRIVMSG eimaj :VERSION if (strncmp(details.text.c_str(), "\1DCC ", 5) == 0) { dl = ext.get(u); if (dl && dl->size()) { for (dccallowlist::const_iterator iter = dl->begin(); iter != dl->end(); ++iter) if (InspIRCd::Match(user->GetFullHost(), iter->hostmask)) return MOD_RES_PASSTHRU; } std::string buf = details.text.substr(5); size_t s = buf.find(' '); if (s == std::string::npos) return MOD_RES_PASSTHRU; const std::string type = buf.substr(0, s); if (stdalgo::string::equalsci(type, "SEND")) { 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 filename = buf.substr(first, s); bool found = false; for (unsigned int i = 0; i < bfl.size(); i++) { if (InspIRCd::Match(filename, bfl[i].filemask, ascii_case_insensitive_map)) { /* We have a matching badfile entry, override whatever the default action is */ if (stdalgo::string::equalsci(bfl[i].action, "allow")) return MOD_RES_PASSTHRU; else { found = true; break; } } } /* only follow the default action if no badfile matches were found above */ if ((!found) && (defaultaction == "allow")) return MOD_RES_PASSTHRU; user->WriteNotice("The user " + u->nick + " is not accepting DCC SENDs from you. Your file " + filename + " was not sent."); u->WriteNotice(user->nick + " (" + user->ident + "@" + user->GetDisplayedHost() + ") attempted to send you a file named " + filename + ", which was blocked."); u->WriteNotice("If you trust " + user->nick + " and were expecting this, you can type /DCCALLOW HELP for information on the DCCALLOW system."); return MOD_RES_DENY; } else if ((blockchat) && (stdalgo::string::equalsci(type, "CHAT"))) { user->WriteNotice("The user " + u->nick + " is not accepting DCC CHAT requests from you."); u->WriteNotice(user->nick + " (" + user->ident + "@" + user->GetDisplayedHost() + ") attempted to initiate a DCC CHAT session, which was blocked."); u->WriteNotice("If you trust " + user->nick + " and were expecting this, you can type /DCCALLOW HELP for information on the DCCALLOW system."); return MOD_RES_DENY; } } } } return MOD_RES_PASSTHRU; } void Expire() { for (userlist::iterator iter = ul.begin(); iter != ul.end();) { User* u = (User*)(*iter); dl = ext.get(u); if (dl) { if (dl->size()) { dccallowlist::iterator iter2 = dl->begin(); while (iter2 != dl->end()) { time_t expires = iter2->set_on + iter2->length; if (iter2->length != 0 && expires <= ServerInstance->Time()) { u->WriteNumeric(RPL_DCCALLOWEXPIRED, u->nick, InspIRCd::Format("DCCALLOW entry for %s has expired", iter2->nickname.c_str())); iter2 = dl->erase(iter2); } else { ++iter2; } } } ++iter; } else { iter = ul.erase(iter); } } } void RemoveNick(User* user) { /* Iterate through all DCCALLOW lists and remove user */ for (userlist::iterator iter = ul.begin(); iter != ul.end();) { User *u = (User*)(*iter); dl = ext.get(u); if (dl) { if (dl->size()) { for (dccallowlist::iterator i = dl->begin(); i != dl->end(); ++i) { if (i->nickname == user->nick) { u->WriteNotice(i->nickname + " left the network or changed their nickname and has been removed from your DCCALLOW list"); u->WriteNumeric(RPL_DCCALLOWREMOVED, u->nick, InspIRCd::Format("Removed %s from your DCCALLOW list", i->nickname.c_str())); dl->erase(i); break; } } } ++iter; } else { iter = ul.erase(iter); } } } void RemoveFromUserlist(User *user) { // remove user from userlist for (userlist::iterator j = ul.begin(); j != ul.end(); ++j) { User* u = (User*)(*j); if (u == user) { ul.erase(j); break; } } } void ReadConfig(ConfigStatus& status) CXX11_OVERRIDE { bannedfilelist newbfl; ConfigTagList tags = ServerInstance->Config->ConfTags("banfile"); for (ConfigIter i = tags.first; i != tags.second; ++i) { BannedFileList bf; bf.filemask = i->second->getString("pattern"); bf.action = i->second->getString("action"); newbfl.push_back(bf); } bfl.swap(newbfl); ConfigTag* tag = ServerInstance->Config->ConfValue("dccallow"); cmd.ext.maxentries = tag->getUInt("maxentries", 20); cmd.defaultlength = tag->getDuration("length", 0); blockchat = tag->getBool("blockchat"); defaultaction = tag->getString("action"); } Version GetVersion() CXX11_OVERRIDE { return Version("Provides the DCCALLOW command", VF_COMMON | VF_VENDOR); } }; MODULE_INIT(ModuleDCCAllow) �����inspircd-3.4.0/src/modules/m_deaf.cpp���������������������������������������������������������������0000664�0000000�0000000�00000011527�13554550454�0017527�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * InspIRCd -- Internet Relay Chat Daemon * * Copyright (C) 2006, 2008 Craig Edwards <craigedwards@brainbox.cc> * Copyright (C) 2007 Robin Burchell <robin+git@viroteck.net> * Copyright (C) 2006-2007 Dennis Friis <peavey@inspircd.org> * Copyright (C) 2012 satmd <satmd@satmd.dyndns.org> * * This file is part of InspIRCd. InspIRCd is free software: you can * redistribute it and/or modify it under the terms of the GNU General Public * License as published by the Free Software Foundation, version 2. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include "inspircd.h" // User mode +d - filter out channel messages and channel notices class DeafMode : public ModeHandler { public: DeafMode(Module* Creator) : ModeHandler(Creator, "deaf", 'd', PARAM_NONE, MODETYPE_USER) { } ModeAction OnModeChange(User* source, User* dest, Channel* channel, std::string& parameter, bool adding) CXX11_OVERRIDE { if (adding == dest->IsModeSet(this)) return MODEACTION_DENY; if (adding) dest->WriteNotice("*** You have enabled user mode +d, deaf mode. This mode means you WILL NOT receive any messages from any channels you are in. If you did NOT mean to do this, use /mode " + dest->nick + " -d."); dest->SetMode(this, adding); return MODEACTION_ALLOW; } }; // User mode +D - filter out user messages and user notices class PrivDeafMode : public ModeHandler { public: PrivDeafMode(Module* Creator) : ModeHandler(Creator, "privdeaf", 'D', PARAM_NONE, MODETYPE_USER) { if (!ServerInstance->Config->ConfValue("deaf")->getBool("enableprivdeaf")) DisableAutoRegister(); } ModeAction OnModeChange(User* source, User* dest, Channel* channel, std::string& parameter, bool adding) CXX11_OVERRIDE { if (adding == dest->IsModeSet(this)) return MODEACTION_DENY; if (adding) dest->WriteNotice("*** You have enabled user mode +D, private deaf mode. This mode means you WILL NOT receive any messages and notices from any nicks. If you did NOT mean to do this, use /mode " + dest->nick + " -D."); dest->SetMode(this, adding); return MODEACTION_ALLOW; } }; class ModuleDeaf : public Module { DeafMode deafmode; PrivDeafMode privdeafmode; std::string deaf_bypasschars; std::string deaf_bypasschars_uline; bool privdeafuline; public: ModuleDeaf() : deafmode(this) , privdeafmode(this) { } void ReadConfig(ConfigStatus& status) CXX11_OVERRIDE { ConfigTag* tag = ServerInstance->Config->ConfValue("deaf"); deaf_bypasschars = tag->getString("bypasschars"); deaf_bypasschars_uline = tag->getString("bypasscharsuline"); privdeafuline = tag->getBool("privdeafuline", true); } ModResult OnUserPreMessage(User* user, const MessageTarget& target, MessageDetails& details) CXX11_OVERRIDE { switch (target.type) { case MessageTarget::TYPE_CHANNEL: { Channel* chan = target.Get<Channel>(); bool is_bypasschar = (deaf_bypasschars.find(details.text[0]) != std::string::npos); bool is_bypasschar_uline = (deaf_bypasschars_uline.find(details.text[0]) != std::string::npos); // If we have no bypasschars_uline in config, and this is a bypasschar (regular) // Then it is obviously going to get through +d, no exemption list required if (deaf_bypasschars_uline.empty() && is_bypasschar) return MOD_RES_PASSTHRU; // If it matches both bypasschar and bypasschar_uline, it will get through. if (is_bypasschar && is_bypasschar_uline) return MOD_RES_PASSTHRU; const Channel::MemberMap& ulist = chan->GetUsers(); for (Channel::MemberMap::const_iterator i = ulist.begin(); i != ulist.end(); ++i) { // not +d if (!i->first->IsModeSet(deafmode)) continue; bool is_a_uline = i->first->server->IsULine(); // matched a U-line only bypass if (is_bypasschar_uline && is_a_uline) continue; // matched a regular bypass if (is_bypasschar && !is_a_uline) continue; // don't deliver message! details.exemptions.insert(i->first); } break; } case MessageTarget::TYPE_USER: { User* targ = target.Get<User>(); if (!targ->IsModeSet(privdeafmode)) return MOD_RES_PASSTHRU; if (!privdeafuline && user->server->IsULine()) return MOD_RES_DENY; if (!user->HasPrivPermission("users/ignore-privdeaf")) return MOD_RES_DENY; break; } case MessageTarget::TYPE_SERVER: break; } return MOD_RES_PASSTHRU; } Version GetVersion() CXX11_OVERRIDE { return Version("Provides user modes +d and +D to block channel and user messages/notices", VF_VENDOR); } }; MODULE_INIT(ModuleDeaf) �������������������������������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/src/modules/m_delayjoin.cpp����������������������������������������������������������0000664�0000000�0000000�00000016440�13554550454�0020605�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * InspIRCd -- Internet Relay Chat Daemon * * Copyright (C) 2010 Jens Voss <DukePyrolator@anope.org> * Copyright (C) 2009 Daniel De Graaf <danieldg@inspircd.org> * Copyright (C) 2008 Robin Burchell <robin+git@viroteck.net> * Copyright (C) 2007-2008 Craig Edwards <craigedwards@brainbox.cc> * * This file is part of InspIRCd. InspIRCd is free software: you can * redistribute it and/or modify it under the terms of the GNU General Public * License as published by the Free Software Foundation, version 2. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include "inspircd.h" #include "modules/ctctags.h" #include "modules/names.h" class DelayJoinMode : public ModeHandler { private: LocalIntExt& unjoined; public: DelayJoinMode(Module* Parent, LocalIntExt& ext) : ModeHandler(Parent, "delayjoin", 'D', PARAM_NONE, MODETYPE_CHANNEL) , unjoined(ext) { ranktoset = ranktounset = OP_VALUE; } ModeAction OnModeChange(User* source, User* dest, Channel* channel, std::string& parameter, bool adding) CXX11_OVERRIDE; void RevealUser(User* user, Channel* chan); }; namespace { /** Hook handler for join client protocol events. * This allows us to block join protocol events completely, including all associated messages (e.g. MODE, away-notify AWAY). * This is not the same as OnUserJoin() because that runs only when a real join happens but this runs also when a module * such as hostcycle generates a join. */ class JoinHook : public ClientProtocol::EventHook { const LocalIntExt& unjoined; public: JoinHook(Module* mod, const LocalIntExt& unjoinedref) : ClientProtocol::EventHook(mod, "JOIN", 10) , unjoined(unjoinedref) { } ModResult OnPreEventSend(LocalUser* user, const ClientProtocol::Event& ev, ClientProtocol::MessageList& messagelist) CXX11_OVERRIDE { const ClientProtocol::Events::Join& join = static_cast<const ClientProtocol::Events::Join&>(ev); const Membership* const memb = join.GetMember(); const User* const u = memb->user; if ((unjoined.get(memb)) && (u != user)) return MOD_RES_DENY; return MOD_RES_PASSTHRU; } }; } class ModuleDelayJoin : public Module , public CTCTags::EventListener , public Names::EventListener { public: LocalIntExt unjoined; JoinHook joinhook; DelayJoinMode djm; ModuleDelayJoin() : CTCTags::EventListener(this) , Names::EventListener(this) , unjoined("delayjoin", ExtensionItem::EXT_MEMBERSHIP, this) , joinhook(this, unjoined) , djm(this, unjoined) { } Version GetVersion() CXX11_OVERRIDE; ModResult OnNamesListItem(LocalUser* issuer, Membership*, std::string& prefixes, std::string& nick) CXX11_OVERRIDE; void OnUserJoin(Membership*, bool, bool, CUList&) CXX11_OVERRIDE; void CleanUser(User* user); void OnUserPart(Membership*, std::string &partmessage, CUList&) CXX11_OVERRIDE; void OnUserKick(User* source, Membership*, const std::string &reason, CUList&) CXX11_OVERRIDE; void OnBuildNeighborList(User* source, IncludeChanList& include, std::map<User*, bool>& exception) CXX11_OVERRIDE; void OnUserMessage(User* user, const MessageTarget& target, const MessageDetails& details) CXX11_OVERRIDE; void OnUserTagMessage(User* user, const MessageTarget& target, const CTCTags::TagMessageDetails& details) CXX11_OVERRIDE; ModResult OnRawMode(User* user, Channel* channel, ModeHandler* mh, const std::string& param, bool adding) CXX11_OVERRIDE; }; ModeAction DelayJoinMode::OnModeChange(User* source, User* dest, Channel* channel, std::string &parameter, bool adding) { /* no change */ if (channel->IsModeSet(this) == adding) return MODEACTION_DENY; if (!adding) { /* * Make all users visible, as +D is being removed. If we don't do this, * they remain permanently invisible on this channel! */ const Channel::MemberMap& users = channel->GetUsers(); for (Channel::MemberMap::const_iterator n = users.begin(); n != users.end(); ++n) RevealUser(n->first, channel); } channel->SetMode(this, adding); return MODEACTION_ALLOW; } Version ModuleDelayJoin::GetVersion() { return Version("Provides channel mode +D, delay-join, users don't appear as joined to others until they speak", VF_VENDOR); } ModResult ModuleDelayJoin::OnNamesListItem(LocalUser* issuer, Membership* memb, std::string& prefixes, std::string& nick) { /* don't prevent the user from seeing themself */ if (issuer == memb->user) return MOD_RES_PASSTHRU; /* If the user is hidden by delayed join, hide them from the NAMES list */ if (unjoined.get(memb)) return MOD_RES_DENY; return MOD_RES_PASSTHRU; } static void populate(CUList& except, Membership* memb) { const Channel::MemberMap& users = memb->chan->GetUsers(); for (Channel::MemberMap::const_iterator i = users.begin(); i != users.end(); ++i) { if (i->first == memb->user || !IS_LOCAL(i->first)) continue; except.insert(i->first); } } void ModuleDelayJoin::OnUserJoin(Membership* memb, bool sync, bool created, CUList& except) { if (memb->chan->IsModeSet(djm)) unjoined.set(memb, 1); } void ModuleDelayJoin::OnUserPart(Membership* memb, std::string &partmessage, CUList& except) { if (unjoined.set(memb, 0)) populate(except, memb); } void ModuleDelayJoin::OnUserKick(User* source, Membership* memb, const std::string &reason, CUList& except) { if (unjoined.set(memb, 0)) populate(except, memb); } void ModuleDelayJoin::OnBuildNeighborList(User* source, IncludeChanList& include, std::map<User*, bool>& exception) { for (IncludeChanList::iterator i = include.begin(); i != include.end(); ) { Membership* memb = *i; if (unjoined.get(memb)) i = include.erase(i); else ++i; } } void ModuleDelayJoin::OnUserTagMessage(User* user, const MessageTarget& target, const CTCTags::TagMessageDetails& details) { if (target.type != MessageTarget::TYPE_CHANNEL) return; Channel* channel = target.Get<Channel>(); djm.RevealUser(user, channel); } void ModuleDelayJoin::OnUserMessage(User* user, const MessageTarget& target, const MessageDetails& details) { if (target.type != MessageTarget::TYPE_CHANNEL) return; Channel* channel = target.Get<Channel>(); djm.RevealUser(user, channel); } void DelayJoinMode::RevealUser(User* user, Channel* chan) { Membership* memb = chan->GetUser(user); if (!memb || !unjoined.set(memb, 0)) return; /* Display the join to everyone else (the user who joined got it earlier) */ CUList except_list; except_list.insert(user); ClientProtocol::Events::Join joinevent(memb); chan->Write(joinevent, 0, except_list); } /* make the user visible if they receive any mode change */ ModResult ModuleDelayJoin::OnRawMode(User* user, Channel* channel, ModeHandler* mh, const std::string& param, bool adding) { if (!channel || param.empty()) return MOD_RES_PASSTHRU; // If not a prefix mode then we got nothing to do here if (!mh->IsPrefixMode()) return MOD_RES_PASSTHRU; User* dest; if (IS_LOCAL(user)) dest = ServerInstance->FindNickOnly(param); else dest = ServerInstance->FindNick(param); if (!dest) return MOD_RES_PASSTHRU; djm.RevealUser(dest, channel); return MOD_RES_PASSTHRU; } MODULE_INIT(ModuleDelayJoin) ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/src/modules/m_delaymsg.cpp�����������������������������������������������������������0000664�0000000�0000000�00000010771�13554550454�0020435�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * InspIRCd -- Internet Relay Chat Daemon * * Copyright (C) 2009 Daniel De Graaf <danieldg@inspircd.org> * * This file is part of InspIRCd. InspIRCd is free software: you can * redistribute it and/or modify it under the terms of the GNU General Public * License as published by the Free Software Foundation, version 2. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include "inspircd.h" #include "modules/ctctags.h" class DelayMsgMode : public ParamMode<DelayMsgMode, LocalIntExt> { public: LocalIntExt jointime; DelayMsgMode(Module* Parent) : ParamMode<DelayMsgMode, LocalIntExt>(Parent, "delaymsg", 'd') , jointime("delaymsg", ExtensionItem::EXT_MEMBERSHIP, Parent) { ranktoset = ranktounset = OP_VALUE; syntax = "<seconds>"; } bool ResolveModeConflict(std::string& their_param, const std::string& our_param, Channel*) CXX11_OVERRIDE { return ConvToNum<intptr_t>(their_param) < ConvToNum<intptr_t>(our_param); } ModeAction OnSet(User* source, Channel* chan, std::string& parameter) CXX11_OVERRIDE; void OnUnset(User* source, Channel* chan) CXX11_OVERRIDE; void SerializeParam(Channel* chan, intptr_t n, std::string& out) { out += ConvToStr(n); } }; class ModuleDelayMsg : public Module , public CTCTags::EventListener { private: DelayMsgMode djm; bool allownotice; ModResult HandleMessage(User* user, const MessageTarget& target, bool notice); public: ModuleDelayMsg() : CTCTags::EventListener(this) , djm(this) { } Version GetVersion() CXX11_OVERRIDE; void OnUserJoin(Membership* memb, bool sync, bool created, CUList&) CXX11_OVERRIDE; ModResult OnUserPreMessage(User* user, const MessageTarget& target, MessageDetails& details) CXX11_OVERRIDE; ModResult OnUserPreTagMessage(User* user, const MessageTarget& target, CTCTags::TagMessageDetails& details) CXX11_OVERRIDE; void ReadConfig(ConfigStatus& status) CXX11_OVERRIDE; }; ModeAction DelayMsgMode::OnSet(User* source, Channel* chan, std::string& parameter) { // Setting a new limit, sanity check intptr_t limit = ConvToNum<intptr_t>(parameter); if (limit <= 0) limit = 1; ext.set(chan, limit); return MODEACTION_ALLOW; } void DelayMsgMode::OnUnset(User* source, Channel* chan) { /* * Clean up metadata */ const Channel::MemberMap& users = chan->GetUsers(); for (Channel::MemberMap::const_iterator n = users.begin(); n != users.end(); ++n) jointime.set(n->second, 0); } Version ModuleDelayMsg::GetVersion() { return Version("Provides channel mode +d <int>, to deny messages to a channel until <int> seconds have passed", VF_VENDOR); } void ModuleDelayMsg::OnUserJoin(Membership* memb, bool sync, bool created, CUList&) { if ((IS_LOCAL(memb->user)) && (memb->chan->IsModeSet(djm))) { djm.jointime.set(memb, ServerInstance->Time()); } } ModResult ModuleDelayMsg::OnUserPreMessage(User* user, const MessageTarget& target, MessageDetails& details) { return HandleMessage(user, target, details.type == MSG_NOTICE); } ModResult ModuleDelayMsg::OnUserPreTagMessage(User* user, const MessageTarget& target, CTCTags::TagMessageDetails& details) { return HandleMessage(user, target, false); } ModResult ModuleDelayMsg::HandleMessage(User* user, const MessageTarget& target, bool notice) { if (!IS_LOCAL(user)) return MOD_RES_PASSTHRU; if ((target.type != MessageTarget::TYPE_CHANNEL) || ((!allownotice) && (notice))) return MOD_RES_PASSTHRU; Channel* channel = target.Get<Channel>(); Membership* memb = channel->GetUser(user); if (!memb) return MOD_RES_PASSTHRU; time_t ts = djm.jointime.get(memb); if (ts == 0) return MOD_RES_PASSTHRU; int len = djm.ext.get(channel); if ((ts + len) > ServerInstance->Time()) { if (channel->GetPrefixValue(user) < VOICE_VALUE) { user->WriteNumeric(ERR_CANNOTSENDTOCHAN, channel->name, InspIRCd::Format("You must wait %d seconds after joining to send to the channel (+d is set)", len)); return MOD_RES_DENY; } } else { /* Timer has expired, we can stop checking now */ djm.jointime.set(memb, 0); } return MOD_RES_PASSTHRU; } void ModuleDelayMsg::ReadConfig(ConfigStatus& status) { ConfigTag* tag = ServerInstance->Config->ConfValue("delaymsg"); allownotice = tag->getBool("allownotice", true); } MODULE_INIT(ModuleDelayMsg) �������inspircd-3.4.0/src/modules/m_denychans.cpp����������������������������������������������������������0000664�0000000�0000000�00000014454�13554550454�0020606�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * InspIRCd -- Internet Relay Chat Daemon * *. Copyright (C) 2018 Peter Powell <petpow@saberuk.com> * Copyright (C) 2009 Daniel De Graaf <danieldg@inspircd.org> * Copyright (C) 2007-2008 Robin Burchell <robin+git@viroteck.net> * Copyright (C) 2007 Dennis Friis <peavey@inspircd.org> * Copyright (C) 2005 Craig Edwards <craigedwards@brainbox.cc> * * This file is part of InspIRCd. InspIRCd is free software: you can * redistribute it and/or modify it under the terms of the GNU General Public * License as published by the Free Software Foundation, version 2. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include "inspircd.h" enum { // InspIRCd-specific. ERR_BADCHANNEL = 926 }; struct BadChannel { bool allowopers; std::string name; std::string reason; std::string redirect; BadChannel(const std::string& Name, const std::string& Redirect, const std::string& Reason, bool AllowOpers) : allowopers(AllowOpers) , name(Name) , reason(Reason) , redirect(Redirect) { } }; typedef std::vector<BadChannel> BadChannels; typedef std::vector<std::string> GoodChannels; class ModuleDenyChannels : public Module { private: BadChannels badchannels; GoodChannels goodchannels; UserModeReference antiredirectmode; ChanModeReference redirectmode; public: ModuleDenyChannels() : antiredirectmode(this, "antiredirect") , redirectmode(this, "redirect") { } void ReadConfig(ConfigStatus& status) CXX11_OVERRIDE { GoodChannels goodchans; ConfigTagList tags = ServerInstance->Config->ConfTags("goodchan"); for (ConfigIter iter = tags.first; iter != tags.second; ++iter) { ConfigTag* tag = iter->second; // Ensure that we have the <goodchan:name> parameter. const std::string name = tag->getString("name"); if (name.empty()) throw ModuleException("<goodchan:name> is a mandatory field, at " + tag->getTagLocation()); goodchans.push_back(name); } BadChannels badchans; tags = ServerInstance->Config->ConfTags("badchan"); for (ConfigIter i = tags.first; i != tags.second; ++i) { ConfigTag* tag = i->second; // Ensure that we have the <badchan:name> parameter. const std::string name = tag->getString("name"); if (name.empty()) throw ModuleException("<badchan:name> is a mandatory field, at " + tag->getTagLocation()); // Ensure that we have the <badchan:reason> parameter. const std::string reason = tag->getString("reason"); if (reason.empty()) throw ModuleException("<badchan:reason> is a mandatory field, at " + tag->getTagLocation()); const std::string redirect = tag->getString("redirect"); if (!redirect.empty()) { // Ensure that <badchan:redirect> contains a channel name. if (!ServerInstance->IsChannel(redirect)) throw ModuleException("<badchan:redirect> is not a valid channel name, at " + tag->getTagLocation()); // We defer the rest of the validation of the redirect channel until we have // finished parsing all of the badchans. } badchans.push_back(BadChannel(name, redirect, reason, tag->getBool("allowopers"))); } // Now we have all of the badchan information recorded we can check that all redirect // channels can actually be redirected to. for (BadChannels::const_iterator i = badchans.begin(); i != badchans.end(); ++i) { const BadChannel& badchan = *i; // If there is no redirect channel we have nothing to do. if (badchan.redirect.empty()) continue; // If the redirect channel is whitelisted then it is okay. bool whitelisted = false; for (GoodChannels::const_iterator j = goodchans.begin(); j != goodchans.end(); ++j) { if (InspIRCd::Match(badchan.redirect, *j)) { whitelisted = true; break; } } if (whitelisted) continue; // If the redirect channel is not blacklisted then it is okay. for (BadChannels::const_iterator j = badchans.begin(); j != badchans.end(); ++j) if (InspIRCd::Match(badchan.redirect, j->name)) throw ModuleException("<badchan:redirect> cannot be a blacklisted channel name"); } // The config file contained no errors so we can apply the new configuration. badchannels.swap(badchans); goodchannels.swap(goodchans); } Version GetVersion() CXX11_OVERRIDE { return Version("Implements config tags which allow blocking of joins to channels", VF_VENDOR); } ModResult OnUserPreJoin(LocalUser* user, Channel* chan, const std::string& cname, std::string& privs, const std::string& keygiven) CXX11_OVERRIDE { for (BadChannels::const_iterator j = badchannels.begin(); j != badchannels.end(); ++j) { const BadChannel& badchan = *j; // If the channel does not match the current entry we have nothing else to do. if (!InspIRCd::Match(cname, badchan.name)) continue; // If the user is an oper and opers are allowed to enter this blacklisted channel // then allow the join. if (user->IsOper() && badchan.allowopers) return MOD_RES_PASSTHRU; // If the channel matches a whitelist then allow the join. for (GoodChannels::const_iterator i = goodchannels.begin(); i != goodchannels.end(); ++i) if (InspIRCd::Match(cname, *i)) return MOD_RES_PASSTHRU; // If there is no redirect chan, the user has enabled the antiredirect mode, or // the target channel redirects elsewhere we just tell the user and deny the join. Channel* target = NULL; if (badchan.redirect.empty() || user->IsModeSet(antiredirectmode) || ((target = ServerInstance->FindChan(badchan.redirect)) && target->IsModeSet(redirectmode))) { user->WriteNumeric(ERR_BADCHANNEL, cname, InspIRCd::Format("Channel %s is forbidden: %s", cname.c_str(), badchan.reason.c_str())); return MOD_RES_DENY; } // Redirect the user to the target channel. user->WriteNumeric(ERR_BADCHANNEL, cname, InspIRCd::Format("Channel %s is forbidden, redirecting to %s: %s", cname.c_str(), badchan.redirect.c_str(), badchan.reason.c_str())); Channel::JoinUser(user, badchan.redirect); return MOD_RES_DENY; } return MOD_RES_PASSTHRU; } }; MODULE_INIT(ModuleDenyChannels) ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/src/modules/m_disable.cpp������������������������������������������������������������0000664�0000000�0000000�00000015406�13554550454�0020233�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * InspIRCd -- Internet Relay Chat Daemon * * Copyright (C) 2019 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 "inspircd.h" enum { // From ircu. ERR_DISABLED = 517 }; // Holds a list of disabled commands. typedef std::vector<std::string> CommandList; // Holds whether modes are disabled or not. typedef std::bitset<64> ModeStatus; class ModuleDisable : public Module { private: CommandList commands; ModeStatus chanmodes; bool fakenonexistent; bool notifyopers; ModeStatus usermodes; void ReadModes(ConfigTag* tag, const std::string& field, ModeType type, ModeStatus& status) { const std::string modes = tag->getString(field); for (std::string::const_iterator iter = modes.begin(); iter != modes.end(); ++iter) { const char& chr = *iter; // Check that the character is a valid mode letter. if (!ModeParser::IsModeChar(chr)) throw ModuleException(InspIRCd::Format("Invalid mode '%c' was specified in <disabled:%s> at %s", chr, field.c_str(), tag->getTagLocation().c_str())); // Check that the mode actually exists. ModeHandler* mh = ServerInstance->Modes->FindMode(chr, type); if (!chr) throw ModuleException(InspIRCd::Format("Nonexistent mode '%c' was specified in <disabled:%s> at %s", chr, field.c_str(), tag->getTagLocation().c_str())); // Disable the mode. ServerInstance->Logs->Log(MODNAME, LOG_DEBUG, "The %c (%s) %s mode has been disabled", mh->GetModeChar(), mh->name.c_str(), type == MODETYPE_CHANNEL ? "channel" : "user"); status.set(chr - 'A'); } } void WriteLog(const char* message, ...) CUSTOM_PRINTF(2, 3) { std::string buffer; VAFORMAT(buffer, message, message); if (notifyopers) ServerInstance->SNO->WriteToSnoMask('a', buffer); else ServerInstance->Logs->Log(MODNAME, LOG_DEFAULT, buffer); } public: void ReadConfig(ConfigStatus& status) CXX11_OVERRIDE { ConfigTag* tag = ServerInstance->Config->ConfValue("disabled"); // Parse the disabled commands. CommandList newcommands; irc::spacesepstream commandlist(tag->getString("commands")); for (std::string command; commandlist.GetToken(command); ) { // Check that the command actually exists. Command* handler = ServerInstance->Parser.GetHandler(command); if (!handler) throw ModuleException(InspIRCd::Format("Nonexistent command '%s' was specified in <disabled:commands> at %s", command.c_str(), tag->getTagLocation().c_str())); // Prevent admins from disabling COMMANDS and MODULES for transparency reasons. if (handler->name == "COMMANDS" || handler->name == "MODULES") continue; // Disable the command. ServerInstance->Logs->Log(MODNAME, LOG_DEBUG, "The %s command has been disabled", handler->name.c_str()); newcommands.push_back(handler->name); } // Parse the disabled channel modes. ModeStatus newchanmodes; ReadModes(tag, "chanmodes", MODETYPE_CHANNEL, newchanmodes); // Parse the disabled user modes. ModeStatus newusermodes; ReadModes(tag, "usermodes", MODETYPE_USER, newusermodes); // The server config was valid so we can use these now. chanmodes = newchanmodes; usermodes = newusermodes; commands.swap(newcommands); // Whether we should fake the non-existence of disabled things. fakenonexistent = tag->getBool("fakenonexistent", tag->getBool("fakenonexistant")); // Whether to notify server operators via snomask `a` about the attempted use of disabled commands/modes. notifyopers = tag->getBool("notifyopers"); } ModResult OnPreCommand(std::string& command, CommandBase::Params& parameters, LocalUser* user, bool validated) CXX11_OVERRIDE { // If a command is unvalidated or the source is not registered we do nothing. if (!validated || user->registered != REG_ALL) return MOD_RES_PASSTHRU; // If the command is not disabled or the user has the servers/use-disabled-commands priv we do nothing. if (!stdalgo::isin(commands, command) || user->HasPrivPermission("servers/use-disabled-commands")) return MOD_RES_PASSTHRU; // The user has tried to execute a disabled command! user->CommandFloodPenalty += 2000; WriteLog("%s was blocked from executing the disabled %s command", user->GetFullRealHost().c_str(), command.c_str()); if (fakenonexistent) { // The server administrator has specified that disabled commands should be // treated as if they do not exist. user->WriteNumeric(ERR_UNKNOWNCOMMAND, command, "Unknown command"); ServerInstance->stats.Unknown++; return MOD_RES_DENY; } // Inform the user that the command they executed has been disabled. user->WriteNumeric(ERR_DISABLED, command, "Command disabled"); return MOD_RES_DENY; } ModResult OnRawMode(User* user, Channel* chan, ModeHandler* mh, const std::string& param, bool adding) CXX11_OVERRIDE { // If a mode change is remote or the source is not registered we do nothing. if (!IS_LOCAL(user) || user->registered != REG_ALL) return MOD_RES_PASSTHRU; // If the mode is not disabled or the user has the servers/use-disabled-modes priv we do nothing. const std::bitset<64>& disabled = (mh->GetModeType() == MODETYPE_CHANNEL) ? chanmodes : usermodes; if (!disabled.test(mh->GetModeChar() - 'A') || user->HasPrivPermission("servers/use-disabled-modes")) return MOD_RES_PASSTHRU; // The user has tried to change a disabled mode! const char* what = mh->GetModeType() == MODETYPE_CHANNEL ? "channel" : "user"; WriteLog("%s was blocked from executing the disabled %s mode %c (%s)", user->GetFullRealHost().c_str(), what, mh->GetModeChar(), mh->name.c_str()); if (fakenonexistent) { // The server administrator has specified that disabled modes should be // treated as if they do not exist. user->WriteNumeric(mh->GetModeType() == MODETYPE_CHANNEL ? ERR_UNKNOWNMODE : ERR_UNKNOWNSNOMASK, mh->GetModeChar(), "is an unknown mode character"); return MOD_RES_DENY; } // Inform the user that the mode they changed has been disabled. user->WriteNumeric(ERR_NOPRIVILEGES, InspIRCd::Format("Permission Denied - %s mode %c (%s) is disabled", what, mh->GetModeChar(), mh->name.c_str())); return MOD_RES_DENY; } Version GetVersion() CXX11_OVERRIDE { return Version("Provides support for disabling commands and modes", VF_VENDOR); } }; MODULE_INIT(ModuleDisable) ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/src/modules/m_dnsbl.cpp��������������������������������������������������������������0000664�0000000�0000000�00000033621�13554550454�0017731�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * InspIRCd -- Internet Relay Chat Daemon * * Copyright (C) 2009-2010 Daniel De Graaf <danieldg@inspircd.org> * Copyright (C) 2006-2008 Robin Burchell <robin+git@viroteck.net> * Copyright (C) 2007 Craig Edwards <craigedwards@brainbox.cc> * Copyright (C) 2006-2007 Dennis Friis <peavey@inspircd.org> * Copyright (C) 2007 John Brooks <john.brooks@dereferenced.net> * * 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 "inspircd.h" #include "xline.h" #include "modules/dns.h" #include "modules/stats.h" /* Class holding data for a single entry */ class DNSBLConfEntry : public refcountbase { public: enum EnumBanaction { I_UNKNOWN, I_KILL, I_ZLINE, I_KLINE, I_GLINE, I_MARK }; enum EnumType { A_RECORD, A_BITMASK }; std::string name, ident, host, domain, reason; EnumBanaction banaction; EnumType type; unsigned long duration; unsigned int bitmask; unsigned char records[256]; unsigned long stats_hits, stats_misses; DNSBLConfEntry(): type(A_BITMASK),duration(86400),bitmask(0),stats_hits(0), stats_misses(0) {} }; /** Resolver for CGI:IRC hostnames encoded in ident/real name */ class DNSBLResolver : public DNS::Request { private: irc::sockets::sockaddrs theirsa; std::string theiruid; LocalStringExt& nameExt; LocalIntExt& countExt; reference<DNSBLConfEntry> ConfEntry; public: DNSBLResolver(DNS::Manager *mgr, Module *me, LocalStringExt& match, LocalIntExt& ctr, const std::string &hostname, LocalUser* u, reference<DNSBLConfEntry> conf) : DNS::Request(mgr, me, hostname, DNS::QUERY_A, true) , theirsa(u->client_sa) , theiruid(u->uuid) , nameExt(match) , countExt(ctr) , ConfEntry(conf) { } /* Note: This may be called multiple times for multiple A record results */ void OnLookupComplete(const DNS::Query *r) CXX11_OVERRIDE { /* Check the user still exists */ LocalUser* them = IS_LOCAL(ServerInstance->FindUUID(theiruid)); if (!them || them->client_sa != theirsa) return; const DNS::ResourceRecord* const ans_record = r->FindAnswerOfType(DNS::QUERY_A); if (!ans_record) return; // All replies should be in 127.0.0.0/8 if (ans_record->rdata.compare(0, 4, "127.") != 0) { ServerInstance->SNO->WriteGlobalSno('d', "DNSBL: %s returned address outside of acceptable subnet 127.0.0.0/8: %s", ConfEntry->domain.c_str(), ans_record->rdata.c_str()); ConfEntry->stats_misses++; return; } int i = countExt.get(them); if (i) countExt.set(them, i - 1); // Now we calculate the bitmask: 256*(256*(256*a+b)+c)+d unsigned int bitmask = 0, record = 0; bool match = false; in_addr resultip; inet_pton(AF_INET, ans_record->rdata.c_str(), &resultip); switch (ConfEntry->type) { case DNSBLConfEntry::A_BITMASK: bitmask = resultip.s_addr >> 24; /* Last octet (network byte order) */ bitmask &= ConfEntry->bitmask; match = (bitmask != 0); break; case DNSBLConfEntry::A_RECORD: record = resultip.s_addr >> 24; /* Last octet */ match = (ConfEntry->records[record] == 1); break; } if (match) { std::string reason = ConfEntry->reason; std::string::size_type x = reason.find("%ip%"); while (x != std::string::npos) { reason.erase(x, 4); reason.insert(x, them->GetIPString()); x = reason.find("%ip%"); } ConfEntry->stats_hits++; switch (ConfEntry->banaction) { case DNSBLConfEntry::I_KILL: { ServerInstance->Users->QuitUser(them, "Killed (" + reason + ")"); break; } case DNSBLConfEntry::I_MARK: { if (!ConfEntry->ident.empty()) { them->WriteNotice("Your ident has been set to " + ConfEntry->ident + " because you matched " + reason); them->ChangeIdent(ConfEntry->ident); } if (!ConfEntry->host.empty()) { them->WriteNotice("Your host has been set to " + ConfEntry->host + " because you matched " + reason); them->ChangeDisplayedHost(ConfEntry->host); } nameExt.set(them, ConfEntry->name); break; } case DNSBLConfEntry::I_KLINE: { KLine* kl = new KLine(ServerInstance->Time(), ConfEntry->duration, ServerInstance->Config->ServerName.c_str(), reason.c_str(), "*", them->GetIPString()); if (ServerInstance->XLines->AddLine(kl,NULL)) { ServerInstance->SNO->WriteGlobalSno('x', "K-line added due to DNSBL match on *@%s to expire in %s (on %s): %s", them->GetIPString().c_str(), InspIRCd::DurationString(kl->duration).c_str(), InspIRCd::TimeString(kl->expiry).c_str(), reason.c_str()); ServerInstance->XLines->ApplyLines(); } else { delete kl; return; } break; } case DNSBLConfEntry::I_GLINE: { GLine* gl = new GLine(ServerInstance->Time(), ConfEntry->duration, ServerInstance->Config->ServerName.c_str(), reason.c_str(), "*", them->GetIPString()); if (ServerInstance->XLines->AddLine(gl,NULL)) { ServerInstance->SNO->WriteGlobalSno('x', "G-line added due to DNSBL match on *@%s to expire in %s (on %s): %s", them->GetIPString().c_str(), InspIRCd::DurationString(gl->duration).c_str(), InspIRCd::TimeString(gl->expiry).c_str(), reason.c_str()); ServerInstance->XLines->ApplyLines(); } else { delete gl; return; } break; } case DNSBLConfEntry::I_ZLINE: { ZLine* zl = new ZLine(ServerInstance->Time(), ConfEntry->duration, ServerInstance->Config->ServerName.c_str(), reason.c_str(), them->GetIPString()); if (ServerInstance->XLines->AddLine(zl,NULL)) { ServerInstance->SNO->WriteGlobalSno('x', "Z-line added due to DNSBL match on %s to expire in %s (on %s): %s", them->GetIPString().c_str(), InspIRCd::DurationString(zl->duration).c_str(), InspIRCd::TimeString(zl->expiry).c_str(), reason.c_str()); ServerInstance->XLines->ApplyLines(); } else { delete zl; return; } break; } case DNSBLConfEntry::I_UNKNOWN: default: break; } ServerInstance->SNO->WriteGlobalSno('d', "Connecting user %s (%s) detected as being on the '%s' DNS blacklist with result %d", them->GetFullRealHost().c_str(), them->GetIPString().c_str(), ConfEntry->name.c_str(), (ConfEntry->type==DNSBLConfEntry::A_BITMASK) ? bitmask : record); } else ConfEntry->stats_misses++; } void OnError(const DNS::Query *q) CXX11_OVERRIDE { LocalUser* them = IS_LOCAL(ServerInstance->FindUUID(theiruid)); if (!them || them->client_sa != theirsa) return; int i = countExt.get(them); if (i) countExt.set(them, i - 1); if (q->error == DNS::ERROR_NO_RECORDS || q->error == DNS::ERROR_DOMAIN_NOT_FOUND) { ConfEntry->stats_misses++; return; } ServerInstance->SNO->WriteGlobalSno('d', "An error occurred whilst checking whether %s (%s) is on the '%s' DNS blacklist: %s", them->GetFullRealHost().c_str(), them->GetIPString().c_str(), ConfEntry->name.c_str(), this->manager->GetErrorStr(q->error).c_str()); } }; typedef std::vector<reference<DNSBLConfEntry> > DNSBLConfList; class ModuleDNSBL : public Module, public Stats::EventListener { DNSBLConfList DNSBLConfEntries; dynamic_reference<DNS::Manager> DNS; LocalStringExt nameExt; LocalIntExt countExt; /* * Convert a string to EnumBanaction */ DNSBLConfEntry::EnumBanaction str2banaction(const std::string &action) { if(action.compare("KILL")==0) return DNSBLConfEntry::I_KILL; if(action.compare("KLINE")==0) return DNSBLConfEntry::I_KLINE; if(action.compare("ZLINE")==0) return DNSBLConfEntry::I_ZLINE; if(action.compare("GLINE")==0) return DNSBLConfEntry::I_GLINE; if(action.compare("MARK")==0) return DNSBLConfEntry::I_MARK; return DNSBLConfEntry::I_UNKNOWN; } public: ModuleDNSBL() : Stats::EventListener(this) , DNS(this, "DNS") , nameExt("dnsbl_match", ExtensionItem::EXT_USER, this) , countExt("dnsbl_pending", ExtensionItem::EXT_USER, this) { } void init() CXX11_OVERRIDE { ServerInstance->SNO->EnableSnomask('d', "DNSBL"); } Version GetVersion() CXX11_OVERRIDE { return Version("Provides handling of DNS blacklists", VF_VENDOR); } /** Fill our conf vector with data */ void ReadConfig(ConfigStatus& status) CXX11_OVERRIDE { DNSBLConfList newentries; ConfigTagList dnsbls = ServerInstance->Config->ConfTags("dnsbl"); for(ConfigIter i = dnsbls.first; i != dnsbls.second; ++i) { ConfigTag* tag = i->second; reference<DNSBLConfEntry> e = new DNSBLConfEntry(); e->name = tag->getString("name"); e->ident = tag->getString("ident"); e->host = tag->getString("host"); e->reason = tag->getString("reason"); e->domain = tag->getString("domain"); if (stdalgo::string::equalsci(tag->getString("type"), "bitmask")) { e->type = DNSBLConfEntry::A_BITMASK; e->bitmask = tag->getUInt("bitmask", 0, 0, UINT_MAX); } else { memset(e->records, 0, sizeof(e->records)); e->type = DNSBLConfEntry::A_RECORD; irc::portparser portrange(tag->getString("records"), false); long item = -1; while ((item = portrange.GetToken())) e->records[item] = 1; } e->banaction = str2banaction(tag->getString("action")); e->duration = tag->getDuration("duration", 60, 1); /* Use portparser for record replies */ /* yeah, logic here is a little messy */ if ((e->bitmask <= 0) && (DNSBLConfEntry::A_BITMASK == e->type)) { throw ModuleException("Invalid <dnsbl:bitmask> at " + tag->getTagLocation()); } else if (e->name.empty()) { throw ModuleException("Empty <dnsbl:name> at " + tag->getTagLocation()); } else if (e->domain.empty()) { throw ModuleException("Empty <dnsbl:domain> at " + tag->getTagLocation()); } else if (e->banaction == DNSBLConfEntry::I_UNKNOWN) { throw ModuleException("Unknown <dnsbl:action> at " + tag->getTagLocation()); } else { if (e->reason.empty()) { std::string location = tag->getTagLocation(); ServerInstance->SNO->WriteGlobalSno('d', "DNSBL(%s): empty reason, using defaults", location.c_str()); e->reason = "Your IP has been blacklisted."; } /* add it, all is ok */ newentries.push_back(e); } } DNSBLConfEntries.swap(newentries); } void OnSetUserIP(LocalUser* user) CXX11_OVERRIDE { if ((user->exempt) || !DNS) return; // Clients can't be in a DNSBL if they aren't connected via IPv4 or IPv6. if (user->client_sa.family() != AF_INET && user->client_sa.family() != AF_INET6) return; if (user->MyClass) { if (!user->MyClass->config->getBool("usednsbl", true)) return; } else ServerInstance->Logs->Log(MODNAME, LOG_DEBUG, "User has no connect class in OnSetUserIP"); std::string reversedip; if (user->client_sa.family() == AF_INET) { unsigned int a, b, c, d; d = (unsigned int) (user->client_sa.in4.sin_addr.s_addr >> 24) & 0xFF; c = (unsigned int) (user->client_sa.in4.sin_addr.s_addr >> 16) & 0xFF; b = (unsigned int) (user->client_sa.in4.sin_addr.s_addr >> 8) & 0xFF; a = (unsigned int) user->client_sa.in4.sin_addr.s_addr & 0xFF; reversedip = ConvToStr(d) + "." + ConvToStr(c) + "." + ConvToStr(b) + "." + ConvToStr(a); } else if (user->client_sa.family() == AF_INET6) { const unsigned char* ip = user->client_sa.in6.sin6_addr.s6_addr; std::string buf = BinToHex(ip, 16); for (std::string::const_reverse_iterator it = buf.rbegin(); it != buf.rend(); ++it) { reversedip.push_back(*it); reversedip.push_back('.'); } reversedip.erase(reversedip.length() - 1, 1); } else return; ServerInstance->Logs->Log(MODNAME, LOG_DEBUG, "Reversed IP %s -> %s", user->GetIPString().c_str(), reversedip.c_str()); countExt.set(user, DNSBLConfEntries.size()); // For each DNSBL, we will run through this lookup for (unsigned i = 0; i < DNSBLConfEntries.size(); ++i) { // Fill hostname with a dnsbl style host (d.c.b.a.domain.tld) std::string hostname = reversedip + "." + DNSBLConfEntries[i]->domain; /* now we'd need to fire off lookups for `hostname'. */ DNSBLResolver *r = new DNSBLResolver(*this->DNS, this, nameExt, countExt, hostname, user, DNSBLConfEntries[i]); try { this->DNS->Process(r); } catch (DNS::Exception &ex) { delete r; ServerInstance->Logs->Log(MODNAME, LOG_DEBUG, ex.GetReason()); } if (user->quitting) break; } } ModResult OnSetConnectClass(LocalUser* user, ConnectClass* myclass) CXX11_OVERRIDE { std::string dnsbl; if (!myclass->config->readString("dnsbl", dnsbl)) return MOD_RES_PASSTHRU; std::string* match = nameExt.get(user); if (!match) return MOD_RES_PASSTHRU; if (InspIRCd::Match(*match, dnsbl)) return MOD_RES_PASSTHRU; return MOD_RES_DENY; } ModResult OnCheckReady(LocalUser *user) CXX11_OVERRIDE { if (countExt.get(user)) return MOD_RES_DENY; return MOD_RES_PASSTHRU; } ModResult OnStats(Stats::Context& stats) CXX11_OVERRIDE { if (stats.GetSymbol() != 'd') return MOD_RES_PASSTHRU; unsigned long total_hits = 0, total_misses = 0; for (std::vector<reference<DNSBLConfEntry> >::const_iterator i = DNSBLConfEntries.begin(); i != DNSBLConfEntries.end(); ++i) { total_hits += (*i)->stats_hits; total_misses += (*i)->stats_misses; stats.AddRow(304, "DNSBLSTATS DNSbl \"" + (*i)->name + "\" had " + ConvToStr((*i)->stats_hits) + " hits and " + ConvToStr((*i)->stats_misses) + " misses"); } stats.AddRow(304, "DNSBLSTATS Total hits: " + ConvToStr(total_hits)); stats.AddRow(304, "DNSBLSTATS Total misses: " + ConvToStr(total_misses)); return MOD_RES_PASSTHRU; } }; MODULE_INIT(ModuleDNSBL) ���������������������������������������������������������������������������������������������������������������inspircd-3.4.0/src/modules/m_exemptchanops.cpp������������������������������������������������������0000664�0000000�0000000�00000011110�13554550454�0021472�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * InspIRCd -- Internet Relay Chat Daemon * * 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 * 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 "inspircd.h" #include "listmode.h" #include "modules/exemption.h" /** Handles channel mode +X */ class ExemptChanOps : public ListModeBase { public: ExemptChanOps(Module* Creator) : ListModeBase(Creator, "exemptchanops", 'X', "End of channel exemptchanops list", 954, 953, false) { syntax = "<restriction>:<prefix>"; } static PrefixMode* FindMode(const std::string& mode) { if (mode.length() == 1) return ServerInstance->Modes->FindPrefixMode(mode[0]); ModeHandler* mh = ServerInstance->Modes->FindMode(mode, MODETYPE_CHANNEL); return mh ? mh->IsPrefixMode() : NULL; } static bool ParseEntry(const std::string& entry, std::string& restriction, std::string& prefix) { // The entry must be in the format <restriction>:<prefix>. std::string::size_type colon = entry.find(':'); if (colon == std::string::npos || colon == entry.length()-1) return false; restriction.assign(entry, 0, colon); prefix.assign(entry, colon + 1, std::string::npos); return true; } ModResult AccessCheck(User* source, Channel* channel, std::string& parameter, bool adding) CXX11_OVERRIDE { std::string restriction; std::string prefix; if (!ParseEntry(parameter, restriction, prefix)) return MOD_RES_PASSTHRU; PrefixMode* pm = FindMode(prefix); if (!pm) return MOD_RES_PASSTHRU; if (channel->GetPrefixValue(source) >= pm->GetLevelRequired(adding)) return MOD_RES_PASSTHRU; source->WriteNumeric(ERR_CHANOPRIVSNEEDED, channel->name, InspIRCd::Format("You must be able to %s mode %c (%s) to %s a restriction containing it", adding ? "set" : "unset", pm->GetModeChar(), pm->name.c_str(), adding ? "add" : "remove")); return MOD_RES_DENY; } bool ValidateParam(User* user, Channel* chan, std::string& word) CXX11_OVERRIDE { std::string restriction; std::string prefix; if (!ParseEntry(word, restriction, prefix)) { user->WriteNumeric(Numerics::InvalidModeParameter(chan, this, word)); return false; } // If there is a '-' in the restriction string ignore it and everything after it // to support "auditorium-vis" and "auditorium-see" in m_auditorium std::string::size_type dash = restriction.find('-'); if (dash != std::string::npos) restriction.erase(dash); if (!ServerInstance->Modes->FindMode(restriction, MODETYPE_CHANNEL)) { user->WriteNumeric(Numerics::InvalidModeParameter(chan, this, word, "Unknown restriction.")); return false; } if (prefix != "*" && !FindMode(prefix)) { user->WriteNumeric(Numerics::InvalidModeParameter(chan, this, word, "Unknown prefix mode.")); return false; } return true; } }; class ExemptHandler : public CheckExemption::EventListener { public: ExemptChanOps ec; ExemptHandler(Module* me) : CheckExemption::EventListener(me) , ec(me) { } ModResult OnCheckExemption(User* user, Channel* chan, const std::string& restriction) CXX11_OVERRIDE { unsigned int mypfx = chan->GetPrefixValue(user); std::string minmode; ListModeBase::ModeList* list = ec.GetList(chan); if (list) { for (ListModeBase::ModeList::iterator i = list->begin(); i != list->end(); ++i) { std::string::size_type pos = (*i).mask.find(':'); if (pos == std::string::npos) continue; if (!i->mask.compare(0, pos, restriction)) minmode.assign(i->mask, pos + 1, std::string::npos); } } PrefixMode* mh = ExemptChanOps::FindMode(minmode); if (mh && mypfx >= mh->GetPrefixRank()) return MOD_RES_ALLOW; if (mh || minmode == "*") return MOD_RES_DENY; return MOD_RES_PASSTHRU; } }; class ModuleExemptChanOps : public Module { ExemptHandler eh; public: ModuleExemptChanOps() : eh(this) { } Version GetVersion() CXX11_OVERRIDE { return Version("Provides the ability to allow channel operators to be exempt from certain modes", VF_VENDOR); } void ReadConfig(ConfigStatus& status) CXX11_OVERRIDE { eh.ec.DoRehash(); } }; MODULE_INIT(ModuleExemptChanOps) ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/src/modules/m_filter.cpp�������������������������������������������������������������0000664�0000000�0000000�00000067201�13554550454�0020115�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * InspIRCd -- Internet Relay Chat Daemon * * Copyright (C) 2009 Daniel De Graaf <danieldg@inspircd.org> * Copyright (C) 2004, 2008 Craig Edwards <craigedwards@brainbox.cc> * Copyright (C) 2007 Dennis Friis <peavey@inspircd.org> * Copyright (C) 2007 Robin Burchell <robin+git@viroteck.net> * * 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 "inspircd.h" #include "xline.h" #include "modules/regex.h" #include "modules/server.h" #include "modules/shun.h" #include "modules/stats.h" #include "modules/account.h" enum FilterFlags { FLAG_PART = 2, FLAG_QUIT = 4, FLAG_PRIVMSG = 8, FLAG_NOTICE = 16 }; enum FilterAction { FA_GLINE, FA_ZLINE, FA_WARN, FA_BLOCK, FA_SILENT, FA_KILL, FA_SHUN, FA_NONE }; class FilterResult { public: Regex* regex; std::string freeform; std::string reason; FilterAction action; unsigned long duration; bool from_config; bool flag_no_opers; bool flag_part_message; bool flag_quit_message; bool flag_privmsg; bool flag_notice; bool flag_strip_color; bool flag_no_registered; FilterResult(dynamic_reference<RegexFactory>& RegexEngine, const std::string& free, const std::string& rea, FilterAction act, unsigned long gt, const std::string& fla, bool cfg) : freeform(free) , reason(rea) , action(act) , duration(gt) , from_config(cfg) { if (!RegexEngine) throw ModuleException("Regex module implementing '"+RegexEngine.GetProvider()+"' is not loaded!"); regex = RegexEngine->Create(free); this->FillFlags(fla); } char FillFlags(const std::string &fl) { flag_no_opers = flag_part_message = flag_quit_message = flag_privmsg = flag_notice = flag_strip_color = flag_no_registered = false; for (std::string::const_iterator n = fl.begin(); n != fl.end(); ++n) { switch (*n) { case 'o': flag_no_opers = true; break; case 'P': flag_part_message = true; break; case 'q': flag_quit_message = true; break; case 'p': flag_privmsg = true; break; case 'n': flag_notice = true; break; case 'c': flag_strip_color = true; break; case 'r': flag_no_registered = true; break; case '*': flag_no_opers = flag_part_message = flag_quit_message = flag_privmsg = flag_notice = flag_strip_color = true; break; default: return *n; break; } } return 0; } std::string GetFlags() { std::string flags; if (flag_no_opers) flags.push_back('o'); if (flag_part_message) flags.push_back('P'); if (flag_quit_message) flags.push_back('q'); if (flag_privmsg) flags.push_back('p'); if (flag_notice) flags.push_back('n'); /* Order is important here, as the logic in FillFlags() stops parsing when it encounters * an unknown character. So the following characters must be last in the string. * 'c' is unsupported on < 2.0.10 * 'r' is unsupported on < 3.2.0 */ if (flag_strip_color) flags.push_back('c'); if (flag_no_registered) flags.push_back('r'); if (flags.empty()) flags.push_back('-'); return flags; } FilterResult() { } }; class CommandFilter : public Command { public: CommandFilter(Module* f) : Command(f, "FILTER", 1, 5) { flags_needed = 'o'; this->syntax = "<pattern> [<action> <flags> [<duration>] :<reason>]"; } CmdResult Handle(User* user, const Params& parameters) CXX11_OVERRIDE; RouteDescriptor GetRouting(User* user, const Params& parameters) CXX11_OVERRIDE { return ROUTE_BROADCAST; } }; class ModuleFilter : public Module , public ServerProtocol::SyncEventListener , public Stats::EventListener { typedef insp::flat_set<std::string, irc::insensitive_swo> ExemptTargetSet; bool initing; bool notifyuser; bool warnonselfmsg; RegexFactory* factory; void FreeFilters(); public: CommandFilter filtcommand; dynamic_reference<RegexFactory> RegexEngine; std::vector<FilterResult> filters; int flags; // List of channel names excluded from filtering. ExemptTargetSet exemptedchans; // List of target nicknames excluded from filtering. ExemptTargetSet exemptednicks; ModuleFilter(); void init() CXX11_OVERRIDE; CullResult cull() CXX11_OVERRIDE; ModResult OnUserPreMessage(User* user, const MessageTarget& target, MessageDetails& details) CXX11_OVERRIDE; FilterResult* FilterMatch(User* user, const std::string &text, int flags); bool DeleteFilter(const std::string& freeform, std::string& reason); std::pair<bool, std::string> AddFilter(const std::string& freeform, FilterAction type, const std::string& reason, unsigned long duration, const std::string& flags, bool config = false); void ReadConfig(ConfigStatus& status) CXX11_OVERRIDE; Version GetVersion() CXX11_OVERRIDE; std::string EncodeFilter(FilterResult* filter); FilterResult DecodeFilter(const std::string &data); void OnSyncNetwork(ProtocolInterface::Server& server) CXX11_OVERRIDE; void OnDecodeMetaData(Extensible* target, const std::string &extname, const std::string &extdata) CXX11_OVERRIDE; ModResult OnStats(Stats::Context& stats) CXX11_OVERRIDE; ModResult OnPreCommand(std::string& command, CommandBase::Params& parameters, LocalUser* user, bool validated) CXX11_OVERRIDE; void OnUnloadModule(Module* mod) CXX11_OVERRIDE; bool AppliesToMe(User* user, FilterResult* filter, int flags); void ReadFilters(); static bool StringToFilterAction(const std::string& str, FilterAction& fa); static std::string FilterActionToString(FilterAction fa); }; CmdResult CommandFilter::Handle(User* user, const Params& parameters) { if (parameters.size() == 1) { /* Deleting a filter */ Module* me = creator; std::string reason; if (static_cast<ModuleFilter*>(me)->DeleteFilter(parameters[0], reason)) { user->WriteNotice("*** Removed filter '" + parameters[0] + "': " + reason); ServerInstance->SNO->WriteToSnoMask(IS_LOCAL(user) ? 'f' : 'F', "%s removed filter '%s': %s", user->nick.c_str(), parameters[0].c_str(), reason.c_str()); return CMD_SUCCESS; } else { user->WriteNotice("*** Filter '" + parameters[0] + "' not found on the list."); return CMD_FAILURE; } } else { /* Adding a filter */ if (parameters.size() >= 4) { const std::string& freeform = parameters[0]; FilterAction type; const std::string& flags = parameters[2]; unsigned int reasonindex; unsigned long duration = 0; if (!ModuleFilter::StringToFilterAction(parameters[1], type)) { if (ServerInstance->XLines->GetFactory("SHUN")) user->WriteNotice("*** Invalid filter type '" + parameters[1] + "'. Supported types are 'gline', 'zline', 'none', 'warn', 'block', 'silent', 'kill', and 'shun'."); else user->WriteNotice("*** Invalid filter type '" + parameters[1] + "'. Supported types are 'gline', 'zline', 'none', 'warn', 'block', 'silent', and 'kill'."); return CMD_FAILURE; } if (type == FA_GLINE || type == FA_ZLINE || type == FA_SHUN) { if (parameters.size() >= 5) { if (!InspIRCd::Duration(parameters[3], duration)) { user->WriteNotice("*** Invalid duration for filter"); return CMD_FAILURE; } reasonindex = 4; } else { user->WriteNotice("*** Not enough parameters: When setting a '" + parameters[1] + "' type filter, a duration must be specified as the third parameter."); return CMD_FAILURE; } } else { reasonindex = 3; } Module* me = creator; std::pair<bool, std::string> result = static_cast<ModuleFilter*>(me)->AddFilter(freeform, type, parameters[reasonindex], duration, flags); if (result.first) { const std::string message = InspIRCd::Format("'%s', type '%s'%s, flags '%s', reason: %s", freeform.c_str(), parameters[1].c_str(), (duration ? InspIRCd::Format(", duration '%s'", InspIRCd::DurationString(duration).c_str()).c_str() : ""), flags.c_str(), parameters[reasonindex].c_str()); user->WriteNotice("*** Added filter " + message); ServerInstance->SNO->WriteToSnoMask(IS_LOCAL(user) ? 'f' : 'F', "%s added filter %s", user->nick.c_str(), message.c_str()); return CMD_SUCCESS; } else { user->WriteNotice("*** Filter '" + freeform + "' could not be added: " + result.second); return CMD_FAILURE; } } else { user->WriteNotice("*** Not enough parameters."); return CMD_FAILURE; } } } bool ModuleFilter::AppliesToMe(User* user, FilterResult* filter, int iflags) { const AccountExtItem* accountext = GetAccountExtItem(); if ((filter->flag_no_opers) && user->IsOper()) return false; if ((filter->flag_no_registered) && accountext && accountext->get(user)) return false; if ((iflags & FLAG_PRIVMSG) && (!filter->flag_privmsg)) return false; if ((iflags & FLAG_NOTICE) && (!filter->flag_notice)) return false; if ((iflags & FLAG_QUIT) && (!filter->flag_quit_message)) return false; if ((iflags & FLAG_PART) && (!filter->flag_part_message)) return false; return true; } ModuleFilter::ModuleFilter() : ServerProtocol::SyncEventListener(this) , Stats::EventListener(this) , initing(true) , filtcommand(this) , RegexEngine(this, "regex") { } void ModuleFilter::init() { ServerInstance->SNO->EnableSnomask('f', "FILTER"); } CullResult ModuleFilter::cull() { FreeFilters(); return Module::cull(); } void ModuleFilter::FreeFilters() { for (std::vector<FilterResult>::const_iterator i = filters.begin(); i != filters.end(); ++i) delete i->regex; filters.clear(); } ModResult ModuleFilter::OnUserPreMessage(User* user, const MessageTarget& msgtarget, MessageDetails& details) { // Leave remote users and servers alone if (!IS_LOCAL(user)) return MOD_RES_PASSTHRU; flags = (details.type == MSG_PRIVMSG) ? FLAG_PRIVMSG : FLAG_NOTICE; FilterResult* f = this->FilterMatch(user, details.text, flags); if (f) { bool is_selfmsg = false; std::string target; switch (msgtarget.type) { case MessageTarget::TYPE_USER: { User* t = msgtarget.Get<User>(); // Check if the target nick is exempted, if yes, ignore this message if (exemptednicks.count(t->nick)) return MOD_RES_PASSTHRU; if (user == t) is_selfmsg = true; target = t->nick; break; } case MessageTarget::TYPE_CHANNEL: { Channel* t = msgtarget.Get<Channel>(); if (exemptedchans.count(t->name)) return MOD_RES_PASSTHRU; target = t->name; break; } case MessageTarget::TYPE_SERVER: break; } if (is_selfmsg && warnonselfmsg) { ServerInstance->SNO->WriteGlobalSno('f', InspIRCd::Format("WARNING: %s's self message matched %s (%s)", user->nick.c_str(), f->freeform.c_str(), f->reason.c_str())); return MOD_RES_PASSTHRU; } else if (f->action == FA_WARN) { ServerInstance->SNO->WriteGlobalSno('f', InspIRCd::Format("WARNING: %s's message to %s matched %s (%s)", user->nick.c_str(), target.c_str(), f->freeform.c_str(), f->reason.c_str())); return MOD_RES_PASSTHRU; } else if (f->action == FA_BLOCK) { ServerInstance->SNO->WriteGlobalSno('f', InspIRCd::Format("%s had their message to %s filtered as it matched %s (%s)", user->nick.c_str(), target.c_str(), f->freeform.c_str(), f->reason.c_str())); if (notifyuser) { if (msgtarget.type == MessageTarget::TYPE_CHANNEL) user->WriteNumeric(ERR_CANNOTSENDTOCHAN, target, InspIRCd::Format("Message to channel blocked and opers notified (%s)", f->reason.c_str())); else user->WriteNotice("Your message to "+target+" was blocked and opers notified: "+f->reason); } else details.echo_original = true; } else if (f->action == FA_SILENT) { if (notifyuser) { if (msgtarget.type == MessageTarget::TYPE_CHANNEL) user->WriteNumeric(ERR_CANNOTSENDTOCHAN, target, InspIRCd::Format("Message to channel blocked (%s)", f->reason.c_str())); else user->WriteNotice("Your message to "+target+" was blocked: "+f->reason); } else details.echo_original = true; } else if (f->action == FA_KILL) { ServerInstance->SNO->WriteGlobalSno('f', InspIRCd::Format("%s was killed because their message to %s matched %s (%s)", user->nick.c_str(), target.c_str(), f->freeform.c_str(), f->reason.c_str())); ServerInstance->Users->QuitUser(user, "Filtered: " + f->reason); } else if (f->action == FA_SHUN && (ServerInstance->XLines->GetFactory("SHUN"))) { Shun* sh = new Shun(ServerInstance->Time(), f->duration, ServerInstance->Config->ServerName.c_str(), f->reason.c_str(), user->GetIPString()); ServerInstance->SNO->WriteGlobalSno('f', InspIRCd::Format("%s (%s) was shunned for %s (expires on %s) because their message to %s matched %s (%s)", user->nick.c_str(), sh->Displayable().c_str(), InspIRCd::DurationString(f->duration).c_str(), InspIRCd::TimeString(ServerInstance->Time() + f->duration).c_str(), target.c_str(), f->freeform.c_str(), f->reason.c_str())); if (ServerInstance->XLines->AddLine(sh, NULL)) { ServerInstance->XLines->ApplyLines(); } else delete sh; } else if (f->action == FA_GLINE) { GLine* gl = new GLine(ServerInstance->Time(), f->duration, ServerInstance->Config->ServerName.c_str(), f->reason.c_str(), "*", user->GetIPString()); ServerInstance->SNO->WriteGlobalSno('f', InspIRCd::Format("%s (%s) was G-lined for %s (expires on %s) because their message to %s matched %s (%s)", user->nick.c_str(), gl->Displayable().c_str(), InspIRCd::DurationString(f->duration).c_str(), InspIRCd::TimeString(ServerInstance->Time() + f->duration).c_str(), target.c_str(), f->freeform.c_str(), f->reason.c_str())); if (ServerInstance->XLines->AddLine(gl,NULL)) { ServerInstance->XLines->ApplyLines(); } else delete gl; } else if (f->action == FA_ZLINE) { ZLine* zl = new ZLine(ServerInstance->Time(), f->duration, ServerInstance->Config->ServerName.c_str(), f->reason.c_str(), user->GetIPString()); ServerInstance->SNO->WriteGlobalSno('f', InspIRCd::Format("%s (%s) was Z-lined for %s (expires on %s) because their message to %s matched %s (%s)", user->nick.c_str(), zl->Displayable().c_str(), InspIRCd::DurationString(f->duration).c_str(), InspIRCd::TimeString(ServerInstance->Time() + f->duration).c_str(), target.c_str(), f->freeform.c_str(), f->reason.c_str())); if (ServerInstance->XLines->AddLine(zl,NULL)) { ServerInstance->XLines->ApplyLines(); } else delete zl; } ServerInstance->Logs->Log(MODNAME, LOG_DEFAULT, user->nick + " had their message filtered, target was " + target + ": " + f->reason + " Action: " + ModuleFilter::FilterActionToString(f->action)); return MOD_RES_DENY; } return MOD_RES_PASSTHRU; } ModResult ModuleFilter::OnPreCommand(std::string& command, CommandBase::Params& parameters, LocalUser* user, bool validated) { if (validated) { flags = 0; bool parting; if (command == "QUIT") { /* QUIT with no reason: nothing to do */ if (parameters.size() < 1) return MOD_RES_PASSTHRU; parting = false; flags = FLAG_QUIT; } else if (command == "PART") { /* PART with no reason: nothing to do */ if (parameters.size() < 2) return MOD_RES_PASSTHRU; if (exemptedchans.count(parameters[0])) return MOD_RES_PASSTHRU; parting = true; flags = FLAG_PART; } else /* We're only messing with PART and QUIT */ return MOD_RES_PASSTHRU; FilterResult* f = this->FilterMatch(user, parameters[parting ? 1 : 0], flags); if (!f) /* PART or QUIT reason doesnt match a filter */ return MOD_RES_PASSTHRU; /* We cant block a part or quit, so instead we change the reason to 'Reason filtered' */ parameters[parting ? 1 : 0] = "Reason filtered"; /* We're warning or blocking, OR theyre quitting and its a KILL action * (we cant kill someone whos already quitting, so filter them anyway) */ if ((f->action == FA_WARN) || (f->action == FA_BLOCK) || (((!parting) && (f->action == FA_KILL))) || (f->action == FA_SILENT)) { return MOD_RES_PASSTHRU; } else { /* Are they parting, if so, kill is applicable */ if ((parting) && (f->action == FA_KILL)) { user->WriteNotice("*** Your PART message was filtered: " + f->reason); ServerInstance->Users->QuitUser(user, "Filtered: " + f->reason); } if (f->action == FA_GLINE) { /* Note: We G-line *@IP so that if their host doesn't resolve the G-line still applies. */ GLine* gl = new GLine(ServerInstance->Time(), f->duration, ServerInstance->Config->ServerName.c_str(), f->reason.c_str(), "*", user->GetIPString()); ServerInstance->SNO->WriteGlobalSno('f', InspIRCd::Format("%s (%s) was G-lined for %s (expires on %s) because their %s message matched %s (%s)", user->nick.c_str(), gl->Displayable().c_str(), InspIRCd::DurationString(f->duration).c_str(), InspIRCd::TimeString(ServerInstance->Time() + f->duration).c_str(), command.c_str(), f->freeform.c_str(), f->reason.c_str())); if (ServerInstance->XLines->AddLine(gl,NULL)) { ServerInstance->XLines->ApplyLines(); } else delete gl; } if (f->action == FA_ZLINE) { ZLine* zl = new ZLine(ServerInstance->Time(), f->duration, ServerInstance->Config->ServerName.c_str(), f->reason.c_str(), user->GetIPString()); ServerInstance->SNO->WriteGlobalSno('f', InspIRCd::Format("%s (%s) was Z-lined for %s (expires on %s) because their %s message matched %s (%s)", user->nick.c_str(), zl->Displayable().c_str(), InspIRCd::DurationString(f->duration).c_str(), InspIRCd::TimeString(ServerInstance->Time() + f->duration).c_str(), command.c_str(), f->freeform.c_str(), f->reason.c_str())); if (ServerInstance->XLines->AddLine(zl,NULL)) { ServerInstance->XLines->ApplyLines(); } else delete zl; } else if (f->action == FA_SHUN && (ServerInstance->XLines->GetFactory("SHUN"))) { /* Note: We shun *!*@IP so that if their host doesnt resolve the shun still applies. */ Shun* sh = new Shun(ServerInstance->Time(), f->duration, ServerInstance->Config->ServerName.c_str(), f->reason.c_str(), user->GetIPString()); ServerInstance->SNO->WriteGlobalSno('f', InspIRCd::Format("%s (%s) was shunned for %s (expires on %s) because their %s message matched %s (%s)", user->nick.c_str(), sh->Displayable().c_str(), InspIRCd::DurationString(f->duration).c_str(), InspIRCd::TimeString(ServerInstance->Time() + f->duration).c_str(), command.c_str(), f->freeform.c_str(), f->reason.c_str())); if (ServerInstance->XLines->AddLine(sh, NULL)) { ServerInstance->XLines->ApplyLines(); } else delete sh; } return MOD_RES_DENY; } } return MOD_RES_PASSTHRU; } void ModuleFilter::ReadConfig(ConfigStatus& status) { ConfigTagList tags = ServerInstance->Config->ConfTags("exemptfromfilter"); exemptedchans.clear(); exemptednicks.clear(); for (ConfigIter i = tags.first; i != tags.second; ++i) { ConfigTag* tag = i->second; // If "target" is not found, try the old "channel" key to keep compatibility with 2.0 configs const std::string target = tag->getString("target", tag->getString("channel")); if (!target.empty()) { if (target[0] == '#') exemptedchans.insert(target); else exemptednicks.insert(target); } } ConfigTag* tag = ServerInstance->Config->ConfValue("filteropts"); std::string newrxengine = tag->getString("engine"); notifyuser = tag->getBool("notifyuser", true); warnonselfmsg = tag->getBool("warnonselfmsg"); factory = RegexEngine ? (RegexEngine.operator->()) : NULL; if (newrxengine.empty()) RegexEngine.SetProvider("regex"); else RegexEngine.SetProvider("regex/" + newrxengine); if (!RegexEngine) { if (newrxengine.empty()) ServerInstance->SNO->WriteGlobalSno('f', "WARNING: No regex engine loaded - Filter functionality disabled until this is corrected."); else ServerInstance->SNO->WriteGlobalSno('f', "WARNING: Regex engine '%s' is not loaded - Filter functionality disabled until this is corrected.", newrxengine.c_str()); initing = false; FreeFilters(); return; } if ((!initing) && (RegexEngine.operator->() != factory)) { ServerInstance->SNO->WriteGlobalSno('f', "Dumping all filters due to regex engine change"); FreeFilters(); } initing = false; ReadFilters(); } Version ModuleFilter::GetVersion() { return Version("Provides text (spam) filtering", VF_VENDOR | VF_COMMON, RegexEngine ? RegexEngine->name : ""); } std::string ModuleFilter::EncodeFilter(FilterResult* filter) { std::ostringstream stream; std::string x = filter->freeform; /* Hax to allow spaces in the freeform without changing the design of the irc protocol */ for (std::string::iterator n = x.begin(); n != x.end(); n++) if (*n == ' ') *n = '\7'; stream << x << " " << FilterActionToString(filter->action) << " " << filter->GetFlags() << " " << filter->duration << " :" << filter->reason; return stream.str(); } FilterResult ModuleFilter::DecodeFilter(const std::string &data) { std::string filteraction; FilterResult res; irc::tokenstream tokens(data); tokens.GetMiddle(res.freeform); tokens.GetMiddle(filteraction); if (!StringToFilterAction(filteraction, res.action)) throw ModuleException("Invalid action: " + filteraction); std::string filterflags; tokens.GetMiddle(filterflags); char c = res.FillFlags(filterflags); if (c != 0) throw ModuleException("Invalid flag: '" + std::string(1, c) + "'"); std::string duration; tokens.GetMiddle(duration); res.duration = ConvToNum<unsigned long>(duration); tokens.GetTrailing(res.reason); /* Hax to allow spaces in the freeform without changing the design of the irc protocol */ for (std::string::iterator n = res.freeform.begin(); n != res.freeform.end(); n++) if (*n == '\7') *n = ' '; return res; } void ModuleFilter::OnSyncNetwork(ProtocolInterface::Server& server) { for (std::vector<FilterResult>::iterator i = filters.begin(); i != filters.end(); ++i) { FilterResult& filter = *i; if (filter.from_config) continue; server.SendMetaData("filter", EncodeFilter(&filter)); } } void ModuleFilter::OnDecodeMetaData(Extensible* target, const std::string &extname, const std::string &extdata) { if ((target == NULL) && (extname == "filter")) { try { FilterResult data = DecodeFilter(extdata); this->AddFilter(data.freeform, data.action, data.reason, data.duration, data.GetFlags()); } catch (ModuleException& e) { ServerInstance->Logs->Log(MODNAME, LOG_DEBUG, "Error when unserializing filter: " + e.GetReason()); } } } FilterResult* ModuleFilter::FilterMatch(User* user, const std::string &text, int flgs) { static std::string stripped_text; stripped_text.clear(); for (std::vector<FilterResult>::iterator i = filters.begin(); i != filters.end(); ++i) { FilterResult* filter = &*i; /* Skip ones that dont apply to us */ if (!AppliesToMe(user, filter, flgs)) continue; if ((filter->flag_strip_color) && (stripped_text.empty())) { stripped_text = text; InspIRCd::StripColor(stripped_text); } if (filter->regex->Matches(filter->flag_strip_color ? stripped_text : text)) return filter; } return NULL; } bool ModuleFilter::DeleteFilter(const std::string& freeform, std::string& reason) { for (std::vector<FilterResult>::iterator i = filters.begin(); i != filters.end(); i++) { if (i->freeform == freeform) { reason.assign(i->reason); delete i->regex; filters.erase(i); return true; } } return false; } std::pair<bool, std::string> ModuleFilter::AddFilter(const std::string& freeform, FilterAction type, const std::string& reason, unsigned long duration, const std::string& flgs, bool config) { for (std::vector<FilterResult>::iterator i = filters.begin(); i != filters.end(); i++) { if (i->freeform == freeform) { return std::make_pair(false, "Filter already exists"); } } try { filters.push_back(FilterResult(RegexEngine, freeform, reason, type, duration, flgs, config)); } catch (ModuleException &e) { ServerInstance->Logs->Log(MODNAME, LOG_DEFAULT, "Error in regular expression '%s': %s", freeform.c_str(), e.GetReason().c_str()); return std::make_pair(false, e.GetReason()); } return std::make_pair(true, ""); } bool ModuleFilter::StringToFilterAction(const std::string& str, FilterAction& fa) { if (stdalgo::string::equalsci(str, "gline")) fa = FA_GLINE; else if (stdalgo::string::equalsci(str, "zline")) fa = FA_ZLINE; else if (stdalgo::string::equalsci(str, "warn")) fa = FA_WARN; else if (stdalgo::string::equalsci(str, "block")) fa = FA_BLOCK; else if (stdalgo::string::equalsci(str, "silent")) fa = FA_SILENT; else if (stdalgo::string::equalsci(str, "kill")) fa = FA_KILL; else if (stdalgo::string::equalsci(str, "shun") && (ServerInstance->XLines->GetFactory("SHUN"))) fa = FA_SHUN; else if (stdalgo::string::equalsci(str, "none")) fa = FA_NONE; else return false; return true; } std::string ModuleFilter::FilterActionToString(FilterAction fa) { switch (fa) { case FA_GLINE: return "gline"; case FA_ZLINE: return "zline"; case FA_WARN: return "warn"; case FA_BLOCK: return "block"; case FA_SILENT: return "silent"; case FA_KILL: return "kill"; case FA_SHUN: return "shun"; default: return "none"; } } void ModuleFilter::ReadFilters() { insp::flat_set<std::string> removedfilters; for (std::vector<FilterResult>::iterator filter = filters.begin(); filter != filters.end(); ) { if (filter->from_config) { removedfilters.insert(filter->freeform); delete filter->regex; filter = filters.erase(filter); continue; } // The filter is not from the config. filter++; } ConfigTagList tags = ServerInstance->Config->ConfTags("keyword"); for (ConfigIter i = tags.first; i != tags.second; ++i) { std::string pattern = i->second->getString("pattern"); std::string reason = i->second->getString("reason"); std::string action = i->second->getString("action"); std::string flgs = i->second->getString("flags"); unsigned long duration = i->second->getDuration("duration", 10*60, 1); if (flgs.empty()) flgs = "*"; FilterAction fa; if (!StringToFilterAction(action, fa)) fa = FA_NONE; std::pair<bool, std::string> result = static_cast<ModuleFilter*>(this)->AddFilter(pattern, fa, reason, duration, flgs, true); if (result.first) removedfilters.erase(pattern); else ServerInstance->Logs->Log(MODNAME, LOG_DEFAULT, "Filter '%s' could not be added: %s", pattern.c_str(), result.second.c_str()); } if (!removedfilters.empty()) { for (insp::flat_set<std::string>::const_iterator it = removedfilters.begin(); it != removedfilters.end(); ++it) ServerInstance->SNO->WriteGlobalSno('f', "Removing filter '" + *(it) + "' due to config rehash."); } } ModResult ModuleFilter::OnStats(Stats::Context& stats) { if (stats.GetSymbol() == 's') { for (std::vector<FilterResult>::iterator i = filters.begin(); i != filters.end(); i++) { stats.AddRow(223, RegexEngine.GetProvider()+":"+i->freeform+" "+i->GetFlags()+" "+FilterActionToString(i->action)+" "+ConvToStr(i->duration)+" :"+i->reason); } for (ExemptTargetSet::const_iterator i = exemptedchans.begin(); i != exemptedchans.end(); ++i) { stats.AddRow(223, "EXEMPT "+(*i)); } for (ExemptTargetSet::const_iterator i = exemptednicks.begin(); i != exemptednicks.end(); ++i) { stats.AddRow(223, "EXEMPT "+(*i)); } } return MOD_RES_PASSTHRU; } void ModuleFilter::OnUnloadModule(Module* mod) { // If the regex engine became unavailable or has changed, remove all filters if (!RegexEngine) { FreeFilters(); } else if (RegexEngine.operator->() != factory) { factory = RegexEngine.operator->(); FreeFilters(); } } MODULE_INIT(ModuleFilter) �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/src/modules/m_flashpolicyd.cpp�������������������������������������������������������0000664�0000000�0000000�00000007671�13554550454�0021316�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * InspIRCd -- Internet Relay Chat Daemon * * Copyright (C) 2013 Daniel Vassdal <shutter@canternet.org> * * This file is part of InspIRCd. InspIRCd is free software: you can * redistribute it and/or modify it under the terms of the GNU General Public * License as published by the Free Software Foundation, version 2. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include "inspircd.h" class FlashPDSocket; namespace { insp::intrusive_list<FlashPDSocket> sockets; std::string policy_reply; const std::string expected_request("<policy-file-request/>\0", 23); } class FlashPDSocket : public BufferedSocket, public Timer, public insp::intrusive_list_node<FlashPDSocket> { /** True if this object is in the cull list */ bool waitingcull; bool Tick(time_t currtime) CXX11_OVERRIDE { AddToCull(); return false; } public: FlashPDSocket(int newfd, unsigned int timeoutsec) : BufferedSocket(newfd) , Timer(timeoutsec) , waitingcull(false) { ServerInstance->Timers.AddTimer(this); } ~FlashPDSocket() { sockets.erase(this); } void OnError(BufferedSocketError) CXX11_OVERRIDE { AddToCull(); } void OnDataReady() CXX11_OVERRIDE { if (recvq == expected_request) WriteData(policy_reply); AddToCull(); } void AddToCull() { if (waitingcull) return; waitingcull = true; Close(); ServerInstance->GlobalCulls.AddItem(this); } }; class ModuleFlashPD : public Module { unsigned int timeout; public: ModResult OnAcceptConnection(int nfd, ListenSocket* from, irc::sockets::sockaddrs* client, irc::sockets::sockaddrs* server) CXX11_OVERRIDE { if (!stdalgo::string::equalsci(from->bind_tag->getString("type"), "flashpolicyd")) return MOD_RES_PASSTHRU; if (policy_reply.empty()) return MOD_RES_DENY; sockets.push_front(new FlashPDSocket(nfd, timeout)); return MOD_RES_ALLOW; } void ReadConfig(ConfigStatus& status) CXX11_OVERRIDE { ConfigTag* tag = ServerInstance->Config->ConfValue("flashpolicyd"); std::string file = tag->getString("file"); if (!file.empty()) { try { FileReader reader(file); policy_reply = reader.GetString(); } catch (CoreException&) { throw ModuleException("A file was specified for FlashPD, but it could not be loaded at " + tag->getTagLocation()); } return; } // A file was not specified. Set the default setting. // We allow access to all client ports by default std::string to_ports; for (std::vector<ListenSocket*>::const_iterator i = ServerInstance->ports.begin(); i != ServerInstance->ports.end(); ++i) { ListenSocket* ls = *i; if (!stdalgo::string::equalsci(ls->bind_tag->getString("type", "clients"), "clients") || !ls->bind_tag->getString("ssl").empty()) continue; to_ports.append(ConvToStr(ls->bind_sa.port())).push_back(','); } if (to_ports.empty()) { policy_reply.clear(); return; } to_ports.erase(to_ports.size() - 1); policy_reply = "<?xml version=\"1.0\"?>\ <!DOCTYPE cross-domain-policy SYSTEM \"/xml/dtds/cross-domain-policy.dtd\">\ <cross-domain-policy>\ <site-control permitted-cross-domain-policies=\"master-only\"/>\ <allow-access-from domain=\"*\" to-ports=\"" + to_ports + "\" />\ </cross-domain-policy>"; timeout = tag->getDuration("timeout", 5, 1); } CullResult cull() CXX11_OVERRIDE { for (insp::intrusive_list<FlashPDSocket>::const_iterator i = sockets.begin(); i != sockets.end(); ++i) { FlashPDSocket* sock = *i; sock->AddToCull(); } return Module::cull(); } Version GetVersion() CXX11_OVERRIDE { return Version("Flash Policy Daemon, allows Flash IRC clients to connect", VF_VENDOR); } }; MODULE_INIT(ModuleFlashPD) �����������������������������������������������������������������������inspircd-3.4.0/src/modules/m_gecosban.cpp�����������������������������������������������������������0000664�0000000�0000000�00000003630�13554550454�0020405�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * InspIRCd -- Internet Relay Chat Daemon * * Copyright (C) 2008 Robin Burchell <robin+git@viroteck.net> * * 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 "inspircd.h" class ModuleGecosBan : public Module { public: Version GetVersion() CXX11_OVERRIDE { return Version("Provides a way to ban users by their real name with the 'a' and 'r' extbans", VF_OPTCOMMON|VF_VENDOR); } ModResult OnCheckBan(User *user, Channel *c, const std::string& mask) CXX11_OVERRIDE { if ((mask.length() > 2) && (mask[1] == ':')) { if (mask[0] == 'r') { if (InspIRCd::Match(user->GetRealName(), mask.substr(2))) return MOD_RES_DENY; } else if (mask[0] == 'a') { // Check that the user actually specified a real name. const size_t divider = mask.find('+', 1); if (divider == std::string::npos) return MOD_RES_PASSTHRU; // Check whether the user's mask matches. if (!c->CheckBan(user, mask.substr(2, divider - 2))) return MOD_RES_PASSTHRU; // Check whether the user's real name matches. if (InspIRCd::Match(user->GetRealName(), mask.substr(divider + 1))) return MOD_RES_DENY; } } return MOD_RES_PASSTHRU; } void On005Numeric(std::map<std::string, std::string>& tokens) CXX11_OVERRIDE { tokens["EXTBAN"].push_back('a'); tokens["EXTBAN"].push_back('r'); } }; MODULE_INIT(ModuleGecosBan) ��������������������������������������������������������������������������������������������������������inspircd-3.4.0/src/modules/m_geoban.cpp�������������������������������������������������������������0000664�0000000�0000000�00000004141�13554550454�0020055�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * InspIRCd -- Internet Relay Chat Daemon * * Copyright (C) 2019 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 "inspircd.h" #include "modules/geolocation.h" #include "modules/whois.h" enum { // InspIRCd-specific. RPL_WHOISCOUNTRY = 344 }; class ModuleGeoBan : public Module , public Whois::EventListener { private: Geolocation::API geoapi; public: ModuleGeoBan() : Whois::EventListener(this) , geoapi(this) { } Version GetVersion() CXX11_OVERRIDE { return Version("Provides a way to ban users by country", VF_OPTCOMMON|VF_VENDOR); } void On005Numeric(std::map<std::string, std::string>& tokens) CXX11_OVERRIDE { tokens["EXTBAN"].push_back('G'); } ModResult OnCheckBan(User* user, Channel*, const std::string& mask) CXX11_OVERRIDE { if ((mask.length() > 2) && (mask[0] == 'G') && (mask[1] == ':')) { Geolocation::Location* location = geoapi ? geoapi->GetLocation(user) : NULL; const std::string code = location ? location->GetCode() : "XX"; // Does this user match against the ban? if (InspIRCd::Match(code, mask.substr(2))) return MOD_RES_DENY; } return MOD_RES_PASSTHRU; } void OnWhois(Whois::Context& whois) CXX11_OVERRIDE { Geolocation::Location* location = geoapi ? geoapi->GetLocation(whois.GetTarget()) : NULL; if (location) whois.SendLine(RPL_WHOISCOUNTRY, location->GetCode(), "is connecting from " + location->GetName()); else whois.SendLine(RPL_WHOISCOUNTRY, "*", "is connecting from an unknown country"); } }; MODULE_INIT(ModuleGeoBan) �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/src/modules/m_geoclass.cpp�����������������������������������������������������������0000664�0000000�0000000�00000006033�13554550454�0020424�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * InspIRCd -- Internet Relay Chat Daemon * * Copyright (C) 2019 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 "inspircd.h" #include "modules/geolocation.h" #include "modules/stats.h" enum { // InspIRCd-specific. RPL_STATSCOUNTRY = 801 }; class ModuleGeoClass : public Module , public Stats::EventListener { private: Geolocation::API geoapi; public: ModuleGeoClass() : Stats::EventListener(this) , geoapi(this) { } Version GetVersion() CXX11_OVERRIDE { return Version("Provides a way to assign users to connect classes by country", VF_VENDOR); } ModResult OnSetConnectClass(LocalUser* user, ConnectClass* myclass) CXX11_OVERRIDE { const std::string country = myclass->config->getString("country"); if (country.empty()) return MOD_RES_PASSTHRU; // If we can't find the location of this user then we can't assign // them to a location-specific connect class. Geolocation::Location* location = geoapi ? geoapi->GetLocation(user) : NULL; const std::string code = location ? location->GetCode() : "XX"; irc::spacesepstream codes(country); for (std::string token; codes.GetToken(token); ) { // If the user matches this country code then they can use this // connect class. if (stdalgo::string::equalsci(token, code)) return MOD_RES_PASSTHRU; } // A list of country codes were specified but the user didn't match // any of them. return MOD_RES_DENY; } ModResult OnStats(Stats::Context& stats) CXX11_OVERRIDE { if (stats.GetSymbol() != 'G') return MOD_RES_PASSTHRU; // Counter for the number of users in each country. typedef std::map<Geolocation::Location*, size_t> CountryCounts; CountryCounts counts; // Counter for the number of users in an unknown country. size_t unknown = 0; const UserManager::LocalList& list = ServerInstance->Users.GetLocalUsers(); for (UserManager::LocalList::const_iterator iter = list.begin(); iter != list.end(); ++iter) { Geolocation::Location* location = geoapi ? geoapi->GetLocation(*iter) : NULL; if (location) counts[location]++; else unknown++; } for (CountryCounts::const_iterator iter = counts.begin(); iter != counts.end(); ++iter) { Geolocation::Location* location = iter->first; stats.AddRow(RPL_STATSCOUNTRY, iter->second, location->GetCode(), location->GetName()); } if (unknown) stats.AddRow(RPL_STATSCOUNTRY, unknown, "*", "Unknown Country"); return MOD_RES_DENY; } }; MODULE_INIT(ModuleGeoClass) �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/src/modules/m_globalload.cpp���������������������������������������������������������0000664�0000000�0000000�00000012447�13554550454�0020732�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * InspIRCd -- Internet Relay Chat Daemon * * Copyright (C) 2011 Jackmcbarn <jackmcbarn@jackmcbarn.no-ip.org> * Copyright (C) 2009 Daniel De Graaf <danieldg@inspircd.org> * Copyright (C) 2006-2008 Craig Edwards <craigedwards@brainbox.cc> * Copyright (C) 2007-2008 Dennis Friis <peavey@inspircd.org> * Copyright (C) 2006-2007 Robin Burchell <robin+git@viroteck.net> * Copyright (C) 2006 John Brooks <john.brooks@dereferenced.net> * * 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 "inspircd.h" /** Handle /GLOADMODULE */ class CommandGloadmodule : public Command { public: CommandGloadmodule(Module* Creator) : Command(Creator,"GLOADMODULE", 1) { flags_needed = 'o'; syntax = "<modulename> [<servermask>]"; } CmdResult Handle(User* user, const Params& parameters) CXX11_OVERRIDE { std::string servername = parameters.size() > 1 ? parameters[1] : "*"; if (InspIRCd::Match(ServerInstance->Config->ServerName.c_str(), servername)) { if (ServerInstance->Modules->Load(parameters[0].c_str())) { ServerInstance->SNO->WriteToSnoMask('a', "NEW MODULE '%s' GLOBALLY LOADED BY '%s'",parameters[0].c_str(), user->nick.c_str()); user->WriteNumeric(RPL_LOADEDMODULE, parameters[0], "Module successfully loaded."); } else { user->WriteNumeric(ERR_CANTLOADMODULE, parameters[0], ServerInstance->Modules->LastError()); } } else ServerInstance->SNO->WriteToSnoMask('a', "MODULE '%s' GLOBAL LOAD BY '%s' (not loaded here)",parameters[0].c_str(), user->nick.c_str()); return CMD_SUCCESS; } RouteDescriptor GetRouting(User* user, const Params& parameters) CXX11_OVERRIDE { return ROUTE_BROADCAST; } }; /** Handle /GUNLOADMODULE */ class CommandGunloadmodule : public Command { public: CommandGunloadmodule(Module* Creator) : Command(Creator,"GUNLOADMODULE", 1) { flags_needed = 'o'; syntax = "<modulename> [<servermask>]"; } CmdResult Handle(User* user, const Params& parameters) CXX11_OVERRIDE { if (!ServerInstance->Config->ConfValue("security")->getBool("allowcoreunload") && InspIRCd::Match(parameters[0], "core_*.so", ascii_case_insensitive_map)) { user->WriteNumeric(ERR_CANTUNLOADMODULE, parameters[0], "You cannot unload core commands!"); return CMD_FAILURE; } std::string servername = parameters.size() > 1 ? parameters[1] : "*"; if (InspIRCd::Match(ServerInstance->Config->ServerName.c_str(), servername)) { Module* m = ServerInstance->Modules->Find(parameters[0]); if (m) { if (ServerInstance->Modules->Unload(m)) { ServerInstance->SNO->WriteToSnoMask('a', "MODULE '%s' GLOBALLY UNLOADED BY '%s'",parameters[0].c_str(), user->nick.c_str()); user->WriteRemoteNumeric(RPL_UNLOADEDMODULE, parameters[0], "Module successfully unloaded."); } else { user->WriteNumeric(ERR_CANTUNLOADMODULE, parameters[0], ServerInstance->Modules->LastError()); } } else user->WriteRemoteNumeric(ERR_CANTUNLOADMODULE, parameters[0], "No such module"); } else ServerInstance->SNO->WriteToSnoMask('a', "MODULE '%s' GLOBAL UNLOAD BY '%s' (not unloaded here)",parameters[0].c_str(), user->nick.c_str()); return CMD_SUCCESS; } RouteDescriptor GetRouting(User* user, const Params& parameters) CXX11_OVERRIDE { return ROUTE_BROADCAST; } }; /** Handle /GRELOADMODULE */ class CommandGreloadmodule : public Command { public: CommandGreloadmodule(Module* Creator) : Command(Creator, "GRELOADMODULE", 1) { flags_needed = 'o'; syntax = "<modulename> [<servermask>]"; } CmdResult Handle(User* user, const Params& parameters) CXX11_OVERRIDE { std::string servername = parameters.size() > 1 ? parameters[1] : "*"; if (InspIRCd::Match(ServerInstance->Config->ServerName.c_str(), servername)) { Module* m = ServerInstance->Modules->Find(parameters[0]); if (m) { ServerInstance->SNO->WriteToSnoMask('a', "MODULE '%s' GLOBALLY RELOADED BY '%s'", parameters[0].c_str(), user->nick.c_str()); ServerInstance->Parser.CallHandler("RELOADMODULE", parameters, user); } else { user->WriteNumeric(RPL_LOADEDMODULE, parameters[0], "Could not find module by that name"); return CMD_FAILURE; } } else ServerInstance->SNO->WriteToSnoMask('a', "MODULE '%s' GLOBAL RELOAD BY '%s' (not reloaded here)",parameters[0].c_str(), user->nick.c_str()); return CMD_SUCCESS; } RouteDescriptor GetRouting(User* user, const Params& parameters) CXX11_OVERRIDE { return ROUTE_BROADCAST; } }; class ModuleGlobalLoad : public Module { CommandGloadmodule cmd1; CommandGunloadmodule cmd2; CommandGreloadmodule cmd3; public: ModuleGlobalLoad() : cmd1(this), cmd2(this), cmd3(this) { } Version GetVersion() CXX11_OVERRIDE { return Version("Allows global loading of a module", VF_COMMON | VF_VENDOR); } }; MODULE_INIT(ModuleGlobalLoad) �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/src/modules/m_globops.cpp������������������������������������������������������������0000664�0000000�0000000�00000003361�13554550454�0020272�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * InspIRCd -- Internet Relay Chat Daemon * * Copyright (C) 2007 Dennis Friis <peavey@inspircd.org> * Copyright (C) 2007 Robin Burchell <robin+git@viroteck.net> * Copyright (C) 2004-2006 Craig Edwards <craigedwards@brainbox.cc> * * This file is part of InspIRCd. InspIRCd is free software: you can * redistribute it and/or modify it under the terms of the GNU General Public * License as published by the Free Software Foundation, version 2. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ // Globops and snomask +g module by C.J.Edwards #include "inspircd.h" /** Handle /GLOBOPS */ class CommandGlobops : public Command { public: CommandGlobops(Module* Creator) : Command(Creator,"GLOBOPS", 1,1) { flags_needed = 'o'; syntax = ":<message>"; } CmdResult Handle(User* user, const Params& parameters) CXX11_OVERRIDE { if (parameters[0].empty()) { user->WriteNumeric(ERR_NOTEXTTOSEND, "No text to send"); return CMD_FAILURE; } ServerInstance->SNO->WriteGlobalSno('g', "From " + user->nick + ": " + parameters[0]); return CMD_SUCCESS; } }; class ModuleGlobops : public Module { CommandGlobops cmd; public: ModuleGlobops() : cmd(this) {} void init() CXX11_OVERRIDE { ServerInstance->SNO->EnableSnomask('g',"GLOBOPS"); } Version GetVersion() CXX11_OVERRIDE { return Version("Provides the GLOBOPS command and snomask 'g'", VF_VENDOR); } }; MODULE_INIT(ModuleGlobops) �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/src/modules/m_haproxy.cpp������������������������������������������������������������0000664�0000000�0000000�00000026017�13554550454�0020322�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * InspIRCd -- Internet Relay Chat Daemon * * Copyright (C) 2018 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 "inspircd.h" #include "iohook.h" #include "modules/ssl.h" enum { // The SSL TLV flag for a client being connected over SSL. PP2_CLIENT_SSL = 0x01, // The family for TCP over IPv4. PP2_FAMILY_IPV4 = 0x11, // The length of the PP2_FAMILY_IPV4 endpoints. PP2_FAMILY_IPV4_LENGTH = 12, // The family for TCP over IPv6. PP2_FAMILY_IPV6 = 0x21, // The length of the PP2_FAMILY_IPV6 endpoints. PP2_FAMILY_IPV6_LENGTH = 36, // The family for UNIX sockets. PP2_FAMILY_UNIX = 0x31, // The length of the PP2_FAMILY_UNIX endpoints. PP2_FAMILY_UNIX_LENGTH = 216, // The bitmask we apply to extract the command. PP2_COMMAND_MASK = 0x0F, // The length of the PROXY protocol header. PP2_HEADER_LENGTH = 16, // The minimum length of a Type-Length-Value entry. PP2_TLV_LENGTH = 3, // The identifier for a SSL TLV entry. PP2_TYPE_SSL = 0x20, // The minimum length of a PP2_TYPE_SSL TLV entry. PP2_TYPE_SSL_LENGTH = 5, // The length of the PROXY protocol signature. PP2_SIGNATURE_LENGTH = 12, // The PROXY protocol version we support. PP2_VERSION = 0x20, // The bitmask we apply to extract the protocol version. PP2_VERSION_MASK = 0xF0 }; enum HAProxyState { // We are waiting for the PROXY header section. HPS_WAITING_FOR_HEADER, // We are waiting for the PROXY address section. HPS_WAITING_FOR_ADDRESS, // The client is fully connected. HPS_CONNECTED }; enum HAProxyCommand { // LOCAL command. HPC_LOCAL = 0x00, // PROXY command. HPC_PROXY = 0x01 }; struct HAProxyHeader { // The signature used to identify the HAProxy protocol. uint8_t signature[PP2_SIGNATURE_LENGTH]; // The version of the PROXY protocol and command being sent. uint8_t version_command; // The family for the address. uint8_t family; // The length of the address section. uint16_t length; }; class HAProxyHookProvider : public IOHookProvider { private: UserCertificateAPI sslapi; public: HAProxyHookProvider(Module* mod) : IOHookProvider(mod, "haproxy", IOHookProvider::IOH_UNKNOWN, true) , sslapi(mod) { } void OnAccept(StreamSocket* sock, irc::sockets::sockaddrs* client, irc::sockets::sockaddrs* server) CXX11_OVERRIDE; void OnConnect(StreamSocket* sock) CXX11_OVERRIDE { // We don't need to implement this. } }; // The signature for a HAProxy PROXY protocol header. static const char proxy_signature[13] = "\x0D\x0A\x0D\x0A\x00\x0D\x0A\x51\x55\x49\x54\x0A"; class HAProxyHook : public IOHookMiddle { private: // The length of the address section. uint16_t address_length; // The endpoint the client is connecting from. irc::sockets::sockaddrs client; // The command sent by the proxy server. HAProxyCommand command; // The endpoint the client is connected to. irc::sockets::sockaddrs server; // The API for interacting with user SSL internals. UserCertificateAPI& sslapi; // The current state of the PROXY parser. HAProxyState state; size_t ReadProxyTLV(StreamSocket* sock, size_t start_index, uint16_t buffer_length) { // A TLV must at least consist of a type (uint8_t) and a length (uint16_t). if (buffer_length < PP2_TLV_LENGTH) { sock->SetError("Truncated HAProxy PROXY TLV type and/or length"); return 0; } // Check that the length can actually contain the TLV value. std::string& recvq = GetRecvQ(); uint16_t length = ntohs(recvq[start_index + 1] | (recvq[start_index + 2] << 8)); if (buffer_length < PP2_TLV_LENGTH + length) { sock->SetError("Truncated HAProxy PROXY TLV value"); return 0; } // What type of TLV are we parsing? switch (recvq[start_index]) { case PP2_TYPE_SSL: if (!ReadProxyTLVSSL(sock, start_index + PP2_TLV_LENGTH, length)) return 0; break; } return PP2_TLV_LENGTH + length; } bool ReadProxyTLVSSL(StreamSocket* sock, size_t start_index, uint16_t buffer_length) { // A SSL TLV must at least consist of client info (uint8_t) and verification info (uint32_t). if (buffer_length < PP2_TYPE_SSL_LENGTH) { sock->SetError("Truncated HAProxy PROXY SSL TLV"); return false; } // If the socket is not a user socket we don't have to do // anything with this TLVs information. if (sock->type != StreamSocket::SS_USER) return true; // If the sslinfo module is not loaded we can't // do anything with this TLV. if (!sslapi) return true; // If the client is not connecting via SSL the rest of this TLV is irrelevant. std::string& recvq = GetRecvQ(); if ((recvq[start_index] & PP2_CLIENT_SSL) == 0) return true; // Create a fake ssl_cert for the user. Ideally we should use the user's // SSL client certificate here but as of 2018-10-16 this is not forwarded // by HAProxy. ssl_cert* cert = new ssl_cert; cert->error = "HAProxy does not forward client SSL certificates"; cert->invalid = true; cert->revoked = true; cert->trusted = false; cert->unknownsigner = true; // Extract the user for this socket and set their certificate. LocalUser* luser = static_cast<UserIOHandler*>(sock)->user; sslapi->SetCertificate(luser, cert); return true; } int ReadData(std::string& destrecvq) { // Once connected we handle no special data. std::string& recvq = GetRecvQ(); destrecvq.append(recvq); recvq.clear(); return 1; } int ReadProxyAddress(StreamSocket* sock, std::string& destrecvq) { // Block until we have the entire address. std::string& recvq = GetRecvQ(); if (recvq.length() < address_length) return 0; switch (command) { case HPC_LOCAL: // Skip the address completely. recvq.erase(0, address_length); break; case HPC_PROXY: // Store the endpoint information. size_t tlv_index = 0; switch (client.family()) { case AF_INET: memcpy(&client.in4.sin_addr.s_addr, &recvq[0], 4); memcpy(&server.in4.sin_addr.s_addr, &recvq[4], 4); memcpy(&client.in4.sin_port, &recvq[8], 2); memcpy(&server.in4.sin_port, &recvq[10], 2); tlv_index = 12; break; case AF_INET6: memcpy(client.in6.sin6_addr.s6_addr, &recvq[0], 16); memcpy(server.in6.sin6_addr.s6_addr, &recvq[16], 16); memcpy(&client.in6.sin6_port, &recvq[32], 2); memcpy(&server.in6.sin6_port, &recvq[34], 2); tlv_index = 36; break; case AF_UNIX: memcpy(client.un.sun_path, &recvq[0], 108); memcpy(server.un.sun_path, &recvq[108], 108); tlv_index = 216; break; } if (!sock->OnSetEndPoint(server, client)) return -1; // Parse any available TLVs. while (tlv_index < address_length) { size_t length = ReadProxyTLV(sock, tlv_index, address_length - tlv_index); if (!length) return -1; tlv_index += length; } // Erase the processed proxy information from the receive queue. recvq.erase(0, address_length); break; } // We're done! state = HPS_CONNECTED; return ReadData(destrecvq); } int ReadProxyHeader(StreamSocket* sock, std::string& destrecvq) { // Block until we have a header. std::string& recvq = GetRecvQ(); if (recvq.length() < PP2_HEADER_LENGTH) return 0; // Read the header. HAProxyHeader header; memcpy(&header, recvq.c_str(), PP2_HEADER_LENGTH); recvq.erase(0, PP2_HEADER_LENGTH); // Check we are actually parsing a HAProxy header. if (memcmp(&header.signature, proxy_signature, PP2_SIGNATURE_LENGTH) != 0) { // If we've reached this point the proxy server did not send a proxy information. sock->SetError("Invalid HAProxy PROXY signature"); return -1; } // We only support this version of the protocol. const uint8_t version = (header.version_command & PP2_VERSION_MASK); if (version != PP2_VERSION) { sock->SetError("Unsupported HAProxy PROXY protocol version"); return -1; } // We only support the LOCAL and PROXY commands. command = static_cast<HAProxyCommand>(header.version_command & PP2_COMMAND_MASK); switch (command) { case HPC_LOCAL: // Intentionally left blank. break; case HPC_PROXY: // Check the protocol support and initialise the sockaddrs. uint16_t shortest_length; switch (header.family) { case PP2_FAMILY_IPV4: // TCP over IPv4. client.sa.sa_family = server.sa.sa_family = AF_INET; shortest_length = PP2_FAMILY_IPV4_LENGTH; break; case PP2_FAMILY_IPV6: // TCP over IPv6. client.sa.sa_family = server.sa.sa_family = AF_INET6; shortest_length = PP2_FAMILY_IPV6_LENGTH; break; case PP2_FAMILY_UNIX: // UNIX stream. client.sa.sa_family = server.sa.sa_family = AF_UNIX; shortest_length = PP2_FAMILY_UNIX_LENGTH; break; default: // Unknown protocol. sock->SetError("Invalid HAProxy PROXY protocol type"); return -1; } // Check that the length can actually contain the addresses. address_length = ntohs(header.length); if (address_length < shortest_length) { sock->SetError("Truncated HAProxy PROXY address section"); return -1; } break; default: sock->SetError("Unsupported HAProxy PROXY command"); return -1; } state = HPS_WAITING_FOR_ADDRESS; return ReadProxyAddress(sock, destrecvq); } public: HAProxyHook(IOHookProvider* Prov, StreamSocket* sock, UserCertificateAPI& api) : IOHookMiddle(Prov) , address_length(0) , sslapi(api) , state(HPS_WAITING_FOR_HEADER) { sock->AddIOHook(this); } int OnStreamSocketWrite(StreamSocket* sock, StreamSocket::SendQueue& uppersendq) CXX11_OVERRIDE { // We don't need to implement this. GetSendQ().moveall(uppersendq); return 1; } int OnStreamSocketRead(StreamSocket* sock, std::string& destrecvq) CXX11_OVERRIDE { switch (state) { case HPS_WAITING_FOR_HEADER: return ReadProxyHeader(sock, destrecvq); case HPS_WAITING_FOR_ADDRESS: return ReadProxyAddress(sock, destrecvq); case HPS_CONNECTED: return ReadData(destrecvq); } // We should never reach this point. return -1; } void OnStreamSocketClose(StreamSocket* sock) CXX11_OVERRIDE { // We don't need to implement this. } }; void HAProxyHookProvider::OnAccept(StreamSocket* sock, irc::sockets::sockaddrs* client, irc::sockets::sockaddrs* server) { new HAProxyHook(this, sock, sslapi); } class ModuleHAProxy : public Module { private: reference<HAProxyHookProvider> hookprov; public: ModuleHAProxy() : hookprov(new HAProxyHookProvider(this)) { } Version GetVersion() CXX11_OVERRIDE { return Version("Provides support for the HAProxy PROXY protocol", VF_VENDOR); } }; MODULE_INIT(ModuleHAProxy) �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/src/modules/m_helpop.cpp�������������������������������������������������������������0000664�0000000�0000000�00000010764�13554550454�0020121�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * InspIRCd -- Internet Relay Chat Daemon * * Copyright (C) 2009 Daniel De Graaf <danieldg@inspircd.org> * Copyright (C) 2005-2009 Robin Burchell <robin+git@viroteck.net> * Copyright (C) 2004-2006, 2008 Craig Edwards <craigedwards@brainbox.cc> * Copyright (C) 2007 Dennis Friis <peavey@inspircd.org> * Copyright (C) 2004-2005 Craig McLure <craig@chatspike.net> * * 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 "inspircd.h" #include "modules/whois.h" enum { // From UnrealIRCd. RPL_WHOISHELPOP = 310, // From ircd-ratbox. ERR_HELPNOTFOUND = 524, RPL_HELPSTART = 704, RPL_HELPTXT = 705, RPL_ENDOFHELP = 706 }; typedef std::map<std::string, std::string, irc::insensitive_swo> HelpopMap; static HelpopMap helpop_map; /** Handles user mode +h */ class Helpop : public SimpleUserModeHandler { public: Helpop(Module* Creator) : SimpleUserModeHandler(Creator, "helpop", 'h') { oper = true; } }; /** Handles /HELPOP */ class CommandHelpop : public Command { private: const std::string startkey; public: std::string nohelp; CommandHelpop(Module* Creator) : Command(Creator, "HELPOP", 0) , startkey("start") { syntax = "<any-text>"; } CmdResult Handle(User* user, const Params& parameters) CXX11_OVERRIDE { const std::string& parameter = (!parameters.empty() ? parameters[0] : startkey); if (parameter == "index") { /* iterate over all helpop items */ user->WriteNumeric(RPL_HELPSTART, parameter, "HELPOP topic index"); for (HelpopMap::const_iterator iter = helpop_map.begin(); iter != helpop_map.end(); iter++) user->WriteNumeric(RPL_HELPTXT, parameter, InspIRCd::Format(" %s", iter->first.c_str())); user->WriteNumeric(RPL_ENDOFHELP, parameter, "*** End of HELPOP topic index"); } else { HelpopMap::const_iterator iter = helpop_map.find(parameter); if (iter == helpop_map.end()) { user->WriteNumeric(ERR_HELPNOTFOUND, parameter, nohelp); return CMD_FAILURE; } const std::string& value = iter->second; irc::sepstream stream(value, '\n', true); std::string token = "*"; user->WriteNumeric(RPL_HELPSTART, parameter, InspIRCd::Format("*** HELPOP for %s", parameter.c_str())); while (stream.GetToken(token)) { // Writing a blank line will not work with some clients if (token.empty()) user->WriteNumeric(RPL_HELPTXT, parameter, ' '); else user->WriteNumeric(RPL_HELPTXT, parameter, token); } user->WriteNumeric(RPL_ENDOFHELP, parameter, "*** End of HELPOP"); } return CMD_SUCCESS; } }; class ModuleHelpop : public Module, public Whois::EventListener { CommandHelpop cmd; Helpop ho; public: ModuleHelpop() : Whois::EventListener(this) , cmd(this) , ho(this) { } void ReadConfig(ConfigStatus& status) CXX11_OVERRIDE { HelpopMap help; ConfigTagList tags = ServerInstance->Config->ConfTags("helpop"); for(ConfigIter i = tags.first; i != tags.second; ++i) { ConfigTag* tag = i->second; std::string key = tag->getString("key"); std::string value; tag->readString("value", value, true); /* Linefeeds allowed */ if (key == "index") { throw ModuleException("m_helpop: The key 'index' is reserved for internal purposes. Please remove it."); } help[key] = value; } if (help.find("start") == help.end()) { // error! throw ModuleException("m_helpop: Helpop file is missing important entry 'start'. Please check the example conf."); } helpop_map.swap(help); ConfigTag* tag = ServerInstance->Config->ConfValue("helpmsg"); cmd.nohelp = tag->getString("nohelp", "There is no help for the topic you searched for. Please try again.", 1); } void OnWhois(Whois::Context& whois) CXX11_OVERRIDE { if (whois.GetTarget()->IsModeSet(ho)) { whois.SendLine(RPL_WHOISHELPOP, "is available for help."); } } Version GetVersion() CXX11_OVERRIDE { return Version("Provides the HELPOP command for useful information", VF_VENDOR); } }; MODULE_INIT(ModuleHelpop) ������������inspircd-3.4.0/src/modules/m_hidechans.cpp����������������������������������������������������������0000664�0000000�0000000�00000004235�13554550454�0020554�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * InspIRCd -- Internet Relay Chat Daemon * * Copyright (C) 2006-2008 Robin Burchell <robin+git@viroteck.net> * Copyright (C) 2007 Dennis Friis <peavey@inspircd.org> * * This file is part of InspIRCd. InspIRCd is free software: you can * redistribute it and/or modify it under the terms of the GNU General Public * License as published by the Free Software Foundation, version 2. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include "inspircd.h" #include "modules/whois.h" /** Handles user mode +I */ class HideChans : public SimpleUserModeHandler { public: HideChans(Module* Creator) : SimpleUserModeHandler(Creator, "hidechans", 'I') { } }; class ModuleHideChans : public Module, public Whois::LineEventListener { bool AffectsOpers; HideChans hm; public: ModuleHideChans() : Whois::LineEventListener(this) , hm(this) { } Version GetVersion() CXX11_OVERRIDE { return Version("Provides support for hiding channels with user mode +I", VF_VENDOR); } void ReadConfig(ConfigStatus& status) CXX11_OVERRIDE { AffectsOpers = ServerInstance->Config->ConfValue("hidechans")->getBool("affectsopers"); } ModResult OnWhoisLine(Whois::Context& whois, Numeric::Numeric& numeric) CXX11_OVERRIDE { /* always show to self */ if (whois.IsSelfWhois()) return MOD_RES_PASSTHRU; /* don't touch anything except 319 */ if (numeric.GetNumeric() != 319) return MOD_RES_PASSTHRU; /* don't touch if -I */ if (!whois.GetTarget()->IsModeSet(hm)) return MOD_RES_PASSTHRU; /* if it affects opers, we don't care if they are opered */ if (AffectsOpers) return MOD_RES_DENY; /* doesn't affect opers, sender is opered */ if (whois.GetSource()->HasPrivPermission("users/auspex")) return MOD_RES_PASSTHRU; /* user must be opered, boned. */ return MOD_RES_DENY; } }; MODULE_INIT(ModuleHideChans) �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/src/modules/m_hidelist.cpp�����������������������������������������������������������0000664�0000000�0000000�00000005500�13554550454�0020427�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * InspIRCd -- Internet Relay Chat Daemon * * Copyright (C) 2014 Attila Molnar <attilamolnar@hush.com> * * This file is part of InspIRCd. InspIRCd is free software: you can * redistribute it and/or modify it under the terms of the GNU General Public * License as published by the Free Software Foundation, version 2. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include "inspircd.h" class ListWatcher : public ModeWatcher { // Minimum rank required to view the list const unsigned int minrank; public: ListWatcher(Module* mod, const std::string& modename, unsigned int rank) : ModeWatcher(mod, modename, MODETYPE_CHANNEL) , minrank(rank) { } bool BeforeMode(User* user, User* destuser, Channel* chan, std::string& param, bool adding) CXX11_OVERRIDE { // Only handle listmode list requests if (!param.empty()) return true; // If the user requesting the list is a member of the channel see if they have the // rank required to view the list Membership* memb = chan->GetUser(user); if ((memb) && (memb->getRank() >= minrank)) return true; if (user->HasPrivPermission("channels/auspex")) return true; user->WriteNumeric(ERR_CHANOPRIVSNEEDED, chan->name, InspIRCd::Format("You do not have access to view the %s list", GetModeName().c_str())); return false; } }; class ModuleHideList : public Module { std::vector<ListWatcher*> watchers; public: void ReadConfig(ConfigStatus& status) CXX11_OVERRIDE { ConfigTagList tags = ServerInstance->Config->ConfTags("hidelist"); typedef std::vector<std::pair<std::string, unsigned int> > NewConfigs; NewConfigs newconfigs; for (ConfigIter i = tags.first; i != tags.second; ++i) { ConfigTag* tag = i->second; std::string modename = tag->getString("mode"); if (modename.empty()) throw ModuleException("Empty <hidelist:mode> at " + tag->getTagLocation()); // If rank is set to 0 everyone inside the channel can view the list, // but non-members may not unsigned int rank = tag->getUInt("rank", HALFOP_VALUE); newconfigs.push_back(std::make_pair(modename, rank)); } stdalgo::delete_all(watchers); watchers.clear(); for (NewConfigs::const_iterator i = newconfigs.begin(); i != newconfigs.end(); ++i) watchers.push_back(new ListWatcher(this, i->first, i->second)); } ~ModuleHideList() { stdalgo::delete_all(watchers); } Version GetVersion() CXX11_OVERRIDE { return Version("Provides support for hiding the list of listmodes", VF_VENDOR); } }; MODULE_INIT(ModuleHideList) ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/src/modules/m_hidemode.cpp�����������������������������������������������������������0000664�0000000�0000000�00000014366�13554550454�0020412�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * InspIRCd -- Internet Relay Chat Daemon * * Copyright (C) 2016 Attila Molnar <attilamolnar@hush.com> * * This file is part of InspIRCd. InspIRCd is free software: you can * redistribute it and/or modify it under the terms of the GNU General Public * License as published by the Free Software Foundation, version 2. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include "inspircd.h" namespace { class Settings { typedef insp::flat_map<std::string, unsigned int> RanksToSeeMap; RanksToSeeMap rankstosee; public: unsigned int GetRequiredRank(const ModeHandler& mh) const { RanksToSeeMap::const_iterator it = rankstosee.find(mh.name); if (it != rankstosee.end()) return it->second; return 0; } void Load() { RanksToSeeMap newranks; ConfigTagList tags = ServerInstance->Config->ConfTags("hidemode"); for (ConfigIter i = tags.first; i != tags.second; ++i) { ConfigTag* tag = i->second; const std::string modename = tag->getString("mode"); if (modename.empty()) throw ModuleException("<hidemode:mode> is empty at " + tag->getTagLocation()); unsigned int rank = tag->getUInt("rank", 0); if (!rank) throw ModuleException("<hidemode:rank> must be greater than 0 at " + tag->getTagLocation()); ServerInstance->Logs->Log(MODNAME, LOG_DEBUG, "Hiding the %s mode from users below rank %u", modename.c_str(), rank); newranks.insert(std::make_pair(modename, rank)); } rankstosee.swap(newranks); } }; class ModeHook : public ClientProtocol::EventHook { typedef insp::flat_map<unsigned int, const ClientProtocol::MessageList*> FilteredModeMap; std::vector<Modes::ChangeList> modechangelists; std::list<ClientProtocol::Messages::Mode> filteredmodelist; std::list<ClientProtocol::MessageList> filteredmsgplists; FilteredModeMap cache; static ModResult HandleResult(const ClientProtocol::MessageList* filteredmessagelist, ClientProtocol::MessageList& messagelist) { // Deny if member isn't allowed to see even a single mode change from this mode event if (!filteredmessagelist) return MOD_RES_DENY; // Member is allowed to see at least one mode change, replace list if (filteredmessagelist != &messagelist) messagelist = *filteredmessagelist; return MOD_RES_PASSTHRU; } Modes::ChangeList* FilterModeChangeList(const ClientProtocol::Events::Mode& mode, unsigned int rank) { Modes::ChangeList* modechangelist = NULL; for (Modes::ChangeList::List::const_iterator i = mode.GetChangeList().getlist().begin(); i != mode.GetChangeList().getlist().end(); ++i) { const Modes::Change& curr = *i; if (settings.GetRequiredRank(*curr.mh) <= rank) { // No restriction on who can see this mode or there is one but the member's rank is sufficient if (modechangelist) modechangelist->push(curr); continue; } // Member cannot see the current mode change if (!modechangelist) { // Create new mode change list or reuse the last one if it's empty if ((modechangelists.empty()) || (!modechangelists.back().empty())) modechangelists.push_back(Modes::ChangeList()); // Add all modes to it which we've accepted so far modechangelists.back().push(mode.GetChangeList().getlist().begin(), i); modechangelist = &modechangelists.back(); } } return modechangelist; } void OnEventInit(const ClientProtocol::Event& ev) CXX11_OVERRIDE { cache.clear(); filteredmsgplists.clear(); filteredmodelist.clear(); modechangelists.clear(); // Ensure no reallocations will happen const size_t numprefixmodes = ServerInstance->Modes.GetPrefixModes().size(); modechangelists.reserve(numprefixmodes); } ModResult OnPreEventSend(LocalUser* user, const ClientProtocol::Event& ev, ClientProtocol::MessageList& messagelist) CXX11_OVERRIDE { const ClientProtocol::Events::Mode& mode = static_cast<const ClientProtocol::Events::Mode&>(ev); Channel* const chan = mode.GetMessages().front().GetChanTarget(); if (!chan) return MOD_RES_PASSTHRU; if (user->HasPrivPermission("channels/auspex")) return MOD_RES_PASSTHRU; Membership* const memb = chan->GetUser(user); if (!memb) return MOD_RES_PASSTHRU; // Check cache first const FilteredModeMap::const_iterator it = cache.find(memb->getRank()); if (it != cache.end()) return HandleResult(it->second, messagelist); // Message for this rank isn't cached, generate it now const Modes::ChangeList* const filteredchangelist = FilterModeChangeList(mode, memb->getRank()); // If no new change list was generated (above method returned NULL) it means the member and everyone else // with the same rank can see everything in the original change list. ClientProtocol::MessageList* finalmsgplist = &messagelist; if (filteredchangelist) { if (filteredchangelist->empty()) { // This rank cannot see any mode changes in the original change list finalmsgplist = NULL; } else { // This rank can see some of the mode changes in the filtered mode change list. // Create and store a new protocol message from it. filteredmsgplists.push_back(ClientProtocol::MessageList()); ClientProtocol::Events::Mode::BuildMessages(mode.GetMessages().front().GetSourceUser(), chan, NULL, *filteredchangelist, filteredmodelist, filteredmsgplists.back()); finalmsgplist = &filteredmsgplists.back(); } } // Cache the result in all cases so it can be reused for further members with the same rank cache.insert(std::make_pair(memb->getRank(), finalmsgplist)); return HandleResult(finalmsgplist, messagelist); } public: Settings settings; ModeHook(Module* mod) : ClientProtocol::EventHook(mod, "MODE", 10) { } }; } class ModuleHideMode : public Module { private: ModeHook modehook; public: ModuleHideMode() : modehook(this) { } void ReadConfig(ConfigStatus& status) CXX11_OVERRIDE { modehook.settings.Load(); } Version GetVersion() CXX11_OVERRIDE { return Version("Provides support for hiding mode changes", VF_VENDOR); } }; MODULE_INIT(ModuleHideMode) ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/src/modules/m_hideoper.cpp�����������������������������������������������������������0000664�0000000�0000000�00000011211�13554550454�0020415�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * InspIRCd -- Internet Relay Chat Daemon * * Copyright (C) 2007 Dennis Friis <peavey@inspircd.org> * Copyright (C) 2007 Robin Burchell <robin+git@viroteck.net> * Copyright (C) 2006 Craig Edwards <craigedwards@brainbox.cc> * * This file is part of InspIRCd. InspIRCd is free software: you can * redistribute it and/or modify it under the terms of the GNU General Public * License as published by the Free Software Foundation, version 2. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include "inspircd.h" #include "modules/stats.h" #include "modules/who.h" #include "modules/whois.h" /** Handles user mode +H */ 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) CXX11_OVERRIDE { 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 , public Stats::EventListener , public Who::EventListener , public Whois::LineEventListener { private: HideOper hm; bool active; public: ModuleHideOper() : Stats::EventListener(this) , Who::EventListener(this) , Whois::LineEventListener(this) , hm(this) , active(false) { } Version GetVersion() CXX11_OVERRIDE { return Version("Provides support for hiding oper status with user mode +H", VF_VENDOR); } void OnUserQuit(User* user, const std::string&, const std::string&) CXX11_OVERRIDE { if (user->IsModeSet(hm)) hm.opercount--; } ModResult OnNumeric(User* user, const Numeric::Numeric& numeric) CXX11_OVERRIDE { if (numeric.GetNumeric() != RPL_LUSEROP || 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(RPL_LUSEROP, opercount, "operator(s) online"); active = false; } return MOD_RES_DENY; } ModResult OnWhoisLine(Whois::Context& whois, Numeric::Numeric& numeric) CXX11_OVERRIDE { /* Dont display numeric 313 (RPL_WHOISOPER) if they have +H set and the * person doing the WHOIS is not an oper */ if (numeric.GetNumeric() != 313) return MOD_RES_PASSTHRU; if (!whois.GetTarget()->IsModeSet(hm)) return MOD_RES_PASSTHRU; if (!whois.GetSource()->HasPrivPermission("users/auspex")) return MOD_RES_DENY; return MOD_RES_PASSTHRU; } ModResult OnWhoLine(const Who::Request& request, LocalUser* source, User* user, Membership* memb, Numeric::Numeric& numeric) CXX11_OVERRIDE { if (user->IsModeSet(hm) && !source->HasPrivPermission("users/auspex")) { // Hide the line completely if doing a "/who * o" query if (request.flags['o']) return MOD_RES_DENY; size_t flag_index; if (!request.GetFieldIndex('f', flag_index)) return MOD_RES_PASSTHRU; // hide the "*" that marks the user as an oper from the /WHO line // #chan ident localhost insp22.test nick H@ :0 Attila if (numeric.GetParams().size() <= flag_index) return MOD_RES_PASSTHRU; std::string& param = numeric.GetParams()[flag_index]; const std::string::size_type pos = param.find('*'); if (pos != std::string::npos) param.erase(pos, 1); } return MOD_RES_PASSTHRU; } ModResult OnStats(Stats::Context& stats) CXX11_OVERRIDE { if (stats.GetSymbol() != 'P') return MOD_RES_PASSTHRU; unsigned int count = 0; const UserManager::OperList& opers = ServerInstance->Users->all_opers; for (UserManager::OperList::const_iterator i = opers.begin(); i != opers.end(); ++i) { User* oper = *i; if (!oper->server->IsULine() && (stats.GetSource()->IsOper() || !oper->IsModeSet(hm))) { LocalUser* lu = IS_LOCAL(oper); stats.AddRow(249, oper->nick + " (" + oper->ident + "@" + oper->GetDisplayedHost() + ") Idle: " + (lu ? ConvToStr(ServerInstance->Time() - lu->idle_lastmsg) + " secs" : "unavailable")); count++; } } stats.AddRow(249, ConvToStr(count)+" OPER(s)"); return MOD_RES_DENY; } }; MODULE_INIT(ModuleHideOper) ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/src/modules/m_hostchange.cpp���������������������������������������������������������0000664�0000000�0000000�00000014577�13554550454�0020763�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * InspIRCd -- Internet Relay Chat Daemon * * Copyright (C) 2005-2007 Craig Edwards <craigedwards@brainbox.cc> * Copyright (C) 2007 Dennis Friis <peavey@inspircd.org> * Copyright (C) 2007 Robin Burchell <robin+git@viroteck.net> * * 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 "inspircd.h" #include "modules/account.h" // Holds information about a <hostchange> rule. class HostRule { public: enum HostChangeAction { // Add the user's account name to their hostname. HCA_ADDACCOUNT, // Add the user's nickname to their hostname. HCA_ADDNICK, // Set the user's hostname to the specific value. HCA_SET }; private: HostChangeAction action; std::string host; std::string mask; insp::flat_set<int> ports; std::string prefix; std::string suffix; public: HostRule(const std::string& Mask, const std::string& Host, const insp::flat_set<int>& Ports) : action(HCA_SET) , host(Host) , mask(Mask) , ports(Ports) { } HostRule(HostChangeAction Action, const std::string& Mask, const insp::flat_set<int>& Ports, const std::string& Prefix, const std::string& Suffix) : action(Action) , mask(Mask) , ports(Ports) , prefix(Prefix) , suffix(Suffix) { } HostChangeAction GetAction() const { return action; } const std::string& GetHost() const { return host; } bool Matches(LocalUser* user) const { if (!ports.empty() && !ports.count(user->server_sa.port())) return false; if (InspIRCd::MatchCIDR(user->MakeHost(), mask)) return true; return InspIRCd::MatchCIDR(user->MakeHostIP(), mask); } void Wrap(const std::string& value, std::string& out) const { if (!prefix.empty()) out.append(prefix); out.append(value); if (!suffix.empty()) out.append(suffix); } }; typedef std::vector<HostRule> HostRules; class ModuleHostChange : public Module { private: std::bitset<UCHAR_MAX> hostmap; HostRules hostrules; std::string CleanName(const std::string& name) { std::string buffer; buffer.reserve(name.length()); for (std::string::const_iterator iter = name.begin(); iter != name.end(); ++iter) { if (hostmap.test(static_cast<unsigned char>(*iter))) { buffer.push_back(*iter); } } return buffer; } public: void ReadConfig(ConfigStatus& status) CXX11_OVERRIDE { HostRules rules; ConfigTagList tags = ServerInstance->Config->ConfTags("hostchange"); for (ConfigIter i = tags.first; i != tags.second; ++i) { ConfigTag* tag = i->second; // Ensure that we have the <hostchange:mask> parameter. const std::string mask = tag->getString("mask"); if (mask.empty()) throw ModuleException("<hostchange:mask> is a mandatory field, at " + tag->getTagLocation()); insp::flat_set<int> ports; const std::string portlist = tag->getString("ports"); if (!ports.empty()) { irc::portparser portrange(portlist, false); while (int port = portrange.GetToken()) ports.insert(port); } // Determine what type of host rule this is. const std::string action = tag->getString("action"); if (stdalgo::string::equalsci(action, "addaccount")) { // The hostname is in the format [prefix]<account>[suffix]. rules.push_back(HostRule(HostRule::HCA_ADDACCOUNT, mask, ports, tag->getString("prefix"), tag->getString("suffix"))); } else if (stdalgo::string::equalsci(action, "addnick")) { // The hostname is in the format [prefix]<nick>[suffix]. rules.push_back(HostRule(HostRule::HCA_ADDNICK, mask, ports, tag->getString("prefix"), tag->getString("suffix"))); } else if (stdalgo::string::equalsci(action, "set")) { // Ensure that we have the <hostchange:value> parameter. const std::string value = tag->getString("value"); if (value.empty()) throw ModuleException("<hostchange:value> is a mandatory field when using the 'set' action, at " + tag->getTagLocation()); // The hostname is in the format <value>. rules.push_back(HostRule(mask, value, ports)); continue; } else { throw ModuleException(action + " is an invalid <hostchange:action> type, at " + tag->getTagLocation()); } } const std::string hmap = ServerInstance->Config->ConfValue("hostname")->getString("charmap", "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz.-_/0123456789"); hostmap.reset(); for (std::string::const_iterator iter = hmap.begin(); iter != hmap.end(); ++iter) hostmap.set(static_cast<unsigned char>(*iter)); hostrules.swap(rules); } Version GetVersion() CXX11_OVERRIDE { return Version("Provides rule-based masking of user hostnames", VF_VENDOR); } void OnUserConnect(LocalUser* user) CXX11_OVERRIDE { for (HostRules::const_iterator iter = hostrules.begin(); iter != hostrules.end(); ++iter) { const HostRule& rule = *iter; if (!rule.Matches(user)) continue; std::string newhost; if (rule.GetAction() == HostRule::HCA_ADDACCOUNT) { // Retrieve the account name. const AccountExtItem* accountext = GetAccountExtItem(); const std::string* accountptr = accountext ? accountext->get(user) : NULL; if (!accountptr) continue; // Remove invalid hostname characters. std::string accountname = CleanName(*accountptr); if (accountname.empty()) continue; // Create the hostname. rule.Wrap(accountname, newhost); } else if (rule.GetAction() == HostRule::HCA_ADDNICK) { // Remove invalid hostname characters. const std::string nickname = CleanName(user->nick); if (nickname.empty()) continue; // Create the hostname. rule.Wrap(nickname, newhost); } else if (rule.GetAction() == HostRule::HCA_SET) { newhost.assign(rule.GetHost()); } if (!newhost.empty()) { user->WriteNotice("Setting your virtual host: " + newhost); if (!user->ChangeDisplayedHost(newhost)) user->WriteNotice("Could not set your virtual host: " + newhost); return; } } } }; MODULE_INIT(ModuleHostChange) ���������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/src/modules/m_hostcycle.cpp����������������������������������������������������������0000664�0000000�0000000�00000006655�13554550454�0020633�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * InspIRCd -- Internet Relay Chat Daemon * * Copyright (C) 2013 Attila Molnar <attilamolnar@hush.com> * 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 * 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 "inspircd.h" #include "modules/cap.h" class ModuleHostCycle : public Module { Cap::Reference chghostcap; const std::string quitmsghost; const std::string quitmsgident; /** Send fake quit/join/mode messages for host or ident cycle. */ void DoHostCycle(User* user, const std::string& newident, const std::string& newhost, const std::string& reason) { // The user has the original ident/host at the time this function is called ClientProtocol::Messages::Quit quitmsg(user, reason); ClientProtocol::Event quitevent(ServerInstance->GetRFCEvents().quit, quitmsg); already_sent_t silent_id = ServerInstance->Users.NextAlreadySentId(); already_sent_t seen_id = ServerInstance->Users.NextAlreadySentId(); IncludeChanList include_chans(user->chans.begin(), user->chans.end()); std::map<User*,bool> exceptions; FOREACH_MOD(OnBuildNeighborList, (user, include_chans, exceptions)); // Users shouldn't see themselves quitting when host cycling exceptions.erase(user); for (std::map<User*,bool>::iterator i = exceptions.begin(); i != exceptions.end(); ++i) { LocalUser* u = IS_LOCAL(i->first); if ((u) && (!u->quitting) && (!chghostcap.get(u))) { if (i->second) { u->already_sent = seen_id; u->Send(quitevent); } else { u->already_sent = silent_id; } } } std::string newfullhost = user->nick + "!" + newident + "@" + newhost; for (IncludeChanList::const_iterator i = include_chans.begin(); i != include_chans.end(); ++i) { Membership* memb = *i; Channel* c = memb->chan; ClientProtocol::Events::Join joinevent(memb, newfullhost); const Channel::MemberMap& ulist = c->GetUsers(); for (Channel::MemberMap::const_iterator j = ulist.begin(); j != ulist.end(); ++j) { LocalUser* u = IS_LOCAL(j->first); if (u == NULL || u == user) continue; if (u->already_sent == silent_id) continue; if (chghostcap.get(u)) continue; if (u->already_sent != seen_id) { u->Send(quitevent); u->already_sent = seen_id; } u->Send(joinevent); } } } public: ModuleHostCycle() : chghostcap(this, "chghost") , quitmsghost("Changing host") , quitmsgident("Changing ident") { } void OnChangeIdent(User* user, const std::string& newident) CXX11_OVERRIDE { DoHostCycle(user, newident, user->GetDisplayedHost(), quitmsgident); } void OnChangeHost(User* user, const std::string& newhost) CXX11_OVERRIDE { DoHostCycle(user, user->ident, newhost, quitmsghost); } Version GetVersion() CXX11_OVERRIDE { return Version("Cycles users in all their channels when their host or ident changes", VF_VENDOR); } }; MODULE_INIT(ModuleHostCycle) �����������������������������������������������������������������������������������inspircd-3.4.0/src/modules/m_httpd.cpp��������������������������������������������������������������0000664�0000000�0000000�00000026313�13554550454�0017752�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * InspIRCd -- Internet Relay Chat Daemon * * Copyright (C) 2009 Daniel De Graaf <danieldg@inspircd.org> * Copyright (C) 2007-2008 Robin Burchell <robin+git@viroteck.net> * Copyright (C) 2008 Pippijn van Steenhoven <pip88nl@gmail.com> * Copyright (C) 2006-2008 Craig Edwards <craigedwards@brainbox.cc> * Copyright (C) 2007 John Brooks <john.brooks@dereferenced.net> * Copyright (C) 2007 Dennis Friis <peavey@inspircd.org> * * This file is part of InspIRCd. InspIRCd is free software: you can * redistribute it and/or modify it under the terms of the GNU General Public * License as published by the Free Software Foundation, version 2. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ /// $CompilerFlags: -Ivendor_directory("http_parser") #include "inspircd.h" #include "iohook.h" #include "modules/httpd.h" #ifdef __GNUC__ # pragma GCC diagnostic push #endif // Fix warnings about the use of commas at end of enumerator lists and long long // on C++03. #if defined __clang__ # pragma clang diagnostic ignored "-Wc++11-extensions" # pragma clang diagnostic ignored "-Wc++11-long-long" #elif defined __GNUC__ # pragma GCC diagnostic ignored "-Wlong-long" # if (__GNUC__ > 4) || ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 8)) # pragma GCC diagnostic ignored "-Wpedantic" # else # pragma GCC diagnostic ignored "-pedantic" # endif #endif // Fix warnings about shadowing in http_parser. #ifdef __GNUC__ # pragma GCC diagnostic ignored "-Wshadow" #endif #include <http_parser.c> #ifdef __GNUC__ # pragma GCC diagnostic pop #endif class ModuleHttpServer; static ModuleHttpServer* HttpModule; static insp::intrusive_list<HttpServerSocket> sockets; static Events::ModuleEventProvider* aclevprov; static Events::ModuleEventProvider* reqevprov; static http_parser_settings parser_settings; /** A socket used for HTTP transport */ class HttpServerSocket : public BufferedSocket, public Timer, public insp::intrusive_list_node<HttpServerSocket> { private: friend class ModuleHttpServer; http_parser parser; http_parser_url url; std::string ip; std::string uri; HTTPHeaders headers; std::string body; size_t total_buffers; int status_code; /** True if this object is in the cull list */ bool waitingcull; bool messagecomplete; bool Tick(time_t currtime) CXX11_OVERRIDE { if (!messagecomplete) { AddToCull(); return false; } return true; } template<int (HttpServerSocket::*f)()> static int Callback(http_parser* p) { HttpServerSocket* sock = static_cast<HttpServerSocket*>(p->data); return (sock->*f)(); } template<int (HttpServerSocket::*f)(const char*, size_t)> static int DataCallback(http_parser* p, const char* buf, size_t len) { HttpServerSocket* sock = static_cast<HttpServerSocket*>(p->data); return (sock->*f)(buf, len); } static void ConfigureParser() { http_parser_settings_init(&parser_settings); parser_settings.on_message_begin = Callback<&HttpServerSocket::OnMessageBegin>; parser_settings.on_url = DataCallback<&HttpServerSocket::OnUrl>; parser_settings.on_header_field = DataCallback<&HttpServerSocket::OnHeaderField>; parser_settings.on_body = DataCallback<&HttpServerSocket::OnBody>; parser_settings.on_message_complete = Callback<&HttpServerSocket::OnMessageComplete>; } int OnMessageBegin() { uri.clear(); header_state = HEADER_NONE; body.clear(); total_buffers = 0; return 0; } bool AcceptData(size_t len) { total_buffers += len; return total_buffers < 8192; } int OnUrl(const char* buf, size_t len) { if (!AcceptData(len)) { status_code = HTTP_STATUS_URI_TOO_LONG; return -1; } uri.append(buf, len); return 0; } enum { HEADER_NONE, HEADER_FIELD, HEADER_VALUE } header_state; std::string header_field; std::string header_value; void OnHeaderComplete() { headers.SetHeader(header_field, header_value); header_field.clear(); header_value.clear(); } int OnHeaderField(const char* buf, size_t len) { if (header_state == HEADER_VALUE) OnHeaderComplete(); header_state = HEADER_FIELD; if (!AcceptData(len)) { status_code = HTTP_STATUS_REQUEST_HEADER_FIELDS_TOO_LARGE; return -1; } header_field.append(buf, len); return 0; } int OnHeaderValue(const char* buf, size_t len) { header_state = HEADER_VALUE; if (!AcceptData(len)) { status_code = HTTP_STATUS_REQUEST_HEADER_FIELDS_TOO_LARGE; return -1; } header_value.append(buf, len); return 0; } int OnHeadersComplete() { if (header_state != HEADER_NONE) OnHeaderComplete(); return 0; } int OnBody(const char* buf, size_t len) { if (!AcceptData(len)) { status_code = HTTP_STATUS_PAYLOAD_TOO_LARGE; return -1; } body.append(buf, len); return 0; } int OnMessageComplete() { messagecomplete = true; ServeData(); return 0; } public: HttpServerSocket(int newfd, const std::string& IP, ListenSocket* via, irc::sockets::sockaddrs* client, irc::sockets::sockaddrs* server, unsigned int timeoutsec) : BufferedSocket(newfd) , Timer(timeoutsec) , ip(IP) , status_code(0) , waitingcull(false) , messagecomplete(false) { if ((!via->iohookprovs.empty()) && (via->iohookprovs.back())) { via->iohookprovs.back()->OnAccept(this, client, server); // IOHook may have errored if (!getError().empty()) { AddToCull(); return; } } parser.data = this; http_parser_init(&parser, HTTP_REQUEST); ServerInstance->Timers.AddTimer(this); } ~HttpServerSocket() { sockets.erase(this); } void OnError(BufferedSocketError) CXX11_OVERRIDE { AddToCull(); } void SendHTTPError(unsigned int response) { HTTPHeaders empty; std::string data = InspIRCd::Format( "<html><head></head><body>Server error %u: %s<br>" "<small>Powered by <a href='https://www.inspircd.org'>InspIRCd</a></small></body></html>", response, http_status_str((http_status)response)); Page(data, response, &empty); } void SendHeaders(unsigned long size, unsigned int response, HTTPHeaders &rheaders) { WriteData(InspIRCd::Format("HTTP/%u.%u %u %s\r\n", parser.http_major ? parser.http_major : 1, parser.http_major ? parser.http_minor : 1, response, http_status_str((http_status)response))); rheaders.CreateHeader("Date", InspIRCd::TimeString(ServerInstance->Time(), "%a, %d %b %Y %H:%M:%S GMT", true)); rheaders.CreateHeader("Server", INSPIRCD_BRANCH); rheaders.SetHeader("Content-Length", ConvToStr(size)); if (size) rheaders.CreateHeader("Content-Type", "text/html"); else rheaders.RemoveHeader("Content-Type"); /* Supporting Connection: keep-alive causes a whole world of hurt syncronizing timeouts, * so remove it, its not essential for what we need. */ rheaders.SetHeader("Connection", "Close"); WriteData(rheaders.GetFormattedHeaders()); WriteData("\r\n"); } void OnDataReady() CXX11_OVERRIDE { if (parser.upgrade || HTTP_PARSER_ERRNO(&parser)) return; http_parser_execute(&parser, &parser_settings, recvq.data(), recvq.size()); if (parser.upgrade || HTTP_PARSER_ERRNO(&parser)) SendHTTPError(status_code ? status_code : 400); } void ServeData() { ModResult MOD_RESULT; std::string method = http_method_str(static_cast<http_method>(parser.method)); HTTPRequestURI parsed; ParseURI(uri, parsed); HTTPRequest acl(method, parsed, &headers, this, ip, body); FIRST_MOD_RESULT_CUSTOM(*aclevprov, HTTPACLEventListener, OnHTTPACLCheck, MOD_RESULT, (acl)); if (MOD_RESULT != MOD_RES_DENY) { HTTPRequest request(method, parsed, &headers, this, ip, body); FIRST_MOD_RESULT_CUSTOM(*reqevprov, HTTPRequestEventListener, OnHTTPRequest, MOD_RESULT, (request)); if (MOD_RESULT == MOD_RES_PASSTHRU) { SendHTTPError(404); } } } void Page(const std::string& s, unsigned int response, HTTPHeaders* hheaders) { SendHeaders(s.length(), response, *hheaders); WriteData(s); Close(true); } void Page(std::stringstream* n, unsigned int response, HTTPHeaders* hheaders) { Page(n->str(), response, hheaders); } void AddToCull() { if (waitingcull) return; waitingcull = true; Close(); ServerInstance->GlobalCulls.AddItem(this); } bool ParseURI(const std::string& uristr, HTTPRequestURI& out) { http_parser_url_init(&url); if (http_parser_parse_url(uristr.c_str(), uristr.size(), 0, &url) != 0) return false; if (url.field_set & (1 << UF_PATH)) out.path = uri.substr(url.field_data[UF_PATH].off, url.field_data[UF_PATH].len); if (url.field_set & (1 << UF_FRAGMENT)) out.fragment = uri.substr(url.field_data[UF_FRAGMENT].off, url.field_data[UF_FRAGMENT].len); std::string param_str; if (url.field_set & (1 << UF_QUERY)) param_str = uri.substr(url.field_data[UF_QUERY].off, url.field_data[UF_QUERY].len); irc::sepstream param_stream(param_str, '&'); std::string token; std::string::size_type eq_pos; while (param_stream.GetToken(token)) { eq_pos = token.find('='); if (eq_pos == std::string::npos) { out.query_params.insert(std::make_pair(token, "")); } else { out.query_params.insert(std::make_pair(token.substr(0, eq_pos), token.substr(eq_pos + 1))); } } return true; } }; class HTTPdAPIImpl : public HTTPdAPIBase { public: HTTPdAPIImpl(Module* parent) : HTTPdAPIBase(parent) { } void SendResponse(HTTPDocumentResponse& resp) CXX11_OVERRIDE { resp.src.sock->Page(resp.document, resp.responsecode, &resp.headers); } }; class ModuleHttpServer : public Module { HTTPdAPIImpl APIImpl; unsigned int timeoutsec; Events::ModuleEventProvider acleventprov; Events::ModuleEventProvider reqeventprov; public: ModuleHttpServer() : APIImpl(this) , acleventprov(this, "event/http-acl") , reqeventprov(this, "event/http-request") { aclevprov = &acleventprov; reqevprov = &reqeventprov; HttpServerSocket::ConfigureParser(); } void init() CXX11_OVERRIDE { HttpModule = this; } void ReadConfig(ConfigStatus& status) CXX11_OVERRIDE { ConfigTag* tag = ServerInstance->Config->ConfValue("httpd"); timeoutsec = tag->getDuration("timeout", 10, 1); } ModResult OnAcceptConnection(int nfd, ListenSocket* from, irc::sockets::sockaddrs* client, irc::sockets::sockaddrs* server) CXX11_OVERRIDE { if (!stdalgo::string::equalsci(from->bind_tag->getString("type"), "httpd")) return MOD_RES_PASSTHRU; sockets.push_front(new HttpServerSocket(nfd, client->addr(), from, client, server, timeoutsec)); return MOD_RES_ALLOW; } void OnUnloadModule(Module* mod) CXX11_OVERRIDE { for (insp::intrusive_list<HttpServerSocket>::const_iterator i = sockets.begin(); i != sockets.end(); ) { HttpServerSocket* sock = *i; ++i; if (sock->GetModHook(mod)) { sock->cull(); delete sock; } } } CullResult cull() CXX11_OVERRIDE { for (insp::intrusive_list<HttpServerSocket>::const_iterator i = sockets.begin(); i != sockets.end(); ++i) { HttpServerSocket* sock = *i; sock->AddToCull(); } return Module::cull(); } Version GetVersion() CXX11_OVERRIDE { return Version("Provides HTTP serving facilities to modules", VF_VENDOR); } }; MODULE_INIT(ModuleHttpServer) ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/src/modules/m_httpd_acl.cpp����������������������������������������������������������0000664�0000000�0000000�00000016763�13554550454�0020601�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * InspIRCd -- Internet Relay Chat Daemon * * Copyright (C) 2009-2010 Daniel De Graaf <danieldg@inspircd.org> * Copyright (C) 2008 Craig Edwards <craigedwards@brainbox.cc> * * This file is part of InspIRCd. InspIRCd is free software: you can * redistribute it and/or modify it under the terms of the GNU General Public * License as published by the Free Software Foundation, version 2. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include "inspircd.h" #include "modules/httpd.h" class HTTPACL { public: std::string path; std::string username; std::string password; std::string whitelist; std::string blacklist; HTTPACL(const std::string &set_path, const std::string &set_username, const std::string &set_password, const std::string &set_whitelist, const std::string &set_blacklist) : path(set_path), username(set_username), password(set_password), whitelist(set_whitelist), blacklist(set_blacklist) { } }; class ModuleHTTPAccessList : public Module, public HTTPACLEventListener { std::string stylesheet; std::vector<HTTPACL> acl_list; HTTPdAPI API; public: ModuleHTTPAccessList() : HTTPACLEventListener(this) , API(this) { } void ReadConfig(ConfigStatus& status) CXX11_OVERRIDE { std::vector<HTTPACL> new_acls; ConfigTagList acls = ServerInstance->Config->ConfTags("httpdacl"); for (ConfigIter i = acls.first; i != acls.second; i++) { ConfigTag* c = i->second; std::string path = c->getString("path"); std::string types = c->getString("types"); irc::commasepstream sep(types); std::string type; std::string username; std::string password; std::string whitelist; std::string blacklist; while (sep.GetToken(type)) { if (stdalgo::string::equalsci(type, "password")) { username = c->getString("username"); password = c->getString("password"); } else if (stdalgo::string::equalsci(type, "whitelist")) { whitelist = c->getString("whitelist"); } else if (stdalgo::string::equalsci(type, "blacklist")) { blacklist = c->getString("blacklist"); } else { throw ModuleException("Invalid HTTP ACL type '" + type + "'"); } } ServerInstance->Logs->Log(MODNAME, LOG_DEBUG, "Read ACL: path=%s pass=%s whitelist=%s blacklist=%s", path.c_str(), password.c_str(), whitelist.c_str(), blacklist.c_str()); new_acls.push_back(HTTPACL(path, username, password, whitelist, blacklist)); } acl_list.swap(new_acls); } void BlockAccess(HTTPRequest* http, unsigned int returnval, const std::string &extraheaderkey = "", const std::string &extraheaderval="") { ServerInstance->Logs->Log(MODNAME, LOG_DEBUG, "BlockAccess (%u)", returnval); std::stringstream data("Access to this resource is denied by an access control list. Please contact your IRC administrator."); HTTPDocumentResponse response(this, *http, &data, returnval); response.headers.SetHeader("X-Powered-By", MODNAME); if (!extraheaderkey.empty()) response.headers.SetHeader(extraheaderkey, extraheaderval); API->SendResponse(response); } bool IsAccessAllowed(HTTPRequest* http) { { ServerInstance->Logs->Log(MODNAME, LOG_DEBUG, "Handling httpd acl event"); for (std::vector<HTTPACL>::const_iterator this_acl = acl_list.begin(); this_acl != acl_list.end(); ++this_acl) { if (InspIRCd::Match(http->GetPath(), this_acl->path, ascii_case_insensitive_map)) { if (!this_acl->blacklist.empty()) { /* Blacklist */ irc::commasepstream sep(this_acl->blacklist); std::string entry; while (sep.GetToken(entry)) { if (InspIRCd::Match(http->GetIP(), entry, ascii_case_insensitive_map)) { ServerInstance->Logs->Log(MODNAME, LOG_DEBUG, "Denying access to blacklisted resource %s (matched by pattern %s) from ip %s (matched by entry %s)", http->GetPath().c_str(), this_acl->path.c_str(), http->GetIP().c_str(), entry.c_str()); BlockAccess(http, 403); return false; } } } if (!this_acl->whitelist.empty()) { /* Whitelist */ irc::commasepstream sep(this_acl->whitelist); std::string entry; bool allow_access = false; while (sep.GetToken(entry)) { if (InspIRCd::Match(http->GetIP(), entry, ascii_case_insensitive_map)) allow_access = true; } if (!allow_access) { ServerInstance->Logs->Log(MODNAME, LOG_DEBUG, "Denying access to whitelisted resource %s (matched by pattern %s) from ip %s (Not in whitelist)", http->GetPath().c_str(), this_acl->path.c_str(), http->GetIP().c_str()); BlockAccess(http, 403); return false; } } if (!this_acl->password.empty() && !this_acl->username.empty()) { /* Password auth, first look to see if we have a basic authentication header */ ServerInstance->Logs->Log(MODNAME, LOG_DEBUG, "Checking HTTP auth password for resource %s (matched by pattern %s) from ip %s, against username %s", http->GetPath().c_str(), this_acl->path.c_str(), http->GetIP().c_str(), this_acl->username.c_str()); if (http->headers->IsSet("Authorization")) { /* Password has been given, validate it */ std::string authorization = http->headers->GetHeader("Authorization"); irc::spacesepstream sep(authorization); std::string authtype; std::string base64; sep.GetToken(authtype); if (authtype == "Basic") { std::string user; std::string pass; sep.GetToken(base64); std::string userpass = Base64ToBin(base64); ServerInstance->Logs->Log(MODNAME, LOG_DEBUG, "HTTP authorization: %s (%s)", userpass.c_str(), base64.c_str()); irc::sepstream userpasspair(userpass, ':'); if (userpasspair.GetToken(user)) { userpasspair.GetToken(pass); /* Access granted if username and password are correct */ if (user == this_acl->username && pass == this_acl->password) { ServerInstance->Logs->Log(MODNAME, LOG_DEBUG, "HTTP authorization: password and username match"); return true; } else /* Invalid password */ BlockAccess(http, 401, "WWW-Authenticate", "Basic realm=\"Restricted Object\""); } else /* Malformed user:pass pair */ BlockAccess(http, 401, "WWW-Authenticate", "Basic realm=\"Restricted Object\""); } else /* Unsupported authentication type */ BlockAccess(http, 401, "WWW-Authenticate", "Basic realm=\"Restricted Object\""); } else { /* No password given at all, access denied */ BlockAccess(http, 401, "WWW-Authenticate", "Basic realm=\"Restricted Object\""); } return false; } /* A path may only match one ACL (the first it finds in the config file) */ break; } } } return true; } ModResult OnHTTPACLCheck(HTTPRequest& req) CXX11_OVERRIDE { if (IsAccessAllowed(&req)) return MOD_RES_PASSTHRU; return MOD_RES_DENY; } Version GetVersion() CXX11_OVERRIDE { return Version("Provides access control lists (passwording of resources, IP restrictions, etc) to m_httpd dependent modules", VF_VENDOR); } }; MODULE_INIT(ModuleHTTPAccessList) �������������inspircd-3.4.0/src/modules/m_httpd_config.cpp�������������������������������������������������������0000664�0000000�0000000�00000005012�13554550454�0021270�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * InspIRCd -- Internet Relay Chat Daemon * * Copyright (C) 2009-2010 Daniel De Graaf <danieldg@inspircd.org> * Copyright (C) 2008 Craig Edwards <craigedwards@brainbox.cc> * * This file is part of InspIRCd. InspIRCd is free software: you can * redistribute it and/or modify it under the terms of the GNU General Public * License as published by the Free Software Foundation, version 2. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include "inspircd.h" #include "modules/httpd.h" class ModuleHttpConfig : public Module, public HTTPRequestEventListener { HTTPdAPI API; public: ModuleHttpConfig() : HTTPRequestEventListener(this) , API(this) { } ModResult OnHTTPRequest(HTTPRequest& request) CXX11_OVERRIDE { if ((request.GetPath() != "/config") && (request.GetPath() != "/config/")) return MOD_RES_PASSTHRU; ServerInstance->Logs->Log(MODNAME, LOG_DEBUG, "Handling request for the HTTP /config route"); std::stringstream buffer; ConfigDataHash& config = ServerInstance->Config->config_data; for (ConfigDataHash::const_iterator citer = config.begin(); citer != config.end(); ++citer) { // Show the location of the tag in a comment. ConfigTag* tag = citer->second; buffer << "# " << tag->getTagLocation() << std::endl << '<' << tag->tag << ' '; // Print out the tag with all keys aligned vertically. const std::string indent(tag->tag.length() + 2, ' '); const ConfigItems& items = tag->getItems(); for (ConfigItems::const_iterator kiter = items.begin(); kiter != items.end(); ) { ConfigItems::const_iterator curr = kiter++; buffer << curr->first << "=\"" << ServerConfig::Escape(curr->second) << '"'; if (kiter != items.end()) buffer << std::endl << indent; } buffer << '>' << std::endl << std::endl; } HTTPDocumentResponse response(this, request, &buffer, 200); response.headers.SetHeader("X-Powered-By", MODNAME); response.headers.SetHeader("Content-Type", "text/plain"); API->SendResponse(response); return MOD_RES_DENY; } Version GetVersion() CXX11_OVERRIDE { return Version("Allows for the server configuration to be viewed over HTTP via m_httpd", VF_VENDOR); } }; MODULE_INIT(ModuleHttpConfig) ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/src/modules/m_httpd_stats.cpp��������������������������������������������������������0000664�0000000�0000000�00000033553�13554550454�0021174�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * InspIRCd -- Internet Relay Chat Daemon * * Copyright (C) 2009 Daniel De Graaf <danieldg@inspircd.org> * Copyright (C) 2007-2008 Robin Burchell <robin+git@viroteck.net> * Copyright (C) 2008 Pippijn van Steenhoven <pip88nl@gmail.com> * Copyright (C) 2006-2008 Craig Edwards <craigedwards@brainbox.cc> * Copyright (C) 2007 Dennis Friis <peavey@inspircd.org> * * This file is part of InspIRCd. InspIRCd is free software: you can * redistribute it and/or modify it under the terms of the GNU General Public * License as published by the Free Software Foundation, version 2. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include "inspircd.h" #include "modules/httpd.h" #include "xline.h" namespace Stats { struct Entities { static const insp::flat_map<char, char const*>& entities; }; static const insp::flat_map<char, char const*>& init_entities() { static insp::flat_map<char, char const*> entities; entities['<'] = "lt"; entities['>'] = "gt"; entities['&'] = "amp"; entities['"'] = "quot"; return entities; } const insp::flat_map<char, char const*>& Entities::entities = init_entities(); std::string Sanitize(const std::string& str) { std::string ret; ret.reserve(str.length() * 2); for (std::string::const_iterator x = str.begin(); x != str.end(); ++x) { insp::flat_map<char, char const*>::const_iterator it = Entities::entities.find(*x); if (it != Entities::entities.end()) { ret += '&'; ret += it->second; ret += ';'; } else if (*x == 0x09 || *x == 0x0A || *x == 0x0D || ((*x >= 0x20) && (*x <= 0x7e))) { // The XML specification defines the following characters as valid inside an XML document: // Char ::= #x9 | #xA | #xD | [#x20-#xD7FF] | [#xE000-#xFFFD] | [#x10000-#x10FFFF] ret += *x; } else { // If we reached this point then the string contains characters which can // not be represented in XML, even using a numeric escape. Therefore, we // Base64 encode the entire string and wrap it in a CDATA. ret.clear(); ret += "<![CDATA["; ret += BinToBase64(str); ret += "]]>"; break; } } return ret; } void DumpMeta(std::ostream& data, Extensible* ext) { data << "<metadata>"; for (Extensible::ExtensibleStore::const_iterator i = ext->GetExtList().begin(); i != ext->GetExtList().end(); i++) { ExtensionItem* item = i->first; std::string value = item->ToHuman(ext, i->second); if (!value.empty()) data << "<meta name=\"" << item->name << "\">" << Sanitize(value) << "</meta>"; else if (!item->name.empty()) data << "<meta name=\"" << item->name << "\"/>"; } data << "</metadata>"; } std::ostream& ServerInfo(std::ostream& data) { return data << "<server><name>" << ServerInstance->Config->ServerName << "</name><description>" << Sanitize(ServerInstance->Config->ServerDesc) << "</description><version>" << Sanitize(ServerInstance->GetVersionString(true)) << "</version></server>"; } std::ostream& ISupport(std::ostream& data) { data << "<isupport>"; const std::vector<Numeric::Numeric>& isupport = ServerInstance->ISupport.GetLines(); for (std::vector<Numeric::Numeric>::const_iterator i = isupport.begin(); i != isupport.end(); ++i) { const Numeric::Numeric& num = *i; for (std::vector<std::string>::const_iterator j = num.GetParams().begin(); j != num.GetParams().end() - 1; ++j) data << "<token>" << Sanitize(*j) << "</token>"; } return data << "</isupport>"; } std::ostream& General(std::ostream& data) { data << "<general>"; data << "<usercount>" << ServerInstance->Users->GetUsers().size() << "</usercount>"; data << "<localusercount>" << ServerInstance->Users->GetLocalUsers().size() << "</localusercount>"; data << "<channelcount>" << ServerInstance->GetChans().size() << "</channelcount>"; data << "<opercount>" << ServerInstance->Users->all_opers.size() << "</opercount>"; data << "<socketcount>" << (SocketEngine::GetUsedFds()) << "</socketcount><socketmax>" << SocketEngine::GetMaxFds() << "</socketmax>"; data << "<uptime><boot_time_t>" << ServerInstance->startup_time << "</boot_time_t></uptime>"; data << "<currenttime>" << ServerInstance->Time() << "</currenttime>"; data << ISupport; return data << "</general>"; } std::ostream& XLines(std::ostream& data) { data << "<xlines>"; std::vector<std::string> xltypes = ServerInstance->XLines->GetAllTypes(); for (std::vector<std::string>::iterator it = xltypes.begin(); it != xltypes.end(); ++it) { XLineLookup* lookup = ServerInstance->XLines->GetAll(*it); if (!lookup) continue; for (LookupIter i = lookup->begin(); i != lookup->end(); ++i) { data << "<xline type=\"" << it->c_str() << "\"><mask>" << Sanitize(i->second->Displayable()) << "</mask><settime>" << i->second->set_time << "</settime><duration>" << i->second->duration << "</duration><reason>" << Sanitize(i->second->reason) << "</reason></xline>"; } } return data << "</xlines>"; } std::ostream& Modules(std::ostream& data) { data << "<modulelist>"; const ModuleManager::ModuleMap& mods = ServerInstance->Modules->GetModules(); for (ModuleManager::ModuleMap::const_iterator i = mods.begin(); i != mods.end(); ++i) { Version v = i->second->GetVersion(); data << "<module><name>" << i->first << "</name><description>" << Sanitize(v.description) << "</description></module>"; } return data << "</modulelist>"; } std::ostream& Channels(std::ostream& data) { data << "<channellist>"; const chan_hash& chans = ServerInstance->GetChans(); for (chan_hash::const_iterator i = chans.begin(); i != chans.end(); ++i) { Channel* c = i->second; data << "<channel>"; data << "<usercount>" << c->GetUsers().size() << "</usercount><channelname>" << Sanitize(c->name) << "</channelname>"; data << "<channeltopic>"; data << "<topictext>" << Sanitize(c->topic) << "</topictext>"; data << "<setby>" << Sanitize(c->setby) << "</setby>"; data << "<settime>" << c->topicset << "</settime>"; data << "</channeltopic>"; data << "<channelmodes>" << Sanitize(c->ChanModes(true)) << "</channelmodes>"; const Channel::MemberMap& ulist = c->GetUsers(); for (Channel::MemberMap::const_iterator x = ulist.begin(); x != ulist.end(); ++x) { Membership* memb = x->second; data << "<channelmember><uid>" << memb->user->uuid << "</uid><privs>" << Sanitize(memb->GetAllPrefixChars()) << "</privs><modes>" << memb->modes << "</modes>"; DumpMeta(data, memb); data << "</channelmember>"; } DumpMeta(data, c); data << "</channel>"; } return data << "</channellist>"; } std::ostream& DumpUser(std::ostream& data, User* u) { data << "<user>"; data << "<nickname>" << u->nick << "</nickname><uuid>" << u->uuid << "</uuid><realhost>" << u->GetRealHost() << "</realhost><displayhost>" << u->GetDisplayedHost() << "</displayhost><realname>" << Sanitize(u->GetRealName()) << "</realname><server>" << u->server->GetName() << "</server><signon>" << u->signon << "</signon><age>" << u->age << "</age>"; if (u->IsAway()) data << "<away>" << Sanitize(u->awaymsg) << "</away><awaytime>" << u->awaytime << "</awaytime>"; if (u->IsOper()) data << "<opertype>" << Sanitize(u->oper->name) << "</opertype>"; data << "<modes>" << u->GetModeLetters().substr(1) << "</modes><ident>" << Sanitize(u->ident) << "</ident>"; LocalUser* lu = IS_LOCAL(u); if (lu) data << "<local/><port>" << lu->server_sa.port() << "</port><servaddr>" << lu->server_sa.str() << "</servaddr><connectclass>" << lu->GetClass()->GetName() << "</connectclass><lastmsg>" << lu->idle_lastmsg << "</lastmsg>"; data << "<ipaddress>" << u->GetIPString() << "</ipaddress>"; DumpMeta(data, u); data << "</user>"; return data; } std::ostream& Users(std::ostream& data) { data << "<userlist>"; const user_hash& users = ServerInstance->Users->GetUsers(); for (user_hash::const_iterator i = users.begin(); i != users.end(); ++i) { User* u = i->second; if (u->registered != REG_ALL) continue; DumpUser(data, u); } return data << "</userlist>"; } std::ostream& Servers(std::ostream& data) { data << "<serverlist>"; ProtocolInterface::ServerList sl; ServerInstance->PI->GetServerList(sl); for (ProtocolInterface::ServerList::const_iterator b = sl.begin(); b != sl.end(); ++b) { data << "<server>"; data << "<servername>" << b->servername << "</servername>"; data << "<parentname>" << b->parentname << "</parentname>"; data << "<description>" << Sanitize(b->description) << "</description>"; data << "<usercount>" << b->usercount << "</usercount>"; // This is currently not implemented, so, commented out. // data << "<opercount>" << b->opercount << "</opercount>"; data << "<lagmillisecs>" << b->latencyms << "</lagmillisecs>"; data << "</server>"; } return data << "</serverlist>"; } std::ostream& Commands(std::ostream& data) { data << "<commandlist>"; const CommandParser::CommandMap& commands = ServerInstance->Parser.GetCommands(); for (CommandParser::CommandMap::const_iterator i = commands.begin(); i != commands.end(); ++i) { data << "<command><name>" << i->second->name << "</name><usecount>" << i->second->use_count << "</usecount></command>"; } return data << "</commandlist>"; } enum OrderBy { OB_NICK, OB_LASTMSG, OB_NONE }; struct UserSorter { OrderBy order; bool desc; UserSorter(OrderBy Order, bool Desc = false) : order(Order), desc(Desc) {} template <typename T> inline bool Compare(const T& a, const T& b) { return desc ? a > b : a < b; } bool operator()(User* u1, User* u2) { switch (order) { case OB_LASTMSG: return Compare(IS_LOCAL(u1)->idle_lastmsg, IS_LOCAL(u2)->idle_lastmsg); break; case OB_NICK: return Compare(u1->nick, u2->nick); break; default: case OB_NONE: return false; break; } } }; std::ostream& ListUsers(std::ostream& data, const HTTPQueryParameters& params) { if (params.empty()) return Users(data); data << "<userlist>"; // Filters size_t limit = params.getNum<size_t>("limit"); bool showunreg = params.getBool("showunreg"); bool localonly = params.getBool("localonly"); // Minimum time since a user's last message unsigned long min_idle = params.getDuration("minidle"); time_t maxlastmsg = ServerInstance->Time() - min_idle; if (min_idle) // We can only check idle times on local users localonly = true; // Sorting const std::string& sortmethod = params.getString("sortby"); bool desc = params.getBool("desc", false); OrderBy orderby; if (stdalgo::string::equalsci(sortmethod, "nick")) orderby = OB_NICK; else if (stdalgo::string::equalsci(sortmethod, "lastmsg")) { orderby = OB_LASTMSG; // We can only check idle times on local users localonly = true; } else orderby = OB_NONE; typedef std::list<User*> NewUserList; NewUserList user_list; user_hash users = ServerInstance->Users->GetUsers(); for (user_hash::iterator i = users.begin(); i != users.end(); ++i) { User* u = i->second; if (!showunreg && u->registered != REG_ALL) continue; LocalUser* lu = IS_LOCAL(u); if (localonly && !lu) continue; if (min_idle && lu->idle_lastmsg > maxlastmsg) continue; user_list.push_back(u); } UserSorter sorter(orderby, desc); if (sorter.order != OB_NONE && !(!localonly && sorter.order == OB_LASTMSG)) user_list.sort(sorter); size_t count = 0; for (NewUserList::const_iterator i = user_list.begin(); i != user_list.end() && (!limit || count < limit); ++i, ++count) DumpUser(data, *i); data << "</userlist>"; return data; } } class ModuleHttpStats : public Module, public HTTPRequestEventListener { HTTPdAPI API; bool enableparams; public: ModuleHttpStats() : HTTPRequestEventListener(this) , API(this) , enableparams(false) { } void ReadConfig(ConfigStatus& status) CXX11_OVERRIDE { ConfigTag* conf = ServerInstance->Config->ConfValue("httpstats"); // Parameterized queries may cause a performance issue // Due to the sheer volume of data // So default them to disabled enableparams = conf->getBool("enableparams"); } ModResult HandleRequest(HTTPRequest* http) { std::string path = http->GetPath(); if (path != "/stats" && path.substr(0, 7) != "/stats/") return MOD_RES_PASSTHRU; if (path[path.size() - 1] == '/') path.erase(path.size() - 1, 1); ServerInstance->Logs->Log(MODNAME, LOG_DEBUG, "Handling httpd event"); bool found = true; std::stringstream data; data << "<inspircdstats>"; if (path == "/stats") { data << Stats::ServerInfo << Stats::General << Stats::XLines << Stats::Modules << Stats::Channels << Stats::Users << Stats::Servers << Stats::Commands; } else if (path == "/stats/general") { data << Stats::General; } else if (path == "/stats/users") { if (enableparams) Stats::ListUsers(data, http->GetParsedURI().query_params); else data << Stats::Users; } else { found = false; } if (found) { data << "</inspircdstats>"; } else { data.clear(); data.str(std::string()); } /* Send the document back to m_httpd */ HTTPDocumentResponse response(this, *http, &data, found ? 200 : 404); response.headers.SetHeader("X-Powered-By", MODNAME); response.headers.SetHeader("Content-Type", "text/xml"); API->SendResponse(response); return MOD_RES_DENY; // Handled } ModResult OnHTTPRequest(HTTPRequest& req) CXX11_OVERRIDE { return HandleRequest(&req); } Version GetVersion() CXX11_OVERRIDE { return Version("Provides statistics over HTTP via m_httpd", VF_VENDOR); } }; MODULE_INIT(ModuleHttpStats) �����������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/src/modules/m_ident.cpp��������������������������������������������������������������0000664�0000000�0000000�00000030504�13554550454�0017727�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * InspIRCd -- Internet Relay Chat Daemon * * Copyright (C) 2009-2010 Daniel De Graaf <danieldg@inspircd.org> * Copyright (C) 2007, 2009 John Brooks <john.brooks@dereferenced.net> * Copyright (C) 2006-2008 Robin Burchell <robin+git@viroteck.net> * Copyright (C) 2005-2008 Craig Edwards <craigedwards@brainbox.cc> * Copyright (C) 2008 Thomas Stagner <aquanight@inspircd.org> * Copyright (C) 2007 Dennis Friis <peavey@inspircd.org> * * This file is part of InspIRCd. InspIRCd is free software: you can * redistribute it and/or modify it under the terms of the GNU General Public * License as published by the Free Software Foundation, version 2. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include "inspircd.h" enum { // Either the ident looup has not started yet or the user is registered. IDENT_UNKNOWN = 0, // Ident lookups are not enabled and a user has been marked as being skipped. IDENT_SKIPPED, // Ident looups are not enabled and a user has been an insecure ident prefix. IDENT_PREFIXED, // An ident lookup was done and an ident was found. IDENT_FOUND, // An ident lookup was done but no ident was found IDENT_MISSING }; /* -------------------------------------------------------------- * Note that this is the third incarnation of m_ident. The first * two attempts were pretty crashy, mainly due to the fact we tried * to use InspSocket/BufferedSocket to make them work. This class * is ok for more heavyweight tasks, it does a lot of things behind * the scenes that are not good for ident sockets and it has a huge * memory footprint! * * To fix all the issues that we had in the old ident modules (many * nasty race conditions that would cause segfaults etc) we have * rewritten this module to use a simplified socket object based * directly off EventHandler. As EventHandler only has low level * readability, writeability and error events tied directly to the * socket engine, this makes our lives easier as nothing happens to * our ident lookup class that is outside of this module, or out- * side of the control of the class. There are no timers, internal * events, or such, which will cause the socket to be deleted, * queued for deletion, etc. In fact, theres not even any queueing! * * Using this framework we have a much more stable module. * * A few things to note: * * O The only place that may *delete* an active or inactive * ident socket is OnUserDisconnect in the module class. * Because this is out of scope of the socket class there is * no possibility that the socket may ever try to delete * itself. * * O Closure of the ident socket with the Close() method will * not cause removal of the socket from memory or detatchment * from its 'parent' User class. It will only flag it as an * inactive socket in the socket engine. * * O Timeouts are handled in OnCheckReaady at the same time as * checking if the ident socket has a result. This is done * by checking if the age the of the class (its instantiation * time) plus the timeout value is greater than the current time. * * O The ident socket is able to but should not modify its * 'parent' user directly. Instead the ident socket class sets * a completion flag and during the next call to OnCheckReady, * the completion flag will be checked and any result copied to * that user's class. This again ensures a single point of socket * deletion for safer, neater code. * * O The code in the constructor of the ident socket is taken from * BufferedSocket but majorly thinned down. It works for both * IPv4 and IPv6. * * O In the event that the ident socket throws a ModuleException, * nothing is done. This is counted as total and complete * failure to create a connection. * -------------------------------------------------------------- */ class IdentRequestSocket : public EventHandler { public: LocalUser *user; /* User we are attached to */ std::string result; /* Holds the ident string if done */ time_t age; bool done; /* True if lookup is finished */ IdentRequestSocket(LocalUser* u) : user(u) { age = ServerInstance->Time(); SetFd(socket(user->server_sa.family(), SOCK_STREAM, 0)); if (GetFd() == -1) throw ModuleException("Could not create socket"); done = false; irc::sockets::sockaddrs bindaddr; irc::sockets::sockaddrs connaddr; memcpy(&bindaddr, &user->server_sa, sizeof(bindaddr)); memcpy(&connaddr, &user->client_sa, sizeof(connaddr)); if (connaddr.family() == AF_INET6) { bindaddr.in6.sin6_port = 0; connaddr.in6.sin6_port = htons(113); } else { bindaddr.in4.sin_port = 0; connaddr.in4.sin_port = htons(113); } /* Attempt to bind (ident requests must come from the ip the query is referring to */ if (SocketEngine::Bind(GetFd(), bindaddr) < 0) { this->Close(); throw ModuleException("failed to bind()"); } SocketEngine::NonBlocking(GetFd()); /* Attempt connection (nonblocking) */ if (SocketEngine::Connect(this, connaddr) == -1 && errno != EINPROGRESS) { this->Close(); throw ModuleException("connect() failed"); } /* Add fd to socket engine */ if (!SocketEngine::AddFd(this, FD_WANT_NO_READ | FD_WANT_POLL_WRITE)) { this->Close(); throw ModuleException("out of fds"); } } void OnEventHandlerWrite() CXX11_OVERRIDE { SocketEngine::ChangeEventMask(this, FD_WANT_POLL_READ | FD_WANT_NO_WRITE); char req[32]; /* Build request in the form 'localport,remoteport\r\n' */ int req_size; if (user->client_sa.family() == AF_INET6) req_size = snprintf(req, sizeof(req), "%d,%d\r\n", ntohs(user->client_sa.in6.sin6_port), ntohs(user->server_sa.in6.sin6_port)); else req_size = snprintf(req, sizeof(req), "%d,%d\r\n", ntohs(user->client_sa.in4.sin_port), ntohs(user->server_sa.in4.sin_port)); /* Send failed if we didnt write the whole ident request -- * might as well give up if this happens! */ if (SocketEngine::Send(this, req, req_size, 0) < req_size) done = true; } void Close() { /* Remove ident socket from engine, and close it, but dont detatch it * from its parent user class, or attempt to delete its memory. */ if (GetFd() > -1) { ServerInstance->Logs->Log(MODNAME, LOG_DEBUG, "Close ident socket %d", GetFd()); SocketEngine::Close(this); } } bool HasResult() { return done; } void OnEventHandlerRead() CXX11_OVERRIDE { /* We don't really need to buffer for incomplete replies here, since IDENT replies are * extremely short - there is *no* sane reason it'd be in more than one packet */ char ibuf[256]; int recvresult = SocketEngine::Recv(this, ibuf, sizeof(ibuf)-1, 0); /* Close (but don't delete from memory) our socket * and flag as done since the ident lookup has finished */ Close(); done = true; /* Cant possibly be a valid response shorter than 3 chars, * because the shortest possible response would look like: '1,1' */ if (recvresult < 3) return; ServerInstance->Logs->Log(MODNAME, LOG_DEBUG, "ReadResponse()"); /* Truncate at the first null character, but first make sure * there is at least one null char (at the end of the buffer). */ ibuf[recvresult] = '\0'; std::string buf(ibuf); /* <2 colons: invalid * 2 colons: reply is an error * >3 colons: there is a colon in the ident */ if (std::count(buf.begin(), buf.end(), ':') != 3) return; std::string::size_type lastcolon = buf.rfind(':'); /* Truncate the ident at any characters we don't like, skip leading spaces */ for (std::string::const_iterator i = buf.begin()+lastcolon+1; i != buf.end(); ++i) { if (result.size() == ServerInstance->Config->Limits.IdentMax) /* Ident is getting too long */ break; if (*i == ' ') continue; /* Add the next char to the result and see if it's still a valid ident, * according to IsIdent(). If it isn't, then erase what we just added and * we're done. */ result += *i; if (!ServerInstance->IsIdent(result)) { result.erase(result.end()-1); break; } } } void OnEventHandlerError(int errornum) CXX11_OVERRIDE { Close(); done = true; } CullResult cull() CXX11_OVERRIDE { Close(); return EventHandler::cull(); } }; class ModuleIdent : public Module { private: unsigned int timeout; bool prefixunqueried; SimpleExtItem<IdentRequestSocket, stdalgo::culldeleter> socket; LocalIntExt state; static void PrefixIdent(LocalUser* user) { // Check that they haven't been prefixed already. if (user->ident[0] == '~') return; // All invalid usernames are prefixed with a tilde. std::string newident(user->ident); newident.insert(newident.begin(), '~'); // If the username is too long then truncate it. if (newident.length() > ServerInstance->Config->Limits.IdentMax) newident.erase(ServerInstance->Config->Limits.IdentMax); // Apply the new username. user->ChangeIdent(newident); } public: ModuleIdent() : socket("ident_socket", ExtensionItem::EXT_USER, this) , state("ident_state", ExtensionItem::EXT_USER, this) { } Version GetVersion() CXX11_OVERRIDE { return Version("Provides support for RFC1413 ident lookups", VF_VENDOR); } void ReadConfig(ConfigStatus& status) CXX11_OVERRIDE { ConfigTag* tag = ServerInstance->Config->ConfValue("ident"); timeout = tag->getDuration("timeout", 5, 1, 60); prefixunqueried = tag->getBool("prefixunqueried"); } void OnSetUserIP(LocalUser* user) CXX11_OVERRIDE { IdentRequestSocket* isock = socket.get(user); if (isock) { // If an ident lookup request was in progress then cancel it. isock->Close(); socket.unset(user); } // The ident protocol requires that clients are connecting over a protocol with ports. if (user->client_sa.family() != AF_INET && user->client_sa.family() != AF_INET6) return; // We don't want to look this up once the user has connected. if (user->registered == REG_ALL) return; ConfigTag* tag = user->MyClass->config; if (!tag->getBool("useident", true)) { state.set(user, IDENT_SKIPPED); return; } user->WriteNotice("*** Looking up your ident..."); try { isock = new IdentRequestSocket(user); socket.set(user, isock); } catch (ModuleException &e) { ServerInstance->Logs->Log(MODNAME, LOG_DEBUG, "Ident exception: " + e.GetReason()); } } /* This triggers pretty regularly, we can use it in preference to * creating a Timer object and especially better than creating a * Timer per ident lookup! */ ModResult OnCheckReady(LocalUser *user) CXX11_OVERRIDE { /* Does user have an ident socket attached at all? */ IdentRequestSocket* isock = socket.get(user); if (!isock) { if (prefixunqueried && state.get(user) == IDENT_SKIPPED) { PrefixIdent(user); state.set(user, IDENT_PREFIXED); } return MOD_RES_PASSTHRU; } time_t compare = isock->age + timeout; /* Check for timeout of the socket */ if (ServerInstance->Time() >= compare) { /* Ident timeout */ state.set(user, IDENT_MISSING); PrefixIdent(user); user->WriteNotice("*** Ident lookup timed out, using " + user->ident + " instead."); } else if (!isock->HasResult()) { // time still good, no result yet... hold the registration return MOD_RES_DENY; } /* wooo, got a result (it will be good, or bad) */ else if (isock->result.empty()) { state.set(user, IDENT_MISSING); PrefixIdent(user); user->WriteNotice("*** Could not find your ident, using " + user->ident + " instead."); } else { state.set(user, IDENT_FOUND); user->ChangeIdent(isock->result); user->WriteNotice("*** Found your ident, '" + user->ident + "'"); } isock->Close(); socket.unset(user); return MOD_RES_PASSTHRU; } ModResult OnSetConnectClass(LocalUser* user, ConnectClass* myclass) CXX11_OVERRIDE { if (myclass->config->getBool("requireident") && state.get(user) != IDENT_FOUND) return MOD_RES_DENY; return MOD_RES_PASSTHRU; } void OnUserConnect(LocalUser* user) CXX11_OVERRIDE { // Clear this as it is no longer necessary. state.unset(user); } }; MODULE_INIT(ModuleIdent) ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/src/modules/m_inviteexception.cpp����������������������������������������������������0000664�0000000�0000000�00000005372�13554550454�0022046�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * InspIRCd -- Internet Relay Chat Daemon * * Copyright (C) 2009 Daniel De Graaf <danieldg@inspircd.org> * Copyright (C) 2006-2008 Craig Edwards <craigedwards@brainbox.cc> * Copyright (C) 2007 Dennis Friis <peavey@inspircd.org> * Copyright (C) 2007 Robin Burchell <robin+git@viroteck.net> * Copyright (C) 2006 Oliver Lupton <oliverlupton@gmail.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 "inspircd.h" #include "listmode.h" /* * Written by Om <om@inspircd.org>, April 2005. * Based on m_exception, which was originally based on m_chanprotect and m_silence * * The +I channel mode takes a nick!ident@host, glob patterns allowed, * and if a user matches an entry on the +I list then they can join the channel, * ignoring if +i is set on the channel * Now supports CIDR and IP addresses -- Brain */ /** Handles channel mode +I */ class InviteException : public ListModeBase { public: InviteException(Module* Creator) : ListModeBase(Creator, "invex", 'I', "End of Channel Invite Exception List", 346, 347, true) { syntax = "<mask>"; } }; class ModuleInviteException : public Module { bool invite_bypass_key; InviteException ie; public: ModuleInviteException() : ie(this) { } void On005Numeric(std::map<std::string, std::string>& tokens) CXX11_OVERRIDE { tokens["INVEX"] = ConvToStr(ie.GetModeChar()); } ModResult OnCheckInvite(User* user, Channel* chan) CXX11_OVERRIDE { ListModeBase::ModeList* list = ie.GetList(chan); if (list) { for (ListModeBase::ModeList::iterator it = list->begin(); it != list->end(); it++) { if (chan->CheckBan(user, it->mask)) { return MOD_RES_ALLOW; } } } return MOD_RES_PASSTHRU; } ModResult OnCheckKey(User* user, Channel* chan, const std::string& key) CXX11_OVERRIDE { if (invite_bypass_key) return OnCheckInvite(user, chan); return MOD_RES_PASSTHRU; } void ReadConfig(ConfigStatus& status) CXX11_OVERRIDE { ie.DoRehash(); invite_bypass_key = ServerInstance->Config->ConfValue("inviteexception")->getBool("bypasskey", true); } Version GetVersion() CXX11_OVERRIDE { return Version("Provides channel mode +I, invite exceptions", VF_VENDOR); } }; MODULE_INIT(ModuleInviteException) ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/src/modules/m_ircv3.cpp��������������������������������������������������������������0000664�0000000�0000000�00000012066�13554550454�0017655�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * InspIRCd -- Internet Relay Chat Daemon * * Copyright (C) 2012 Attila Molnar <attilamolnar@hush.com> * * This file is part of InspIRCd. InspIRCd is free software: you can * redistribute it and/or modify it under the terms of the GNU General Public * License as published by the Free Software Foundation, version 2. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include "inspircd.h" #include "modules/account.h" #include "modules/away.h" #include "modules/cap.h" #include "modules/ircv3.h" class AwayMessage : public ClientProtocol::Message { public: AwayMessage(User* user) : ClientProtocol::Message("AWAY", user) { SetParams(user, user->awaymsg); } AwayMessage() : ClientProtocol::Message("AWAY") { } void SetParams(User* user, const std::string& awaymsg) { // Going away: 1 parameter which is the away reason // Back from away: no parameter if (!awaymsg.empty()) PushParam(awaymsg); } }; class JoinHook : public ClientProtocol::EventHook { ClientProtocol::Events::Join extendedjoinmsg; public: const std::string asterisk; ClientProtocol::EventProvider awayprotoev; AwayMessage awaymsg; Cap::Capability extendedjoincap; Cap::Capability awaycap; JoinHook(Module* mod) : ClientProtocol::EventHook(mod, "JOIN") , asterisk(1, '*') , awayprotoev(mod, "AWAY") , extendedjoincap(mod, "extended-join") , awaycap(mod, "away-notify") { } void OnEventInit(const ClientProtocol::Event& ev) CXX11_OVERRIDE { const ClientProtocol::Events::Join& join = static_cast<const ClientProtocol::Events::Join&>(ev); // An extended join has two extra parameters: // First the account name of the joining user or an asterisk if the user is not logged in. // The second parameter is the realname of the joining user. Membership* const memb = join.GetMember(); const std::string* account = &asterisk; const AccountExtItem* const accountext = GetAccountExtItem(); if (accountext) { const std::string* accountname = accountext->get(memb->user); if (accountname) account = accountname; } extendedjoinmsg.ClearParams(); extendedjoinmsg.SetSource(join); extendedjoinmsg.PushParamRef(memb->chan->name); extendedjoinmsg.PushParamRef(*account); extendedjoinmsg.PushParamRef(memb->user->GetRealName()); awaymsg.ClearParams(); if ((memb->user->IsAway()) && (awaycap.IsActive())) { awaymsg.SetSource(join); awaymsg.SetParams(memb->user, memb->user->awaymsg); } } ModResult OnPreEventSend(LocalUser* user, const ClientProtocol::Event& ev, ClientProtocol::MessageList& messagelist) CXX11_OVERRIDE { if (extendedjoincap.get(user)) messagelist.front() = &extendedjoinmsg; if ((!awaymsg.GetParams().empty()) && (awaycap.get(user))) messagelist.push_back(&awaymsg); return MOD_RES_PASSTHRU; } }; class ModuleIRCv3 : public Module , public AccountEventListener , public Away::EventListener { Cap::Capability cap_accountnotify; JoinHook joinhook; ClientProtocol::EventProvider accountprotoev; public: ModuleIRCv3() : AccountEventListener(this) , Away::EventListener(this) , cap_accountnotify(this, "account-notify") , joinhook(this) , accountprotoev(this, "ACCOUNT") { } void ReadConfig(ConfigStatus& status) CXX11_OVERRIDE { ConfigTag* conf = ServerInstance->Config->ConfValue("ircv3"); cap_accountnotify.SetActive(conf->getBool("accountnotify", true)); joinhook.awaycap.SetActive(conf->getBool("awaynotify", true)); joinhook.extendedjoincap.SetActive(conf->getBool("extendedjoin", true)); } void OnAccountChange(User* user, const std::string& newaccount) CXX11_OVERRIDE { if (!(user->registered & REG_NICKUSER)) return; // Logged in: 1 parameter which is the account name // Logged out: 1 parameter which is a "*" ClientProtocol::Message msg("ACCOUNT", user); const std::string& param = (newaccount.empty() ? joinhook.asterisk : newaccount); msg.PushParamRef(param); ClientProtocol::Event accountevent(accountprotoev, msg); IRCv3::WriteNeighborsWithCap(user, accountevent, cap_accountnotify); } void OnUserAway(User* user) CXX11_OVERRIDE { if (!joinhook.awaycap.IsActive()) return; // Going away: n!u@h AWAY :reason AwayMessage msg(user); ClientProtocol::Event awayevent(joinhook.awayprotoev, msg); IRCv3::WriteNeighborsWithCap(user, awayevent, joinhook.awaycap); } void OnUserBack(User* user) CXX11_OVERRIDE { if (!joinhook.awaycap.IsActive()) return; // Back from away: n!u@h AWAY AwayMessage msg(user); ClientProtocol::Event awayevent(joinhook.awayprotoev, msg); IRCv3::WriteNeighborsWithCap(user, awayevent, joinhook.awaycap); } Version GetVersion() CXX11_OVERRIDE { return Version("Provides support for extended-join, away-notify and account-notify CAP capabilities", VF_VENDOR); } }; MODULE_INIT(ModuleIRCv3) ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/src/modules/m_ircv3_accounttag.cpp���������������������������������������������������0000664�0000000�0000000�00000002755�13554550454�0022071�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * InspIRCd -- Internet Relay Chat Daemon * * Copyright (C) 2016 Attila Molnar <attilamolnar@hush.com> * * This file is part of InspIRCd. InspIRCd is free software: you can * redistribute it and/or modify it under the terms of the GNU General Public * License as published by the Free Software Foundation, version 2. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include "inspircd.h" #include "modules/ircv3.h" #include "modules/account.h" class AccountTag : public IRCv3::CapTag<AccountTag> { public: const std::string* GetValue(const ClientProtocol::Message& msg) const { User* const user = msg.GetSourceUser(); if (!user) return NULL; AccountExtItem* const accextitem = GetAccountExtItem(); if (!accextitem) return NULL; return accextitem->get(user); } AccountTag(Module* mod) : IRCv3::CapTag<AccountTag>(mod, "account-tag", "account") { } }; class ModuleIRCv3AccountTag : public Module { AccountTag tag; public: ModuleIRCv3AccountTag() : tag(this) { } Version GetVersion() CXX11_OVERRIDE { return Version("Provides the account-tag IRCv3 extension", VF_VENDOR); } }; MODULE_INIT(ModuleIRCv3AccountTag) �������������������inspircd-3.4.0/src/modules/m_ircv3_batch.cpp��������������������������������������������������������0000664�0000000�0000000�00000013415�13554550454�0021015�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * InspIRCd -- Internet Relay Chat Daemon * * Copyright (C) 2016 Attila Molnar <attilamolnar@hush.com> * * This file is part of InspIRCd. InspIRCd is free software: you can * redistribute it and/or modify it under the terms of the GNU General Public * License as published by the Free Software Foundation, version 2. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include "inspircd.h" #include "modules/cap.h" #include "modules/ircv3_batch.h" class BatchMessage : public ClientProtocol::Message { public: BatchMessage(const IRCv3::Batch::Batch& batch, bool start) : ClientProtocol::Message("BATCH", ServerInstance->Config->ServerName) { char c = (start ? '+' : '-'); PushParam(std::string(1, c) + batch.GetRefTagStr()); if ((start) && (!batch.GetType().empty())) PushParamRef(batch.GetType()); } }; /** Extra structure allocated only for running batches, containing objects only relevant for * that specific run of the batch. */ struct IRCv3::Batch::BatchInfo { /** List of users that have received the batch start message */ std::vector<LocalUser*> users; BatchMessage startmsg; ClientProtocol::Event startevent; BatchMessage endmsg; ClientProtocol::Event endevent; BatchInfo(ClientProtocol::EventProvider& protoevprov, IRCv3::Batch::Batch& b) : startmsg(b, true) , startevent(protoevprov, startmsg) , endmsg(b, false) , endevent(protoevprov, endmsg) { } }; class IRCv3::Batch::ManagerImpl : public Manager { typedef std::vector<Batch*> BatchList; Cap::Capability cap; ClientProtocol::EventProvider protoevprov; LocalIntExt batchbits; BatchList active_batches; bool unloading; bool ShouldSendTag(LocalUser* user, const ClientProtocol::MessageTagData& tagdata) CXX11_OVERRIDE { if (!cap.get(user)) return false; Batch& batch = *static_cast<Batch*>(tagdata.provdata); // Check if this is the first message the user is getting that is part of the batch const intptr_t bits = batchbits.get(user); if (!(bits & batch.GetBit())) { // Send the start batch command ("BATCH +reftag TYPE"), remember the user so we can send them a // "BATCH -reftag" message later when the batch ends and set the flag we just checked so this is // only done once per user per batch. batchbits.set(user, (bits | batch.GetBit())); batch.batchinfo->users.push_back(user); user->Send(batch.batchinfo->startevent); } return true; } unsigned int NextFreeId() const { if (active_batches.empty()) return 0; return active_batches.back()->GetId()+1; } public: ManagerImpl(Module* mod) : Manager(mod) , cap(mod, "batch") , protoevprov(mod, "BATCH") , batchbits("batchbits", ExtensionItem::EXT_USER, mod) , unloading(false) { } void Init() { // Set batchbits to 0 for all users in case we were reloaded and the previous, now meaningless, // batchbits are set on users const UserManager::LocalList& users = ServerInstance->Users.GetLocalUsers(); for (UserManager::LocalList::const_iterator i = users.begin(); i != users.end(); ++i) { LocalUser* const user = *i; batchbits.set(user, 0); } } void Shutdown() { unloading = true; while (!active_batches.empty()) ManagerImpl::End(*active_batches.back()); } void RemoveFromAll(LocalUser* user) { const intptr_t bits = batchbits.get(user); // User is quitting, remove them from all lists for (BatchList::iterator i = active_batches.begin(); i != active_batches.end(); ++i) { Batch& batch = **i; // Check the bit first to avoid list scan in case they're not on the list if ((bits & batch.GetBit()) != 0) stdalgo::vector::swaperase(batch.batchinfo->users, user); } } void Start(Batch& batch) CXX11_OVERRIDE { if (unloading) return; if (batch.IsRunning()) return; // Already started, don't start again const size_t id = NextFreeId(); if (id >= MAX_BATCHES) return; batch.Setup(id); // Set the manager field which Batch::IsRunning() checks and is also used by AddToBatch() // to set the message tag batch.manager = this; batch.batchinfo = new IRCv3::Batch::BatchInfo(protoevprov, batch); batch.batchstartmsg = &batch.batchinfo->startmsg; batch.batchendmsg = &batch.batchinfo->endmsg; active_batches.push_back(&batch); } void End(Batch& batch) CXX11_OVERRIDE { if (!batch.IsRunning()) return; // Mark batch as stopped batch.manager = NULL; BatchInfo& batchinfo = *batch.batchinfo; // Send end batch message to all users who got the batch start message and unset bit so it can be reused for (std::vector<LocalUser*>::const_iterator i = batchinfo.users.begin(); i != batchinfo.users.end(); ++i) { LocalUser* const user = *i; user->Send(batchinfo.endevent); batchbits.set(user, batchbits.get(user) & ~batch.GetBit()); } // erase() not swaperase because the reftag generation logic depends on the order of the elements stdalgo::erase(active_batches, &batch); delete batch.batchinfo; batch.batchinfo = NULL; } }; class ModuleIRCv3Batch : public Module { IRCv3::Batch::ManagerImpl manager; public: ModuleIRCv3Batch() : manager(this) { } void init() CXX11_OVERRIDE { manager.Init(); } void OnUnloadModule(Module* mod) CXX11_OVERRIDE { if (mod == this) manager.Shutdown(); } void OnUserDisconnect(LocalUser* user) CXX11_OVERRIDE { // Remove the user from all internal lists manager.RemoveFromAll(user); } Version GetVersion() CXX11_OVERRIDE { return Version("Provides the batch IRCv3 extension", VF_VENDOR); } }; MODULE_INIT(ModuleIRCv3Batch) ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/src/modules/m_ircv3_capnotify.cpp����������������������������������������������������0000664�0000000�0000000�00000011572�13554550454�0021732�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * InspIRCd -- Internet Relay Chat Daemon * * Copyright (C) 2015 Attila Molnar <attilamolnar@hush.com> * * This file is part of InspIRCd. InspIRCd is free software: you can * redistribute it and/or modify it under the terms of the GNU General Public * License as published by the Free Software Foundation, version 2. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include "inspircd.h" #include "modules/cap.h" #include "modules/reload.h" class CapNotify : public Cap::Capability { bool OnRequest(LocalUser* user, bool add) CXX11_OVERRIDE { // Users using the negotiation protocol v3.2 or newer may not turn off cap-notify if ((!add) && (GetProtocol(user) != Cap::CAP_LEGACY)) return false; return true; } bool OnList(LocalUser* user) CXX11_OVERRIDE { // If the client supports 3.2 enable cap-notify for them if (GetProtocol(user) != Cap::CAP_LEGACY) set(user, true); return true; } public: CapNotify(Module* mod) : Cap::Capability(mod, "cap-notify") { } }; class CapNotifyMessage : public Cap::MessageBase { public: CapNotifyMessage(bool add, const std::string& capname) : Cap::MessageBase((add ? "NEW" : "DEL")) { PushParamRef(capname); } }; class CapNotifyValueMessage : public Cap::MessageBase { std::string s; const std::string::size_type pos; public: CapNotifyValueMessage(const std::string& capname) : Cap::MessageBase("NEW") , s(capname) , pos(s.size()+1) { s.push_back('='); PushParamRef(s); } void SetCapValue(const std::string& capvalue) { s.erase(pos); s.append(capvalue); InvalidateCache(); } }; class ModuleIRCv3CapNotify : public Module, public Cap::EventListener, public ReloadModule::EventListener { CapNotify capnotify; std::string reloadedmod; std::vector<std::string> reloadedcaps; ClientProtocol::EventProvider protoev; void Send(const std::string& capname, Cap::Capability* cap, bool add) { CapNotifyMessage msg(add, capname); CapNotifyValueMessage msgwithval(capname); ClientProtocol::Event event(protoev, msg); ClientProtocol::Event eventwithval(protoev, msgwithval); const UserManager::LocalList& list = ServerInstance->Users.GetLocalUsers(); for (UserManager::LocalList::const_iterator i = list.begin(); i != list.end(); ++i) { LocalUser* user = *i; if (!capnotify.get(user)) continue; // Check that this user can actually see the cap. if (!cap->OnList(user)) continue; // If the cap is being added and the client supports cap values then show the value, if any if ((add) && (capnotify.GetProtocol(user) != Cap::CAP_LEGACY)) { const std::string* capvalue = cap->GetValue(user); if ((capvalue) && (!capvalue->empty())) { msgwithval.SetUser(user); msgwithval.SetCapValue(*capvalue); user->Send(eventwithval); continue; } } msg.SetUser(user); user->Send(event); } } public: ModuleIRCv3CapNotify() : Cap::EventListener(this) , ReloadModule::EventListener(this) , capnotify(this) , protoev(this, "CAP_NOTIFY") { } void OnCapAddDel(Cap::Capability* cap, bool add) CXX11_OVERRIDE { if (cap->creator == this) return; if (cap->creator->ModuleSourceFile == reloadedmod) { if (!add) reloadedcaps.push_back(cap->GetName()); return; } Send(cap->GetName(), cap, add); } void OnCapValueChange(Cap::Capability* cap) CXX11_OVERRIDE { // The value of a cap has changed, send CAP DEL and CAP NEW with the new value Send(cap->GetName(), cap, false); Send(cap->GetName(), cap, true); } void OnReloadModuleSave(Module* mod, ReloadModule::CustomData& cd) CXX11_OVERRIDE { if (mod == this) return; reloadedmod = mod->ModuleSourceFile; // Request callback when reload is complete cd.add(this, NULL); } void OnReloadModuleRestore(Module* mod, void* data) CXX11_OVERRIDE { // Reloading can change the set of caps provided by a module so assuming that if the reload succeded all // caps that the module previously provided are available or all were lost if the reload failed is wrong. // Instead, we verify the availability of each cap individually. dynamic_reference_nocheck<Cap::Manager> capmanager(this, "capmanager"); if (capmanager) { for (std::vector<std::string>::const_iterator i = reloadedcaps.begin(); i != reloadedcaps.end(); ++i) { const std::string& capname = *i; if (!capmanager->Find(capname)) Send(capname, NULL, false); } } reloadedmod.clear(); reloadedcaps.clear(); } Version GetVersion() CXX11_OVERRIDE { return Version("Provides the cap-notify IRCv3 extension", VF_VENDOR); } }; MODULE_INIT(ModuleIRCv3CapNotify) ��������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/src/modules/m_ircv3_chghost.cpp������������������������������������������������������0000664�0000000�0000000�00000003350�13554550454�0021370�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * InspIRCd -- Internet Relay Chat Daemon * * Copyright (C) 2015 Attila Molnar <attilamolnar@hush.com> * * This file is part of InspIRCd. InspIRCd is free software: you can * redistribute it and/or modify it under the terms of the GNU General Public * License as published by the Free Software Foundation, version 2. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include "inspircd.h" #include "modules/cap.h" #include "modules/ircv3.h" class ModuleIRCv3ChgHost : public Module { Cap::Capability cap; ClientProtocol::EventProvider protoevprov; void DoChgHost(User* user, const std::string& ident, const std::string& host) { if (!(user->registered & REG_NICKUSER)) return; ClientProtocol::Message msg("CHGHOST", user); msg.PushParamRef(ident); msg.PushParamRef(host); ClientProtocol::Event protoev(protoevprov, msg); IRCv3::WriteNeighborsWithCap(user, protoev, cap, true); } public: ModuleIRCv3ChgHost() : cap(this, "chghost") , protoevprov(this, "CHGHOST") { } void OnChangeIdent(User* user, const std::string& newident) CXX11_OVERRIDE { DoChgHost(user, newident, user->GetDisplayedHost()); } void OnChangeHost(User* user, const std::string& newhost) CXX11_OVERRIDE { DoChgHost(user, user->ident, newhost); } Version GetVersion() CXX11_OVERRIDE { return Version("Provides the chghost IRCv3 extension", VF_VENDOR); } }; MODULE_INIT(ModuleIRCv3ChgHost) ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/src/modules/m_ircv3_ctctags.cpp������������������������������������������������������0000664�0000000�0000000�00000026412�13554550454�0021365�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * InspIRCd -- Internet Relay Chat Daemon * * Copyright (C) 2019 Peter Powell <petpow@saberuk.com> * Copyright (C) 2016 Attila Molnar <attilamolnar@hush.com> * * This file is part of InspIRCd. InspIRCd is free software: you can * redistribute it and/or modify it under the terms of the GNU General Public * License as published by the Free Software Foundation, version 2. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include "inspircd.h" #include "modules/cap.h" #include "modules/ctctags.h" class CommandTagMsg : public Command { private: Cap::Capability& cap; Events::ModuleEventProvider tagevprov; ClientProtocol::EventProvider msgevprov; bool FirePreEvents(User* source, MessageTarget& msgtarget, CTCTags::TagMessageDetails& msgdetails) { // Inform modules that a TAGMSG wants to be sent. ModResult modres; FIRST_MOD_RESULT_CUSTOM(tagevprov, CTCTags::EventListener, OnUserPreTagMessage, modres, (source, msgtarget, msgdetails)); if (modres == MOD_RES_DENY) { // Inform modules that a module blocked the TAGMSG. FOREACH_MOD_CUSTOM(tagevprov, CTCTags::EventListener, OnUserTagMessageBlocked, (source, msgtarget, msgdetails)); return false; } // Inform modules that a TAGMSG is about to be sent. FOREACH_MOD_CUSTOM(tagevprov, CTCTags::EventListener, OnUserTagMessage, (source, msgtarget, msgdetails)); return true; } CmdResult FirePostEvent(User* source, const MessageTarget& msgtarget, const CTCTags::TagMessageDetails& msgdetails) { // If the source is local then update its idle time. LocalUser* lsource = IS_LOCAL(source); if (lsource) lsource->idle_lastmsg = ServerInstance->Time(); // Inform modules that a TAGMSG was sent. FOREACH_MOD_CUSTOM(tagevprov, CTCTags::EventListener, OnUserPostTagMessage, (source, msgtarget, msgdetails)); return CMD_SUCCESS; } CmdResult HandleChannelTarget(User* source, const Params& parameters, const char* target, PrefixMode* pm) { Channel* chan = ServerInstance->FindChan(target); if (!chan) { // The target channel does not exist. source->WriteNumeric(Numerics::NoSuchChannel(parameters[0])); return CMD_FAILURE; } // Fire the pre-message events. MessageTarget msgtarget(chan, pm ? pm->GetPrefix() : 0); CTCTags::TagMessageDetails msgdetails(parameters.GetTags()); if (!FirePreEvents(source, msgtarget, msgdetails)) return CMD_FAILURE; unsigned int minrank = pm ? pm->GetPrefixRank() : 0; CTCTags::TagMessage message(source, chan, msgdetails.tags_out); message.SetSideEffect(true); const Channel::MemberMap& userlist = chan->GetUsers(); for (Channel::MemberMap::const_iterator iter = userlist.begin(); iter != userlist.end(); ++iter) { LocalUser* luser = IS_LOCAL(iter->first); // Don't send to remote users or the user who is the source. if (!luser || luser == source) continue; // Don't send to unprivileged or exempt users. if (iter->second->getRank() < minrank || msgdetails.exemptions.count(luser)) continue; // Send to users if they have the capability. if (cap.get(luser)) luser->Send(msgevprov, message); } return FirePostEvent(source, msgtarget, msgdetails); } CmdResult HandleServerTarget(User* source, const Params& parameters) { // If the source isn't allowed to mass message users then reject // the attempt to mass-message users. if (!source->HasPrivPermission("users/mass-message")) return CMD_FAILURE; // Extract the server glob match from the target parameter. std::string servername(parameters[0], 1); // Fire the pre-message events. MessageTarget msgtarget(&servername); CTCTags::TagMessageDetails msgdetails(parameters.GetTags()); if (!FirePreEvents(source, msgtarget, msgdetails)) return CMD_FAILURE; // If the current server name matches the server name glob then send // the message out to the local users. if (InspIRCd::Match(ServerInstance->Config->ServerName, servername)) { CTCTags::TagMessage message(source, "$*", msgdetails.tags_out); message.SetSideEffect(true); const UserManager::LocalList& list = ServerInstance->Users.GetLocalUsers(); for (UserManager::LocalList::const_iterator iter = list.begin(); iter != list.end(); ++iter) { LocalUser* luser = IS_LOCAL(*iter); // Don't send to unregistered users or the user who is the source. if (luser->registered != REG_ALL || luser == source) continue; // Don't send to exempt users. if (msgdetails.exemptions.count(luser)) continue; // Send to users if they have the capability. if (cap.get(luser)) luser->Send(msgevprov, message); } } // Fire the post-message event. return FirePostEvent(source, msgtarget, msgdetails); } CmdResult HandleUserTarget(User* source, const Params& parameters) { User* target; if (IS_LOCAL(source)) { // Local sources can specify either a nick or a nick@server mask as the target. const char* targetserver = strchr(parameters[0].c_str(), '@'); if (targetserver) { // The target is a user on a specific server (e.g. jto@tolsun.oulu.fi). target = ServerInstance->FindNickOnly(parameters[0].substr(0, targetserver - parameters[0].c_str())); if (target && strcasecmp(target->server->GetName().c_str(), targetserver + 1)) target = NULL; } else { // If the source is a local user then we only look up the target by nick. target = ServerInstance->FindNickOnly(parameters[0]); } } else { // Remote users can only specify a nick or UUID as the target. target = ServerInstance->FindNick(parameters[0]); } if (!target || target->registered != REG_ALL) { // The target user does not exist or is not fully registered. source->WriteNumeric(Numerics::NoSuchNick(parameters[0])); return CMD_FAILURE; } // Fire the pre-message events. MessageTarget msgtarget(target); CTCTags::TagMessageDetails msgdetails(parameters.GetTags()); if (!FirePreEvents(source, msgtarget, msgdetails)) return CMD_FAILURE; LocalUser* const localtarget = IS_LOCAL(target); if (localtarget && cap.get(localtarget)) { // Send to the target if they have the capability and are a local user. CTCTags::TagMessage message(source, localtarget, msgdetails.tags_out); message.SetSideEffect(true); localtarget->Send(msgevprov, message); } // Fire the post-message event. return FirePostEvent(source, msgtarget, msgdetails); } public: CommandTagMsg(Module* Creator, Cap::Capability& Cap) : Command(Creator, "TAGMSG", 1) , cap(Cap) , tagevprov(Creator, "event/tagmsg") , msgevprov(Creator, "TAGMSG") { allow_empty_last_param = false; } CmdResult Handle(User* user, const Params& parameters) CXX11_OVERRIDE { if (CommandParser::LoopCall(user, this, parameters, 0)) return CMD_SUCCESS; // Check that the source has the message tags capability. if (IS_LOCAL(user) && !cap.get(user)) return CMD_FAILURE; // The target is a server glob. if (parameters[0][0] == '$') return HandleServerTarget(user, parameters); // If the message begins with a status character then look it up. const char* target = parameters[0].c_str(); PrefixMode* pmh = ServerInstance->Modes->FindPrefix(target[0]); if (pmh) target++; // The target is a channel name. if (*target == '#') return HandleChannelTarget(user, parameters, target, pmh); // The target is a nickname. return HandleUserTarget(user, parameters); } RouteDescriptor GetRouting(User* user, const Params& parameters) CXX11_OVERRIDE { if (IS_LOCAL(user)) // This is handled by the OnUserPostTagMessage hook to split the LoopCall pieces return ROUTE_LOCALONLY; else return ROUTE_MESSAGE(parameters[0]); } }; class C2CTags : public ClientProtocol::MessageTagProvider { private: Cap::Capability& cap; public: C2CTags(Module* Creator, Cap::Capability& Cap) : ClientProtocol::MessageTagProvider(Creator) , cap(Cap) { } ModResult OnProcessTag(User* user, const std::string& tagname, std::string& tagvalue) CXX11_OVERRIDE { // A client-only tag is prefixed with a plus sign (+) and otherwise conforms // to the format specified in IRCv3.2 tags. if (tagname[0] != '+' || tagname.length() < 2) return MOD_RES_PASSTHRU; // If the user is local then we check whether they have the message-tags cap // enabled. If not then we reject all client-only tags originating from them. LocalUser* lu = IS_LOCAL(user); if (lu && !cap.get(lu)) return MOD_RES_DENY; // Remote users have their client-only tags checked by their local server. return MOD_RES_ALLOW; } bool ShouldSendTag(LocalUser* user, const ClientProtocol::MessageTagData& tagdata) CXX11_OVERRIDE { return cap.get(user); } }; class ModuleIRCv3CTCTags : public Module , public CTCTags::EventListener { private: Cap::Capability cap; CommandTagMsg cmd; C2CTags c2ctags; ChanModeReference moderatedmode; ChanModeReference noextmsgmode; ModResult CopyClientTags(const ClientProtocol::TagMap& tags_in, ClientProtocol::TagMap& tags_out) { for (ClientProtocol::TagMap::const_iterator i = tags_in.begin(); i != tags_in.end(); ++i) { const ClientProtocol::MessageTagData& tagdata = i->second; if (tagdata.tagprov == &c2ctags) tags_out.insert(*i); } return MOD_RES_PASSTHRU; } public: ModuleIRCv3CTCTags() : CTCTags::EventListener(this) , cap(this, "message-tags") , cmd(this, cap) , c2ctags(this, cap) , moderatedmode(this, "moderated") , noextmsgmode(this, "noextmsg") { } ModResult OnUserPreMessage(User* user, const MessageTarget& target, MessageDetails& details) CXX11_OVERRIDE { return CopyClientTags(details.tags_in, details.tags_out); } ModResult OnUserPreTagMessage(User* user, const MessageTarget& target, CTCTags::TagMessageDetails& details) CXX11_OVERRIDE { if (IS_LOCAL(user) && target.type == MessageTarget::TYPE_CHANNEL) { Channel* chan = target.Get<Channel>(); if (chan->IsModeSet(noextmsgmode) && !chan->HasUser(user)) { // The noextmsg mode is set and the user is not in the channel. user->WriteNumeric(ERR_CANNOTSENDTOCHAN, chan->name, "Cannot send to channel (no external messages)"); return MOD_RES_DENY; } bool no_chan_priv = chan->GetPrefixValue(user) < VOICE_VALUE; if (no_chan_priv && chan->IsModeSet(moderatedmode)) { // The moderated mode is set and the user has no status rank. user->WriteNumeric(ERR_CANNOTSENDTOCHAN, chan->name, "Cannot send to channel (+m is set)"); return MOD_RES_DENY; } if (no_chan_priv && ServerInstance->Config->RestrictBannedUsers != ServerConfig::BUT_NORMAL && chan->IsBanned(user)) { // The user is banned in the channel and restrictbannedusers is enabled. if (ServerInstance->Config->RestrictBannedUsers == ServerConfig::BUT_RESTRICT_NOTIFY) user->WriteNumeric(ERR_CANNOTSENDTOCHAN, chan->name, "Cannot send to channel (you're banned)"); return MOD_RES_DENY; } } return CopyClientTags(details.tags_in, details.tags_out); } Version GetVersion() CXX11_OVERRIDE { return Version("Provides the message-tags IRCv3 extension", VF_VENDOR | VF_COMMON); } }; MODULE_INIT(ModuleIRCv3CTCTags) ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/src/modules/m_ircv3_echomessage.cpp��������������������������������������������������0000664�0000000�0000000�00000010427�13554550454�0022217�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * InspIRCd -- Internet Relay Chat Daemon * * Copyright (C) 2015 Attila Molnar <attilamolnar@hush.com> * Copyright (C) 2013-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 "inspircd.h" #include "modules/cap.h" #include "modules/ctctags.h" class ModuleIRCv3EchoMessage : public Module , public CTCTags::EventListener { private: Cap::Capability cap; ClientProtocol::EventProvider tagmsgprov; public: ModuleIRCv3EchoMessage() : CTCTags::EventListener(this) , cap(this, "echo-message") , tagmsgprov(this, "TAGMSG") { } void OnUserPostMessage(User* user, const MessageTarget& target, const MessageDetails& details) CXX11_OVERRIDE { if (!cap.get(user) || !details.echo) return; // Caps are only set on local users LocalUser* const localuser = static_cast<LocalUser*>(user); const std::string& text = details.echo_original ? details.original_text : details.text; const ClientProtocol::TagMap& tags = details.echo_original ? details.tags_in : details.tags_out; switch (target.type) { case MessageTarget::TYPE_USER: { User* destuser = target.Get<User>(); ClientProtocol::Messages::Privmsg privmsg(ClientProtocol::Messages::Privmsg::nocopy, user, destuser, text, details.type); privmsg.AddTags(tags); localuser->Send(ServerInstance->GetRFCEvents().privmsg, privmsg); break; } case MessageTarget::TYPE_CHANNEL: { Channel* chan = target.Get<Channel>(); ClientProtocol::Messages::Privmsg privmsg(ClientProtocol::Messages::Privmsg::nocopy, user, chan, text, details.type, target.status); privmsg.AddTags(tags); localuser->Send(ServerInstance->GetRFCEvents().privmsg, privmsg); break; } case MessageTarget::TYPE_SERVER: { const std::string* servername = target.Get<std::string>(); ClientProtocol::Messages::Privmsg privmsg(ClientProtocol::Messages::Privmsg::nocopy, user, *servername, text, details.type); privmsg.AddTags(tags); localuser->Send(ServerInstance->GetRFCEvents().privmsg, privmsg); break; } } } void OnUserPostTagMessage(User* user, const MessageTarget& target, const CTCTags::TagMessageDetails& details) CXX11_OVERRIDE { if (!cap.get(user) || !details.echo) return; // Caps are only set on local users LocalUser* const localuser = static_cast<LocalUser*>(user); const ClientProtocol::TagMap& tags = details.echo_original ? details.tags_in : details.tags_out; switch (target.type) { case MessageTarget::TYPE_USER: { User* destuser = target.Get<User>(); CTCTags::TagMessage message(user, destuser, tags); localuser->Send(tagmsgprov, message); break; } case MessageTarget::TYPE_CHANNEL: { Channel* chan = target.Get<Channel>(); CTCTags::TagMessage message(user, chan, tags); localuser->Send(tagmsgprov, message); break; } case MessageTarget::TYPE_SERVER: { const std::string* servername = target.Get<std::string>(); CTCTags::TagMessage message(user, servername->c_str(), tags); localuser->Send(tagmsgprov, message); break; } } } void OnUserMessageBlocked(User* user, const MessageTarget& target, const MessageDetails& details) CXX11_OVERRIDE { // Prevent spammers from knowing that their spam was blocked. if (details.echo_original) OnUserPostMessage(user, target, details); } void OnUserTagMessageBlocked(User* user, const MessageTarget& target, const CTCTags::TagMessageDetails& details) CXX11_OVERRIDE { // Prevent spammers from knowing that their spam was blocked. if (details.echo_original) OnUserPostTagMessage(user, target, details); } Version GetVersion() CXX11_OVERRIDE { return Version("Provides the echo-message IRCv3 extension", VF_VENDOR); } }; MODULE_INIT(ModuleIRCv3EchoMessage) �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/src/modules/m_ircv3_invitenotify.cpp�������������������������������������������������0000664�0000000�0000000�00000004411�13554550454�0022457�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * InspIRCd -- Internet Relay Chat Daemon * * Copyright (C) 2015 Attila Molnar <attilamolnar@hush.com> * * This file is part of InspIRCd. InspIRCd is free software: you can * redistribute it and/or modify it under the terms of the GNU General Public * License as published by the Free Software Foundation, version 2. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include "inspircd.h" #include "modules/cap.h" class ModuleIRCv3InviteNotify : public Module { Cap::Capability cap; public: ModuleIRCv3InviteNotify() : cap(this, "invite-notify") { } void OnUserInvite(User* source, User* dest, Channel* chan, time_t expiry, unsigned int notifyrank, CUList& notifyexcepts) CXX11_OVERRIDE { ClientProtocol::Messages::Invite invitemsg(source, dest, chan); ClientProtocol::Event inviteevent(ServerInstance->GetRFCEvents().invite, invitemsg); const Channel::MemberMap& users = chan->GetUsers(); for (Channel::MemberMap::const_iterator i = users.begin(); i != users.end(); ++i) { User* user = i->first; // Skip members who don't use this extension or were excluded by other modules if ((!cap.get(user)) || (notifyexcepts.count(user))) continue; Membership* memb = i->second; // Check whether the member has a high enough rank to see the notification if (memb->getRank() < notifyrank) continue; // Caps are only set on local users LocalUser* const localuser = static_cast<LocalUser*>(user); // Send and add the user to the exceptions so they won't get the NOTICE invite announcement message localuser->Send(inviteevent); notifyexcepts.insert(user); } } void Prioritize() CXX11_OVERRIDE { // Prioritize after all modules to see all excepted users ServerInstance->Modules.SetPriority(this, I_OnUserInvite, PRIORITY_LAST); } Version GetVersion() CXX11_OVERRIDE { return Version("Provides the invite-notify IRCv3 extension", VF_VENDOR); } }; MODULE_INIT(ModuleIRCv3InviteNotify) �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/src/modules/m_ircv3_msgid.cpp��������������������������������������������������������0000664�0000000�0000000�00000006243�13554550454�0021040�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * InspIRCd -- Internet Relay Chat Daemon * * Copyright (C) 2019 Peter Powell <petpow@saberuk.com> * Copyright (C) 2016 Attila Molnar <attilamolnar@hush.com> * * This file is part of InspIRCd. InspIRCd is free software: you can * redistribute it and/or modify it under the terms of the GNU General Public * License as published by the Free Software Foundation, version 2. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include "inspircd.h" #include "modules/cap.h" #include "modules/ctctags.h" class MsgIdTag : public ClientProtocol::MessageTagProvider { private: Cap::Reference ctctagcap; public: MsgIdTag(Module* mod) : ClientProtocol::MessageTagProvider(mod) , ctctagcap(mod, "message-tags") { } ModResult OnProcessTag(User* user, const std::string& tagname, std::string& tagvalue) CXX11_OVERRIDE { if (!irc::equals(tagname, "msgid")) return MOD_RES_PASSTHRU; // We should only allow this tag if it is added by a remote server. return IS_LOCAL(user) ? MOD_RES_DENY : MOD_RES_ALLOW; } bool ShouldSendTag(LocalUser* user, const ClientProtocol::MessageTagData& tagdata) CXX11_OVERRIDE { return ctctagcap.get(user); } }; class MsgIdGenerator { uint64_t counter; std::string strid; const std::string::size_type baselen; public: MsgIdGenerator() : counter(0) , strid(InspIRCd::Format("%s~%lu~", ServerInstance->Config->GetSID().c_str(), ServerInstance->startup_time)) , baselen(strid.length()) { } const std::string& GetNext() { strid.erase(baselen); strid.append(ConvToStr(counter++)); return strid; } }; class ModuleMsgId : public Module , public CTCTags::EventListener { private: MsgIdTag tag; MsgIdGenerator generator; ModResult CopyMessageId(const ClientProtocol::TagMap& tags_in, ClientProtocol::TagMap& tags_out) { ClientProtocol::TagMap::const_iterator iter = tags_in.find("msgid"); if (iter != tags_in.end()) { // If the remote server has sent a message identifier we should use that as // identifiers need to be the same on all sides of the network. tags_out.insert(*iter); return MOD_RES_PASSTHRU; } // Otherwise, we can just create a new message identifier. tags_out.insert(std::make_pair("msgid", ClientProtocol::MessageTagData(&tag, generator.GetNext()))); return MOD_RES_PASSTHRU; } public: ModuleMsgId() : CTCTags::EventListener(this) , tag(this) { } ModResult OnUserPreMessage(User* user, const MessageTarget& target, MessageDetails& details) CXX11_OVERRIDE { return CopyMessageId(details.tags_in, details.tags_out); } ModResult OnUserPreTagMessage(User* user, const MessageTarget& target, CTCTags::TagMessageDetails& details) CXX11_OVERRIDE { return CopyMessageId(details.tags_in, details.tags_out); } Version GetVersion() CXX11_OVERRIDE { return Version("Provides the msgid IRCv3 tag", VF_VENDOR); } }; MODULE_INIT(ModuleMsgId) �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/src/modules/m_ircv3_servertime.cpp���������������������������������������������������0000664�0000000�0000000�00000004632�13554550454�0022122�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * InspIRCd -- Internet Relay Chat Daemon * * Copyright (C) 2016 Attila Molnar <attilamolnar@hush.com> * * This file is part of InspIRCd. InspIRCd is free software: you can * redistribute it and/or modify it under the terms of the GNU General Public * License as published by the Free Software Foundation, version 2. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include "inspircd.h" #include "modules/ircv3.h" #include "modules/ircv3_servertime.h" #include "modules/server.h" class ServerTimeTag : public IRCv3::ServerTime::Manager , public IRCv3::CapTag<ServerTimeTag> , public ServerProtocol::MessageEventListener { time_t lasttime; long lasttimens; std::string lasttimestring; void RefreshTimeString() { const time_t currtime = ServerInstance->Time(); const long currtimens = ServerInstance->Time_ns(); if (currtime != lasttime || currtimens != lasttimens) { lasttime = currtime; lasttimens = currtimens; // Cache the string so it's not recreated every time a message is sent. lasttimestring = IRCv3::ServerTime::FormatTime(currtime, (currtimens ? currtimens / 1000000 : 0)); } } public: using ServerProtocol::MessageEventListener::OnBuildMessage; ServerTimeTag(Module* mod) : IRCv3::ServerTime::Manager(mod) , IRCv3::CapTag<ServerTimeTag>(mod, "server-time", "time") , ServerProtocol::MessageEventListener(mod) , lasttime(0) , lasttimens(0) { tagprov = this; } const std::string* GetValue(const ClientProtocol::Message& msg) { // Client protocol. RefreshTimeString(); return &lasttimestring; } void OnBuildMessage(User* source, const char* command, ClientProtocol::TagMap& tags) CXX11_OVERRIDE { // Server protocol. RefreshTimeString(); tags.insert(std::make_pair(tagname, ClientProtocol::MessageTagData(this, lasttimestring))); } }; class ModuleIRCv3ServerTime : public Module { ServerTimeTag tag; public: ModuleIRCv3ServerTime() : tag(this) { } Version GetVersion() CXX11_OVERRIDE { return Version("Provides the server-time IRCv3 extension", VF_VENDOR); } }; MODULE_INIT(ModuleIRCv3ServerTime) ������������������������������������������������������������������������������������������������������inspircd-3.4.0/src/modules/m_ircv3_sts.cpp����������������������������������������������������������0000664�0000000�0000000�00000013445�13554550454�0020550�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * InspIRCd -- Internet Relay Chat Daemon * * Copyright (C) 2015 Attila Molnar <attilamolnar@hush.com> * Copyright (C) 2017 Peter Powell <petpow@saberuk.com> * * This file is part of InspIRCd. InspIRCd is free software: you can * redistribute it and/or modify it under the terms of the GNU General Public * License as published by the Free Software Foundation, version 2. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include "inspircd.h" #include "modules/cap.h" #include "modules/ssl.h" class STSCap : public Cap::Capability { private: std::string host; std::string plaintextpolicy; std::string securepolicy; bool OnList(LocalUser* user) CXX11_OVERRIDE { // Don't send the cap to clients that only support cap-3.1. if (GetProtocol(user) == Cap::CAP_LEGACY) return false; // Don't send the cap to clients in a class which has STS disabled. if (!user->GetClass()->config->getBool("usests", true)) return false; // Plaintext listeners have their own policy. SSLIOHook* sslhook = SSLIOHook::IsSSL(&user->eh); if (!sslhook) return true; // If no hostname has been provided for the connection, an STS persistence policy SHOULD NOT be advertised. std::string snihost; if (!sslhook->GetServerName(snihost)) return false; // Before advertising an STS persistence policy over a secure connection, servers SHOULD verify whether the // hostname provided by clients, for example, via TLS Server Name Indication (SNI), has been whitelisted by // administrators in the server configuration. return InspIRCd::Match(snihost, host, ascii_case_insensitive_map); } bool OnRequest(LocalUser* user, bool adding) CXX11_OVERRIDE { // Clients MUST NOT request this capability with CAP REQ. Servers MAY reply with a CAP NAK message if a // client requests this capability. return false; } const std::string* GetValue(LocalUser* user) const CXX11_OVERRIDE { return SSLIOHook::IsSSL(&user->eh) ? &securepolicy : &plaintextpolicy; } public: STSCap(Module* mod) : Cap::Capability(mod, "sts") { } ~STSCap() { // TODO: Send duration=0 when STS vanishes. } void SetPolicy(const std::string& newhost, unsigned long duration, unsigned int port, bool preload) { // To enforce an STS upgrade policy, servers MUST send this key to insecurely connected clients. Servers // MAY send this key to securely connected clients, but it will be ignored. std::string newplaintextpolicy("port="); newplaintextpolicy.append(ConvToStr(port)); // To enforce an STS persistence policy, servers MUST send this key to securely connected clients. Servers // MAY send this key to all clients, but insecurely connected clients MUST ignore it. std::string newsecurepolicy("duration="); newsecurepolicy.append(ConvToStr(duration)); // Servers MAY send this key to all clients, but insecurely connected clients MUST ignore it. if (preload) newsecurepolicy.append(",preload"); // Apply the new policy. bool changed = false; if (!irc::equals(host, newhost)) { ServerInstance->Logs->Log(MODNAME, LOG_DEBUG, "Changing STS SNI hostname from \"%s\" to \"%s\"", host.c_str(), newhost.c_str()); host = newhost; changed = true; } if (plaintextpolicy != newplaintextpolicy) { ServerInstance->Logs->Log(MODNAME, LOG_DEBUG, "Changing plaintext STS policy from \"%s\" to \"%s\"", plaintextpolicy.c_str(), newplaintextpolicy.c_str()); plaintextpolicy.swap(newplaintextpolicy); changed = true; } if (securepolicy != newsecurepolicy) { ServerInstance->Logs->Log(MODNAME, LOG_DEBUG, "Changing secure STS policy from \"%s\" to \"%s\"", securepolicy.c_str(), newsecurepolicy.c_str()); securepolicy.swap(newsecurepolicy); changed = true; } // If the policy has changed then notify all clients via cap-notify. if (changed) NotifyValueChange(); } }; class ModuleIRCv3STS : public Module { private: STSCap cap; // The IRCv3 STS specification requires that the server is listening using SSL using a valid certificate. bool HasValidSSLPort(unsigned int port) { for (std::vector<ListenSocket*>::const_iterator iter = ServerInstance->ports.begin(); iter != ServerInstance->ports.end(); ++iter) { ListenSocket* ls = *iter; // Is this listener on the right port? unsigned int saport = ls->bind_sa.port(); if (saport != port) continue; // Is this listener using SSL? if (ls->bind_tag->getString("ssl").empty()) continue; // TODO: Add a way to check if a listener's TLS cert is CA-verified. return true; } return false; } public: ModuleIRCv3STS() : cap(this) { } void ReadConfig(ConfigStatus& status) CXX11_OVERRIDE { // TODO: Multiple SNI profiles ConfigTag* tag = ServerInstance->Config->ConfValue("sts"); if (tag == ServerInstance->Config->EmptyTag) throw ModuleException("You must define a STS policy!"); const std::string host = tag->getString("host"); if (host.empty()) throw ModuleException("<sts:host> must contain a hostname, at " + tag->getTagLocation()); unsigned int port = tag->getUInt("port", 0, 0, UINT16_MAX); if (!HasValidSSLPort(port)) throw ModuleException("<sts:port> must be a TLS port, at " + tag->getTagLocation()); unsigned long duration = tag->getDuration("duration", 60*60*24*30*2); bool preload = tag->getBool("preload"); cap.SetPolicy(host, duration, port, preload); } Version GetVersion() CXX11_OVERRIDE { return Version("Provides IRCv3 Strict Transport Security policy advertisement", VF_OPTCOMMON|VF_VENDOR); } }; MODULE_INIT(ModuleIRCv3STS) ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/src/modules/m_joinflood.cpp����������������������������������������������������������0000664�0000000�0000000�00000011264�13554550454�0020611�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * InspIRCd -- Internet Relay Chat Daemon * * Copyright (C) 2009 Daniel De Graaf <danieldg@inspircd.org> * Copyright (C) 2007 Dennis Friis <peavey@inspircd.org> * Copyright (C) 2007 Robin Burchell <robin+git@viroteck.net> * Copyright (C) 2006-2007 Craig Edwards <craigedwards@brainbox.cc> * Copyright (C) 2006 Oliver Lupton <oliverlupton@gmail.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 "inspircd.h" enum { // From RFC 2182. ERR_UNAVAILRESOURCE = 437 }; // The number of seconds the channel will be closed for. static unsigned int duration; /** Holds settings and state associated with channel mode +j */ class joinfloodsettings { public: unsigned int secs; unsigned int joins; time_t reset; time_t unlocktime; unsigned int counter; joinfloodsettings(unsigned int b, unsigned int c) : secs(b), joins(c), unlocktime(0), counter(0) { reset = ServerInstance->Time() + secs; } void addjoin() { if (ServerInstance->Time() > reset) { counter = 1; reset = ServerInstance->Time() + secs; } else counter++; } bool shouldlock() { return (counter >= this->joins); } void clear() { counter = 0; } bool islocked() { if (ServerInstance->Time() > unlocktime) unlocktime = 0; return (unlocktime != 0); } void lock() { unlocktime = ServerInstance->Time() + duration; } bool operator==(const joinfloodsettings& other) const { return ((this->secs == other.secs) && (this->joins == other.joins)); } }; /** Handles channel mode +j */ class JoinFlood : public ParamMode<JoinFlood, SimpleExtItem<joinfloodsettings> > { public: JoinFlood(Module* Creator) : ParamMode<JoinFlood, SimpleExtItem<joinfloodsettings> >(Creator, "joinflood", 'j') { syntax = "<joins>:<seconds>"; } ModeAction OnSet(User* source, Channel* channel, std::string& parameter) CXX11_OVERRIDE { std::string::size_type colon = parameter.find(':'); if ((colon == std::string::npos) || (parameter.find('-') != std::string::npos)) { source->WriteNumeric(Numerics::InvalidModeParameter(channel, this, parameter)); return MODEACTION_DENY; } /* Set up the flood parameters for this channel */ unsigned int njoins = ConvToNum<unsigned int>(parameter.substr(0, colon)); unsigned int nsecs = ConvToNum<unsigned int>(parameter.substr(colon+1)); if ((njoins<1) || (nsecs<1)) { source->WriteNumeric(Numerics::InvalidModeParameter(channel, this, parameter)); return MODEACTION_DENY; } ext.set(channel, new joinfloodsettings(nsecs, njoins)); return MODEACTION_ALLOW; } void SerializeParam(Channel* chan, const joinfloodsettings* jfs, std::string& out) { out.append(ConvToStr(jfs->joins)).push_back(':'); out.append(ConvToStr(jfs->secs)); } }; class ModuleJoinFlood : public Module { JoinFlood jf; public: ModuleJoinFlood() : jf(this) { } void ReadConfig(ConfigStatus&) CXX11_OVERRIDE { ConfigTag* tag = ServerInstance->Config->ConfValue("joinflood"); duration = tag->getDuration("duration", 60, 10, 600); } ModResult OnUserPreJoin(LocalUser* user, Channel* chan, const std::string& cname, std::string& privs, const std::string& keygiven) CXX11_OVERRIDE { if (chan) { joinfloodsettings *f = jf.ext.get(chan); if (f && f->islocked()) { user->WriteNumeric(ERR_UNAVAILRESOURCE, chan->name, "This channel is temporarily unavailable (+j is set). Please try again later."); return MOD_RES_DENY; } } return MOD_RES_PASSTHRU; } void OnUserJoin(Membership* memb, bool sync, bool created, CUList& excepts) CXX11_OVERRIDE { /* We arent interested in JOIN events caused by a network burst */ if (sync) return; joinfloodsettings *f = jf.ext.get(memb->chan); /* But all others are OK */ if ((f) && (!f->islocked())) { f->addjoin(); if (f->shouldlock()) { f->clear(); f->lock(); memb->chan->WriteNotice(InspIRCd::Format("This channel has been closed to new users for %u seconds because there have been more than %d joins in %d seconds.", duration, f->joins, f->secs)); } } } Version GetVersion() CXX11_OVERRIDE { return Version("Provides channel mode +j, join flood protection", VF_VENDOR); } }; MODULE_INIT(ModuleJoinFlood) ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/src/modules/m_kicknorejoin.cpp�������������������������������������������������������0000664�0000000�0000000�00000010373�13554550454�0021313�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * InspIRCd -- Internet Relay Chat Daemon * * Copyright (C) 2009 Daniel De Graaf <danieldg@inspircd.org> * Copyright (C) 2008 Pippijn van Steenhoven <pip88nl@gmail.com> * Copyright (C) 2007 Dennis Friis <peavey@inspircd.org> * Copyright (C) 2006-2007 Robin Burchell <robin+git@viroteck.net> * Copyright (C) 2006 John Brooks <john.brooks@dereferenced.net> * Copyright (C) 2006 Craig Edwards <craigedwards@brainbox.cc> * Copyright (C) 2006 Oliver Lupton <oliverlupton@gmail.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 "inspircd.h" #include "modules/invite.h" enum { // From RFC 2182. ERR_UNAVAILRESOURCE = 437 }; class KickRejoinData { struct KickedUser { std::string uuid; time_t expire; KickedUser(User* user, unsigned int Delay) : uuid(user->uuid) , expire(ServerInstance->Time() + Delay) { } }; typedef std::vector<KickedUser> KickedList; mutable KickedList kicked; public: const unsigned int delay; KickRejoinData(unsigned int Delay) : delay(Delay) { } bool canjoin(LocalUser* user) const { for (KickedList::iterator i = kicked.begin(); i != kicked.end(); ) { KickedUser& rec = *i; if (rec.expire > ServerInstance->Time()) { if (rec.uuid == user->uuid) return false; ++i; } else { // Expired record, remove. stdalgo::vector::swaperase(kicked, i); if (kicked.empty()) break; } } return true; } void add(User* user) { // One user can be in the list multiple times if the user gets kicked, force joins // (skipping OnUserPreJoin) and gets kicked again, but that's okay because canjoin() // works correctly in this case as well kicked.push_back(KickedUser(user, delay)); } }; /** Handles channel mode +J */ class KickRejoin : public ParamMode<KickRejoin, SimpleExtItem<KickRejoinData> > { const unsigned int max; public: KickRejoin(Module* Creator) : ParamMode<KickRejoin, SimpleExtItem<KickRejoinData> >(Creator, "kicknorejoin", 'J') , max(60) { syntax = "<seconds>"; } ModeAction OnSet(User* source, Channel* channel, std::string& parameter) CXX11_OVERRIDE { unsigned int v = ConvToNum<unsigned int>(parameter); if (v <= 0) { source->WriteNumeric(Numerics::InvalidModeParameter(channel, this, parameter)); return MODEACTION_DENY; } if (IS_LOCAL(source) && v > max) v = max; ext.set(channel, new KickRejoinData(v)); return MODEACTION_ALLOW; } void SerializeParam(Channel* chan, const KickRejoinData* krd, std::string& out) { out.append(ConvToStr(krd->delay)); } std::string GetModuleSettings() const { return ConvToStr(max); } }; class ModuleKickNoRejoin : public Module { KickRejoin kr; Invite::API invapi; public: ModuleKickNoRejoin() : kr(this) , invapi(this) { } ModResult OnUserPreJoin(LocalUser* user, Channel* chan, const std::string& cname, std::string& privs, const std::string& keygiven) CXX11_OVERRIDE { if (chan) { const KickRejoinData* data = kr.ext.get(chan); if ((data) && !invapi->IsInvited(user, chan) && (!data->canjoin(user))) { user->WriteNumeric(ERR_UNAVAILRESOURCE, chan, InspIRCd::Format("You must wait %u seconds after being kicked to rejoin (+J is set)", data->delay)); return MOD_RES_DENY; } } return MOD_RES_PASSTHRU; } void OnUserKick(User* source, Membership* memb, const std::string &reason, CUList& excepts) CXX11_OVERRIDE { if ((!IS_LOCAL(memb->user)) || (source == memb->user)) return; KickRejoinData* data = kr.ext.get(memb->chan); if (data) { data->add(memb->user); } } Version GetVersion() CXX11_OVERRIDE { return Version("Provides channel mode +J, delays rejoins after kicks", VF_VENDOR | VF_COMMON, kr.GetModuleSettings()); } }; MODULE_INIT(ModuleKickNoRejoin) ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/src/modules/m_knock.cpp��������������������������������������������������������������0000664�0000000�0000000�00000007144�13554550454�0017735�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * InspIRCd -- Internet Relay Chat Daemon * * Copyright (C) 2004-2006, 2008 Craig Edwards <craigedwards@brainbox.cc> * Copyright (C) 2007 Dennis Friis <peavey@inspircd.org> * Copyright (C) 2007 Robin Burchell <robin+git@viroteck.net> * * 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 "inspircd.h" enum { // From UnrealIRCd. ERR_CANNOTKNOCK = 480, // From ircd-ratbox. ERR_CHANOPEN = 713, ERR_KNOCKONCHAN = 714 }; /** Handles the /KNOCK command */ class CommandKnock : public Command { SimpleChannelModeHandler& noknockmode; ChanModeReference inviteonlymode; public: bool sendnotice; bool sendnumeric; CommandKnock(Module* Creator, SimpleChannelModeHandler& Noknockmode) : Command(Creator,"KNOCK", 2, 2) , noknockmode(Noknockmode) , inviteonlymode(Creator, "inviteonly") { syntax = "<channel> :<reason>"; Penalty = 5; } CmdResult Handle(User* user, const Params& parameters) CXX11_OVERRIDE { Channel* c = ServerInstance->FindChan(parameters[0]); if (!c) { user->WriteNumeric(Numerics::NoSuchChannel(parameters[0])); return CMD_FAILURE; } if (c->HasUser(user)) { user->WriteNumeric(ERR_KNOCKONCHAN, c->name, InspIRCd::Format("Can't KNOCK on %s, you are already on that channel.", c->name.c_str())); return CMD_FAILURE; } if (c->IsModeSet(noknockmode)) { user->WriteNumeric(ERR_CANNOTKNOCK, InspIRCd::Format("Can't KNOCK on %s, +K is set.", c->name.c_str())); return CMD_FAILURE; } if (!c->IsModeSet(inviteonlymode)) { user->WriteNumeric(ERR_CHANOPEN, c->name, InspIRCd::Format("Can't KNOCK on %s, channel is not invite only so knocking is pointless!", c->name.c_str())); return CMD_FAILURE; } if (sendnotice) c->WriteNotice(InspIRCd::Format("User %s is KNOCKing on %s (%s)", user->nick.c_str(), c->name.c_str(), parameters[1].c_str())); if (sendnumeric) { Numeric::Numeric numeric(710); numeric.push(c->name).push(user->GetFullHost()).push("is KNOCKing: " + parameters[1]); ClientProtocol::Messages::Numeric numericmsg(numeric, c->name); c->Write(ServerInstance->GetRFCEvents().numeric, numericmsg); } user->WriteNotice("KNOCKing on " + c->name); return CMD_SUCCESS; } RouteDescriptor GetRouting(User* user, const Params& parameters) CXX11_OVERRIDE { return ROUTE_OPT_BCAST; } }; class ModuleKnock : public Module { SimpleChannelModeHandler kn; CommandKnock cmd; public: ModuleKnock() : kn(this, "noknock", 'K') , cmd(this, kn) { } void ReadConfig(ConfigStatus& status) CXX11_OVERRIDE { std::string knocknotify = ServerInstance->Config->ConfValue("knock")->getString("notify"); if (stdalgo::string::equalsci(knocknotify, "numeric")) { cmd.sendnotice = false; cmd.sendnumeric = true; } else if (stdalgo::string::equalsci(knocknotify, "both")) { cmd.sendnotice = true; cmd.sendnumeric = true; } else { cmd.sendnotice = true; cmd.sendnumeric = false; } } Version GetVersion() CXX11_OVERRIDE { return Version("Provides the KNOCK command and channel mode +K", VF_OPTCOMMON | VF_VENDOR); } }; MODULE_INIT(ModuleKnock) ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/src/modules/m_ldapauth.cpp�����������������������������������������������������������0000664�0000000�0000000�00000026541�13554550454�0020434�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * InspIRCd -- Internet Relay Chat Daemon * * Copyright (C) 2013 Adam <Adam@anope.org> * Copyright (C) 2011 Pierre Carrier <pierre@spotify.com> * Copyright (C) 2009-2010 Robin Burchell <robin+git@viroteck.net> * Copyright (C) 2009 Daniel De Graaf <danieldg@inspircd.org> * Copyright (C) 2008 Pippijn van Steenhoven <pip88nl@gmail.com> * Copyright (C) 2008 Craig Edwards <craigedwards@brainbox.cc> * Copyright (C) 2008 Dennis Friis <peavey@inspircd.org> * Copyright (C) 2007 Carsten Valdemar Munk <carsten.munk+inspircd@gmail.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 "inspircd.h" #include "modules/ldap.h" namespace { Module* me; std::string killreason; LocalIntExt* authed; bool verbose; std::string vhost; LocalStringExt* vhosts; std::vector<std::pair<std::string, std::string> > requiredattributes; } class BindInterface : public LDAPInterface { const std::string provider; const std::string uid; std::string DN; bool checkingAttributes; bool passed; int attrCount; static std::string SafeReplace(const std::string& text, std::map<std::string, std::string>& replacements) { std::string result; result.reserve(text.length()); for (unsigned int i = 0; i < text.length(); ++i) { char c = text[i]; if (c == '$') { // find the first nonalpha i++; unsigned int start = i; while (i < text.length() - 1 && isalpha(text[i + 1])) ++i; std::string key(text, start, (i - start) + 1); result.append(replacements[key]); } else result.push_back(c); } return result; } static void SetVHost(User* user, const std::string& DN) { if (!vhost.empty()) { irc::commasepstream stream(DN); // mashed map of key:value parts of the DN std::map<std::string, std::string> dnParts; std::string dnPart; while (stream.GetToken(dnPart)) { std::string::size_type pos = dnPart.find('='); if (pos == std::string::npos) // malformed continue; std::string key(dnPart, 0, pos); std::string value(dnPart, pos + 1, dnPart.length() - pos + 1); // +1s to skip the = itself dnParts[key] = value; } // change host according to config key vhosts->set(user, SafeReplace(vhost, dnParts)); } } public: BindInterface(Module* c, const std::string& p, const std::string& u, const std::string& dn) : LDAPInterface(c) , provider(p), uid(u), DN(dn), checkingAttributes(false), passed(false), attrCount(0) { } void OnResult(const LDAPResult& r) CXX11_OVERRIDE { User* user = ServerInstance->FindUUID(uid); dynamic_reference<LDAPProvider> LDAP(me, provider); if (!user || !LDAP) { if (!checkingAttributes || !--attrCount) delete this; return; } if (!checkingAttributes && requiredattributes.empty()) { // We're done, there are no attributes to check SetVHost(user, DN); authed->set(user, 1); delete this; return; } // Already checked attributes? if (checkingAttributes) { if (!passed) { // Only one has to pass passed = true; SetVHost(user, DN); authed->set(user, 1); } // Delete this if this is the last ref if (!--attrCount) delete this; return; } // check required attributes checkingAttributes = true; for (std::vector<std::pair<std::string, std::string> >::const_iterator it = requiredattributes.begin(); it != requiredattributes.end(); ++it) { // Note that only one of these has to match for it to be success const std::string& attr = it->first; const std::string& val = it->second; ServerInstance->Logs->Log(MODNAME, LOG_DEBUG, "LDAP compare: %s=%s", attr.c_str(), val.c_str()); try { LDAP->Compare(this, DN, attr, val); ++attrCount; } catch (LDAPException &ex) { if (verbose) ServerInstance->SNO->WriteToSnoMask('c', "Unable to compare attributes %s=%s: %s", attr.c_str(), val.c_str(), ex.GetReason().c_str()); } } // Nothing done if (!attrCount) { if (verbose) ServerInstance->SNO->WriteToSnoMask('c', "Forbidden connection from %s (unable to validate attributes)", user->GetFullRealHost().c_str()); ServerInstance->Users->QuitUser(user, killreason); delete this; } } void OnError(const LDAPResult& err) CXX11_OVERRIDE { if (checkingAttributes && --attrCount) return; if (passed) { delete this; return; } User* user = ServerInstance->FindUUID(uid); if (user) { if (verbose) ServerInstance->SNO->WriteToSnoMask('c', "Forbidden connection from %s (%s)", user->GetFullRealHost().c_str(), err.getError().c_str()); ServerInstance->Users->QuitUser(user, killreason); } delete this; } }; class SearchInterface : public LDAPInterface { const std::string provider; const std::string uid; public: SearchInterface(Module* c, const std::string& p, const std::string& u) : LDAPInterface(c), provider(p), uid(u) { } void OnResult(const LDAPResult& r) CXX11_OVERRIDE { LocalUser* user = IS_LOCAL(ServerInstance->FindUUID(uid)); dynamic_reference<LDAPProvider> LDAP(me, provider); if (!LDAP || r.empty() || !user) { if (user) ServerInstance->Users->QuitUser(user, killreason); delete this; return; } try { const LDAPAttributes& a = r.get(0); std::string bindDn = a.get("dn"); if (bindDn.empty()) { ServerInstance->Users->QuitUser(user, killreason); delete this; return; } LDAP->Bind(new BindInterface(this->creator, provider, uid, bindDn), bindDn, user->password); } catch (LDAPException& ex) { ServerInstance->SNO->WriteToSnoMask('a', "Error searching LDAP server: " + ex.GetReason()); } delete this; } void OnError(const LDAPResult& err) CXX11_OVERRIDE { ServerInstance->SNO->WriteToSnoMask('a', "Error searching LDAP server: %s", err.getError().c_str()); User* user = ServerInstance->FindUUID(uid); if (user) ServerInstance->Users->QuitUser(user, killreason); delete this; } }; class AdminBindInterface : public LDAPInterface { const std::string provider; const std::string uuid; const std::string base; const std::string what; public: AdminBindInterface(Module* c, const std::string& p, const std::string& u, const std::string& b, const std::string& w) : LDAPInterface(c), provider(p), uuid(u), base(b), what(w) { } void OnResult(const LDAPResult& r) CXX11_OVERRIDE { dynamic_reference<LDAPProvider> LDAP(me, provider); if (LDAP) { try { LDAP->Search(new SearchInterface(this->creator, provider, uuid), base, what); } catch (LDAPException& ex) { ServerInstance->SNO->WriteToSnoMask('a', "Error searching LDAP server: " + ex.GetReason()); } } delete this; } void OnError(const LDAPResult& err) CXX11_OVERRIDE { ServerInstance->SNO->WriteToSnoMask('a', "Error binding as manager to LDAP server: " + err.getError()); delete this; } }; class ModuleLDAPAuth : public Module { dynamic_reference<LDAPProvider> LDAP; LocalIntExt ldapAuthed; LocalStringExt ldapVhost; std::string base; std::string attribute; std::vector<std::string> allowpatterns; std::vector<std::string> whitelistedcidrs; bool useusername; public: ModuleLDAPAuth() : LDAP(this, "LDAP") , ldapAuthed("ldapauth", ExtensionItem::EXT_USER, this) , ldapVhost("ldapauth_vhost", ExtensionItem::EXT_USER, this) { me = this; authed = &ldapAuthed; vhosts = &ldapVhost; } void ReadConfig(ConfigStatus& status) CXX11_OVERRIDE { ConfigTag* tag = ServerInstance->Config->ConfValue("ldapauth"); whitelistedcidrs.clear(); requiredattributes.clear(); base = tag->getString("baserdn"); attribute = tag->getString("attribute"); killreason = tag->getString("killreason"); vhost = tag->getString("host"); // Set to true if failed connects should be reported to operators verbose = tag->getBool("verbose"); useusername = tag->getBool("userfield"); LDAP.SetProvider("LDAP/" + tag->getString("dbid")); ConfigTagList whitelisttags = ServerInstance->Config->ConfTags("ldapwhitelist"); for (ConfigIter i = whitelisttags.first; i != whitelisttags.second; ++i) { std::string cidr = i->second->getString("cidr"); if (!cidr.empty()) { whitelistedcidrs.push_back(cidr); } } ConfigTagList attributetags = ServerInstance->Config->ConfTags("ldaprequire"); for (ConfigIter i = attributetags.first; i != attributetags.second; ++i) { const std::string attr = i->second->getString("attribute"); const std::string val = i->second->getString("value"); if (!attr.empty() && !val.empty()) requiredattributes.push_back(make_pair(attr, val)); } std::string allowpattern = tag->getString("allowpattern"); irc::spacesepstream ss(allowpattern); for (std::string more; ss.GetToken(more); ) { allowpatterns.push_back(more); } } void OnUserConnect(LocalUser *user) CXX11_OVERRIDE { std::string* cc = ldapVhost.get(user); if (cc) { user->ChangeDisplayedHost(*cc); ldapVhost.unset(user); } } ModResult OnUserRegister(LocalUser* user) CXX11_OVERRIDE { for (std::vector<std::string>::const_iterator i = allowpatterns.begin(); i != allowpatterns.end(); ++i) { if (InspIRCd::Match(user->nick, *i)) { ldapAuthed.set(user,1); return MOD_RES_PASSTHRU; } } for (std::vector<std::string>::iterator i = whitelistedcidrs.begin(); i != whitelistedcidrs.end(); i++) { if (InspIRCd::MatchCIDR(user->GetIPString(), *i, ascii_case_insensitive_map)) { ldapAuthed.set(user,1); return MOD_RES_PASSTHRU; } } if (user->password.empty()) { if (verbose) ServerInstance->SNO->WriteToSnoMask('c', "Forbidden connection from %s (no password provided)", user->GetFullRealHost().c_str()); ServerInstance->Users->QuitUser(user, killreason); return MOD_RES_DENY; } if (!LDAP) { if (verbose) ServerInstance->SNO->WriteToSnoMask('c', "Forbidden connection from %s (unable to find LDAP provider)", user->GetFullRealHost().c_str()); ServerInstance->Users->QuitUser(user, killreason); return MOD_RES_DENY; } std::string what; std::string::size_type pos = user->password.find(':'); if (pos != std::string::npos) { what = attribute + "=" + user->password.substr(0, pos); // 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); } try { LDAP->BindAsManager(new AdminBindInterface(this, LDAP.GetProvider(), user->uuid, base, what)); } catch (LDAPException &ex) { ServerInstance->SNO->WriteToSnoMask('a', "LDAP exception: " + ex.GetReason()); ServerInstance->Users->QuitUser(user, killreason); } return MOD_RES_DENY; } ModResult OnCheckReady(LocalUser* user) CXX11_OVERRIDE { return ldapAuthed.get(user) ? MOD_RES_PASSTHRU : MOD_RES_DENY; } Version GetVersion() CXX11_OVERRIDE { return Version("Allow/deny connections based upon answers from an LDAP server", VF_VENDOR); } }; MODULE_INIT(ModuleLDAPAuth) ���������������������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/src/modules/m_ldapoper.cpp�����������������������������������������������������������0000664�0000000�0000000�00000014451�13554550454�0020435�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * InspIRCd -- Internet Relay Chat Daemon * * Copyright (C) 2013 Adam <Adam@anope.org> * Copyright (C) 2009 Robin Burchell <robin+git@viroteck.net> * Copyright (C) 2008 Pippijn van Steenhoven <pip88nl@gmail.com> * Copyright (C) 2008 Craig Edwards <craigedwards@brainbox.cc> * Copyright (C) 2007 Carsten Valdemar Munk <carsten.munk+inspircd@gmail.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 "inspircd.h" #include "modules/ldap.h" namespace { Module* me; } class LDAPOperBase : public LDAPInterface { protected: const std::string uid; const std::string opername; const std::string password; void Fallback(User* user) { if (!user) return; Command* oper_command = ServerInstance->Parser.GetHandler("OPER"); if (!oper_command) return; CommandBase::Params params; params.push_back(opername); params.push_back(password); ClientProtocol::TagMap tags; oper_command->Handle(user, CommandBase::Params(params, tags)); } void Fallback() { User* user = ServerInstance->FindUUID(uid); Fallback(user); } public: LDAPOperBase(Module* mod, const std::string& uuid, const std::string& oper, const std::string& pass) : LDAPInterface(mod) , uid(uuid), opername(oper), password(pass) { } void OnError(const LDAPResult& err) CXX11_OVERRIDE { ServerInstance->SNO->WriteToSnoMask('a', "Error searching LDAP server: %s", err.getError().c_str()); Fallback(); delete this; } }; class BindInterface : public LDAPOperBase { public: BindInterface(Module* mod, const std::string& uuid, const std::string& oper, const std::string& pass) : LDAPOperBase(mod, uuid, oper, pass) { } void OnResult(const LDAPResult& r) CXX11_OVERRIDE { User* user = ServerInstance->FindUUID(uid); ServerConfig::OperIndex::const_iterator iter = ServerInstance->Config->oper_blocks.find(opername); if (!user || iter == ServerInstance->Config->oper_blocks.end()) { Fallback(); delete this; return; } OperInfo* ifo = iter->second; user->Oper(ifo); delete this; } }; class SearchInterface : public LDAPOperBase { const std::string provider; bool HandleResult(const LDAPResult& result) { dynamic_reference<LDAPProvider> LDAP(me, provider); if (!LDAP || result.empty()) return false; try { const LDAPAttributes& attr = result.get(0); std::string bindDn = attr.get("dn"); if (bindDn.empty()) return false; LDAP->Bind(new BindInterface(this->creator, uid, opername, password), bindDn, password); } catch (LDAPException& ex) { ServerInstance->SNO->WriteToSnoMask('a', "Error searching LDAP server: " + ex.GetReason()); } return true; } public: SearchInterface(Module* mod, const std::string& prov, const std::string &uuid, const std::string& oper, const std::string& pass) : LDAPOperBase(mod, uuid, oper, pass) , provider(prov) { } void OnResult(const LDAPResult& result) CXX11_OVERRIDE { if (!HandleResult(result)) Fallback(); delete this; } }; class AdminBindInterface : public LDAPInterface { const std::string provider; const std::string user; const std::string opername; const std::string password; const std::string base; const std::string what; public: AdminBindInterface(Module* c, const std::string& p, const std::string& u, const std::string& o, const std::string& pa, const std::string& b, const std::string& w) : LDAPInterface(c), provider(p), user(u), opername(p), password(pa), base(b), what(w) { } void OnResult(const LDAPResult& r) CXX11_OVERRIDE { dynamic_reference<LDAPProvider> LDAP(me, provider); if (LDAP) { try { LDAP->Search(new SearchInterface(this->creator, provider, user, opername, password), base, what); } catch (LDAPException& ex) { ServerInstance->SNO->WriteToSnoMask('a', "Error searching LDAP server: " + ex.GetReason()); } } delete this; } void OnError(const LDAPResult& err) CXX11_OVERRIDE { ServerInstance->SNO->WriteToSnoMask('a', "Error binding as manager to LDAP server: " + err.getError()); delete this; } }; class ModuleLDAPAuth : public Module { dynamic_reference<LDAPProvider> LDAP; std::string base; std::string attribute; public: ModuleLDAPAuth() : LDAP(this, "LDAP") { me = this; } void ReadConfig(ConfigStatus& status) CXX11_OVERRIDE { ConfigTag* tag = ServerInstance->Config->ConfValue("ldapoper"); LDAP.SetProvider("LDAP/" + tag->getString("dbid")); base = tag->getString("baserdn"); attribute = tag->getString("attribute"); } ModResult OnPreCommand(std::string& command, CommandBase::Params& parameters, LocalUser* user, bool validated) CXX11_OVERRIDE { if (validated && command == "OPER" && parameters.size() >= 2) { const std::string& opername = parameters[0]; const std::string& password = parameters[1]; ServerConfig::OperIndex::const_iterator it = ServerInstance->Config->oper_blocks.find(opername); if (it == ServerInstance->Config->oper_blocks.end()) return MOD_RES_PASSTHRU; ConfigTag* tag = it->second->oper_block; if (!tag) return MOD_RES_PASSTHRU; std::string acceptedhosts = tag->getString("host"); std::string hostname = user->ident + "@" + user->GetRealHost(); if (!InspIRCd::MatchMask(acceptedhosts, hostname, user->GetIPString())) return MOD_RES_PASSTHRU; if (!LDAP) return MOD_RES_PASSTHRU; try { std::string what = attribute + "=" + opername; LDAP->BindAsManager(new AdminBindInterface(this, LDAP.GetProvider(), user->uuid, opername, password, base, what)); return MOD_RES_DENY; } catch (LDAPException& ex) { ServerInstance->SNO->WriteToSnoMask('a', "LDAP exception: " + ex.GetReason()); } } return MOD_RES_PASSTHRU; } Version GetVersion() CXX11_OVERRIDE { return Version("Adds the ability to authenticate opers via LDAP", VF_VENDOR); } }; MODULE_INIT(ModuleLDAPAuth) �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/src/modules/m_lockserv.cpp�����������������������������������������������������������0000664�0000000�0000000�00000006657�13554550454�0020470�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * InspIRCd -- Internet Relay Chat Daemon * * Copyright (C) 2006-2007 Dennis Friis <peavey@inspircd.org> * Copyright (C) 2007 Robin Burchell <robin+git@viroteck.net> * * 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 "inspircd.h" /** Adds numerics * 988 <nick> <servername> :Closed for new connections * 989 <nick> <servername> :Open for new connections */ enum { // InspIRCd-specific. RPL_SERVLOCKON = 988, RPL_SERVLOCKOFF = 989 }; class CommandLockserv : public Command { std::string& locked; public: CommandLockserv(Module* Creator, std::string& lock) : Command(Creator, "LOCKSERV", 0, 1), locked(lock) { allow_empty_last_param = false; flags_needed = 'o'; } CmdResult Handle(User* user, const Params& parameters) CXX11_OVERRIDE { if (!locked.empty()) { user->WriteNotice("The server is already locked."); return CMD_FAILURE; } locked = parameters.empty() ? "Server is temporarily closed. Please try again later." : parameters[0]; user->WriteNumeric(RPL_SERVLOCKON, user->server->GetName(), "Closed for new connections"); ServerInstance->SNO->WriteGlobalSno('a', "Oper %s used LOCKSERV to temporarily disallow new connections", user->nick.c_str()); return CMD_SUCCESS; } }; class CommandUnlockserv : public Command { std::string& locked; public: CommandUnlockserv(Module* Creator, std::string& lock) : Command(Creator, "UNLOCKSERV", 0), locked(lock) { flags_needed = 'o'; } CmdResult Handle(User* user, const Params& parameters) CXX11_OVERRIDE { if (locked.empty()) { user->WriteNotice("The server isn't locked."); return CMD_FAILURE; } locked.clear(); user->WriteNumeric(RPL_SERVLOCKOFF, user->server->GetName(), "Open for new connections"); ServerInstance->SNO->WriteGlobalSno('a', "Oper %s used UNLOCKSERV to allow new connections", user->nick.c_str()); return CMD_SUCCESS; } }; class ModuleLockserv : public Module { std::string locked; CommandLockserv lockcommand; CommandUnlockserv unlockcommand; public: ModuleLockserv() : lockcommand(this, locked), unlockcommand(this, locked) { } void ReadConfig(ConfigStatus& status) CXX11_OVERRIDE { // Emergency way to unlock if (!status.srcuser) locked.clear(); } void OnModuleRehash(User* user, const std::string& param) CXX11_OVERRIDE { if (irc::equals(param, "lockserv") && !locked.empty()) locked.clear(); } ModResult OnUserRegister(LocalUser* user) CXX11_OVERRIDE { if (!locked.empty()) { ServerInstance->Users->QuitUser(user, locked); return MOD_RES_DENY; } return MOD_RES_PASSTHRU; } ModResult OnCheckReady(LocalUser* user) CXX11_OVERRIDE { return !locked.empty() ? MOD_RES_DENY : MOD_RES_PASSTHRU; } Version GetVersion() CXX11_OVERRIDE { return Version("Provides the LOCKSERV and UNLOCKSERV commands to lock the server and block all incoming connections until unlocked again", VF_VENDOR); } }; MODULE_INIT(ModuleLockserv) ���������������������������������������������������������������������������������inspircd-3.4.0/src/modules/m_maphide.cpp������������������������������������������������������������0000664�0000000�0000000�00000002731�13554550454�0020234�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * InspIRCd -- Internet Relay Chat Daemon * * Copyright (C) 2008 Craig Edwards <craigedwards@brainbox.cc> * * This file is part of InspIRCd. InspIRCd is free software: you can * redistribute it and/or modify it under the terms of the GNU General Public * License as published by the Free Software Foundation, version 2. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include "inspircd.h" class ModuleMapHide : public Module { std::string url; public: void ReadConfig(ConfigStatus& status) CXX11_OVERRIDE { url = ServerInstance->Config->ConfValue("security")->getString("maphide"); } ModResult OnPreCommand(std::string& command, CommandBase::Params& parameters, LocalUser* user, bool validated) CXX11_OVERRIDE { if (validated && !user->IsOper() && !url.empty() && (command == "MAP" || command == "LINKS")) { user->WriteNotice("/" + command + " has been disabled; visit " + url); return MOD_RES_DENY; } else return MOD_RES_PASSTHRU; } Version GetVersion() CXX11_OVERRIDE { return Version("Replaces the output of the MAP and LINKS commands with an URL", VF_VENDOR); } }; MODULE_INIT(ModuleMapHide) ���������������������������������������inspircd-3.4.0/src/modules/m_md5.cpp����������������������������������������������������������������0000664�0000000�0000000�00000017424�13554550454�0017317�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * InspIRCd -- Internet Relay Chat Daemon * * Copyright (C) 2009 Daniel De Graaf <danieldg@inspircd.org> * Copyright (C) 2008 Pippijn van Steenhoven <pip88nl@gmail.com> * Copyright (C) 2007-2008 Robin Burchell <robin+git@viroteck.net> * Copyright (C) 2007 Dennis Friis <peavey@inspircd.org> * Copyright (C) 2006 Craig Edwards <craigedwards@brainbox.cc> * * This file is part of InspIRCd. InspIRCd is free software: you can * redistribute it and/or modify it under the terms of the GNU General Public * License as published by the Free Software Foundation, version 2. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include "inspircd.h" #include "modules/hash.h" /* The four core functions - F1 is optimized somewhat */ #define F1(x, y, z) (z ^ (x & (y ^ z))) #define F2(x, y, z) F1(z, x, y) #define F3(x, y, z) (x ^ y ^ z) #define F4(x, y, z) (y ^ (x | ~z)) /* This is the central step in the MD5 algorithm. */ #define MD5STEP(f,w,x,y,z,in,s) \ (w += f(x,y,z) + in, w = (w<<s | w>>(32-s)) + x) typedef uint32_t word32; /* NOT unsigned long. We don't support 16 bit platforms, anyway. */ typedef unsigned char byte; /** An MD5 context, used by m_opermd5 */ class MD5Context { public: word32 buf[4]; word32 bytes[2]; word32 in[16]; }; class MD5Provider : public HashProvider { void byteSwap(word32 *buf, unsigned words) { byte *p = (byte *)buf; do { *buf++ = (word32)((unsigned)p[3] << 8 | p[2]) << 16 | ((unsigned)p[1] << 8 | p[0]); p += 4; } while (--words); } void MD5Init(MD5Context *ctx) { /* These are the defaults for md5 */ ctx->buf[0] = 0x67452301; ctx->buf[1] = 0xefcdab89; ctx->buf[2] = 0x98badcfe; ctx->buf[3] = 0x10325476; ctx->bytes[0] = 0; ctx->bytes[1] = 0; } void MD5Update(MD5Context *ctx, byte const *buf, int len) { word32 t; /* Update byte count */ t = ctx->bytes[0]; if ((ctx->bytes[0] = t + len) < t) ctx->bytes[1]++; /* Carry from low to high */ t = 64 - (t & 0x3f); /* Space available in ctx->in (at least 1) */ if ((unsigned)t > (unsigned)len) { memcpy((byte *)ctx->in + 64 - (unsigned)t, buf, len); return; } /* First chunk is an odd size */ memcpy((byte *)ctx->in + 64 - (unsigned)t, buf, (unsigned)t); byteSwap(ctx->in, 16); MD5Transform(ctx->buf, ctx->in); buf += (unsigned)t; len -= (unsigned)t; /* Process data in 64-byte chunks */ while (len >= 64) { memcpy(ctx->in, buf, 64); byteSwap(ctx->in, 16); MD5Transform(ctx->buf, ctx->in); buf += 64; len -= 64; } /* Handle any remaining bytes of data. */ memcpy(ctx->in, buf, len); } void MD5Final(byte digest[16], MD5Context *ctx) { int count = (int)(ctx->bytes[0] & 0x3f); /* Bytes in ctx->in */ byte *p = (byte *)ctx->in + count; /* First unused byte */ /* Set the first char of padding to 0x80. There is always room. */ *p++ = 0x80; /* Bytes of padding needed to make 56 bytes (-8..55) */ count = 56 - 1 - count; if (count < 0) { /* Padding forces an extra block */ memset(p, 0, count+8); byteSwap(ctx->in, 16); MD5Transform(ctx->buf, ctx->in); p = (byte *)ctx->in; count = 56; } memset(p, 0, count+8); byteSwap(ctx->in, 14); /* Append length in bits and transform */ ctx->in[14] = ctx->bytes[0] << 3; ctx->in[15] = ctx->bytes[1] << 3 | ctx->bytes[0] >> 29; MD5Transform(ctx->buf, ctx->in); byteSwap(ctx->buf, 4); memcpy(digest, ctx->buf, 16); memset(ctx, 0, sizeof(*ctx)); } void MD5Transform(word32 buf[4], word32 const in[16]) { word32 a, b, c, d; a = buf[0]; b = buf[1]; c = buf[2]; d = buf[3]; MD5STEP(F1, a, b, c, d, in[0] + 0xd76aa478, 7); MD5STEP(F1, d, a, b, c, in[1] + 0xe8c7b756, 12); MD5STEP(F1, c, d, a, b, in[2] + 0x242070db, 17); MD5STEP(F1, b, c, d, a, in[3] + 0xc1bdceee, 22); MD5STEP(F1, a, b, c, d, in[4] + 0xf57c0faf, 7); MD5STEP(F1, d, a, b, c, in[5] + 0x4787c62a, 12); MD5STEP(F1, c, d, a, b, in[6] + 0xa8304613, 17); MD5STEP(F1, b, c, d, a, in[7] + 0xfd469501, 22); MD5STEP(F1, a, b, c, d, in[8] + 0x698098d8, 7); MD5STEP(F1, d, a, b, c, in[9] + 0x8b44f7af, 12); MD5STEP(F1, c, d, a, b, in[10] + 0xffff5bb1, 17); MD5STEP(F1, b, c, d, a, in[11] + 0x895cd7be, 22); MD5STEP(F1, a, b, c, d, in[12] + 0x6b901122, 7); MD5STEP(F1, d, a, b, c, in[13] + 0xfd987193, 12); MD5STEP(F1, c, d, a, b, in[14] + 0xa679438e, 17); MD5STEP(F1, b, c, d, a, in[15] + 0x49b40821, 22); MD5STEP(F2, a, b, c, d, in[1] + 0xf61e2562, 5); MD5STEP(F2, d, a, b, c, in[6] + 0xc040b340, 9); MD5STEP(F2, c, d, a, b, in[11] + 0x265e5a51, 14); MD5STEP(F2, b, c, d, a, in[0] + 0xe9b6c7aa, 20); MD5STEP(F2, a, b, c, d, in[5] + 0xd62f105d, 5); MD5STEP(F2, d, a, b, c, in[10] + 0x02441453, 9); MD5STEP(F2, c, d, a, b, in[15] + 0xd8a1e681, 14); MD5STEP(F2, b, c, d, a, in[4] + 0xe7d3fbc8, 20); MD5STEP(F2, a, b, c, d, in[9] + 0x21e1cde6, 5); MD5STEP(F2, d, a, b, c, in[14] + 0xc33707d6, 9); MD5STEP(F2, c, d, a, b, in[3] + 0xf4d50d87, 14); MD5STEP(F2, b, c, d, a, in[8] + 0x455a14ed, 20); MD5STEP(F2, a, b, c, d, in[13] + 0xa9e3e905, 5); MD5STEP(F2, d, a, b, c, in[2] + 0xfcefa3f8, 9); MD5STEP(F2, c, d, a, b, in[7] + 0x676f02d9, 14); MD5STEP(F2, b, c, d, a, in[12] + 0x8d2a4c8a, 20); MD5STEP(F3, a, b, c, d, in[5] + 0xfffa3942, 4); MD5STEP(F3, d, a, b, c, in[8] + 0x8771f681, 11); MD5STEP(F3, c, d, a, b, in[11] + 0x6d9d6122, 16); MD5STEP(F3, b, c, d, a, in[14] + 0xfde5380c, 23); MD5STEP(F3, a, b, c, d, in[1] + 0xa4beea44, 4); MD5STEP(F3, d, a, b, c, in[4] + 0x4bdecfa9, 11); MD5STEP(F3, c, d, a, b, in[7] + 0xf6bb4b60, 16); MD5STEP(F3, b, c, d, a, in[10] + 0xbebfbc70, 23); MD5STEP(F3, a, b, c, d, in[13] + 0x289b7ec6, 4); MD5STEP(F3, d, a, b, c, in[0] + 0xeaa127fa, 11); MD5STEP(F3, c, d, a, b, in[3] + 0xd4ef3085, 16); MD5STEP(F3, b, c, d, a, in[6] + 0x04881d05, 23); MD5STEP(F3, a, b, c, d, in[9] + 0xd9d4d039, 4); MD5STEP(F3, d, a, b, c, in[12] + 0xe6db99e5, 11); MD5STEP(F3, c, d, a, b, in[15] + 0x1fa27cf8, 16); MD5STEP(F3, b, c, d, a, in[2] + 0xc4ac5665, 23); MD5STEP(F4, a, b, c, d, in[0] + 0xf4292244, 6); MD5STEP(F4, d, a, b, c, in[7] + 0x432aff97, 10); MD5STEP(F4, c, d, a, b, in[14] + 0xab9423a7, 15); MD5STEP(F4, b, c, d, a, in[5] + 0xfc93a039, 21); MD5STEP(F4, a, b, c, d, in[12] + 0x655b59c3, 6); MD5STEP(F4, d, a, b, c, in[3] + 0x8f0ccc92, 10); MD5STEP(F4, c, d, a, b, in[10] + 0xffeff47d, 15); MD5STEP(F4, b, c, d, a, in[1] + 0x85845dd1, 21); MD5STEP(F4, a, b, c, d, in[8] + 0x6fa87e4f, 6); MD5STEP(F4, d, a, b, c, in[15] + 0xfe2ce6e0, 10); MD5STEP(F4, c, d, a, b, in[6] + 0xa3014314, 15); MD5STEP(F4, b, c, d, a, in[13] + 0x4e0811a1, 21); MD5STEP(F4, a, b, c, d, in[4] + 0xf7537e82, 6); MD5STEP(F4, d, a, b, c, in[11] + 0xbd3af235, 10); MD5STEP(F4, c, d, a, b, in[2] + 0x2ad7d2bb, 15); MD5STEP(F4, b, c, d, a, in[9] + 0xeb86d391, 21); buf[0] += a; buf[1] += b; buf[2] += c; buf[3] += d; } void MyMD5(void *dest, void *orig, int len) { MD5Context context; MD5Init(&context); MD5Update(&context, (const unsigned char*)orig, len); MD5Final((unsigned char*)dest, &context); } public: std::string GenerateRaw(const std::string& data) CXX11_OVERRIDE { char res[16]; MyMD5(res, (void*)data.data(), data.length()); return std::string(res, 16); } MD5Provider(Module* parent) : HashProvider(parent, "md5", 16, 64) {} }; class ModuleMD5 : public Module { MD5Provider md5; public: ModuleMD5() : md5(this) { } Version GetVersion() CXX11_OVERRIDE { return Version("Implements MD5 hashing",VF_VENDOR); } }; MODULE_INIT(ModuleMD5) ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/src/modules/m_messageflood.cpp�������������������������������������������������������0000664�0000000�0000000�00000012714�13554550454�0021277�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * InspIRCd -- Internet Relay Chat Daemon * * Copyright (C) 2009 Daniel De Graaf <danieldg@inspircd.org> * Copyright (C) 2008 Pippijn van Steenhoven <pip88nl@gmail.com> * Copyright (C) 2007 Robin Burchell <robin+git@viroteck.net> * Copyright (C) 2007 John Brooks <john.brooks@dereferenced.net> * Copyright (C) 2007 Dennis Friis <peavey@inspircd.org> * Copyright (C) 2006 Craig Edwards <craigedwards@brainbox.cc> * Copyright (C) 2006 Oliver Lupton <oliverlupton@gmail.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 "inspircd.h" #include "modules/ctctags.h" #include "modules/exemption.h" /** Holds flood settings and state for mode +f */ class floodsettings { public: bool ban; unsigned int secs; unsigned int lines; time_t reset; insp::flat_map<User*, double> counters; floodsettings(bool a, unsigned int b, unsigned int c) : ban(a) , secs(b) , lines(c) { reset = ServerInstance->Time() + secs; } bool addmessage(User* who, double weight) { if (ServerInstance->Time() > reset) { counters.clear(); reset = ServerInstance->Time() + secs; } counters[who] += weight; return (counters[who] >= this->lines); } void clear(User* who) { counters.erase(who); } }; /** Handles channel mode +f */ class MsgFlood : public ParamMode<MsgFlood, SimpleExtItem<floodsettings> > { public: MsgFlood(Module* Creator) : ParamMode<MsgFlood, SimpleExtItem<floodsettings> >(Creator, "flood", 'f') { syntax = "[*]<messages>:<seconds>"; } ModeAction OnSet(User* source, Channel* channel, std::string& parameter) CXX11_OVERRIDE { std::string::size_type colon = parameter.find(':'); if ((colon == std::string::npos) || (parameter.find('-') != std::string::npos)) { source->WriteNumeric(Numerics::InvalidModeParameter(channel, this, parameter)); return MODEACTION_DENY; } /* Set up the flood parameters for this channel */ bool ban = (parameter[0] == '*'); unsigned int nlines = ConvToNum<unsigned int>(parameter.substr(ban ? 1 : 0, ban ? colon-1 : colon)); unsigned int nsecs = ConvToNum<unsigned int>(parameter.substr(colon+1)); if ((nlines<2) || (nsecs<1)) { source->WriteNumeric(Numerics::InvalidModeParameter(channel, this, parameter)); return MODEACTION_DENY; } ext.set(channel, new floodsettings(ban, nsecs, nlines)); return MODEACTION_ALLOW; } void SerializeParam(Channel* chan, const floodsettings* fs, std::string& out) { if (fs->ban) out.push_back('*'); out.append(ConvToStr(fs->lines)).push_back(':'); out.append(ConvToStr(fs->secs)); } }; class ModuleMsgFlood : public Module , public CTCTags::EventListener { private: CheckExemption::EventProvider exemptionprov; MsgFlood mf; double notice; double privmsg; double tagmsg; public: ModuleMsgFlood() : CTCTags::EventListener(this) , exemptionprov(this) , mf(this) { } void ReadConfig(ConfigStatus&) CXX11_OVERRIDE { ConfigTag* tag = ServerInstance->Config->ConfValue("messageflood"); notice = tag->getFloat("notice", 1.0); privmsg = tag->getFloat("privmsg", 1.0); tagmsg = tag->getFloat("tagmsg", 0.2); } ModResult HandleMessage(User* user, const MessageTarget& target, double weight) { if (target.type != MessageTarget::TYPE_CHANNEL) return MOD_RES_PASSTHRU; Channel* dest = target.Get<Channel>(); if ((!IS_LOCAL(user)) || !dest->IsModeSet(mf)) return MOD_RES_PASSTHRU; ModResult res = CheckExemption::Call(exemptionprov, user, dest, "flood"); if (res == MOD_RES_ALLOW) return MOD_RES_PASSTHRU; floodsettings *f = mf.ext.get(dest); if (f) { if (f->addmessage(user, weight)) { /* Youre outttta here! */ f->clear(user); if (f->ban) { Modes::ChangeList changelist; changelist.push_add(ServerInstance->Modes->FindMode('b', MODETYPE_CHANNEL), "*!*@" + user->GetDisplayedHost()); ServerInstance->Modes->Process(ServerInstance->FakeClient, dest, NULL, changelist); } const std::string kickMessage = "Channel flood triggered (trigger is " + ConvToStr(f->lines) + " lines in " + ConvToStr(f->secs) + " secs)"; dest->KickUser(ServerInstance->FakeClient, user, kickMessage); return MOD_RES_DENY; } } return MOD_RES_PASSTHRU; } ModResult OnUserPreMessage(User* user, const MessageTarget& target, MessageDetails& details) CXX11_OVERRIDE { return HandleMessage(user, target, (details.type == MSG_PRIVMSG ? privmsg : notice)); } ModResult OnUserPreTagMessage(User* user, const MessageTarget& target, CTCTags::TagMessageDetails& details) CXX11_OVERRIDE { return HandleMessage(user, target, tagmsg); } void Prioritize() CXX11_OVERRIDE { // we want to be after all modules that might deny the message (e.g. m_muteban, m_noctcp, m_blockcolor, etc.) ServerInstance->Modules->SetPriority(this, I_OnUserPreMessage, PRIORITY_LAST); } Version GetVersion() CXX11_OVERRIDE { return Version("Provides channel mode +f, message flood protection", VF_VENDOR); } }; MODULE_INIT(ModuleMsgFlood) ����������������������������������������������������inspircd-3.4.0/src/modules/m_mlock.cpp��������������������������������������������������������������0000664�0000000�0000000�00000003402�13554550454�0017726�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * InspIRCd -- Internet Relay Chat Daemon * * Copyright (C) 2012 William Pitcock <nenolod@dereferenced.org> * * This file is part of InspIRCd. InspIRCd is free software: you can * redistribute it and/or modify it under the terms of the GNU General Public * License as published by the Free Software Foundation, version 2. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include "inspircd.h" enum { // From Charybdis. ERR_MLOCKRESTRICTED = 742 }; class ModuleMLock : public Module { StringExtItem mlock; public: ModuleMLock() : mlock("mlock", ExtensionItem::EXT_CHANNEL, this) { } Version GetVersion() CXX11_OVERRIDE { return Version("Implements the ability to have server-side MLOCK enforcement", VF_VENDOR); } ModResult OnRawMode(User* source, Channel* channel, ModeHandler* mh, const std::string& parameter, bool adding) CXX11_OVERRIDE { if (!channel) return MOD_RES_PASSTHRU; if (!IS_LOCAL(source)) return MOD_RES_PASSTHRU; std::string *mlock_str = mlock.get(channel); if (!mlock_str) return MOD_RES_PASSTHRU; const char mode = mh->GetModeChar(); std::string::size_type p = mlock_str->find(mode); if (p != std::string::npos) { source->WriteNumeric(ERR_MLOCKRESTRICTED, channel->name, mode, *mlock_str, "MODE cannot be set due to the channel having an active MLOCK restriction policy"); return MOD_RES_DENY; } return MOD_RES_PASSTHRU; } }; MODULE_INIT(ModuleMLock) ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/src/modules/m_modenotice.cpp���������������������������������������������������������0000664�0000000�0000000�00000003507�13554550454�0020755�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * InspIRCd -- Internet Relay Chat Daemon * * Copyright (C) 2009 Daniel De Graaf <danieldg@inspircd.org> * * This file is part of InspIRCd. InspIRCd is free software: you can * redistribute it and/or modify it under the terms of the GNU General Public * License as published by the Free Software Foundation, version 2. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include "inspircd.h" class CommandModeNotice : public Command { public: CommandModeNotice(Module* parent) : Command(parent,"MODENOTICE",2,2) { syntax = "<modeletters> :<message>"; flags_needed = 'o'; } CmdResult Handle(User* src, const Params& parameters) CXX11_OVERRIDE { std::string msg = "*** From " + src->nick + ": " + parameters[1]; int mlen = parameters[0].length(); const UserManager::LocalList& list = ServerInstance->Users.GetLocalUsers(); for (UserManager::LocalList::const_iterator i = list.begin(); i != list.end(); ++i) { User* user = *i; for (int n = 0; n < mlen; n++) { if (!user->IsModeSet(parameters[0][n])) goto next_user; } user->WriteNotice(msg); next_user: ; } return CMD_SUCCESS; } RouteDescriptor GetRouting(User* user, const Params& parameters) CXX11_OVERRIDE { return ROUTE_OPT_BCAST; } }; class ModuleModeNotice : public Module { CommandModeNotice cmd; public: ModuleModeNotice() : cmd(this) { } Version GetVersion() CXX11_OVERRIDE { return Version("Provides the MODENOTICE command", VF_VENDOR); } }; MODULE_INIT(ModuleModeNotice) �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/src/modules/m_monitor.cpp������������������������������������������������������������0000664�0000000�0000000�00000024764�13554550454�0020326�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * InspIRCd -- Internet Relay Chat Daemon * * Copyright (C) 2016 Attila Molnar <attilamolnar@hush.com> * * This file is part of InspIRCd. InspIRCd is free software: you can * redistribute it and/or modify it under the terms of the GNU General Public * License as published by the Free Software Foundation, version 2. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include "inspircd.h" namespace IRCv3 { namespace Monitor { class ExtItem; struct Entry; class Manager; class ManagerInternal; typedef std::vector<Entry*> WatchedList; typedef std::vector<LocalUser*> WatcherList; } } struct IRCv3::Monitor::Entry { WatcherList watchers; std::string nick; void SetNick(const std::string& Nick) { nick.clear(); // We may show this string to other users so do not leak the casing std::transform(Nick.begin(), Nick.end(), std::back_inserter(nick), ::tolower); } const std::string& GetNick() const { return nick; } }; class IRCv3::Monitor::Manager { struct ExtData { WatchedList list; }; class ExtItem : public ExtensionItem { Manager& manager; public: ExtItem(Module* mod, const std::string& extname, Manager& managerref) : ExtensionItem(extname, ExtensionItem::EXT_USER, mod) , manager(managerref) { } ExtData* get(Extensible* container, bool create = false) { ExtData* extdata = static_cast<ExtData*>(get_raw(container)); if ((!extdata) && (create)) { extdata = new ExtData; set_raw(container, extdata); } return extdata; } void unset(Extensible* container) { free(container, unset_raw(container)); } std::string ToInternal(const Extensible* container, void* item) const CXX11_OVERRIDE { std::string ret; const ExtData* extdata = static_cast<ExtData*>(item); for (WatchedList::const_iterator i = extdata->list.begin(); i != extdata->list.end(); ++i) { const Entry* entry = *i; ret.append(entry->GetNick()).push_back(' '); } if (!ret.empty()) ret.erase(ret.size()-1); return ret; } void FromInternal(Extensible* container, const std::string& value) CXX11_OVERRIDE; void free(Extensible* container, void* item) CXX11_OVERRIDE { delete static_cast<ExtData*>(item); } }; public: Manager(Module* mod, const std::string& extname) : ext(mod, extname, *this) { } enum WatchResult { WR_OK, WR_TOOMANY, WR_ALREADYWATCHING, WR_INVALIDNICK }; WatchResult Watch(LocalUser* user, const std::string& nick, unsigned int maxwatch) { if (!ServerInstance->IsNick(nick)) return WR_INVALIDNICK; WatchedList* watched = GetWatchedPriv(user, true); if (watched->size() >= maxwatch) return WR_TOOMANY; Entry* entry = AddWatcher(nick, user); if (stdalgo::isin(*watched, entry)) return WR_ALREADYWATCHING; entry->watchers.push_back(user); watched->push_back(entry); return WR_OK; } bool Unwatch(LocalUser* user, const std::string& nick) { WatchedList* list = GetWatchedPriv(user); if (!list) return false; bool ret = RemoveWatcher(nick, user, *list); // If no longer watching any nick unset ext if (list->empty()) ext.unset(user); return ret; } const WatchedList& GetWatched(LocalUser* user) { WatchedList* list = GetWatchedPriv(user); if (list) return *list; return emptywatchedlist; } void UnwatchAll(LocalUser* user) { WatchedList* list = GetWatchedPriv(user); if (!list) return; while (!list->empty()) { Entry* entry = list->front(); RemoveWatcher(entry->GetNick(), user, *list); } ext.unset(user); } WatcherList* GetWatcherList(const std::string& nick) { Entry* entry = Find(nick); if (entry) return &entry->watchers; return NULL; } static User* FindNick(const std::string& nick) { User* user = ServerInstance->FindNickOnly(nick); if ((user) && (user->registered == REG_ALL)) return user; return NULL; } private: typedef TR1NS::unordered_map<std::string, Entry, irc::insensitive, irc::StrHashComp> NickHash; Entry* Find(const std::string& nick) { NickHash::iterator it = nicks.find(nick); if (it != nicks.end()) return &it->second; return NULL; } Entry* AddWatcher(const std::string& nick, LocalUser* user) { std::pair<NickHash::iterator, bool> ret = nicks.insert(std::make_pair(nick, Entry())); Entry& entry = ret.first->second; if (ret.second) entry.SetNick(nick); return &entry; } bool RemoveWatcher(const std::string& nick, LocalUser* user, WatchedList& watchedlist) { NickHash::iterator it = nicks.find(nick); // If nobody is watching this nick the user trying to remove it isn't watching it for sure if (it == nicks.end()) return false; Entry& entry = it->second; // Erase from the user's list of watched nicks if (!stdalgo::vector::swaperase(watchedlist, &entry)) return false; // User is not watching this nick // Erase from the nick's list of watching users stdalgo::vector::swaperase(entry.watchers, user); // If nobody else is watching the nick remove map entry if (entry.watchers.empty()) nicks.erase(it); return true; } WatchedList* GetWatchedPriv(LocalUser* user, bool create = false) { ExtData* extdata = ext.get(user, create); if (!extdata) return NULL; return &extdata->list; } NickHash nicks; ExtItem ext; WatchedList emptywatchedlist; }; void IRCv3::Monitor::Manager::ExtItem::FromInternal(Extensible* container, const std::string& value) { irc::spacesepstream ss(value); for (std::string nick; ss.GetToken(nick); ) manager.Watch(static_cast<LocalUser*>(container), nick, UINT_MAX); } #ifndef INSPIRCD_MONITOR_MANAGER_ONLY enum { RPL_MONONLINE = 730, RPL_MONOFFLINE = 731, RPL_MONLIST = 732, RPL_ENDOFMONLIST = 733, ERR_MONLISTFULL = 734 }; class CommandMonitor : public SplitCommand { typedef Numeric::Builder<> ReplyBuilder; // Additional penalty for the /MONITOR L and /MONITOR S commands that request a list from the server static const unsigned int ListPenalty = 3000; IRCv3::Monitor::Manager& manager; void HandlePlus(LocalUser* user, const std::string& input) { ReplyBuilder online(user, RPL_MONONLINE); ReplyBuilder offline(user, RPL_MONOFFLINE); irc::commasepstream ss(input); for (std::string nick; ss.GetToken(nick); ) { IRCv3::Monitor::Manager::WatchResult result = manager.Watch(user, nick, maxmonitor); if (result == IRCv3::Monitor::Manager::WR_TOOMANY) { // List is full, send error which includes the remaining nicks that were not processed user->WriteNumeric(ERR_MONLISTFULL, maxmonitor, InspIRCd::Format("%s%s%s", nick.c_str(), (ss.StreamEnd() ? "" : ","), ss.GetRemaining().c_str()), "Monitor list is full"); break; } else if (result != IRCv3::Monitor::Manager::WR_OK) continue; // Already added or invalid nick ReplyBuilder& out = (IRCv3::Monitor::Manager::FindNick(nick) ? online : offline); out.Add(nick); } online.Flush(); offline.Flush(); } void HandleMinus(LocalUser* user, const std::string& input) { irc::commasepstream ss(input); for (std::string nick; ss.GetToken(nick); ) manager.Unwatch(user, nick); } public: unsigned int maxmonitor; CommandMonitor(Module* mod, IRCv3::Monitor::Manager& managerref) : SplitCommand(mod, "MONITOR", 1) , manager(managerref) { Penalty = 2; allow_empty_last_param = false; syntax = "C|L|S|(+|-) <nick>[,<nick>]+"; } CmdResult HandleLocal(LocalUser* user, const Params& parameters) CXX11_OVERRIDE { char subcmd = toupper(parameters[0][0]); if (subcmd == '+') { if (parameters.size() > 1) HandlePlus(user, parameters[1]); } else if (subcmd == '-') { if (parameters.size() > 1) HandleMinus(user, parameters[1]); } else if (subcmd == 'C') { manager.UnwatchAll(user); } else if (subcmd == 'L') { user->CommandFloodPenalty += ListPenalty; const IRCv3::Monitor::WatchedList& list = manager.GetWatched(user); ReplyBuilder out(user, RPL_MONLIST); for (IRCv3::Monitor::WatchedList::const_iterator i = list.begin(); i != list.end(); ++i) { IRCv3::Monitor::Entry* entry = *i; out.Add(entry->GetNick()); } out.Flush(); user->WriteNumeric(RPL_ENDOFMONLIST, "End of MONITOR list"); } else if (subcmd == 'S') { user->CommandFloodPenalty += ListPenalty; ReplyBuilder online(user, RPL_MONONLINE); ReplyBuilder offline(user, RPL_MONOFFLINE); const IRCv3::Monitor::WatchedList& list = manager.GetWatched(user); for (IRCv3::Monitor::WatchedList::const_iterator i = list.begin(); i != list.end(); ++i) { IRCv3::Monitor::Entry* entry = *i; ReplyBuilder& out = (IRCv3::Monitor::Manager::FindNick(entry->GetNick()) ? online : offline); out.Add(entry->GetNick()); } online.Flush(); offline.Flush(); } else return CMD_FAILURE; return CMD_SUCCESS; } }; class ModuleMonitor : public Module { IRCv3::Monitor::Manager manager; CommandMonitor cmd; void SendAlert(unsigned int numeric, const std::string& nick) { const IRCv3::Monitor::WatcherList* list = manager.GetWatcherList(nick); if (!list) return; for (IRCv3::Monitor::WatcherList::const_iterator i = list->begin(); i != list->end(); ++i) { LocalUser* curr = *i; curr->WriteNumeric(numeric, nick); } } public: ModuleMonitor() : manager(this, "monitor") , cmd(this, manager) { } void ReadConfig(ConfigStatus& status) CXX11_OVERRIDE { ConfigTag* tag = ServerInstance->Config->ConfValue("monitor"); cmd.maxmonitor = tag->getUInt("maxentries", 30, 1); } void OnPostConnect(User* user) CXX11_OVERRIDE { SendAlert(RPL_MONONLINE, user->nick); } void OnUserPostNick(User* user, const std::string& oldnick) CXX11_OVERRIDE { // Detect and ignore nickname case change if (ServerInstance->FindNickOnly(oldnick) == user) return; SendAlert(RPL_MONOFFLINE, oldnick); SendAlert(RPL_MONONLINE, user->nick); } void OnUserQuit(User* user, const std::string& message, const std::string& oper_message) CXX11_OVERRIDE { LocalUser* localuser = IS_LOCAL(user); if (localuser) manager.UnwatchAll(localuser); SendAlert(RPL_MONOFFLINE, user->nick); } void On005Numeric(std::map<std::string, std::string>& tokens) CXX11_OVERRIDE { tokens["MONITOR"] = ConvToStr(cmd.maxmonitor); } Version GetVersion() CXX11_OVERRIDE { return Version("Provides MONITOR support", VF_VENDOR); } }; MODULE_INIT(ModuleMonitor) #endif ������������inspircd-3.4.0/src/modules/m_muteban.cpp������������������������������������������������������������0000664�0000000�0000000�00000004544�13554550454�0020264�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * InspIRCd -- Internet Relay Chat Daemon * * Copyright (C) 2009 Daniel De Graaf <danieldg@inspircd.org> * Copyright (C) 2008 Robin Burchell <robin+git@viroteck.net> * * 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 "inspircd.h" #include "modules/ctctags.h" class ModuleQuietBan : public Module , public CTCTags::EventListener { private: bool notifyuser; public: ModuleQuietBan() : CTCTags::EventListener(this) { } void ReadConfig(ConfigStatus& status) CXX11_OVERRIDE { ConfigTag* tag = ServerInstance->Config->ConfValue("muteban"); notifyuser = tag->getBool("notifyuser", true); } Version GetVersion() CXX11_OVERRIDE { return Version("Provides extban 'm', mute bans", VF_OPTCOMMON|VF_VENDOR); } ModResult HandleMessage(User* user, const MessageTarget& target, bool& echo_original) { if (!IS_LOCAL(user) || target.type != MessageTarget::TYPE_CHANNEL) return MOD_RES_PASSTHRU; Channel* chan = target.Get<Channel>(); if (chan->GetExtBanStatus(user, 'm') == MOD_RES_DENY && chan->GetPrefixValue(user) < VOICE_VALUE) { if (!notifyuser) { echo_original = true; return MOD_RES_DENY; } user->WriteNumeric(ERR_CANNOTSENDTOCHAN, chan->name, "Cannot send to channel (you're muted)"); return MOD_RES_DENY; } return MOD_RES_PASSTHRU; } ModResult OnUserPreMessage(User* user, const MessageTarget& target, MessageDetails& details) CXX11_OVERRIDE { return HandleMessage(user, target, details.echo_original); } ModResult OnUserPreTagMessage(User* user, const MessageTarget& target, CTCTags::TagMessageDetails& details) CXX11_OVERRIDE { return HandleMessage(user, target, details.echo_original); } void On005Numeric(std::map<std::string, std::string>& tokens) CXX11_OVERRIDE { tokens["EXTBAN"].push_back('m'); } }; MODULE_INIT(ModuleQuietBan) ������������������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/src/modules/m_namedmodes.cpp���������������������������������������������������������0000664�0000000�0000000�00000011461�13554550454�0020741�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * InspIRCd -- Internet Relay Chat Daemon * * 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 * 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 "inspircd.h" enum { // InspIRCd-specific. RPL_ENDOFPROPLIST = 960, RPL_PROPLIST = 961 }; static void DisplayList(LocalUser* user, Channel* channel) { Numeric::ParamBuilder<1> numeric(user, RPL_PROPLIST); numeric.AddStatic(channel->name); const ModeParser::ModeHandlerMap& mhs = ServerInstance->Modes->GetModes(MODETYPE_CHANNEL); for (ModeParser::ModeHandlerMap::const_iterator i = mhs.begin(); i != mhs.end(); ++i) { ModeHandler* mh = i->second; if (!channel->IsModeSet(mh)) continue; numeric.Add("+" + mh->name); ParamModeBase* pm = mh->IsParameterMode(); if (pm) { if ((pm->IsParameterSecret()) && (!channel->HasUser(user)) && (!user->HasPrivPermission("channels/auspex"))) numeric.Add("<" + mh->name + ">"); else numeric.Add(channel->GetModeParameter(mh)); } } numeric.Flush(); user->WriteNumeric(RPL_ENDOFPROPLIST, channel->name, "End of mode list"); } class CommandProp : public SplitCommand { public: CommandProp(Module* parent) : SplitCommand(parent, "PROP", 1) { syntax = "<channel> [[(+|-)]<mode> [<value>]]"; } CmdResult HandleLocal(LocalUser* src, const Params& parameters) CXX11_OVERRIDE { Channel* const chan = ServerInstance->FindChan(parameters[0]); if (!chan) { src->WriteNumeric(Numerics::NoSuchChannel(parameters[0])); return CMD_FAILURE; } if (parameters.size() == 1) { DisplayList(src, chan); return CMD_SUCCESS; } unsigned int i = 1; Modes::ChangeList modes; 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()); ModeHandler* mh = ServerInstance->Modes->FindMode(prop, MODETYPE_CHANNEL); if (mh) { if (mh->NeedsParam(plus)) { if (i != parameters.size()) modes.push(mh, plus, parameters[i++]); } else modes.push(mh, plus); } } ServerInstance->Modes->ProcessSingle(src, chan, NULL, modes, ModeParser::MODE_CHECKACCESS); return CMD_SUCCESS; } }; class DummyZ : public ModeHandler { public: DummyZ(Module* parent) : ModeHandler(parent, "namebase", 'Z', PARAM_ALWAYS, MODETYPE_CHANNEL) { list = true; } // Handle /MODE #chan Z void DisplayList(User* user, Channel* chan) CXX11_OVERRIDE { LocalUser* luser = IS_LOCAL(user); if (luser) ::DisplayList(luser, chan); } }; class ModuleNamedModes : public Module { CommandProp cmd; DummyZ dummyZ; public: ModuleNamedModes() : cmd(this), dummyZ(this) { } Version GetVersion() CXX11_OVERRIDE { return Version("Provides the ability to manipulate modes via long names", VF_VENDOR); } void Prioritize() CXX11_OVERRIDE { ServerInstance->Modules->SetPriority(this, I_OnPreMode, PRIORITY_FIRST); } ModResult OnPreMode(User* source, User* dest, Channel* channel, Modes::ChangeList& modes) CXX11_OVERRIDE { if (!channel) return MOD_RES_PASSTHRU; Modes::ChangeList::List& list = modes.getlist(); for (Modes::ChangeList::List::iterator i = list.begin(); i != list.end(); ) { Modes::Change& curr = *i; // Replace all namebase (dummyZ) modes being changed with the actual // mode handler and parameter. The parameter format of the namebase mode is // <modename>[=<parameter>]. if (curr.mh == &dummyZ) { std::string name = curr.param; std::string value; std::string::size_type eq = name.find('='); if (eq != std::string::npos) { value.assign(name, eq + 1, std::string::npos); name.erase(eq); } ModeHandler* mh = ServerInstance->Modes->FindMode(name, MODETYPE_CHANNEL); if (!mh) { // Mode handler not found i = list.erase(i); continue; } curr.param.clear(); if (mh->NeedsParam(curr.adding)) { if (value.empty()) { // Mode needs a parameter but there wasn't one i = list.erase(i); continue; } // Change parameter to the text after the '=' curr.param = value; } // Put the actual ModeHandler in place of the namebase handler curr.mh = mh; } ++i; } return MOD_RES_PASSTHRU; } }; MODULE_INIT(ModuleNamedModes) ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/src/modules/m_namesx.cpp�������������������������������������������������������������0000664�0000000�0000000�00000006233�13554550454�0020121�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * InspIRCd -- Internet Relay Chat Daemon * * Copyright (C) 2009 Daniel De Graaf <danieldg@inspircd.org> * Copyright (C) 2006, 2008 Craig Edwards <craigedwards@brainbox.cc> * Copyright (C) 2007 Dennis Friis <peavey@inspircd.org> * Copyright (C) 2007 Robin Burchell <robin+git@viroteck.net> * * 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 "inspircd.h" #include "modules/cap.h" #include "modules/names.h" #include "modules/who.h" class ModuleNamesX : public Module , public Names::EventListener , public Who::EventListener { private: Cap::Capability cap; public: ModuleNamesX() : Names::EventListener(this) , Who::EventListener(this) , cap(this, "multi-prefix") { } Version GetVersion() CXX11_OVERRIDE { return Version("Provides the NAMESX (CAP multi-prefix) capability", VF_VENDOR); } void On005Numeric(std::map<std::string, std::string>& tokens) CXX11_OVERRIDE { // The legacy PROTOCTL system is a wrapper around the cap. dynamic_reference_nocheck<Cap::Manager> capmanager(this, "capmanager"); if (capmanager) tokens["NAMESX"]; } ModResult OnPreCommand(std::string& command, CommandBase::Params& parameters, LocalUser* user, bool validated) CXX11_OVERRIDE { /* We don't actually create a proper command handler class for PROTOCTL, * because other modules might want to have PROTOCTL hooks too. * Therefore, we just hook its as an unvalidated command therefore we * can capture it even if it doesnt exist! :-) */ if (command == "PROTOCTL") { if ((parameters.size()) && (!strcasecmp(parameters[0].c_str(),"NAMESX"))) { cap.set(user, true); return MOD_RES_DENY; } } return MOD_RES_PASSTHRU; } ModResult OnNamesListItem(LocalUser* issuer, Membership* memb, std::string& prefixes, std::string& nick) CXX11_OVERRIDE { if (cap.get(issuer)) prefixes = memb->GetAllPrefixChars(); return MOD_RES_PASSTHRU; } ModResult OnWhoLine(const Who::Request& request, LocalUser* source, User* user, Membership* memb, Numeric::Numeric& numeric) CXX11_OVERRIDE { if ((!memb) || (!cap.get(source))) return MOD_RES_PASSTHRU; // Don't do anything if the user has only one prefix std::string prefixes = memb->GetAllPrefixChars(); if (prefixes.length() <= 1) return MOD_RES_PASSTHRU; size_t flag_index; if (!request.GetFieldIndex('f', flag_index)) return MOD_RES_PASSTHRU; // #chan ident localhost insp22.test nick H@ :0 Attila if (numeric.GetParams().size() <= flag_index) return MOD_RES_PASSTHRU; numeric.GetParams()[flag_index].append(prefixes, 1, std::string::npos); return MOD_RES_PASSTHRU; } }; MODULE_INIT(ModuleNamesX) ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/src/modules/m_nationalchars.cpp������������������������������������������������������0000664�0000000�0000000�00000030476�13554550454�0021462�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * InspIRCd -- Internet Relay Chat Daemon * * Copyright (C) 2009 Daniel De Graaf <danieldg@inspircd.org> * Copyright (C) 2009 Dennis Friis <peavey@inspircd.org> * Copyright (C) 2009 Craig Edwards <craigedwards@brainbox.cc> * Copyright (C) 2009 Robin Burchell <robin+git@viroteck.net> * * 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/>. */ /* Contains a code of Unreal IRCd + Bynets patch (https://www.unrealircd.org and https://bynets.org) Original patch is made by Dmitry "Killer{R}" Kononko. (http://killprog.com) Changed at 2008-06-15 - 2009-02-11 by Chernov-Phoenix Alexey (Phoenix@RusNet) mailto:phoenix /email address separator/ pravmail.ru */ #include "inspircd.h" #include <fstream> class lwbNickHandler { public: static bool Call(const std::string&); }; /*,m_reverse_additionalUp[256];*/ static unsigned char m_reverse_additional[256],m_additionalMB[256],m_additionalUtf8[256],m_additionalUtf8range[256],m_additionalUtf8interval[256]; char utf8checkrest(unsigned char * mb, unsigned char cnt) { for (unsigned char * tmp=mb; tmp<mb+cnt; tmp++) { /* & is faster! -- Phoenix (char & b11000000 == b10000000) */ if ((*tmp & 192) != 128) return -1; } return cnt + 1; } char utf8size(unsigned char * mb) { if (!*mb) return -1; if (!(*mb & 128)) return 1; if ((*mb & 224) == 192) return utf8checkrest(mb + 1,1); if ((*mb & 240) == 224) return utf8checkrest(mb + 1,2); if ((*mb & 248) == 240) return utf8checkrest(mb + 1,3); return -1; } /* Conditions added */ bool lwbNickHandler::Call(const std::string& nick) { if (nick.empty()) return false; const char* n = nick.c_str(); unsigned int p = 0; for (const char* i = n; *i; i++, p++) { /* 1. Multibyte encodings support: */ /* 1.1. 16bit char. areas, e.g. chinese:*/ /* if current character is the last, we DO NOT check it against multibyte table */ /* if there are mbtable ranges, use ONLY them. No 8bit at all */ if (i[1] && m_additionalMB[0]) { /* otherwise let's take a look at the current character and the following one */ bool found = false; for(unsigned char * mb = m_additionalMB; (*mb) && (mb < m_additionalMB + sizeof(m_additionalMB)); mb += 4) { if ( (i[0] >= mb[0]) && (i[0] <= mb[1]) && (i[1] >= mb[2]) && (i[1] <= mb[3]) ) { /* multibyte range character found */ i++; p++; found = true; break; } } if (found) /* next char! */ continue; else /* there are ranges, but incorrect char (8bit?) given, sorry */ return false; } /* 2. 8bit character support */ if (((*i >= 'A') && (*i <= '}')) || m_reverse_additional[(unsigned char)*i]) /* "A"-"}" can occur anywhere in a nickname */ continue; if ((((*i >= '0') && (*i <= '9')) || (*i == '-')) && (i > n)) /* "0"-"9", "-" can occur anywhere BUT the first char of a nickname */ continue; /* 3.1. Check against a simple UTF-8 characters enumeration */ int cursize, cursize2, ncursize = utf8size((unsigned char *)i); /* do check only if current multibyte character is valid UTF-8 only */ if (ncursize != -1) { bool found = false; for (unsigned char * mb = m_additionalUtf8; (utf8size(mb) != -1) && (mb < m_additionalUtf8 + sizeof(m_additionalUtf8)); mb += cursize) { cursize = utf8size(mb); /* Size differs? Pick the next! */ if (cursize != ncursize) continue; if (!strncmp(i, (char *)mb, cursize)) { i += cursize - 1; p += cursize - 1; found = true; break; } } if (found) continue; /* 3.2. Check against an UTF-8 ranges: <start character> and <length of the range>. */ found = false; for (unsigned char * mb = m_additionalUtf8range; (utf8size(mb) != -1) && (mb < m_additionalUtf8range + sizeof(m_additionalUtf8range)); mb += cursize + 1) { cursize = utf8size(mb); /* Size differs (or lengthbyte is zero)? Pick the next! */ if ((cursize != ncursize) || (!mb[cursize])) continue; unsigned char uright[5] = {0,0,0,0,0}, range = mb[cursize] - 1; strncpy((char* ) uright, (char *) mb, cursize); for (int temp = cursize - 1; (temp >= 0) && range; --temp) { /* all but the first char are 64-based */ if (temp) { char part64 = range & 63; /* i.e. % 64 */ /* handle carrying over */ if (uright[temp] + part64 - 1 > 191) { uright[temp] -= 64; range += 64; } uright[temp] += part64; range >>= 6; /* divide it on a 64 */ } /* the first char of UTF-8 doesn't follow the rule */ else { uright[temp] += range; } } if ((strncmp(i, (char *) mb, cursize) >= 0) && (strncmp(i, (char *) uright, cursize) <= 0)) { i += cursize - 1; p += cursize - 1; found = true; break; } } if (found) continue; /* 3.3. Check against an UTF-8 intervals: <start character> and <end character>. */ found = false; for (unsigned char * mb = m_additionalUtf8interval; (utf8size(mb) != -1) && (utf8size(mb+utf8size(mb)) != -1) && (mb < m_additionalUtf8interval + sizeof(m_additionalUtf8interval)); mb += (cursize+cursize2) ) { cursize = utf8size(mb); cursize2= utf8size(mb+cursize); int minlen = cursize > ncursize ? ncursize : cursize; int minlen2 = cursize2 > ncursize ? ncursize : cursize2; unsigned char* uright = mb + cursize; if ((strncmp(i, (char *) mb, minlen) >= 0) && (strncmp(i, (char *) uright, minlen2) <= 0)) { i += cursize - 1; p += cursize - 1; found = true; break; } } if (found) continue; } /* invalid character! abort */ return false; } /* too long? or not -- pointer arithmetic rocks */ return (p < ServerInstance->Config->Limits.NickMax); } class ModuleNationalChars : public Module { std::string charset; unsigned char m_additional[256], m_additionalUp[256], m_lower[256], m_upper[256]; TR1NS::function<bool(const std::string&)> rememberer; bool forcequit; const unsigned char * lowermap_rememberer; unsigned char prev_map[256]; template <typename T> void RehashHashmap(T& hashmap) { T newhash(hashmap.bucket_count()); for (typename T::const_iterator i = hashmap.begin(); i != hashmap.end(); ++i) newhash.insert(std::make_pair(i->first, i->second)); hashmap.swap(newhash); } void CheckRehash() { // See if anything changed if (!memcmp(prev_map, national_case_insensitive_map, sizeof(prev_map))) return; memcpy(prev_map, national_case_insensitive_map, sizeof(prev_map)); RehashHashmap(ServerInstance->Users.clientlist); RehashHashmap(ServerInstance->Users.uuidlist); RehashHashmap(ServerInstance->chanlist); } public: ModuleNationalChars() : rememberer(ServerInstance->IsNick), lowermap_rememberer(national_case_insensitive_map) { memcpy(prev_map, national_case_insensitive_map, sizeof(prev_map)); } void init() CXX11_OVERRIDE { memcpy(m_lower, rfc_case_insensitive_map, 256); national_case_insensitive_map = m_lower; ServerInstance->IsNick = &lwbNickHandler::Call; } void ReadConfig(ConfigStatus& status) CXX11_OVERRIDE { ConfigTag* tag = ServerInstance->Config->ConfValue("nationalchars"); charset = tag->getString("file"); std::string casemapping = tag->getString("casemapping", FileSystem::GetFileName(charset)); if (casemapping.find(' ') != std::string::npos) throw ModuleException("<nationalchars:casemapping> must not contain any spaces!"); ServerInstance->Config->CaseMapping = casemapping; #if defined _WIN32 if (!FileSystem::StartsWithWindowsDriveLetter(charset)) charset.insert(0, "./locales/"); #else if(charset[0] != '/') charset.insert(0, "../locales/"); #endif unsigned char * tables[8] = { m_additional, m_additionalMB, m_additionalUp, m_lower, m_upper, m_additionalUtf8, m_additionalUtf8range, m_additionalUtf8interval }; if (!loadtables(charset, tables, 8, 5)) throw ModuleException("The locale file failed to load. Check your log file for more information."); forcequit = tag->getBool("forcequit"); CheckForceQuit("National character set changed"); CheckRehash(); } void CheckForceQuit(const char * message) { if (!forcequit) return; const UserManager::LocalList& list = ServerInstance->Users.GetLocalUsers(); for (UserManager::LocalList::const_iterator iter = list.begin(); iter != list.end(); ) { /* Fix by Brain: Dont quit UID users */ // Quitting the user removes it from the list User* n = *iter; ++iter; if (!isdigit(n->nick[0]) && !ServerInstance->IsNick(n->nick)) ServerInstance->Users->QuitUser(n, message); } } ~ModuleNationalChars() { ServerInstance->IsNick = rememberer; national_case_insensitive_map = lowermap_rememberer; CheckForceQuit("National characters module unloaded"); CheckRehash(); } Version GetVersion() CXX11_OVERRIDE { return Version("Provides an ability to have non-RFC1459 nicks & support for national CASEMAPPING", VF_VENDOR | VF_COMMON, charset); } /*make an array to check against it 8bit characters a bit faster. Whether allowed or uppercase (for your needs).*/ void makereverse(unsigned char * from, unsigned char * to, unsigned int cnt) { memset(to, 0, cnt); for(unsigned char * n=from; (*n) && ((*n)<cnt) && (n<from+cnt); n++) to[*n] = 1; } /*so Bynets Unreal distribution stuff*/ bool loadtables(std::string filename, unsigned char ** tables, unsigned char cnt, char faillimit) { std::ifstream ifs(ServerInstance->Config->Paths.PrependConfig(filename).c_str()); if (ifs.fail()) { ServerInstance->Logs->Log(MODNAME, LOG_DEFAULT, "loadtables() called for missing file: %s", filename.c_str()); return false; } for (unsigned char n=0; n< cnt; n++) { memset(tables[n], 0, 256); } memcpy(m_lower, rfc_case_insensitive_map, 256); for (unsigned char n = 0; n < cnt; n++) { if (loadtable(ifs, tables[n], 255) && (n < faillimit)) { ServerInstance->Logs->Log(MODNAME, LOG_DEFAULT, "loadtables() called for illegal file: %s (line %d)", filename.c_str(), n+1); return false; } } makereverse(m_additional, m_reverse_additional, sizeof(m_additional)); return true; } unsigned char symtoi(const char *t,unsigned char base) /* base = 16 for hexadecimal, 10 for decimal, 8 for octal ;) */ { unsigned char tmp = 0, current; while ((*t) && (*t !=' ') && (*t != 13) && (*t != 10) && (*t != ',')) { tmp *= base; current = ascii_case_insensitive_map[(unsigned char)*t]; if (current >= 'a') current = current - 'a' + 10; else current = current - '0'; tmp+=current; t++; } return tmp; } int loadtable(std::ifstream &ifs , unsigned char *chartable, unsigned int maxindex) { std::string buf; getline(ifs, buf); unsigned int i = 0; int fail = 0; buf.erase(buf.find_last_not_of("\n") + 1); if (buf[0] == '.') /* simple plain-text string after dot */ { i = buf.size() - 1; if (i > (maxindex + 1)) i = maxindex + 1; memcpy(chartable, buf.c_str() + 1, i); } else { const char * p = buf.c_str(); while (*p) { if (i > maxindex) { fail = 1; break; } if (*p != '\'') /* decimal or hexadecimal char code */ { if (*p == '0') { if (p[1] == 'x') /* hex with the leading "0x" */ chartable[i] = symtoi(p + 2, 16); else chartable[i] = symtoi(p + 1, 8); } /* hex form */ else if (*p == 'x') { chartable[i] = symtoi(p + 1, 16); }else /* decimal form */ { chartable[i] = symtoi(p, 10); } } else /* plain-text char between '' */ { if (*(p + 1) == '\\') { chartable[i] = *(p + 2); p += 3; }else { chartable[i] = *(p + 1); p += 2; } } while (*p && (*p != ',') && (*p != ' ') && (*p != 13) && (*p != 10)) p++; while (*p && ((*p == ',') || (*p == ' ') || (*p == 13) || (*p == 10))) p++; i++; } } return fail; } }; MODULE_INIT(ModuleNationalChars) ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/src/modules/m_nickflood.cpp����������������������������������������������������������0000664�0000000�0000000�00000012444�13554550454�0020577�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * InspIRCd -- Internet Relay Chat Daemon * * Copyright (C) 2009 Daniel De Graaf <danieldg@inspircd.org> * Copyright (C) 2007, 2009 Robin Burchell <robin+git@viroteck.net> * * 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 "inspircd.h" #include "modules/exemption.h" // The number of seconds nickname changing will be blocked for. static unsigned int duration; /** Holds settings and state associated with channel mode +F */ class nickfloodsettings { public: unsigned int secs; unsigned int nicks; time_t reset; time_t unlocktime; unsigned int counter; nickfloodsettings(unsigned int b, unsigned int c) : secs(b), nicks(c), unlocktime(0), counter(0) { reset = ServerInstance->Time() + secs; } void addnick() { if (ServerInstance->Time() > reset) { counter = 1; reset = ServerInstance->Time() + secs; } else counter++; } bool shouldlock() { return ((ServerInstance->Time() <= reset) && (counter == this->nicks)); } void clear() { counter = 0; } bool islocked() { if (ServerInstance->Time() > unlocktime) unlocktime = 0; return (unlocktime != 0); } void lock() { unlocktime = ServerInstance->Time() + duration; } }; /** Handles channel mode +F */ class NickFlood : public ParamMode<NickFlood, SimpleExtItem<nickfloodsettings> > { public: NickFlood(Module* Creator) : ParamMode<NickFlood, SimpleExtItem<nickfloodsettings> >(Creator, "nickflood", 'F') { syntax = "<nick-changes>:<seconds>"; } ModeAction OnSet(User* source, Channel* channel, std::string& parameter) CXX11_OVERRIDE { std::string::size_type colon = parameter.find(':'); if ((colon == std::string::npos) || (parameter.find('-') != std::string::npos)) { source->WriteNumeric(Numerics::InvalidModeParameter(channel, this, parameter)); return MODEACTION_DENY; } /* Set up the flood parameters for this channel */ unsigned int nnicks = ConvToNum<unsigned int>(parameter.substr(0, colon)); unsigned int nsecs = ConvToNum<unsigned int>(parameter.substr(colon+1)); if ((nnicks<1) || (nsecs<1)) { source->WriteNumeric(Numerics::InvalidModeParameter(channel, this, parameter)); return MODEACTION_DENY; } ext.set(channel, new nickfloodsettings(nsecs, nnicks)); return MODEACTION_ALLOW; } void SerializeParam(Channel* chan, const nickfloodsettings* nfs, std::string& out) { out.append(ConvToStr(nfs->nicks)).push_back(':'); out.append(ConvToStr(nfs->secs)); } }; class ModuleNickFlood : public Module { CheckExemption::EventProvider exemptionprov; NickFlood nf; public: ModuleNickFlood() : exemptionprov(this) , nf(this) { } void ReadConfig(ConfigStatus&) CXX11_OVERRIDE { ConfigTag* tag = ServerInstance->Config->ConfValue("nickflood"); duration = tag->getDuration("duration", 60, 10, 600); } ModResult OnUserPreNick(LocalUser* user, const std::string& newnick) CXX11_OVERRIDE { for (User::ChanList::iterator i = user->chans.begin(); i != user->chans.end(); i++) { Channel* channel = (*i)->chan; ModResult res; nickfloodsettings *f = nf.ext.get(channel); if (f) { res = CheckExemption::Call(exemptionprov, user, channel, "nickflood"); if (res == MOD_RES_ALLOW) continue; if (f->islocked()) { user->WriteNumeric(ERR_CANTCHANGENICK, InspIRCd::Format("%s has been locked for nickchanges for %u seconds because there have been more than %u nick changes in %u seconds", channel->name.c_str(), duration, f->nicks, f->secs)); return MOD_RES_DENY; } if (f->shouldlock()) { f->clear(); f->lock(); channel->WriteNotice(InspIRCd::Format("No nick changes are allowed for %u seconds because there have been more than %u nick changes in %u seconds.", duration, f->nicks, f->secs)); return MOD_RES_DENY; } } } return MOD_RES_PASSTHRU; } /* * XXX: HACK: We do the increment on the *POST* event here (instead of all together) because we have no way of knowing whether other modules would block a nickchange. */ void OnUserPostNick(User* user, const std::string &oldnick) CXX11_OVERRIDE { if (isdigit(user->nick[0])) /* allow switches to UID */ return; for (User::ChanList::iterator i = user->chans.begin(); i != user->chans.end(); ++i) { Channel* channel = (*i)->chan; ModResult res; nickfloodsettings *f = nf.ext.get(channel); if (f) { res = CheckExemption::Call(exemptionprov, user, channel, "nickflood"); if (res == MOD_RES_ALLOW) return; /* moved this here to avoid incrementing the counter for nick * changes that are denied for some other reason (bans, +N, etc.) * per bug #874. */ f->addnick(); } } } Version GetVersion() CXX11_OVERRIDE { return Version("Provides channel mode +F, nick flood protection", VF_VENDOR); } }; MODULE_INIT(ModuleNickFlood) ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/src/modules/m_nicklock.cpp�����������������������������������������������������������0000664�0000000�0000000�00000011107�13554550454�0020417�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * InspIRCd -- Internet Relay Chat Daemon * * Copyright (C) 2009-2010 Daniel De Graaf <danieldg@inspircd.org> * Copyright (C) 2007, 2009 Dennis Friis <peavey@inspircd.org> * Copyright (C) 2007-2008 Robin Burchell <robin+git@viroteck.net> * Copyright (C) 2005-2006 Craig Edwards <craigedwards@brainbox.cc> * * This file is part of InspIRCd. InspIRCd is free software: you can * redistribute it and/or modify it under the terms of the GNU General Public * License as published by the Free Software Foundation, version 2. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include "inspircd.h" enum { // InspIRCd-specific. ERR_NICKNOTLOCKED = 946, RPL_NICKLOCKON = 947, RPL_NICKLOCKOFF = 945 }; /** Handle /NICKLOCK */ class CommandNicklock : public Command { public: LocalIntExt& locked; CommandNicklock (Module* Creator, LocalIntExt& ext) : Command(Creator,"NICKLOCK", 2), locked(ext) { flags_needed = 'o'; syntax = "<nick> <newnick>"; TRANSLATE2(TR_NICK, TR_TEXT); } CmdResult Handle(User* user, const Params& parameters) CXX11_OVERRIDE { User* target = ServerInstance->FindNick(parameters[0]); if ((!target) || (target->registered != REG_ALL)) { user->WriteNotice("*** No such nickname: '" + parameters[0] + "'"); return CMD_FAILURE; } /* Do local sanity checks and bails */ if (IS_LOCAL(user)) { if (!ServerInstance->IsNick(parameters[1])) { user->WriteNotice("*** Invalid nickname '" + parameters[1] + "'"); return CMD_FAILURE; } user->WriteNumeric(RPL_NICKLOCKON, parameters[1], "Nickname now locked."); } /* If we made it this far, extend the user */ if (IS_LOCAL(target)) { locked.set(target, 1); std::string oldnick = target->nick; if (target->ChangeNick(parameters[1])) ServerInstance->SNO->WriteGlobalSno('a', user->nick+" used NICKLOCK to change and hold "+oldnick+" to "+parameters[1]); else { std::string newnick = target->nick; ServerInstance->SNO->WriteGlobalSno('a', user->nick+" used NICKLOCK, but "+oldnick+" failed nick change to "+parameters[1]+" and was locked to "+newnick+" instead"); } } return CMD_SUCCESS; } RouteDescriptor GetRouting(User* user, const Params& parameters) CXX11_OVERRIDE { return ROUTE_OPT_UCAST(parameters[0]); } }; /** Handle /NICKUNLOCK */ class CommandNickunlock : public Command { public: LocalIntExt& locked; CommandNickunlock (Module* Creator, LocalIntExt& ext) : Command(Creator,"NICKUNLOCK", 1), locked(ext) { flags_needed = 'o'; syntax = "<nick>"; TRANSLATE1(TR_NICK); } CmdResult Handle(User* user, const Params& parameters) CXX11_OVERRIDE { User* target = ServerInstance->FindNick(parameters[0]); if (!target) { user->WriteNotice("*** No such nickname: '" + parameters[0] + "'"); return CMD_FAILURE; } if (IS_LOCAL(target)) { if (locked.set(target, 0)) { ServerInstance->SNO->WriteGlobalSno('a', user->nick+" used NICKUNLOCK on "+target->nick); user->WriteRemoteNumeric(RPL_NICKLOCKOFF, target->nick, "Nickname now unlocked."); } else { user->WriteRemoteNumeric(ERR_NICKNOTLOCKED, target->nick, "This user's nickname is not locked."); return CMD_FAILURE; } } return CMD_SUCCESS; } RouteDescriptor GetRouting(User* user, const Params& parameters) CXX11_OVERRIDE { return ROUTE_OPT_UCAST(parameters[0]); } }; class ModuleNickLock : public Module { LocalIntExt locked; CommandNicklock cmd1; CommandNickunlock cmd2; public: ModuleNickLock() : locked("nick_locked", ExtensionItem::EXT_USER, this) , cmd1(this, locked) , cmd2(this, locked) { } Version GetVersion() CXX11_OVERRIDE { return Version("Provides the NICKLOCK command, allows an oper to change a users nick and lock them to it until they quit", VF_OPTCOMMON | VF_VENDOR); } ModResult OnUserPreNick(LocalUser* user, const std::string& newnick) CXX11_OVERRIDE { if (locked.get(user)) { user->WriteNumeric(ERR_CANTCHANGENICK, "You cannot change your nickname (your nick is locked)"); return MOD_RES_DENY; } return MOD_RES_PASSTHRU; } void Prioritize() CXX11_OVERRIDE { Module *nflood = ServerInstance->Modules->Find("m_nickflood.so"); ServerInstance->Modules->SetPriority(this, I_OnUserPreNick, PRIORITY_BEFORE, nflood); } }; MODULE_INIT(ModuleNickLock) ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/src/modules/m_noctcp.cpp�������������������������������������������������������������0000664�0000000�0000000�00000006203�13554550454�0020111�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * InspIRCd -- Internet Relay Chat Daemon * * Copyright (C) 2007-2008 Robin Burchell <robin+git@viroteck.net> * Copyright (C) 2007 Dennis Friis <peavey@inspircd.org> * Copyright (C) 2004, 2006 Craig Edwards <craigedwards@brainbox.cc> * * This file is part of InspIRCd. InspIRCd is free software: you can * redistribute it and/or modify it under the terms of the GNU General Public * License as published by the Free Software Foundation, version 2. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include "inspircd.h" #include "modules/exemption.h" class NoCTCPUser : public SimpleUserModeHandler { public: NoCTCPUser(Module* Creator) : SimpleUserModeHandler(Creator, "u_noctcp", 'T') { if (!ServerInstance->Config->ConfValue("noctcp")->getBool("enableumode")) DisableAutoRegister(); } }; class ModuleNoCTCP : public Module { CheckExemption::EventProvider exemptionprov; SimpleChannelModeHandler nc; NoCTCPUser ncu; public: ModuleNoCTCP() : exemptionprov(this) , nc(this, "noctcp", 'C') , ncu(this) { } Version GetVersion() CXX11_OVERRIDE { return Version("Provides user mode +T and channel mode +C to block CTCPs", VF_VENDOR); } ModResult OnUserPreMessage(User* user, const MessageTarget& target, MessageDetails& details) CXX11_OVERRIDE { if (!IS_LOCAL(user)) return MOD_RES_PASSTHRU; std::string ctcpname; if (!details.IsCTCP(ctcpname) || irc::equals(ctcpname, "ACTION")) return MOD_RES_PASSTHRU; switch (target.type) { case MessageTarget::TYPE_CHANNEL: { if (user->HasPrivPermission("channels/ignore-noctcp")) return MOD_RES_PASSTHRU; Channel* c = target.Get<Channel>(); const Channel::MemberMap& members = c->GetUsers(); for (Channel::MemberMap::const_iterator member = members.begin(); member != members.end(); ++member) { User* u = member->first; if (u->IsModeSet(ncu)) details.exemptions.insert(u); } ModResult res = CheckExemption::Call(exemptionprov, user, c, "noctcp"); if (res == MOD_RES_ALLOW) return MOD_RES_PASSTHRU; if (!c->GetExtBanStatus(user, 'C').check(!c->IsModeSet(nc))) { user->WriteNumeric(ERR_CANNOTSENDTOCHAN, c->name, "Can't send CTCP to channel (+C is set)"); return MOD_RES_DENY; } break; } case MessageTarget::TYPE_USER: { if (user->HasPrivPermission("users/ignore-noctcp")) return MOD_RES_PASSTHRU; User* u = target.Get<User>(); if (u->IsModeSet(ncu)) { user->WriteNumeric(ERR_CANTSENDTOUSER, u->nick, "Can't send CTCP to user (+T is set)"); return MOD_RES_DENY; } break; } case MessageTarget::TYPE_SERVER: break; } return MOD_RES_PASSTHRU; } void On005Numeric(std::map<std::string, std::string>& tokens) CXX11_OVERRIDE { tokens["EXTBAN"].push_back('C'); } }; MODULE_INIT(ModuleNoCTCP) ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/src/modules/m_nokicks.cpp������������������������������������������������������������0000664�0000000�0000000�00000003462�13554550454�0020270�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * InspIRCd -- Internet Relay Chat Daemon * * Copyright (C) 2009 Daniel De Graaf <danieldg@inspircd.org> * Copyright (C) 2004, 2008 Craig Edwards <craigedwards@brainbox.cc> * Copyright (C) 2007 Dennis Friis <peavey@inspircd.org> * Copyright (C) 2007 Robin Burchell <robin+git@viroteck.net> * * 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 "inspircd.h" class ModuleNoKicks : public Module { SimpleChannelModeHandler nk; public: ModuleNoKicks() : nk(this, "nokick", 'Q') { } void On005Numeric(std::map<std::string, std::string>& tokens) CXX11_OVERRIDE { tokens["EXTBAN"].push_back('Q'); } ModResult OnUserPreKick(User* source, Membership* memb, const std::string &reason) CXX11_OVERRIDE { if (!memb->chan->GetExtBanStatus(source, 'Q').check(!memb->chan->IsModeSet(nk))) { // Can't kick with Q in place, not even opers with override, and founders source->WriteNumeric(ERR_CHANOPRIVSNEEDED, memb->chan->name, InspIRCd::Format("Can't kick user %s from channel (+Q is set)", memb->user->nick.c_str())); return MOD_RES_DENY; } return MOD_RES_PASSTHRU; } Version GetVersion() CXX11_OVERRIDE { return Version("Provides channel mode +Q to prevent kicks on the channel", VF_VENDOR); } }; MODULE_INIT(ModuleNoKicks) ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/src/modules/m_nonicks.cpp������������������������������������������������������������0000664�0000000�0000000�00000004120�13554550454�0020263�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * InspIRCd -- Internet Relay Chat Daemon * * Copyright (C) 2007-2008 Robin Burchell <robin+git@viroteck.net> * Copyright (C) 2007 Dennis Friis <peavey@inspircd.org> * Copyright (C) 2004, 2006 Craig Edwards <craigedwards@brainbox.cc> * * This file is part of InspIRCd. InspIRCd is free software: you can * redistribute it and/or modify it under the terms of the GNU General Public * License as published by the Free Software Foundation, version 2. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include "inspircd.h" #include "modules/exemption.h" class ModuleNoNickChange : public Module { CheckExemption::EventProvider exemptionprov; SimpleChannelModeHandler nn; public: ModuleNoNickChange() : exemptionprov(this) , nn(this, "nonick", 'N') { } Version GetVersion() CXX11_OVERRIDE { return Version("Provides channel mode +N and extban 'N' which prevents nick changes on the channel", VF_VENDOR); } void On005Numeric(std::map<std::string, std::string>& tokens) CXX11_OVERRIDE { tokens["EXTBAN"].push_back('N'); } ModResult OnUserPreNick(LocalUser* user, const std::string& newnick) CXX11_OVERRIDE { for (User::ChanList::iterator i = user->chans.begin(); i != user->chans.end(); i++) { Channel* curr = (*i)->chan; ModResult res = CheckExemption::Call(exemptionprov, user, curr, "nonick"); if (res == MOD_RES_ALLOW) continue; if (user->HasPrivPermission("channels/ignore-nonicks")) continue; if (!curr->GetExtBanStatus(user, 'N').check(!curr->IsModeSet(nn))) { user->WriteNumeric(ERR_CANTCHANGENICK, InspIRCd::Format("Cannot change nickname while on %s (+N is set)", curr->name.c_str())); return MOD_RES_DENY; } } return MOD_RES_PASSTHRU; } }; MODULE_INIT(ModuleNoNickChange) ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/src/modules/m_nonotice.cpp�����������������������������������������������������������0000664�0000000�0000000�00000004017�13554550454�0020442�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * InspIRCd -- Internet Relay Chat Daemon * * Copyright (C) 2004, 2008 Craig Edwards <craigedwards@brainbox.cc> * Copyright (C) 2007 Dennis Friis <peavey@inspircd.org> * Copyright (C) 2007 Robin Burchell <robin+git@viroteck.net> * * 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 "inspircd.h" #include "modules/exemption.h" class ModuleNoNotice : public Module { CheckExemption::EventProvider exemptionprov; SimpleChannelModeHandler nt; public: ModuleNoNotice() : exemptionprov(this) , nt(this, "nonotice", 'T') { } void On005Numeric(std::map<std::string, std::string>& tokens) CXX11_OVERRIDE { tokens["EXTBAN"].push_back('T'); } ModResult OnUserPreMessage(User* user, const MessageTarget& target, MessageDetails& details) CXX11_OVERRIDE { ModResult res; if ((details.type == MSG_NOTICE) && (target.type == MessageTarget::TYPE_CHANNEL) && (IS_LOCAL(user))) { Channel* c = target.Get<Channel>(); if (!c->GetExtBanStatus(user, 'T').check(!c->IsModeSet(nt))) { res = CheckExemption::Call(exemptionprov, user, c, "nonotice"); if (res == MOD_RES_ALLOW) return MOD_RES_PASSTHRU; else { user->WriteNumeric(ERR_CANNOTSENDTOCHAN, c->name, "Can't send NOTICE to channel (+T is set)"); return MOD_RES_DENY; } } } return MOD_RES_PASSTHRU; } Version GetVersion() CXX11_OVERRIDE { return Version("Provides channel mode +T to block notices to the channel", VF_VENDOR); } }; MODULE_INIT(ModuleNoNotice) �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/src/modules/m_nopartmsg.cpp����������������������������������������������������������0000664�0000000�0000000�00000002446�13554550454�0020642�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * InspIRCd -- Internet Relay Chat Daemon * * Copyright (C) 2008 Robin Burchell <robin+git@viroteck.net> * * 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 "inspircd.h" class ModulePartMsgBan : public Module { public: Version GetVersion() CXX11_OVERRIDE { return Version("Provides extban 'p', part message bans", VF_OPTCOMMON|VF_VENDOR); } void OnUserPart(Membership* memb, std::string &partmessage, CUList& excepts) CXX11_OVERRIDE { if (!IS_LOCAL(memb->user)) return; if (memb->chan->GetExtBanStatus(memb->user, 'p') == MOD_RES_DENY) partmessage.clear(); } void On005Numeric(std::map<std::string, std::string>& tokens) CXX11_OVERRIDE { tokens["EXTBAN"].push_back('p'); } }; MODULE_INIT(ModulePartMsgBan) ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/src/modules/m_ojoin.cpp��������������������������������������������������������������0000664�0000000�0000000�00000010624�13554550454�0017743�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * InspIRCd -- Internet Relay Chat Daemon * * Copyright (C) 2009 Taros <taros34@hotmail.com> * 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 * 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 "inspircd.h" #define NETWORK_VALUE 9000000 /** Handle /OJOIN */ class CommandOjoin : public SplitCommand { public: bool active; bool notice; bool op; ModeHandler* npmh; CommandOjoin(Module* parent, ModeHandler& mode) : SplitCommand(parent, "OJOIN", 1) , npmh(&mode) { flags_needed = 'o'; syntax = "<channel>"; active = false; } CmdResult HandleLocal(LocalUser* user, const Params& parameters) CXX11_OVERRIDE { // Make sure the channel name is allowable. if (!ServerInstance->IsChannel(parameters[0])) { user->WriteNotice("*** Invalid characters in channel name or name too long"); return CMD_FAILURE; } active = true; // override is false because we want OnUserPreJoin to run Channel* channel = Channel::JoinUser(user, parameters[0], false); active = false; if (channel) { ServerInstance->SNO->WriteGlobalSno('a', user->nick+" used OJOIN to join "+channel->name); if (notice) { const std::string msg = user->nick + " joined on official network business."; channel->WriteNotice(msg); ServerInstance->PI->SendChannelNotice(channel, 0, msg); } } else { channel = ServerInstance->FindChan(parameters[0]); if (!channel) return CMD_FAILURE; ServerInstance->SNO->WriteGlobalSno('a', user->nick+" used OJOIN in "+parameters[0]); // they're already in the channel Modes::ChangeList changelist; changelist.push_add(npmh, user->nick); if (op) changelist.push_add(ServerInstance->Modes->FindMode('o', MODETYPE_CHANNEL), user->nick); ServerInstance->Modes->Process(ServerInstance->FakeClient, channel, NULL, changelist); } return CMD_SUCCESS; } }; /** channel mode +Y */ class NetworkPrefix : public PrefixMode { public: NetworkPrefix(Module* parent, char NPrefix) : PrefixMode(parent, "official-join", 'Y', NETWORK_VALUE, NPrefix) { ranktoset = ranktounset = UINT_MAX; } ModResult AccessCheck(User* source, Channel* channel, std::string &parameter, bool adding) CXX11_OVERRIDE { User* theuser = ServerInstance->FindNick(parameter); // remove own privs? if (source == theuser && !adding) return MOD_RES_ALLOW; return MOD_RES_PASSTHRU; } }; class ModuleOjoin : public Module { NetworkPrefix np; CommandOjoin mycommand; public: ModuleOjoin() : np(this, ServerInstance->Config->ConfValue("ojoin")->getString("prefix").c_str()[0]) , mycommand(this, np) { } ModResult OnUserPreJoin(LocalUser* user, Channel* chan, const std::string& cname, std::string& privs, const std::string& keygiven) CXX11_OVERRIDE { if (mycommand.active) { privs += np.GetModeChar(); if (mycommand.op) privs += 'o'; return MOD_RES_ALLOW; } return MOD_RES_PASSTHRU; } void ReadConfig(ConfigStatus& status) CXX11_OVERRIDE { ConfigTag* Conf = ServerInstance->Config->ConfValue("ojoin"); mycommand.notice = Conf->getBool("notice", true); mycommand.op = Conf->getBool("op", true); } ModResult OnUserPreKick(User* source, Membership* memb, const std::string &reason) CXX11_OVERRIDE { // Don't do anything if they're not +Y if (!memb->HasMode(&np)) return MOD_RES_PASSTHRU; // Let them do whatever they want to themselves. if (source == memb->user) return MOD_RES_PASSTHRU; source->WriteNumeric(ERR_RESTRICTED, memb->chan->name, "Can't kick "+memb->user->nick+" as they're on official network business."); return MOD_RES_DENY; } void Prioritize() CXX11_OVERRIDE { ServerInstance->Modules->SetPriority(this, I_OnUserPreJoin, PRIORITY_FIRST); } Version GetVersion() CXX11_OVERRIDE { return Version("Provides the OJOIN command, allows an oper to join a channel and be immune to kicks", VF_VENDOR); } }; MODULE_INIT(ModuleOjoin) ������������������������������������������������������������������������������������������������������������inspircd-3.4.0/src/modules/m_operchans.cpp����������������������������������������������������������0000664�0000000�0000000�00000005513�13554550454�0020610�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * InspIRCd -- Internet Relay Chat Daemon * * Copyright (C) 2009 Daniel De Graaf <danieldg@inspircd.org> * Copyright (C) 2007 Dennis Friis <peavey@inspircd.org> * Copyright (C) 2007 Robin Burchell <robin+git@viroteck.net> * Copyright (C) 2004, 2006 Craig Edwards <craigedwards@brainbox.cc> * * This file is part of InspIRCd. InspIRCd is free software: you can * redistribute it and/or modify it under the terms of the GNU General Public * License as published by the Free Software Foundation, version 2. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include "inspircd.h" enum { // From UnrealIRCd. ERR_CANTJOINOPERSONLY = 520 }; class OperChans : public SimpleChannelModeHandler { public: /* This is an oper-only mode */ OperChans(Module* Creator) : SimpleChannelModeHandler(Creator, "operonly", 'O') { oper = true; } }; class ModuleOperChans : public Module { private: OperChans oc; std::string space; std::string underscore; public: ModuleOperChans() : oc(this) , space(" ") , underscore("_") { } ModResult OnUserPreJoin(LocalUser* user, Channel* chan, const std::string& cname, std::string& privs, const std::string& keygiven) CXX11_OVERRIDE { if (chan && chan->IsModeSet(oc) && !user->IsOper()) { user->WriteNumeric(ERR_CANTJOINOPERSONLY, chan->name, InspIRCd::Format("Only server operators may join %s (+O is set)", chan->name.c_str())); return MOD_RES_DENY; } return MOD_RES_PASSTHRU; } ModResult OnCheckBan(User* user, Channel* chan, const std::string& mask) CXX11_OVERRIDE { // Check whether the entry is an extban. if (mask.length() <= 2 || mask[0] != 'O' || mask[1] != ':') return MOD_RES_PASSTHRU; // If the user is not an oper they can't match this. if (!user->IsOper()) return MOD_RES_PASSTHRU; // Check whether the oper's type matches the ban. const std::string submask = mask.substr(2); if (InspIRCd::Match(user->oper->name, submask)) return MOD_RES_DENY; // If the oper's type contains spaces recheck with underscores. std::string opername(user->oper->name); stdalgo::string::replace_all(opername, space, underscore); if (InspIRCd::Match(opername, submask)) return MOD_RES_DENY; return MOD_RES_PASSTHRU; } void On005Numeric(std::map<std::string, std::string>& tokens) CXX11_OVERRIDE { tokens["EXTBAN"].push_back('O'); } Version GetVersion() CXX11_OVERRIDE { return Version("Provides support for oper-only channels via channel mode +O and extban 'O'", VF_VENDOR); } }; MODULE_INIT(ModuleOperChans) �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/src/modules/m_operjoin.cpp�����������������������������������������������������������0000664�0000000�0000000�00000004404�13554550454�0020451�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * InspIRCd -- Internet Relay Chat Daemon * * Copyright (C) 2009-2010 Daniel De Graaf <danieldg@inspircd.org> * Copyright (C) 2008 Thomas Stagner <aquanight@inspircd.org> * Copyright (C) 2007 Dennis Friis <peavey@inspircd.org> * Copyright (C) 2005-2007 Robin Burchell <robin+git@viroteck.net> * Copyright (C) 2006-2007 Craig Edwards <craigedwards@brainbox.cc> * Copyright (C) 2004 Christopher Hall <typobox43@gmail.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 "inspircd.h" class ModuleOperjoin : public Module { std::vector<std::string> operChans; bool override; public: void ReadConfig(ConfigStatus& status) CXX11_OVERRIDE { ConfigTag* tag = ServerInstance->Config->ConfValue("operjoin"); override = tag->getBool("override", false); irc::commasepstream ss(tag->getString("channel")); operChans.clear(); for (std::string channame; ss.GetToken(channame); ) operChans.push_back(channame); } Version GetVersion() CXX11_OVERRIDE { return Version("Forces opers to join the specified channel(s) on oper-up", VF_VENDOR); } void OnPostOper(User* user, const std::string &opertype, const std::string &opername) CXX11_OVERRIDE { LocalUser* localuser = IS_LOCAL(user); if (!localuser) return; for (std::vector<std::string>::const_iterator i = operChans.begin(); i != operChans.end(); ++i) if (ServerInstance->IsChannel(*i)) Channel::JoinUser(localuser, *i, override); irc::commasepstream ss(localuser->oper->getConfig("autojoin")); for (std::string channame; ss.GetToken(channame); ) { if (ServerInstance->IsChannel(channame)) Channel::JoinUser(localuser, channame, override); } } }; MODULE_INIT(ModuleOperjoin) ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/src/modules/m_operlevels.cpp���������������������������������������������������������0000664�0000000�0000000�00000004124�13554550454�0021003�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * InspIRCd -- Internet Relay Chat Daemon * * Copyright (C) 2009 Daniel De Graaf <danieldg@inspircd.org> * Copyright (C) 2006-2007 Robin Burchell <robin+git@viroteck.net> * Copyright (C) 2007 Dennis Friis <peavey@inspircd.org> * Copyright (C) 2005 Craig Edwards <craigedwards@brainbox.cc> * * This file is part of InspIRCd. InspIRCd is free software: you can * redistribute it and/or modify it under the terms of the GNU General Public * License as published by the Free Software Foundation, version 2. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include "inspircd.h" class ModuleOperLevels : public Module { public: Version GetVersion() CXX11_OVERRIDE { return Version("Gives each oper type a 'level', cannot kill opers 'above' your level", VF_VENDOR); } ModResult OnKill(User* source, User* dest, const std::string &reason) CXX11_OVERRIDE { // oper killing an oper? if (dest->IsOper() && source->IsOper()) { unsigned long dest_level = ConvToNum<unsigned long>(dest->oper->getConfig("level")); unsigned long source_level = ConvToNum<unsigned long>(source->oper->getConfig("level")); if (dest_level > source_level) { if (IS_LOCAL(source)) { ServerInstance->SNO->WriteGlobalSno('a', "Oper %s (level %lu) attempted to /KILL a higher level oper: %s (level %lu), reason: %s", source->nick.c_str(), source_level, dest->nick.c_str(), dest_level, reason.c_str()); } dest->WriteNotice("*** Oper " + source->nick + " attempted to /KILL you!"); source->WriteNumeric(ERR_NOPRIVILEGES, InspIRCd::Format("Permission Denied - Oper %s is a higher level than you", dest->nick.c_str())); return MOD_RES_DENY; } } return MOD_RES_PASSTHRU; } }; MODULE_INIT(ModuleOperLevels) ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/src/modules/m_operlog.cpp������������������������������������������������������������0000664�0000000�0000000�00000004266�13554550454�0020301�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * InspIRCd -- Internet Relay Chat Daemon * * Copyright (C) 2007 Dennis Friis <peavey@inspircd.org> * Copyright (C) 2007 Robin Burchell <robin+git@viroteck.net> * Copyright (C) 2006 Craig Edwards <craigedwards@brainbox.cc> * * This file is part of InspIRCd. InspIRCd is free software: you can * redistribute it and/or modify it under the terms of the GNU General Public * License as published by the Free Software Foundation, version 2. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include "inspircd.h" class ModuleOperLog : public Module { bool tosnomask; public: void init() CXX11_OVERRIDE { ServerInstance->SNO->EnableSnomask('r', "OPERLOG"); } Version GetVersion() CXX11_OVERRIDE { return Version("Provides logging of all oper commands to the ircd log at the default loglevel", VF_VENDOR); } void ReadConfig(ConfigStatus& status) CXX11_OVERRIDE { tosnomask = ServerInstance->Config->ConfValue("operlog")->getBool("tosnomask", false); } ModResult OnPreCommand(std::string& command, CommandBase::Params& parameters, LocalUser* user, bool validated) CXX11_OVERRIDE { /* If the command doesnt appear to be valid, we dont want to mess with it. */ if (!validated) return MOD_RES_PASSTHRU; if ((user->IsOper()) && (user->HasCommandPermission(command))) { Command* thiscommand = ServerInstance->Parser.GetHandler(command); if ((thiscommand) && (thiscommand->flags_needed == 'o')) { std::string msg = "[" + user->GetFullRealHost() + "] " + command + " " + stdalgo::string::join(parameters); ServerInstance->Logs->Log(MODNAME, LOG_DEFAULT, "OPERLOG: " + msg); if (tosnomask) ServerInstance->SNO->WriteGlobalSno('r', msg); } } return MOD_RES_PASSTHRU; } void On005Numeric(std::map<std::string, std::string>& tokens) CXX11_OVERRIDE { tokens["OPERLOG"]; } }; MODULE_INIT(ModuleOperLog) ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/src/modules/m_opermodes.cpp����������������������������������������������������������0000664�0000000�0000000�00000004051�13554550454�0020617�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * InspIRCd -- Internet Relay Chat Daemon * * Copyright (C) 2009 Daniel De Graaf <danieldg@inspircd.org> * Copyright (C) 2007-2008 Robin Burchell <robin+git@viroteck.net> * Copyright (C) 2007 Dennis Friis <peavey@inspircd.org> * Copyright (C) 2005-2007 Craig Edwards <craigedwards@brainbox.cc> * * This file is part of InspIRCd. InspIRCd is free software: you can * redistribute it and/or modify it under the terms of the GNU General Public * License as published by the Free Software Foundation, version 2. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include "inspircd.h" class ModuleModesOnOper : public Module { public: Version GetVersion() CXX11_OVERRIDE { return Version("Sets (and unsets) modes on opers when they oper up", VF_VENDOR); } void OnPostOper(User* user, const std::string &opertype, const std::string &opername) CXX11_OVERRIDE { if (!IS_LOCAL(user)) return; // whenever a user opers, go through the oper types, find their <type:modes>, // and if they have one apply their modes. The mode string can contain +modes // to add modes to the user or -modes to take modes from the user. std::string ThisOpersModes = user->oper->getConfig("modes"); if (!ThisOpersModes.empty()) { ApplyModes(user, ThisOpersModes); } } void ApplyModes(User *u, std::string &smodes) { char first = *(smodes.c_str()); if ((first != '+') && (first != '-')) smodes = "+" + smodes; std::string buf; irc::spacesepstream ss(smodes); CommandBase::Params modes; modes.push_back(u->nick); // split into modes and mode params while (ss.GetToken(buf)) modes.push_back(buf); ServerInstance->Parser.CallHandler("MODE", modes, u); } }; MODULE_INIT(ModuleModesOnOper) ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/src/modules/m_opermotd.cpp�����������������������������������������������������������0000664�0000000�0000000�00000006204�13554550454�0020455�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * InspIRCd -- Internet Relay Chat Daemon * * Copyright (C) 2007 Dennis Friis <peavey@inspircd.org> * Copyright (C) 2005, 2007 Robin Burchell <robin+git@viroteck.net> * Copyright (C) 2005-2006 Craig Edwards <craigedwards@brainbox.cc> * Copyright (C) 2004 Christopher Hall <typobox43@gmail.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 "inspircd.h" enum { // From UnrealIRCd. ERR_NOOPERMOTD = 425, // From ircd-ratbox. RPL_OMOTDSTART = 720, RPL_OMOTD = 721, RPL_ENDOFOMOTD = 722 }; /** Handle /OPERMOTD */ class CommandOpermotd : public Command { public: file_cache opermotd; CommandOpermotd(Module* Creator) : Command(Creator,"OPERMOTD", 0, 1) { flags_needed = 'o'; syntax = "[<servername>]"; } CmdResult Handle(User* user, const Params& parameters) CXX11_OVERRIDE { if ((parameters.empty()) || (irc::equals(parameters[0], ServerInstance->Config->ServerName))) ShowOperMOTD(user, true); return CMD_SUCCESS; } RouteDescriptor GetRouting(User* user, const Params& parameters) CXX11_OVERRIDE { if ((!parameters.empty()) && (parameters[0].find('.') != std::string::npos)) return ROUTE_OPT_UCAST(parameters[0]); return ROUTE_LOCALONLY; } void ShowOperMOTD(User* user, bool show_missing) { if (opermotd.empty()) { if (show_missing) user->WriteRemoteNumeric(ERR_NOOPERMOTD, "OPERMOTD file is missing."); return; } user->WriteRemoteNumeric(RPL_OMOTDSTART, "Server operators message of the day"); for (file_cache::const_iterator i = opermotd.begin(); i != opermotd.end(); ++i) { user->WriteRemoteNumeric(RPL_OMOTD, InspIRCd::Format("- %s", i->c_str())); } user->WriteRemoteNumeric(RPL_ENDOFOMOTD, "End of OPERMOTD"); } }; class ModuleOpermotd : public Module { CommandOpermotd cmd; bool onoper; public: ModuleOpermotd() : cmd(this) { } Version GetVersion() CXX11_OVERRIDE { return Version("Shows a message to opers after oper-up and adds the OPERMOTD command", VF_VENDOR | VF_OPTCOMMON); } void OnOper(User* user, const std::string &opertype) CXX11_OVERRIDE { if (onoper && IS_LOCAL(user)) cmd.ShowOperMOTD(user, false); } void ReadConfig(ConfigStatus& status) CXX11_OVERRIDE { cmd.opermotd.clear(); ConfigTag* conf = ServerInstance->Config->ConfValue("opermotd"); onoper = conf->getBool("onoper", true); try { FileReader reader(conf->getString("file", "opermotd")); cmd.opermotd = reader.GetVector(); InspIRCd::ProcessColors(cmd.opermotd); } catch (CoreException&) { // Nothing happens here as we do the error handling in ShowOperMOTD. } } }; MODULE_INIT(ModuleOpermotd) ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/src/modules/m_operprefix.cpp���������������������������������������������������������0000664�0000000�0000000�00000010102�13554550454�0020777�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * InspIRCd -- Internet Relay Chat Daemon * * Copyright (C) 2009 Daniel De Graaf <danieldg@inspircd.org> * Copyright (C) 2008 Robin Burchell <robin+git@viroteck.net> * * 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/>. */ /* * Originally by Chernov-Phoenix Alexey (Phoenix@RusNet) mailto:phoenix /email address separator/ pravmail.ru */ #include "inspircd.h" #define OPERPREFIX_VALUE 1000000 class OperPrefixMode : public PrefixMode { public: OperPrefixMode(Module* Creator) : PrefixMode(Creator, "operprefix", 'y', OPERPREFIX_VALUE) { prefix = ServerInstance->Config->ConfValue("operprefix")->getString("prefix", "!", 1, 1)[0]; ranktoset = ranktounset = UINT_MAX; } }; class ModuleOperPrefixMode; class HideOperWatcher : public ModeWatcher { ModuleOperPrefixMode* parentmod; public: HideOperWatcher(ModuleOperPrefixMode* parent); void AfterMode(User* source, User* dest, Channel* channel, const std::string &parameter, bool adding) CXX11_OVERRIDE; }; class ModuleOperPrefixMode : public Module { OperPrefixMode opm; HideOperWatcher hideoperwatcher; UserModeReference hideopermode; public: ModuleOperPrefixMode() : opm(this), hideoperwatcher(this) , hideopermode(this, "hideoper") { /* To give clients a chance to learn about the new prefix we don't give +y to opers * right now. That means if the module was loaded after opers have joined channels * they need to rejoin them in order to get the oper prefix. */ } ModResult OnUserPreJoin(LocalUser* user, Channel* chan, const std::string& cname, std::string& privs, const std::string& keygiven) CXX11_OVERRIDE { if ((user->IsOper()) && (!user->IsModeSet(hideopermode))) privs.push_back('y'); return MOD_RES_PASSTHRU; } void OnPostJoin(Membership* memb) CXX11_OVERRIDE { if ((!IS_LOCAL(memb->user)) || (!memb->user->IsOper()) || (memb->user->IsModeSet(hideopermode))) return; if (memb->HasMode(&opm)) return; // The user was force joined and OnUserPreJoin() did not run. Set the operprefix now. Modes::ChangeList changelist; changelist.push_add(&opm, memb->user->nick); ServerInstance->Modes.Process(ServerInstance->FakeClient, memb->chan, NULL, changelist); } void SetOperPrefix(User* user, bool add) { Modes::ChangeList changelist; changelist.push(&opm, add, user->nick); for (User::ChanList::iterator v = user->chans.begin(); v != user->chans.end(); v++) ServerInstance->Modes->Process(ServerInstance->FakeClient, (*v)->chan, NULL, changelist); } void OnPostOper(User* user, const std::string& opername, const std::string& opertype) CXX11_OVERRIDE { if (IS_LOCAL(user) && (!user->IsModeSet(hideopermode))) SetOperPrefix(user, true); } Version GetVersion() CXX11_OVERRIDE { return Version("Gives opers channel mode +y which provides a staff prefix", VF_VENDOR); } void Prioritize() CXX11_OVERRIDE { // m_opermodes may set +H on the oper to hide him, we don't want to set the oper prefix in that case Module* opermodes = ServerInstance->Modules->Find("m_opermodes.so"); ServerInstance->Modules->SetPriority(this, I_OnPostOper, PRIORITY_AFTER, opermodes); } }; HideOperWatcher::HideOperWatcher(ModuleOperPrefixMode* parent) : ModeWatcher(parent, "hideoper", MODETYPE_USER) , parentmod(parent) { } void HideOperWatcher::AfterMode(User* source, User* dest, Channel* channel, const std::string& parameter, bool adding) { // If hideoper is being unset because the user is deopering, don't set +y if (IS_LOCAL(dest) && dest->IsOper()) parentmod->SetOperPrefix(dest, !adding); } MODULE_INIT(ModuleOperPrefixMode) ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/src/modules/m_override.cpp�����������������������������������������������������������0000664�0000000�0000000�00000016364�13554550454�0020453�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * InspIRCd -- Internet Relay Chat Daemon * * Copyright (C) 2009-2010 Daniel De Graaf <danieldg@inspircd.org> * Copyright (C) 2009 Uli Schlachter <psychon@znc.in> * Copyright (C) 2007-2009 Robin Burchell <robin+git@viroteck.net> * Copyright (C) 2007-2008 Dennis Friis <peavey@inspircd.org> * Copyright (C) 2008 Pippijn van Steenhoven <pip88nl@gmail.com> * Copyright (C) 2008 Geoff Bricker <geoff.bricker@gmail.com> * Copyright (C) 2004-2006 Craig Edwards <craigedwards@brainbox.cc> * Copyright (C) 2006 Oliver Lupton <oliverlupton@gmail.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 "inspircd.h" #include "modules/invite.h" class Override : public SimpleUserModeHandler { public: Override(Module* Creator) : SimpleUserModeHandler(Creator, "override", 'O') { oper = true; if (!ServerInstance->Config->ConfValue("override")->getBool("enableumode")) DisableAutoRegister(); } }; class ModuleOverride : public Module { bool RequireKey; bool NoisyOverride; bool UmodeEnabled; Override ou; ChanModeReference topiclock; ChanModeReference inviteonly; ChanModeReference key; ChanModeReference limit; Invite::API invapi; static bool IsOverride(unsigned int userlevel, const Modes::ChangeList::List& list) { for (Modes::ChangeList::List::const_iterator i = list.begin(); i != list.end(); ++i) { ModeHandler* mh = i->mh; if (mh->GetLevelRequired(i->adding) > userlevel) return true; } return false; } ModResult HandleJoinOverride(LocalUser* user, Channel* chan, const std::string& keygiven, const char* bypasswhat, const char* mode) { if (RequireKey && keygiven != "override") { // Can't join normally -- must use a special key to bypass restrictions user->WriteNotice("*** You may not join normally. You must join with a key of 'override' to oper override."); return MOD_RES_PASSTHRU; } if (NoisyOverride) chan->WriteNotice(InspIRCd::Format("%s used oper override to bypass %s", user->nick.c_str(), bypasswhat)); ServerInstance->SNO->WriteGlobalSno('v', user->nick+" used oper override to bypass " + mode + " on " + chan->name); return MOD_RES_ALLOW; } public: ModuleOverride() : UmodeEnabled(false) , ou(this) , topiclock(this, "topiclock") , inviteonly(this, "inviteonly") , key(this, "key") , limit(this, "limit") , invapi(this) { } void init() CXX11_OVERRIDE { ServerInstance->SNO->EnableSnomask('v', "OVERRIDE"); UmodeEnabled = ServerInstance->Config->ConfValue("override")->getBool("enableumode"); } void ReadConfig(ConfigStatus& status) CXX11_OVERRIDE { // re-read our config options ConfigTag* tag = ServerInstance->Config->ConfValue("override"); NoisyOverride = tag->getBool("noisy"); RequireKey = tag->getBool("requirekey"); } void On005Numeric(std::map<std::string, std::string>& tokens) CXX11_OVERRIDE { tokens["OVERRIDE"]; } bool CanOverride(User* source, const char* token) { // If we require oper override umode (+O) but it is not set if (UmodeEnabled && !source->IsModeSet(ou)) return false; std::string tokenlist = source->oper->getConfig("override"); // its defined or * is set, return its value as a boolean for if the token is set return ((tokenlist.find(token, 0) != std::string::npos) || (tokenlist.find("*", 0) != std::string::npos)); } ModResult OnPreTopicChange(User *source, Channel *channel, const std::string &topic) CXX11_OVERRIDE { if (IS_LOCAL(source) && source->IsOper() && CanOverride(source, "TOPIC")) { if (!channel->HasUser(source) || (channel->IsModeSet(topiclock) && channel->GetPrefixValue(source) < HALFOP_VALUE)) { ServerInstance->SNO->WriteGlobalSno('v',source->nick+" used oper override to change a topic on "+channel->name); } // Explicit allow return MOD_RES_ALLOW; } return MOD_RES_PASSTHRU; } ModResult OnUserPreKick(User* source, Membership* memb, const std::string &reason) CXX11_OVERRIDE { if (source->IsOper() && CanOverride(source,"KICK")) { // If the kicker's status is less than the target's, or the kicker's status is less than or equal to voice if ((memb->chan->GetPrefixValue(source) < memb->getRank()) || (memb->chan->GetPrefixValue(source) <= VOICE_VALUE) || (memb->chan->GetPrefixValue(source) == HALFOP_VALUE && memb->getRank() == HALFOP_VALUE)) { ServerInstance->SNO->WriteGlobalSno('v',source->nick+" used oper override to kick "+memb->user->nick+" on "+memb->chan->name+" ("+reason+")"); return MOD_RES_ALLOW; } } return MOD_RES_PASSTHRU; } ModResult OnPreMode(User* source, User* dest, Channel* channel, Modes::ChangeList& modes) CXX11_OVERRIDE { if (!channel) return MOD_RES_PASSTHRU; if (!source->IsOper() || !IS_LOCAL(source)) return MOD_RES_PASSTHRU; const Modes::ChangeList::List& list = modes.getlist(); unsigned int mode = channel->GetPrefixValue(source); if (!IsOverride(mode, list)) return MOD_RES_PASSTHRU; if (CanOverride(source, "MODE")) { std::string msg = source->nick + " overriding modes: "; // Construct a MODE string in the old format for sending it as a snotice std::string params; char pm = 0; for (Modes::ChangeList::List::const_iterator i = list.begin(); i != list.end(); ++i) { const Modes::Change& item = *i; if (!item.param.empty()) params.append(1, ' ').append(item.param); char wanted_pm = (item.adding ? '+' : '-'); if (wanted_pm != pm) { pm = wanted_pm; msg += pm; } msg += item.mh->GetModeChar(); } msg += params; ServerInstance->SNO->WriteGlobalSno('v',msg); return MOD_RES_ALLOW; } return MOD_RES_PASSTHRU; } ModResult OnUserPreJoin(LocalUser* user, Channel* chan, const std::string& cname, std::string& privs, const std::string& keygiven) CXX11_OVERRIDE { if (user->IsOper()) { if (chan) { if (chan->IsModeSet(inviteonly) && (CanOverride(user,"INVITE"))) { if (!invapi->IsInvited(user, chan)) return HandleJoinOverride(user, chan, keygiven, "invite-only", "+i"); return MOD_RES_ALLOW; } if (chan->IsModeSet(key) && (CanOverride(user,"KEY")) && keygiven != chan->GetModeParameter(key)) return HandleJoinOverride(user, chan, keygiven, "the channel key", "+k"); if (chan->IsModeSet(limit) && (chan->GetUserCounter() >= ConvToNum<size_t>(chan->GetModeParameter(limit))) && (CanOverride(user,"LIMIT"))) return HandleJoinOverride(user, chan, keygiven, "the channel limit", "+l"); if (chan->IsBanned(user) && CanOverride(user,"BANWALK")) return HandleJoinOverride(user, chan, keygiven, "channel ban", "channel ban"); } } return MOD_RES_PASSTHRU; } Version GetVersion() CXX11_OVERRIDE { return Version("Provides support for allowing opers to override certain things",VF_VENDOR); } }; MODULE_INIT(ModuleOverride) ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/src/modules/m_passforward.cpp��������������������������������������������������������0000664�0000000�0000000�00000005620�13554550454�0021160�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * InspIRCd -- Internet Relay Chat Daemon * * Copyright (C) 2010 Daniel De Graaf <danieldg@inspircd.org> * * This file is part of InspIRCd. InspIRCd is free software: you can * redistribute it and/or modify it under the terms of the GNU General Public * License as published by the Free Software Foundation, version 2. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include "inspircd.h" #include "modules/account.h" class ModulePassForward : public Module { std::string nickrequired, forwardmsg, forwardcmd; public: Version GetVersion() CXX11_OVERRIDE { return Version("Sends server password to NickServ", VF_VENDOR); } void ReadConfig(ConfigStatus& status) CXX11_OVERRIDE { ConfigTag* tag = ServerInstance->Config->ConfValue("passforward"); nickrequired = tag->getString("nick", "NickServ"); forwardmsg = tag->getString("forwardmsg", "NOTICE $nick :*** Forwarding PASS to $nickrequired"); forwardcmd = tag->getString("cmd", "SQUERY $nickrequired :IDENTIFY $pass"); } void FormatStr(std::string& result, const std::string& format, const LocalUser* user) { for (unsigned int i = 0; i < format.length(); i++) { char c = format[i]; if (c == '$') { if (!format.compare(i, 13, "$nickrequired", 13)) { result.append(nickrequired); i += 12; } else if (!format.compare(i, 5, "$nick", 5)) { result.append(user->nick); i += 4; } else if (!format.compare(i, 5, "$user", 5)) { result.append(user->ident); i += 4; } else if (!format.compare(i, 5, "$pass", 5)) { result.append(user->password); i += 4; } else result.push_back(c); } else result.push_back(c); } } void OnPostConnect(User* ruser) CXX11_OVERRIDE { LocalUser* user = IS_LOCAL(ruser); if (!user || user->password.empty()) return; // If the connect class requires a password, don't forward it if (!user->MyClass->config->getString("password").empty()) return; AccountExtItem* actext = GetAccountExtItem(); if (actext && actext->get(user)) { // User is logged in already (probably via SASL) don't forward the password return; } if (!nickrequired.empty()) { /* Check if nick exists and its server is ulined */ User* u = ServerInstance->FindNick(nickrequired); if (!u || !u->server->IsULine()) return; } std::string tmp; FormatStr(tmp, forwardmsg, user); ServerInstance->Parser.ProcessBuffer(user, tmp); tmp.clear(); FormatStr(tmp,forwardcmd, user); ServerInstance->Parser.ProcessBuffer(user, tmp); } }; MODULE_INIT(ModulePassForward) ����������������������������������������������������������������������������������������������������������������inspircd-3.4.0/src/modules/m_password_hash.cpp������������������������������������������������������0000664�0000000�0000000�00000007350�13554550454�0021474�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * InspIRCd -- Internet Relay Chat Daemon * * Copyright (C) 2009-2010 Daniel De Graaf <danieldg@inspircd.org> * Copyright (C) 2008 Thomas Stagner <aquanight@inspircd.org> * * This file is part of InspIRCd. InspIRCd is free software: you can * redistribute it and/or modify it under the terms of the GNU General Public * License as published by the Free Software Foundation, version 2. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include "inspircd.h" #include "modules/hash.h" /* Handle /MKPASSWD */ class CommandMkpasswd : public Command { public: CommandMkpasswd(Module* Creator) : Command(Creator, "MKPASSWD", 2) { syntax = "<hashtype> <plaintext>"; Penalty = 5; } CmdResult Handle(User* user, const Params& parameters) CXX11_OVERRIDE { if (!parameters[0].compare(0, 5, "hmac-", 5)) { std::string type(parameters[0], 5); HashProvider* hp = ServerInstance->Modules->FindDataService<HashProvider>("hash/" + type); if (!hp) { user->WriteNotice("Unknown hash type"); return CMD_FAILURE; } if (hp->IsKDF()) { user->WriteNotice(type + " does not support HMAC"); return CMD_FAILURE; } std::string salt = ServerInstance->GenRandomStr(hp->out_size, false); std::string target = hp->hmac(salt, parameters[1]); std::string str = BinToBase64(salt) + "$" + BinToBase64(target, NULL, 0); user->WriteNotice(parameters[0] + " hashed password for " + parameters[1] + " is " + str); return CMD_SUCCESS; } HashProvider* hp = ServerInstance->Modules->FindDataService<HashProvider>("hash/" + parameters[0]); if (!hp) { user->WriteNotice("Unknown hash type"); return CMD_FAILURE; } std::string hexsum = hp->Generate(parameters[1]); user->WriteNotice(parameters[0] + " hashed password for " + parameters[1] + " is " + hexsum); return CMD_SUCCESS; } }; class ModulePasswordHash : public Module { private: CommandMkpasswd cmd; public: ModulePasswordHash() : cmd(this) { } ModResult OnPassCompare(Extensible* ex, const std::string &data, const std::string &input, const std::string &hashtype) CXX11_OVERRIDE { if (!hashtype.compare(0, 5, "hmac-", 5)) { std::string type(hashtype, 5); HashProvider* hp = ServerInstance->Modules->FindDataService<HashProvider>("hash/" + type); if (!hp) return MOD_RES_PASSTHRU; if (hp->IsKDF()) { ServerInstance->Logs->Log(MODNAME, LOG_DEFAULT, "Tried to use HMAC with %s, which does not support HMAC", type.c_str()); return MOD_RES_DENY; } // this is a valid hash, from here on we either accept or deny std::string::size_type sep = data.find('$'); if (sep == std::string::npos) return MOD_RES_DENY; std::string salt = Base64ToBin(data.substr(0, sep)); std::string target = Base64ToBin(data.substr(sep + 1)); if (target == hp->hmac(salt, input)) return MOD_RES_ALLOW; else return MOD_RES_DENY; } HashProvider* hp = ServerInstance->Modules->FindDataService<HashProvider>("hash/" + hashtype); /* Is this a valid hash name? */ if (hp) { if (hp->Compare(input, data)) return MOD_RES_ALLOW; else /* No match, and must be hashed, forbid */ return MOD_RES_DENY; } // We don't handle this type, let other mods or the core decide return MOD_RES_PASSTHRU; } Version GetVersion() CXX11_OVERRIDE { return Version("Provides the ability to hash passwords to other modules", VF_VENDOR); } }; MODULE_INIT(ModulePasswordHash) ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/src/modules/m_pbkdf2.cpp�������������������������������������������������������������0000664�0000000�0000000�00000014341�13554550454�0017775�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * InspIRCd -- Internet Relay Chat Daemon * * Copyright (C) 2014 Daniel Vassdal <shutter@canternet.org> * * This file is part of InspIRCd. InspIRCd is free software: you can * redistribute it and/or modify it under the terms of the GNU General Public * License as published by the Free Software Foundation, version 2. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include "inspircd.h" #include "modules/hash.h" // Format: // Iterations:B64(Hash):B64(Salt) // E.g. // 10200:AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA:BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB class PBKDF2Hash { public: unsigned int iterations; unsigned int length; std::string salt; std::string hash; PBKDF2Hash(unsigned int itr, unsigned int dkl, const std::string& slt, const std::string& hsh = "") : iterations(itr), length(dkl), salt(slt), hash(hsh) { } PBKDF2Hash(const std::string& data) { irc::sepstream ss(data, ':'); std::string tok; ss.GetToken(tok); this->iterations = ConvToNum<unsigned int>(tok); ss.GetToken(tok); this->hash = Base64ToBin(tok); ss.GetToken(tok); this->salt = Base64ToBin(tok); this->length = this->hash.length(); } std::string ToString() { if (!IsValid()) return ""; return ConvToStr(this->iterations) + ":" + BinToBase64(this->hash) + ":" + BinToBase64(this->salt); } bool IsValid() { if (!this->iterations || !this->length || this->salt.empty() || this->hash.empty()) return false; return true; } }; class PBKDF2Provider : public HashProvider { public: HashProvider* provider; unsigned int iterations; unsigned int dkey_length; std::string PBKDF2(const std::string& pass, const std::string& salt, unsigned int itr = 0, unsigned int dkl = 0) { size_t blocks = std::ceil((double)dkl / provider->out_size); std::string output; std::string tmphash; std::string salt_block = salt; for (size_t block = 1; block <= blocks; block++) { char salt_data[4]; for (size_t i = 0; i < sizeof(salt_data); i++) salt_data[i] = block >> (24 - i * 8) & 0x0F; salt_block.erase(salt.length()); salt_block.append(salt_data, sizeof(salt_data)); std::string blockdata = provider->hmac(pass, salt_block); std::string lasthash = blockdata; for (size_t iter = 1; iter < itr; iter++) { tmphash = provider->hmac(pass, lasthash); for (size_t i = 0; i < provider->out_size; i++) blockdata[i] ^= tmphash[i]; lasthash.swap(tmphash); } output += blockdata; } output.erase(dkl); return output; } std::string GenerateRaw(const std::string& data) CXX11_OVERRIDE { PBKDF2Hash hs(this->iterations, this->dkey_length, ServerInstance->GenRandomStr(dkey_length, false)); hs.hash = PBKDF2(data, hs.salt, this->iterations, this->dkey_length); return hs.ToString(); } bool Compare(const std::string& input, const std::string& hash) CXX11_OVERRIDE { PBKDF2Hash hs(hash); if (!hs.IsValid()) return false; std::string cmp = PBKDF2(input, hs.salt, hs.iterations, hs.length); return (cmp == hs.hash); } std::string ToPrintable(const std::string& raw) CXX11_OVERRIDE { return raw; } PBKDF2Provider(Module* mod, HashProvider* hp) : HashProvider(mod, "pbkdf2-hmac-" + hp->name.substr(hp->name.find('/') + 1)) , provider(hp) { DisableAutoRegister(); } }; struct ProviderConfig { unsigned long dkey_length; unsigned long iterations; }; typedef std::map<std::string, ProviderConfig> ProviderConfigMap; class ModulePBKDF2 : public Module { std::vector<PBKDF2Provider*> providers; ProviderConfig globalconfig; ProviderConfigMap providerconfigs; ProviderConfig GetConfigForProvider(const std::string& name) const { ProviderConfigMap::const_iterator it = providerconfigs.find(name); if (it == providerconfigs.end()) return globalconfig; return it->second; } void ConfigureProviders() { for (std::vector<PBKDF2Provider*>::iterator i = providers.begin(); i != providers.end(); ++i) { PBKDF2Provider* pi = *i; ProviderConfig config = GetConfigForProvider(pi->name); pi->iterations = config.iterations; pi->dkey_length = config.dkey_length; } } void GetConfig() { // First set the common values ConfigTag* tag = ServerInstance->Config->ConfValue("pbkdf2"); ProviderConfig newglobal; newglobal.iterations = tag->getUInt("iterations", 12288, 1); newglobal.dkey_length = tag->getUInt("length", 32, 1, 1024); // Then the specific values ProviderConfigMap newconfigs; ConfigTagList tags = ServerInstance->Config->ConfTags("pbkdf2prov"); for (ConfigIter i = tags.first; i != tags.second; ++i) { tag = i->second; std::string hash_name = "hash/" + tag->getString("hash"); ProviderConfig& config = newconfigs[hash_name]; config.iterations = tag->getUInt("iterations", newglobal.iterations, 1); config.dkey_length = tag->getUInt("length", newglobal.dkey_length, 1, 1024); } // Config is valid, apply it providerconfigs.swap(newconfigs); std::swap(globalconfig, newglobal); ConfigureProviders(); } public: ~ModulePBKDF2() { stdalgo::delete_all(providers); } void OnServiceAdd(ServiceProvider& provider) CXX11_OVERRIDE { // Check if it's a hash provider if (provider.name.compare(0, 5, "hash/")) return; HashProvider* hp = static_cast<HashProvider*>(&provider); if (hp->IsKDF()) return; PBKDF2Provider* prov = new PBKDF2Provider(this, hp); providers.push_back(prov); ServerInstance->Modules.AddService(*prov); ConfigureProviders(); } void OnServiceDel(ServiceProvider& prov) CXX11_OVERRIDE { for (std::vector<PBKDF2Provider*>::iterator i = providers.begin(); i != providers.end(); ++i) { PBKDF2Provider* item = *i; if (item->provider != &prov) continue; ServerInstance->Modules->DelService(*item); delete item; providers.erase(i); break; } } void ReadConfig(ConfigStatus& status) CXX11_OVERRIDE { GetConfig(); } Version GetVersion() CXX11_OVERRIDE { return Version("Implements PBKDF2 hashing", VF_VENDOR); } }; MODULE_INIT(ModulePBKDF2) �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/src/modules/m_permchannels.cpp�������������������������������������������������������0000664�0000000�0000000�00000023255�13554550454�0021310�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * InspIRCd -- Internet Relay Chat Daemon * * Copyright (C) 2009-2010 Daniel De Graaf <danieldg@inspircd.org> * Copyright (C) 2008-2009 Robin Burchell <robin+git@viroteck.net> * * 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 "inspircd.h" #include "listmode.h" #include <fstream> /** Handles the +P channel mode */ class PermChannel : public ModeHandler { public: PermChannel(Module* Creator) : ModeHandler(Creator, "permanent", 'P', PARAM_NONE, MODETYPE_CHANNEL) { oper = true; } ModeAction OnModeChange(User* source, User* dest, Channel* channel, std::string& parameter, bool adding) CXX11_OVERRIDE { if (adding == channel->IsModeSet(this)) return MODEACTION_DENY; channel->SetMode(this, adding); if (!adding) channel->CheckDestroy(); return MODEACTION_ALLOW; } }; // Not in a class due to circular dependancy hell. static std::string permchannelsconf; static bool WriteDatabase(PermChannel& permchanmode, Module* mod, bool save_listmodes) { /* * We need to perform an atomic write so as not to fuck things up. * So, let's write to a temporary file, flush it, then rename the file.. * -- w00t */ // If the user has not specified a configuration file then we don't write one. if (permchannelsconf.empty()) return true; std::string permchannelsnewconf = permchannelsconf + ".tmp"; std::ofstream stream(permchannelsnewconf.c_str()); if (!stream.is_open()) { ServerInstance->Logs->Log(MODNAME, LOG_DEFAULT, "Cannot create database \"%s\"! %s (%d)", permchannelsnewconf.c_str(), strerror(errno), errno); ServerInstance->SNO->WriteToSnoMask('a', "database: cannot create new permchan db \"%s\": %s (%d)", permchannelsnewconf.c_str(), strerror(errno), errno); return false; } stream << "# This file is automatically generated by m_permchannels. Any changes will be overwritten." << std::endl << "<config format=\"xml\">" << std::endl; const chan_hash& chans = ServerInstance->GetChans(); for (chan_hash::const_iterator i = chans.begin(); i != chans.end(); ++i) { Channel* chan = i->second; if (!chan->IsModeSet(permchanmode)) continue; std::string chanmodes = chan->ChanModes(true); if (save_listmodes) { std::string modes; std::string params; const ModeParser::ListModeList& listmodes = ServerInstance->Modes->GetListModes(); for (ModeParser::ListModeList::const_iterator j = listmodes.begin(); j != listmodes.end(); ++j) { ListModeBase* lm = *j; ListModeBase::ModeList* list = lm->GetList(chan); if (!list || list->empty()) continue; size_t n = 0; // Append the parameters for (ListModeBase::ModeList::const_iterator k = list->begin(); k != list->end(); ++k, n++) { params += k->mask; params += ' '; } // Append the mode letters (for example "IIII", "gg") modes.append(n, lm->GetModeChar()); } if (!params.empty()) { // Remove the last space params.erase(params.end()-1); // If there is at least a space in chanmodes (that is, a non-listmode has a parameter) // insert the listmode mode letters before the space. Otherwise just append them. std::string::size_type p = chanmodes.find(' '); if (p == std::string::npos) chanmodes += modes; else chanmodes.insert(p, modes); // Append the listmode parameters (the masks themselves) chanmodes += ' '; chanmodes += params; } } stream << "<permchannels channel=\"" << ServerConfig::Escape(chan->name) << "\" ts=\"" << chan->age << "\" topic=\"" << ServerConfig::Escape(chan->topic) << "\" topicts=\"" << chan->topicset << "\" topicsetby=\"" << ServerConfig::Escape(chan->setby) << "\" modes=\"" << ServerConfig::Escape(chanmodes) << "\">" << std::endl; } if (stream.fail()) { ServerInstance->Logs->Log(MODNAME, LOG_DEFAULT, "Cannot write to new database \"%s\"! %s (%d)", permchannelsnewconf.c_str(), strerror(errno), errno); ServerInstance->SNO->WriteToSnoMask('a', "database: cannot write to new permchan db \"%s\": %s (%d)", permchannelsnewconf.c_str(), strerror(errno), errno); return false; } stream.close(); #ifdef _WIN32 remove(permchannelsconf.c_str()); #endif // Use rename to move temporary to new db - this is guarenteed not to fuck up, even in case of a crash. if (rename(permchannelsnewconf.c_str(), permchannelsconf.c_str()) < 0) { ServerInstance->Logs->Log(MODNAME, LOG_DEFAULT, "Cannot replace old database \"%s\" with new database \"%s\"! %s (%d)", permchannelsconf.c_str(), permchannelsnewconf.c_str(), strerror(errno), errno); ServerInstance->SNO->WriteToSnoMask('a', "database: cannot replace old permchan db \"%s\" with new db \"%s\": %s (%d)", permchannelsconf.c_str(), permchannelsnewconf.c_str(), strerror(errno), errno); return false; } return true; } class ModulePermanentChannels : public Module , public Timer { PermChannel p; bool dirty; bool loaded; bool save_listmodes; public: ModulePermanentChannels() : Timer(0, true) , p(this) , dirty(false) , loaded(false) { } void ReadConfig(ConfigStatus& status) CXX11_OVERRIDE { ConfigTag* tag = ServerInstance->Config->ConfValue("permchanneldb"); permchannelsconf = tag->getString("filename"); save_listmodes = tag->getBool("listmodes"); SetInterval(tag->getDuration("saveperiod", 5)); if (!permchannelsconf.empty()) permchannelsconf = ServerInstance->Config->Paths.PrependConfig(permchannelsconf); } void LoadDatabase() { /* * Process config-defined list of permanent channels. * -- w00t */ ConfigTagList permchannels = ServerInstance->Config->ConfTags("permchannels"); for (ConfigIter i = permchannels.first; i != permchannels.second; ++i) { ConfigTag* tag = i->second; std::string channel = tag->getString("channel"); std::string modes = tag->getString("modes"); if (!ServerInstance->IsChannel(channel)) { ServerInstance->Logs->Log(MODNAME, LOG_DEFAULT, "Ignoring permchannels tag with invalid channel name (\"" + channel + "\")"); continue; } Channel *c = ServerInstance->FindChan(channel); if (!c) { time_t TS = tag->getInt("ts", ServerInstance->Time(), 1); c = new Channel(channel, TS); time_t topicset = tag->getInt("topicts", 0); std::string topic = tag->getString("topic"); if ((topicset != 0) || (!topic.empty())) { if (topicset == 0) topicset = ServerInstance->Time(); std::string topicsetby = tag->getString("topicsetby"); if (topicsetby.empty()) topicsetby = ServerInstance->Config->ServerName; c->SetTopic(ServerInstance->FakeClient, topic, topicset, &topicsetby); } ServerInstance->Logs->Log(MODNAME, LOG_DEBUG, "Added %s with topic %s", channel.c_str(), c->topic.c_str()); if (modes.empty()) continue; irc::spacesepstream list(modes); std::string modeseq; std::string par; list.GetToken(modeseq); // XXX bleh, should we pass this to the mode parser instead? ugly. --w00t for (std::string::iterator n = modeseq.begin(); n != modeseq.end(); ++n) { ModeHandler* mode = ServerInstance->Modes->FindMode(*n, MODETYPE_CHANNEL); if (mode) { if (mode->NeedsParam(true)) list.GetToken(par); else par.clear(); mode->OnModeChange(ServerInstance->FakeClient, ServerInstance->FakeClient, c, par, true); } } // We always apply the permchannels mode to permanent channels. par.clear(); p.OnModeChange(ServerInstance->FakeClient, ServerInstance->FakeClient, c, par, true); } } } ModResult OnRawMode(User* user, Channel* chan, ModeHandler* mh, const std::string& param, bool adding) CXX11_OVERRIDE { if (chan && (chan->IsModeSet(p) || mh == &p)) dirty = true; return MOD_RES_PASSTHRU; } void OnPostTopicChange(User*, Channel *c, const std::string&) CXX11_OVERRIDE { if (c->IsModeSet(p)) dirty = true; } bool Tick(time_t) CXX11_OVERRIDE { if (dirty) WriteDatabase(p, this, save_listmodes); dirty = false; return true; } void Prioritize() CXX11_OVERRIDE { // XXX: Load the DB here because the order in which modules are init()ed at boot is // alphabetical, this means we must wait until all modules have done their init() // to be able to set the modes they provide (e.g.: m_stripcolor is inited after us) // Prioritize() is called after all module initialization is complete, consequently // all modes are available now if (loaded) return; loaded = true; // Load only when there are no linked servers - we set the TS of the channels we // create to the current time, this can lead to desync because spanningtree has // no way of knowing what we do ProtocolInterface::ServerList serverlist; ServerInstance->PI->GetServerList(serverlist); if (serverlist.size() < 2) { try { LoadDatabase(); } catch (CoreException& e) { ServerInstance->Logs->Log(MODNAME, LOG_DEFAULT, "Error loading permchannels database: " + std::string(e.GetReason())); } } } Version GetVersion() CXX11_OVERRIDE { return Version("Provides channel mode +P to provide permanent channels", VF_VENDOR); } ModResult OnChannelPreDelete(Channel *c) CXX11_OVERRIDE { if (c->IsModeSet(p)) return MOD_RES_DENY; return MOD_RES_PASSTHRU; } }; MODULE_INIT(ModulePermanentChannels) ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/src/modules/m_randquote.cpp����������������������������������������������������������0000664�0000000�0000000�00000003355�13554550454�0020632�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * InspIRCd -- Internet Relay Chat Daemon * * Copyright (C) 2010 Daniel De Graaf <danieldg@inspircd.org> * Copyright (C) 2007-2008 Robin Burchell <robin+git@viroteck.net> * Copyright (C) 2007 Dennis Friis <peavey@inspircd.org> * Copyright (C) 2003, 2006 Craig Edwards <craigedwards@brainbox.cc> * Copyright (C) 2005 Craig McLure <craig@chatspike.net> * * 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 "inspircd.h" class ModuleRandQuote : public Module { private: std::string prefix; std::string suffix; std::vector<std::string> quotes; public: void init() CXX11_OVERRIDE { ConfigTag* conf = ServerInstance->Config->ConfValue("randquote"); prefix = conf->getString("prefix"); suffix = conf->getString("suffix"); FileReader reader(conf->getString("file", "quotes")); quotes = reader.GetVector(); } void OnUserConnect(LocalUser* user) CXX11_OVERRIDE { if (!quotes.empty()) { unsigned long random = ServerInstance->GenRandomInt(quotes.size()); user->WriteNotice(prefix + quotes[random] + suffix); } } Version GetVersion() CXX11_OVERRIDE { return Version("Provides random quotes on connect", VF_VENDOR); } }; MODULE_INIT(ModuleRandQuote) �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/src/modules/m_redirect.cpp�����������������������������������������������������������0000664�0000000�0000000�00000010027�13554550454�0020423�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * InspIRCd -- Internet Relay Chat Daemon * * Copyright (C) 2012 Shawn Smith <ShawnSmith0828@gmail.com> * Copyright (C) 2009 Daniel De Graaf <danieldg@inspircd.org> * Copyright (C) 2007-2008 Robin Burchell <robin+git@viroteck.net> * Copyright (C) 2007 Dennis Friis <peavey@inspircd.org> * Copyright (C) 2004, 2006 Craig Edwards <craigedwards@brainbox.cc> * Copyright (C) 2006 Oliver Lupton <oliverlupton@gmail.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 "inspircd.h" /** Handle channel mode +L */ class Redirect : public ParamMode<Redirect, LocalStringExt> { public: Redirect(Module* Creator) : ParamMode<Redirect, LocalStringExt>(Creator, "redirect", 'L') { syntax = "<target>"; } ModeAction OnSet(User* source, Channel* channel, std::string& parameter) CXX11_OVERRIDE { if (IS_LOCAL(source)) { if (!ServerInstance->IsChannel(parameter)) { source->WriteNumeric(Numerics::NoSuchChannel(parameter)); return MODEACTION_DENY; } } if (IS_LOCAL(source) && !source->IsOper()) { Channel* c = ServerInstance->FindChan(parameter); if (!c) { source->WriteNumeric(690, InspIRCd::Format("Target channel %s must exist to be set as a redirect.", parameter.c_str())); return MODEACTION_DENY; } else if (c->GetPrefixValue(source) < OP_VALUE) { source->WriteNumeric(690, InspIRCd::Format("You must be opped on %s to set it as a redirect.", parameter.c_str())); return MODEACTION_DENY; } } /* * We used to do some checking for circular +L here, but there is no real need for this any more especially as we * now catch +L looping in PreJoin. Remove it, since O(n) logic makes me sad, and we catch it anyway. :) -- w00t */ ext.set(channel, parameter); return MODEACTION_ALLOW; } void SerializeParam(Channel* chan, const std::string* str, std::string& out) { out += *str; } }; class ModuleRedirect : public Module { Redirect re; SimpleUserModeHandler antiredirectmode; ChanModeReference limitmode; public: ModuleRedirect() : re(this) , antiredirectmode(this, "antiredirect", 'L') , limitmode(this, "limit") { } ModResult OnUserPreJoin(LocalUser* user, Channel* chan, const std::string& cname, std::string& privs, const std::string& keygiven) CXX11_OVERRIDE { if (chan) { if (chan->IsModeSet(re) && chan->IsModeSet(limitmode)) { if (chan->GetUserCounter() >= ConvToNum<size_t>(chan->GetModeParameter(limitmode))) { const std::string& channel = *re.ext.get(chan); /* sometimes broken ulines can make circular or chained +L, avoid this */ Channel* destchan = ServerInstance->FindChan(channel); if (destchan && destchan->IsModeSet(re)) { user->WriteNumeric(470, cname, '*', "You may not join this channel. A redirect is set, but you may not be redirected as it is a circular loop."); return MOD_RES_DENY; } if (user->IsModeSet(antiredirectmode)) { user->WriteNumeric(470, cname, channel, "Force redirection stopped."); return MOD_RES_DENY; } else { user->WriteNumeric(470, cname, channel, "You may not join this channel, so you are automatically being transferred to the redirected channel."); Channel::JoinUser(user, channel); return MOD_RES_DENY; } } } } return MOD_RES_PASSTHRU; } Version GetVersion() CXX11_OVERRIDE { return Version("Provides channel mode +L (limit redirection) and user mode +L (no forced redirection)", VF_VENDOR); } }; MODULE_INIT(ModuleRedirect) ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/src/modules/m_regex_glob.cpp���������������������������������������������������������0000664�0000000�0000000�00000002765�13554550454�0020751�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * InspIRCd -- Internet Relay Chat Daemon * * Copyright (C) 2009 Daniel De Graaf <danieldg@inspircd.org> * Copyright (C) 2008 Thomas Stagner <aquanight@inspircd.org> * * This file is part of InspIRCd. InspIRCd is free software: you can * redistribute it and/or modify it under the terms of the GNU General Public * License as published by the Free Software Foundation, version 2. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include "modules/regex.h" #include "inspircd.h" class GlobRegex : public Regex { public: GlobRegex(const std::string& rx) : Regex(rx) { } bool Matches(const std::string& text) CXX11_OVERRIDE { return InspIRCd::Match(text, this->regex_string); } }; class GlobFactory : public RegexFactory { public: Regex* Create(const std::string& expr) CXX11_OVERRIDE { return new GlobRegex(expr); } GlobFactory(Module* m) : RegexFactory(m, "regex/glob") {} }; class ModuleRegexGlob : public Module { GlobFactory gf; public: ModuleRegexGlob() : gf(this) { } Version GetVersion() CXX11_OVERRIDE { return Version("Regex provider module using plain wildcard matching", VF_VENDOR); } }; MODULE_INIT(ModuleRegexGlob) �����������inspircd-3.4.0/src/modules/m_remove.cpp�������������������������������������������������������������0000664�0000000�0000000�00000016553�13554550454�0020131�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * InspIRCd -- Internet Relay Chat Daemon * * Copyright (C) 2009 Daniel De Graaf <danieldg@inspircd.org> * Copyright (C) 2008 Pippijn van Steenhoven <pip88nl@gmail.com> * Copyright (C) 2007 Dennis Friis <peavey@inspircd.org> * Copyright (C) 2005, 2007 Robin Burchell <robin+git@viroteck.net> * Copyright (C) 2005-2006 Craig Edwards <craigedwards@brainbox.cc> * Copyright (C) 2006 Oliver Lupton <oliverlupton@gmail.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 "inspircd.h" /* * This module supports the use of the +q and +a usermodes, but should work without them too. * Usage of the command is restricted to +hoaq, and you cannot remove a user with a "higher" level than yourself. * eg: +h can remove +hv and users with no modes. +a can remove +aohv and users with no modes. */ /** Base class for /FPART and /REMOVE */ class RemoveBase : public Command { bool& supportnokicks; ChanModeReference& nokicksmode; public: unsigned int protectedrank; RemoveBase(Module* Creator, bool& snk, ChanModeReference& nkm, const char* cmdn) : Command(Creator, cmdn, 2, 3) , supportnokicks(snk) , nokicksmode(nkm) { } CmdResult HandleRMB(User* user, const CommandBase::Params& parameters, bool fpart) { User* target; Channel* channel; std::string reason; // If the command is a /REMOVE then detect the parameter order bool neworder = ((fpart) || (parameters[0][0] == '#')); /* Set these to the parameters needed, the new version of this module switches it's parameters around * supplying a new command with the new order while keeping the old /remove with the older order. * /remove <nick> <channel> [reason ...] * /fpart <channel> <nick> [reason ...] */ const std::string& channame = parameters[neworder ? 0 : 1]; const std::string& username = parameters[neworder ? 1 : 0]; /* Look up the user we're meant to be removing from the channel */ if (IS_LOCAL(user)) target = ServerInstance->FindNickOnly(username); else target = ServerInstance->FindNick(username); /* And the channel we're meant to be removing them from */ channel = ServerInstance->FindChan(channame); /* Fix by brain - someone needs to learn to validate their input! */ if (!channel) { user->WriteNumeric(Numerics::NoSuchChannel(channame)); return CMD_FAILURE; } if ((!target) || (target->registered != REG_ALL)) { user->WriteNumeric(Numerics::NoSuchNick(username)); return CMD_FAILURE; } if (!channel->HasUser(target)) { user->WriteNotice(InspIRCd::Format("*** User %s is not on channel %s", target->nick.c_str(), channel->name.c_str())); return CMD_FAILURE; } if (target->server->IsULine()) { user->WriteNumeric(ERR_CHANOPRIVSNEEDED, channame, "Only a U-line may remove a U-line from a channel."); return CMD_FAILURE; } /* We support the +Q channel mode via. the m_nokicks module, if the module is loaded and the mode is set then disallow the /remove */ if ((!IS_LOCAL(user)) || (!supportnokicks) || (!channel->IsModeSet(nokicksmode))) { /* We'll let everyone remove their level and below, eg: * ops can remove ops, halfops, voices, and those with no mode (no moders actually are set to 1) a ulined target will get a higher level than it's possible for a /remover to get..so they're safe. * Nobody may remove people with >= protectedrank rank. */ unsigned int ulevel = channel->GetPrefixValue(user); unsigned int tlevel = channel->GetPrefixValue(target); if ((!IS_LOCAL(user)) || ((ulevel > VOICE_VALUE) && (ulevel >= tlevel) && ((protectedrank == 0) || (tlevel < protectedrank)))) { // REMOVE will be sent to the target's server and it will reply with a PART (or do nothing if it doesn't understand the command) if (!IS_LOCAL(target)) { // Send an ENCAP REMOVE with parameters being in the old <user> <chan> order which is // compatible with both 2.0 and 3.0. This also turns FPART into REMOVE. CommandBase::Params p; p.push_back(target->uuid); p.push_back(channel->name); if (parameters.size() > 2) p.push_back(":" + parameters[2]); ServerInstance->PI->SendEncapsulatedData(target->server->GetName(), "REMOVE", p, user); return CMD_SUCCESS; } std::string reasonparam; /* If a reason is given, use it */ if(parameters.size() > 2) reasonparam = parameters[2]; else reasonparam = "No reason given"; /* Build up the part reason string. */ reason = "Removed by " + user->nick + ": " + reasonparam; channel->WriteNotice(InspIRCd::Format("%s removed %s from the channel", user->nick.c_str(), target->nick.c_str())); target->WriteNotice("*** " + user->nick + " removed you from " + channel->name + " with the message: " + reasonparam); channel->PartUser(target, reason); } else { user->WriteNotice(InspIRCd::Format("*** You do not have access to /REMOVE %s from %s", target->nick.c_str(), channel->name.c_str())); return CMD_FAILURE; } } else { /* m_nokicks.so was loaded and +Q was set, block! */ user->WriteNumeric(ERR_RESTRICTED, channel->name, InspIRCd::Format("Can't remove user %s from channel (+Q is set)", target->nick.c_str())); return CMD_FAILURE; } return CMD_SUCCESS; } }; /** Handle /REMOVE */ class CommandRemove : public RemoveBase { public: CommandRemove(Module* Creator, bool& snk, ChanModeReference& nkm) : RemoveBase(Creator, snk, nkm, "REMOVE") { syntax = "<channel> <nick> [:<reason>]"; TRANSLATE3(TR_NICK, TR_TEXT, TR_TEXT); } CmdResult Handle(User* user, const Params& parameters) CXX11_OVERRIDE { return HandleRMB(user, parameters, false); } }; /** Handle /FPART */ class CommandFpart : public RemoveBase { public: CommandFpart(Module* Creator, bool& snk, ChanModeReference& nkm) : RemoveBase(Creator, snk, nkm, "FPART") { syntax = "<channel> <nick> [:<reason>]"; TRANSLATE3(TR_TEXT, TR_NICK, TR_TEXT); } CmdResult Handle(User* user, const Params& parameters) CXX11_OVERRIDE { return HandleRMB(user, parameters, true); } }; class ModuleRemove : public Module { ChanModeReference nokicksmode; CommandRemove cmd1; CommandFpart cmd2; bool supportnokicks; public: ModuleRemove() : nokicksmode(this, "nokick") , cmd1(this, supportnokicks, nokicksmode) , cmd2(this, supportnokicks, nokicksmode) { } void On005Numeric(std::map<std::string, std::string>& tokens) CXX11_OVERRIDE { tokens["REMOVE"]; } void ReadConfig(ConfigStatus& status) CXX11_OVERRIDE { ConfigTag* tag = ServerInstance->Config->ConfValue("remove"); supportnokicks = tag->getBool("supportnokicks"); cmd1.protectedrank = cmd2.protectedrank = tag->getUInt("protectedrank", 50000); } Version GetVersion() CXX11_OVERRIDE { return Version("Provides the REMOVE command as an alternative to KICK, it makes users appear to have left the channel", VF_OPTCOMMON | VF_VENDOR); } }; MODULE_INIT(ModuleRemove) �����������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/src/modules/m_repeat.cpp�������������������������������������������������������������0000664�0000000�0000000�00000025777�13554550454�0020124�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * InspIRCd -- Internet Relay Chat Daemon * * Copyright (C) 2013 Daniel Vassdal <shutter@canternet.org> * * This file is part of InspIRCd. InspIRCd is free software: you can * redistribute it and/or modify it under the terms of the GNU General Public * License as published by the Free Software Foundation, version 2. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include "inspircd.h" #include "modules/exemption.h" class ChannelSettings { public: enum RepeatAction { ACT_KICK, ACT_BLOCK, ACT_BAN }; RepeatAction Action; unsigned int Backlog; unsigned int Lines; unsigned int Diff; unsigned long Seconds; void serialize(std::string& out) const { if (Action == ACT_BAN) out.push_back('*'); else if (Action == ACT_BLOCK) out.push_back('~'); out.append(ConvToStr(Lines)).push_back(':'); out.append(ConvToStr(Seconds)); if (Diff) { out.push_back(':'); out.append(ConvToStr(Diff)); if (Backlog) { out.push_back(':'); out.append(ConvToStr(Backlog)); } } } }; class RepeatMode : public ParamMode<RepeatMode, SimpleExtItem<ChannelSettings> > { private: struct RepeatItem { time_t ts; std::string line; RepeatItem(time_t TS, const std::string& Line) : ts(TS), line(Line) { } }; typedef std::deque<RepeatItem> RepeatItemList; struct MemberInfo { RepeatItemList ItemList; unsigned int Counter; MemberInfo() : Counter(0) {} }; struct ModuleSettings { unsigned int MaxLines; unsigned int MaxSecs; unsigned int MaxBacklog; unsigned int MaxDiff; unsigned int MaxMessageSize; ModuleSettings() : MaxLines(0), MaxSecs(0), MaxBacklog(0), MaxDiff() { } }; std::vector<unsigned int> mx[2]; ModuleSettings ms; bool CompareLines(const std::string& message, const std::string& historyline, unsigned int trigger) { if (message == historyline) return true; else if (trigger) return (Levenshtein(message, historyline) <= trigger); return false; } unsigned int Levenshtein(const std::string& s1, const std::string& s2) { unsigned int l1 = s1.size(); unsigned int l2 = s2.size(); for (unsigned int i = 0; i < l2; i++) mx[0][i] = i; for (unsigned int i = 0; i < l1; i++) { mx[1][0] = i + 1; for (unsigned int j = 0; j < l2; j++) mx[1][j + 1] = std::min(std::min(mx[1][j] + 1, mx[0][j + 1] + 1), mx[0][j] + ((s1[i] == s2[j]) ? 0 : 1)); mx[0].swap(mx[1]); } return mx[0][l2]; } public: SimpleExtItem<MemberInfo> MemberInfoExt; RepeatMode(Module* Creator) : ParamMode<RepeatMode, SimpleExtItem<ChannelSettings> >(Creator, "repeat", 'E') , MemberInfoExt("repeat_memb", ExtensionItem::EXT_MEMBERSHIP, Creator) { syntax = "[~|*]<lines>:<sec>[:<difference>][:<backlog>]"; } void OnUnset(User* source, Channel* chan) CXX11_OVERRIDE { // Unset the per-membership extension when the mode is removed const Channel::MemberMap& users = chan->GetUsers(); for (Channel::MemberMap::const_iterator i = users.begin(); i != users.end(); ++i) MemberInfoExt.unset(i->second); } ModeAction OnSet(User* source, Channel* channel, std::string& parameter) CXX11_OVERRIDE { ChannelSettings settings; if (!ParseSettings(source, parameter, settings)) { source->WriteNumeric(Numerics::InvalidModeParameter(channel, this, parameter)); return MODEACTION_DENY; } if ((settings.Backlog > 0) && (settings.Lines > settings.Backlog)) { source->WriteNumeric(Numerics::InvalidModeParameter(channel, this, parameter, "You can't set lines higher than backlog.")); return MODEACTION_DENY; } LocalUser* localsource = IS_LOCAL(source); if ((localsource) && (!ValidateSettings(localsource, channel, parameter, settings))) return MODEACTION_DENY; ext.set(channel, settings); return MODEACTION_ALLOW; } bool MatchLine(Membership* memb, ChannelSettings* rs, std::string message) { // If the message is larger than whatever size it's set to, // let's pretend it isn't. If the first 512 (def. setting) match, it's probably spam. if (message.size() > ms.MaxMessageSize) message.erase(ms.MaxMessageSize); MemberInfo* rp = MemberInfoExt.get(memb); if (!rp) { rp = new MemberInfo; MemberInfoExt.set(memb, rp); } unsigned int matches = 0; if (!rs->Backlog) matches = rp->Counter; RepeatItemList& items = rp->ItemList; const unsigned int trigger = (message.size() * rs->Diff / 100); const time_t now = ServerInstance->Time(); std::transform(message.begin(), message.end(), message.begin(), ::tolower); for (std::deque<RepeatItem>::iterator it = items.begin(); it != items.end(); ++it) { if (it->ts < now) { items.erase(it, items.end()); matches = 0; break; } if (CompareLines(message, it->line, trigger)) { if (++matches >= rs->Lines) { if (rs->Action != ChannelSettings::ACT_BLOCK) rp->Counter = 0; return true; } } else if ((ms.MaxBacklog == 0) || (rs->Backlog == 0)) { matches = 0; items.clear(); break; } } unsigned int max_items = (rs->Backlog ? rs->Backlog : 1); if (items.size() >= max_items) items.pop_back(); items.push_front(RepeatItem(now + rs->Seconds, message)); rp->Counter = matches; return false; } void Resize(size_t size) { size_t newsize = size+1; if (newsize <= mx[0].size()) return; ms.MaxMessageSize = size; mx[0].resize(newsize); mx[1].resize(newsize); } void ReadConfig() { ConfigTag* conf = ServerInstance->Config->ConfValue("repeat"); ms.MaxLines = conf->getUInt("maxlines", 20); ms.MaxBacklog = conf->getUInt("maxbacklog", 20); ms.MaxSecs = conf->getDuration("maxtime", conf->getDuration("maxsecs", 0)); ms.MaxDiff = conf->getUInt("maxdistance", 50); if (ms.MaxDiff > 100) ms.MaxDiff = 100; unsigned int newsize = conf->getUInt("size", 512); if (newsize > ServerInstance->Config->Limits.MaxLine) newsize = ServerInstance->Config->Limits.MaxLine; Resize(newsize); } std::string GetModuleSettings() const { return ConvToStr(ms.MaxLines) + ":" + ConvToStr(ms.MaxSecs) + ":" + ConvToStr(ms.MaxDiff) + ":" + ConvToStr(ms.MaxBacklog); } void SerializeParam(Channel* chan, const ChannelSettings* chset, std::string& out) { chset->serialize(out); } private: bool ParseSettings(User* source, std::string& parameter, ChannelSettings& settings) { irc::sepstream stream(parameter, ':'); std::string item; if (!stream.GetToken(item)) // Required parameter missing return false; if ((item[0] == '*') || (item[0] == '~')) { settings.Action = ((item[0] == '*') ? ChannelSettings::ACT_BAN : ChannelSettings::ACT_BLOCK); item.erase(item.begin()); } else settings.Action = ChannelSettings::ACT_KICK; if ((settings.Lines = ConvToNum<unsigned int>(item)) == 0) return false; if ((!stream.GetToken(item)) || !InspIRCd::Duration(item, settings.Seconds) || (settings.Seconds == 0)) // Required parameter missing return false; // The diff and backlog parameters are optional settings.Diff = settings.Backlog = 0; if (stream.GetToken(item)) { // There is a diff parameter, see if it's valid (> 0) if ((settings.Diff = ConvToNum<unsigned int>(item)) == 0) return false; if (stream.GetToken(item)) { // There is a backlog parameter, see if it's valid if ((settings.Backlog = ConvToNum<unsigned int>(item)) == 0) return false; // If there are still tokens, then it's invalid because we allow only 4 if (stream.GetToken(item)) return false; } } return true; } bool ValidateSettings(LocalUser* source, Channel* channel, const std::string& parameter, const ChannelSettings& settings) { if (ms.MaxLines && settings.Lines > ms.MaxLines) { source->WriteNumeric(Numerics::InvalidModeParameter(channel, this, parameter, InspIRCd::Format( "The line number you specified is too big. Maximum allowed is %u.", ms.MaxLines))); return false; } if (ms.MaxSecs && settings.Seconds > ms.MaxSecs) { source->WriteNumeric(Numerics::InvalidModeParameter(channel, this, parameter, InspIRCd::Format( "The seconds you specified are too big. Maximum allowed is %u.", ms.MaxSecs))); return false; } if (settings.Diff && settings.Diff > ms.MaxDiff) { if (ms.MaxDiff == 0) source->WriteNumeric(Numerics::InvalidModeParameter(channel, this, parameter, "The server administrator has disabled matching on edit distance.")); else source->WriteNumeric(Numerics::InvalidModeParameter(channel, this, parameter, InspIRCd::Format( "The distance you specified is too big. Maximum allowed is %u.", ms.MaxDiff))); return false; } if (settings.Backlog && settings.Backlog > ms.MaxBacklog) { if (ms.MaxBacklog == 0) source->WriteNumeric(Numerics::InvalidModeParameter(channel, this, parameter, "The server administrator has disabled backlog matching.")); else source->WriteNumeric(Numerics::InvalidModeParameter(channel, this, parameter, InspIRCd::Format( "The backlog you specified is too big. Maximum allowed is %u.", ms.MaxBacklog))); return false; } return true; } }; class RepeatModule : public Module { CheckExemption::EventProvider exemptionprov; RepeatMode rm; public: RepeatModule() : exemptionprov(this) , rm(this) { } void ReadConfig(ConfigStatus& status) CXX11_OVERRIDE { rm.ReadConfig(); } ModResult OnUserPreMessage(User* user, const MessageTarget& target, MessageDetails& details) CXX11_OVERRIDE { if (target.type != MessageTarget::TYPE_CHANNEL || !IS_LOCAL(user)) return MOD_RES_PASSTHRU; Channel* chan = target.Get<Channel>(); ChannelSettings* settings = rm.ext.get(chan); if (!settings) return MOD_RES_PASSTHRU; Membership* memb = chan->GetUser(user); if (!memb) return MOD_RES_PASSTHRU; ModResult res = CheckExemption::Call(exemptionprov, user, chan, "repeat"); if (res == MOD_RES_ALLOW) return MOD_RES_PASSTHRU; if (rm.MatchLine(memb, settings, details.text)) { if (settings->Action == ChannelSettings::ACT_BLOCK) { user->WriteNotice("*** This line is too similar to one of your last lines."); return MOD_RES_DENY; } if (settings->Action == ChannelSettings::ACT_BAN) { Modes::ChangeList changelist; changelist.push_add(ServerInstance->Modes->FindMode('b', MODETYPE_CHANNEL), "*!*@" + user->GetDisplayedHost()); ServerInstance->Modes->Process(ServerInstance->FakeClient, chan, NULL, changelist); } memb->chan->KickUser(ServerInstance->FakeClient, user, "Repeat flood"); return MOD_RES_DENY; } return MOD_RES_PASSTHRU; } void Prioritize() CXX11_OVERRIDE { ServerInstance->Modules->SetPriority(this, I_OnUserPreMessage, PRIORITY_LAST); } Version GetVersion() CXX11_OVERRIDE { return Version("Provides channel mode +E, blocking of similar messages", VF_COMMON|VF_VENDOR, rm.GetModuleSettings()); } }; MODULE_INIT(RepeatModule) �inspircd-3.4.0/src/modules/m_restrictchans.cpp������������������������������������������������������0000664�0000000�0000000�00000005331�13554550454�0021500�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * InspIRCd -- Internet Relay Chat Daemon * * Copyright (C) 2009 Daniel De Graaf <danieldg@inspircd.org> * Copyright (C) 2007 Dennis Friis <peavey@inspircd.org> * Copyright (C) 2007 Robin Burchell <robin+git@viroteck.net> * Copyright (C) 2005-2006 Craig Edwards <craigedwards@brainbox.cc> * * This file is part of InspIRCd. InspIRCd is free software: you can * redistribute it and/or modify it under the terms of the GNU General Public * License as published by the Free Software Foundation, version 2. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include "inspircd.h" #include "modules/account.h" typedef insp::flat_set<std::string, irc::insensitive_swo> AllowChans; class ModuleRestrictChans : public Module { AllowChans allowchans; bool allowregistered; bool CanCreateChannel(LocalUser* user, const std::string& name) { const AccountExtItem* accountext = GetAccountExtItem(); if (allowregistered && accountext && accountext->get(user)) return true; if (user->HasPrivPermission("channels/restricted-create")) return true; for (AllowChans::const_iterator it = allowchans.begin(), it_end = allowchans.end(); it != it_end; ++it) { if (InspIRCd::Match(name, *it)) return true; } return false; } public: ModuleRestrictChans() : allowregistered(false) { } void ReadConfig(ConfigStatus& status) CXX11_OVERRIDE { AllowChans newallows; ConfigTagList tags = ServerInstance->Config->ConfTags("allowchannel"); for (ConfigIter i = tags.first; i != tags.second; ++i) { const std::string name = i->second->getString("name"); if (name.empty()) throw ModuleException("Empty <allowchannel:name> at " + i->second->getTagLocation()); newallows.insert(name); } allowchans.swap(newallows); // Global config ConfigTag* tag = ServerInstance->Config->ConfValue("restrictchans"); allowregistered = tag->getBool("allowregistered", false); } ModResult OnUserPreJoin(LocalUser* user, Channel* chan, const std::string& cname, std::string& privs, const std::string& keygiven) CXX11_OVERRIDE { // channel does not yet exist (record is null, about to be created IF we were to allow it) if (!chan && !CanCreateChannel(user, cname)) return MOD_RES_DENY; return MOD_RES_PASSTHRU; } Version GetVersion() CXX11_OVERRIDE { return Version("Allows restricting who can create channels", VF_VENDOR); } }; MODULE_INIT(ModuleRestrictChans) �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/src/modules/m_restrictmsg.cpp��������������������������������������������������������0000664�0000000�0000000�00000004340�13554550454�0021171�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * InspIRCd -- Internet Relay Chat Daemon * * Copyright (C) 2007 Dennis Friis <peavey@inspircd.org> * Copyright (C) 2007 Robin Burchell <robin+git@viroteck.net> * Copyright (C) 2005 Craig Edwards <craigedwards@brainbox.cc> * * This file is part of InspIRCd. InspIRCd is free software: you can * redistribute it and/or modify it under the terms of the GNU General Public * License as published by the Free Software Foundation, version 2. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include "inspircd.h" #include "modules/ctctags.h" class ModuleRestrictMsg : public Module , public CTCTags::EventListener { private: ModResult HandleMessage(User* user, const MessageTarget& target) { if ((target.type == MessageTarget::TYPE_USER) && (IS_LOCAL(user))) { User* u = target.Get<User>(); // message allowed if: // (1) the sender is opered // (2) the recipient is opered // (3) the recipient is on a ulined server // anything else, blocked. if (u->IsOper() || user->IsOper() || u->server->IsULine()) { return MOD_RES_PASSTHRU; } user->WriteNumeric(ERR_CANTSENDTOUSER, u->nick, "You are not permitted to send private messages to this user"); return MOD_RES_DENY; } // however, we must allow channel messages... return MOD_RES_PASSTHRU; } public: ModuleRestrictMsg() : CTCTags::EventListener(this) { } ModResult OnUserPreMessage(User* user, const MessageTarget& target, MessageDetails& details) CXX11_OVERRIDE { return HandleMessage(user, target); } ModResult OnUserPreTagMessage(User* user, const MessageTarget& target, CTCTags::TagMessageDetails& details) CXX11_OVERRIDE { return HandleMessage(user, target); } Version GetVersion() CXX11_OVERRIDE { return Version("Forbids users from messaging each other, but users may still message opers and opers may message other opers", VF_VENDOR); } }; MODULE_INIT(ModuleRestrictMsg) ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/src/modules/m_rline.cpp��������������������������������������������������������������0000664�0000000�0000000�00000022567�13554550454�0017747�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * InspIRCd -- Internet Relay Chat Daemon * * Copyright (C) 2009 Daniel De Graaf <danieldg@inspircd.org> * Copyright (C) 2008 Craig Edwards <craigedwards@brainbox.cc> * Copyright (C) 2008 Thomas Stagner <aquanight@inspircd.org> * Copyright (C) 2008 Robin Burchell <robin+git@viroteck.net> * * 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 "inspircd.h" #include "modules/regex.h" #include "modules/stats.h" #include "xline.h" static bool ZlineOnMatch = false; static bool added_zline = false; class RLine : public XLine { public: /** Create a R-line. * @param s_time The set time * @param d The duration of the xline * @param src The sender of the xline * @param re The reason of the xline * @param regex Pattern to match with * @ */ RLine(time_t s_time, unsigned long d, const std::string& src, const std::string& re, const std::string& regexs, dynamic_reference<RegexFactory>& rxfactory) : XLine(s_time, d, src, re, "R") , matchtext(regexs) { /* This can throw on failure, but if it does we DONT catch it here, we catch it and display it * where the object is created, we might not ALWAYS want it to output stuff to snomask x all the time */ regex = rxfactory->Create(regexs); } /** Destructor */ ~RLine() { delete regex; } bool Matches(User* u) CXX11_OVERRIDE { LocalUser* lu = IS_LOCAL(u); if (lu && lu->exempt) return false; const std::string host = u->nick + "!" + u->ident + "@" + u->GetRealHost() + " " + u->GetRealName(); const std::string ip = u->nick + "!" + u->ident + "@" + u->GetIPString() + " " + u->GetRealName(); return (regex->Matches(host) || regex->Matches(ip)); } bool Matches(const std::string& compare) CXX11_OVERRIDE { return regex->Matches(compare); } void Apply(User* u) CXX11_OVERRIDE { if (ZlineOnMatch) { ZLine* zl = new ZLine(ServerInstance->Time(), duration ? expiry - ServerInstance->Time() : 0, ServerInstance->Config->ServerName.c_str(), reason.c_str(), u->GetIPString()); if (ServerInstance->XLines->AddLine(zl, NULL)) { std::string expirystr = zl->duration ? InspIRCd::Format(" to expire in %s (on %s)", InspIRCd::DurationString(zl->duration).c_str(), InspIRCd::TimeString(zl->expiry).c_str()) : ""; ServerInstance->SNO->WriteToSnoMask('x', "Z-line added due to R-line match on %s%s: %s", zl->ipaddr.c_str(), expirystr.c_str(), zl->reason.c_str()); added_zline = true; } else delete zl; } DefaultApply(u, "R", false); } const std::string& Displayable() CXX11_OVERRIDE { return matchtext; } std::string matchtext; Regex *regex; }; /** An XLineFactory specialized to generate RLine* pointers */ class RLineFactory : public XLineFactory { public: dynamic_reference<RegexFactory>& rxfactory; RLineFactory(dynamic_reference<RegexFactory>& rx) : XLineFactory("R"), rxfactory(rx) { } /** Generate a RLine */ XLine* Generate(time_t set_time, unsigned long duration, const std::string& source, const std::string& reason, const std::string& xline_specific_mask) CXX11_OVERRIDE { if (!rxfactory) { ServerInstance->SNO->WriteToSnoMask('a', "Cannot create regexes until engine is set to a loaded provider!"); throw ModuleException("Regex engine not set or loaded!"); } return new RLine(set_time, duration, source, reason, xline_specific_mask, rxfactory); } }; /** Handle /RLINE * Syntax is same as other lines: RLINE regex_goes_here 1d :reason */ class CommandRLine : public Command { std::string rxengine; RLineFactory& factory; public: CommandRLine(Module* Creator, RLineFactory& rlf) : Command(Creator,"RLINE", 1, 3), factory(rlf) { flags_needed = 'o'; this->syntax = "<regex> [<duration> :<reason>]"; } CmdResult Handle(User* user, const Params& parameters) CXX11_OVERRIDE { if (parameters.size() >= 3) { // Adding - XXX todo make this respect <insane> tag perhaps.. unsigned long duration; if (!InspIRCd::Duration(parameters[1], duration)) { user->WriteNotice("*** Invalid duration for R-line."); return CMD_FAILURE; } XLine *r = NULL; try { r = factory.Generate(ServerInstance->Time(), duration, user->nick.c_str(), parameters[2].c_str(), parameters[0].c_str()); } catch (ModuleException &e) { ServerInstance->SNO->WriteToSnoMask('a', "Could not add R-line: " + e.GetReason()); } if (r) { if (ServerInstance->XLines->AddLine(r, user)) { if (!duration) { ServerInstance->SNO->WriteToSnoMask('x', "%s added permanent R-line for %s: %s", user->nick.c_str(), parameters[0].c_str(), parameters[2].c_str()); } else { ServerInstance->SNO->WriteToSnoMask('x', "%s added timed R-line for %s, expires in %s (on %s): %s", user->nick.c_str(), parameters[0].c_str(), InspIRCd::DurationString(duration).c_str(), InspIRCd::TimeString(ServerInstance->Time() + duration).c_str(), parameters[2].c_str()); } ServerInstance->XLines->ApplyLines(); } else { delete r; user->WriteNotice("*** R-line for " + parameters[0] + " already exists."); } } } else { std::string reason; if (ServerInstance->XLines->DelLine(parameters[0].c_str(), "R", reason, user)) { ServerInstance->SNO->WriteToSnoMask('x', "%s removed R-line on %s: %s", user->nick.c_str(), parameters[0].c_str(), reason.c_str()); } else { user->WriteNotice("*** R-line " + parameters[0] + " not found on the list."); } } return CMD_SUCCESS; } RouteDescriptor GetRouting(User* user, const Params& parameters) CXX11_OVERRIDE { if (IS_LOCAL(user)) return ROUTE_LOCALONLY; // spanningtree will send ADDLINE return ROUTE_BROADCAST; } }; class ModuleRLine : public Module, public Stats::EventListener { dynamic_reference<RegexFactory> rxfactory; RLineFactory f; CommandRLine r; bool MatchOnNickChange; bool initing; RegexFactory* factory; public: ModuleRLine() : Stats::EventListener(this) , rxfactory(this, "regex") , f(rxfactory) , r(this, f) , initing(true) { } void init() CXX11_OVERRIDE { ServerInstance->XLines->RegisterFactory(&f); } ~ModuleRLine() { ServerInstance->XLines->DelAll("R"); ServerInstance->XLines->UnregisterFactory(&f); } Version GetVersion() CXX11_OVERRIDE { return Version("Provides support for banning users through regular expression patterns", VF_COMMON | VF_VENDOR, rxfactory ? rxfactory->name : ""); } ModResult OnUserRegister(LocalUser* user) CXX11_OVERRIDE { // Apply lines on user connect XLine *rl = ServerInstance->XLines->MatchesLine("R", user); if (rl) { // Bang. :P rl->Apply(user); return MOD_RES_DENY; } return MOD_RES_PASSTHRU; } void ReadConfig(ConfigStatus& status) CXX11_OVERRIDE { ConfigTag* tag = ServerInstance->Config->ConfValue("rline"); MatchOnNickChange = tag->getBool("matchonnickchange"); ZlineOnMatch = tag->getBool("zlineonmatch"); std::string newrxengine = tag->getString("engine"); factory = rxfactory ? (rxfactory.operator->()) : NULL; if (newrxengine.empty()) rxfactory.SetProvider("regex"); else rxfactory.SetProvider("regex/" + newrxengine); if (!rxfactory) { if (newrxengine.empty()) ServerInstance->SNO->WriteToSnoMask('a', "WARNING: No regex engine loaded - R-line functionality disabled until this is corrected."); else ServerInstance->SNO->WriteToSnoMask('a', "WARNING: Regex engine '%s' is not loaded - R-line functionality disabled until this is corrected.", newrxengine.c_str()); ServerInstance->XLines->DelAll(f.GetType()); } else if ((!initing) && (rxfactory.operator->() != factory)) { ServerInstance->SNO->WriteToSnoMask('a', "Regex engine has changed, removing all R-lines."); ServerInstance->XLines->DelAll(f.GetType()); } initing = false; } ModResult OnStats(Stats::Context& stats) CXX11_OVERRIDE { if (stats.GetSymbol() != 'R') return MOD_RES_PASSTHRU; ServerInstance->XLines->InvokeStats("R", 223, stats); return MOD_RES_DENY; } void OnUserPostNick(User *user, const std::string &oldnick) CXX11_OVERRIDE { if (!IS_LOCAL(user)) return; if (!MatchOnNickChange) return; XLine *rl = ServerInstance->XLines->MatchesLine("R", user); if (rl) { // Bang! :D rl->Apply(user); } } void OnBackgroundTimer(time_t curtime) CXX11_OVERRIDE { if (added_zline) { added_zline = false; ServerInstance->XLines->ApplyLines(); } } void OnUnloadModule(Module* mod) CXX11_OVERRIDE { // If the regex engine became unavailable or has changed, remove all R-lines. if (!rxfactory) { ServerInstance->XLines->DelAll(f.GetType()); } else if (rxfactory.operator->() != factory) { factory = rxfactory.operator->(); ServerInstance->XLines->DelAll(f.GetType()); } } void Prioritize() CXX11_OVERRIDE { Module* mod = ServerInstance->Modules->Find("m_cgiirc.so"); ServerInstance->Modules->SetPriority(this, I_OnUserRegister, PRIORITY_AFTER, mod); } }; MODULE_INIT(ModuleRLine) �����������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/src/modules/m_rmode.cpp��������������������������������������������������������������0000664�0000000�0000000�00000006042�13554550454�0017732�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * InspIRCd -- Internet Relay Chat Daemon * * Copyright (C) 2013 Daniel Vassdal <shutter@canternet.org> * * This file is part of InspIRCd. InspIRCd is free software: you can * redistribute it and/or modify it under the terms of the GNU General Public * License as published by the Free Software Foundation, version 2. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include "inspircd.h" #include "listmode.h" /** Handle /RMODE */ class CommandRMode : public Command { public: CommandRMode(Module* Creator) : Command(Creator,"RMODE", 2, 3) { allow_empty_last_param = false; syntax = "<channel> <mode> [<pattern>]"; } CmdResult Handle(User* user, const Params& parameters) CXX11_OVERRIDE { ModeHandler* mh; Channel* chan = ServerInstance->FindChan(parameters[0]); char modeletter = parameters[1][0]; if (chan == NULL) { user->WriteNotice("The channel " + parameters[0] + " does not exist."); return CMD_FAILURE; } mh = ServerInstance->Modes->FindMode(modeletter, MODETYPE_CHANNEL); if (mh == NULL || parameters[1].size() > 1) { user->WriteNotice(parameters[1] + " is not a valid channel mode."); return CMD_FAILURE; } if (chan->GetPrefixValue(user) < mh->GetLevelRequired(false)) { user->WriteNotice("You do not have access to unset " + ConvToStr(modeletter) + " on " + chan->name + "."); return CMD_FAILURE; } std::string pattern = parameters.size() > 2 ? parameters[2] : "*"; PrefixMode* pm; ListModeBase* lm; ListModeBase::ModeList* ml; Modes::ChangeList changelist; if ((pm = mh->IsPrefixMode())) { // As user prefix modes don't have a GetList() method, let's iterate through the channel's users. const Channel::MemberMap& users = chan->GetUsers(); for (Channel::MemberMap::const_iterator it = users.begin(); it != users.end(); ++it) { if (!InspIRCd::Match(it->first->nick, pattern)) continue; if (it->second->HasMode(pm) && !((it->first == user) && (pm->GetPrefixRank() > VOICE_VALUE))) changelist.push_remove(mh, it->first->nick); } } else if ((lm = mh->IsListModeBase()) && ((ml = lm->GetList(chan)) != NULL)) { for (ListModeBase::ModeList::iterator it = ml->begin(); it != ml->end(); ++it) { if (!InspIRCd::Match(it->mask, pattern)) continue; changelist.push_remove(mh, it->mask); } } else { if (chan->IsModeSet(mh)) changelist.push_remove(mh); } ServerInstance->Modes->Process(user, chan, NULL, changelist); return CMD_SUCCESS; } }; class ModuleRMode : public Module { CommandRMode cmd; public: ModuleRMode() : cmd(this) { } Version GetVersion() CXX11_OVERRIDE { return Version("Allows glob-based removal of list modes", VF_VENDOR); } }; MODULE_INIT(ModuleRMode) ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/src/modules/m_sajoin.cpp�������������������������������������������������������������0000664�0000000�0000000�00000007234�13554550454�0020113�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * InspIRCd -- Internet Relay Chat Daemon * * Copyright (C) 2007 Dennis Friis <peavey@inspircd.org> * Copyright (C) 2007 Robin Burchell <robin+git@viroteck.net> * Copyright (C) 2004-2005, 2007 Craig Edwards <craigedwards@brainbox.cc> * * This file is part of InspIRCd. InspIRCd is free software: you can * redistribute it and/or modify it under the terms of the GNU General Public * License as published by the Free Software Foundation, version 2. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include "inspircd.h" /** Handle /SAJOIN */ class CommandSajoin : public Command { public: CommandSajoin(Module* Creator) : Command(Creator,"SAJOIN", 1) { allow_empty_last_param = false; flags_needed = 'o'; syntax = "[<nick>] <channel>[,<channel>]+"; TRANSLATE2(TR_NICK, TR_TEXT); } CmdResult Handle(User* user, const Params& parameters) CXX11_OVERRIDE { const unsigned int channelindex = (parameters.size() > 1) ? 1 : 0; if (CommandParser::LoopCall(user, this, parameters, channelindex)) return CMD_FAILURE; const std::string& channel = parameters[channelindex]; const std::string& nickname = parameters.size() > 1 ? parameters[0] : user->nick; User* dest = ServerInstance->FindNick(nickname); if ((dest) && (dest->registered == REG_ALL)) { if (user != dest && !user->HasPrivPermission("users/sajoin-others")) { user->WriteNotice("*** You are not allowed to /SAJOIN other users (the privilege users/sajoin-others is needed to /SAJOIN others)."); return CMD_FAILURE; } if (dest->server->IsULine()) { user->WriteNumeric(ERR_NOPRIVILEGES, "Cannot use an SA command on a U-lined client"); return CMD_FAILURE; } if (IS_LOCAL(user) && !ServerInstance->IsChannel(channel)) { /* we didn't need to check this for each character ;) */ user->WriteNotice("*** Invalid characters in channel name or name too long"); return CMD_FAILURE; } Channel* chan = ServerInstance->FindChan(channel); if ((chan) && (chan->HasUser(dest))) { user->WriteRemoteNotice("*** " + dest->nick + " is already on " + channel); return CMD_FAILURE; } /* For local users, we call Channel::JoinUser which may create a channel and set its TS. * For non-local users, we just return CMD_SUCCESS, knowing this will propagate it where it needs to be * and then that server will handle the command. */ LocalUser* localuser = IS_LOCAL(dest); if (localuser) { chan = Channel::JoinUser(localuser, channel, true); if (chan) { ServerInstance->SNO->WriteGlobalSno('a', user->nick+" used SAJOIN to make "+dest->nick+" join "+channel); return CMD_SUCCESS; } else { user->WriteNotice("*** Could not join "+dest->nick+" to "+channel); return CMD_FAILURE; } } else { return CMD_SUCCESS; } } else { user->WriteNotice("*** No such nickname: '" + nickname + "'"); return CMD_FAILURE; } } RouteDescriptor GetRouting(User* user, const Params& parameters) CXX11_OVERRIDE { return ROUTE_OPT_UCAST(parameters[0]); } }; class ModuleSajoin : public Module { CommandSajoin cmd; public: ModuleSajoin() : cmd(this) { } Version GetVersion() CXX11_OVERRIDE { return Version("Provides the SAJOIN command, allows opers to force-join users to channels", VF_OPTCOMMON | VF_VENDOR); } }; MODULE_INIT(ModuleSajoin) ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/src/modules/m_sakick.cpp�������������������������������������������������������������0000664�0000000�0000000�00000005227�13554550454�0020075�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * InspIRCd -- Internet Relay Chat Daemon * * Copyright (C) 2009 John Brooks <john.brooks@dereferenced.net> * Copyright (C) 2009 Daniel De Graaf <danieldg@inspircd.org> * * This file is part of InspIRCd. InspIRCd is free software: you can * redistribute it and/or modify it under the terms of the GNU General Public * License as published by the Free Software Foundation, version 2. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include "inspircd.h" /** Handle /SAKICK */ class CommandSakick : public Command { public: CommandSakick(Module* Creator) : Command(Creator,"SAKICK", 2, 3) { flags_needed = 'o'; syntax = "<channel> <nick> [:<reason>]"; TRANSLATE3(TR_TEXT, TR_NICK, TR_TEXT); } CmdResult Handle(User* user, const Params& parameters) CXX11_OVERRIDE { User* dest = ServerInstance->FindNick(parameters[1]); Channel* channel = ServerInstance->FindChan(parameters[0]); if ((dest) && (dest->registered == REG_ALL) && (channel)) { const std::string& reason = (parameters.size() > 2) ? parameters[2] : dest->nick; if (dest->server->IsULine()) { user->WriteNumeric(ERR_NOPRIVILEGES, "Cannot use an SA command on a U-lined client"); return CMD_FAILURE; } if (!channel->HasUser(dest)) { user->WriteNotice("*** " + dest->nick + " is not on " + channel->name); return CMD_FAILURE; } /* For local clients, directly kick them. For remote clients, * just return CMD_SUCCESS knowing the protocol module will route the SAKICK to the user's * local server and that will kick them instead. */ if (IS_LOCAL(dest)) { // Target is on this server, kick them and send the snotice channel->KickUser(ServerInstance->FakeClient, dest, reason); ServerInstance->SNO->WriteGlobalSno('a', user->nick + " SAKICKed " + dest->nick + " on " + channel->name); } return CMD_SUCCESS; } else { user->WriteNotice("*** Invalid nickname or channel"); } return CMD_FAILURE; } RouteDescriptor GetRouting(User* user, const Params& parameters) CXX11_OVERRIDE { return ROUTE_OPT_UCAST(parameters[1]); } }; class ModuleSakick : public Module { CommandSakick cmd; public: ModuleSakick() : cmd(this) { } Version GetVersion() CXX11_OVERRIDE { return Version("Provides the SAKICK command", VF_OPTCOMMON|VF_VENDOR); } }; MODULE_INIT(ModuleSakick) �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/src/modules/m_samode.cpp�������������������������������������������������������������0000664�0000000�0000000�00000010272�13554550454�0020074�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * InspIRCd -- Internet Relay Chat Daemon * * Copyright (C) 2009 Daniel De Graaf <danieldg@inspircd.org> * Copyright (C) 2007 Dennis Friis <peavey@inspircd.org> * Copyright (C) 2006-2007 Robin Burchell <robin+git@viroteck.net> * Copyright (C) 2004-2005 Craig Edwards <craigedwards@brainbox.cc> * * This file is part of InspIRCd. InspIRCd is free software: you can * redistribute it and/or modify it under the terms of the GNU General Public * License as published by the Free Software Foundation, version 2. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include "inspircd.h" /** Handle /SAMODE */ class CommandSamode : public Command { bool logged; public: bool active; CommandSamode(Module* Creator) : Command(Creator,"SAMODE", 2) { allow_empty_last_param = false; flags_needed = 'o'; syntax = "<target> (+|-)<modes> [<mode-parameters>]"; active = false; } CmdResult Handle(User* user, const Params& parameters) CXX11_OVERRIDE { if (parameters[0].c_str()[0] != '#') { User* target = ServerInstance->FindNickOnly(parameters[0]); if ((!target) || (target->registered != REG_ALL)) { user->WriteNumeric(Numerics::NoSuchNick(parameters[0])); return CMD_FAILURE; } // Changing the modes of another user requires a special permission if ((target != user) && (!user->HasPrivPermission("users/samode-usermodes"))) { user->WriteNotice("*** You are not allowed to /SAMODE other users (the privilege users/samode-usermodes is needed to /SAMODE others)."); return CMD_FAILURE; } } // XXX: Make ModeParser clear LastParse Modes::ChangeList emptychangelist; ServerInstance->Modes->ProcessSingle(ServerInstance->FakeClient, NULL, ServerInstance->FakeClient, emptychangelist); logged = false; this->active = true; ServerInstance->Parser.CallHandler("MODE", parameters, user); this->active = false; if (!logged) { // If we haven't logged anything yet then the client queried the list of a listmode // (e.g. /SAMODE #chan b), which was handled internally by the MODE command handler. // // Viewing the modes of a user or a channel could also result in this, but // that is not possible with /SAMODE because we require at least 2 parameters. LogUsage(user, stdalgo::string::join(parameters)); } return CMD_SUCCESS; } void LogUsage(const User* user, const std::string& text) { logged = true; ServerInstance->SNO->WriteGlobalSno('a', user->nick + " used SAMODE: " + text); } }; class ModuleSaMode : public Module { CommandSamode cmd; public: ModuleSaMode() : cmd(this) { } Version GetVersion() CXX11_OVERRIDE { return Version("Provides the SAMODE command, allows opers to change modes on channels and users", VF_VENDOR); } ModResult OnPreMode(User* source, User* dest, Channel* channel, Modes::ChangeList& modes) CXX11_OVERRIDE { if (cmd.active) return MOD_RES_ALLOW; return MOD_RES_PASSTHRU; } void OnMode(User* user, User* destuser, Channel* destchan, const Modes::ChangeList& modes, ModeParser::ModeProcessFlag processflags) CXX11_OVERRIDE { if (!cmd.active) return; std::string logtext = (destuser ? destuser->nick : destchan->name); logtext.push_back(' '); logtext += ClientProtocol::Messages::Mode::ToModeLetters(modes); for (Modes::ChangeList::List::const_iterator i = modes.getlist().begin(); i != modes.getlist().end(); ++i) { const Modes::Change& item = *i; if (!item.param.empty()) logtext.append(1, ' ').append(item.param); } cmd.LogUsage(user, logtext); } void Prioritize() CXX11_OVERRIDE { Module* disable = ServerInstance->Modules->Find("m_disable.so"); ServerInstance->Modules->SetPriority(this, I_OnRawMode, PRIORITY_BEFORE, disable); Module *override = ServerInstance->Modules->Find("m_override.so"); ServerInstance->Modules->SetPriority(this, I_OnPreMode, PRIORITY_BEFORE, override); } }; MODULE_INIT(ModuleSaMode) ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/src/modules/m_sanick.cpp�������������������������������������������������������������0000664�0000000�0000000�00000005267�13554550454�0020104�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * InspIRCd -- Internet Relay Chat Daemon * * Copyright (C) 2007, 2009 Dennis Friis <peavey@inspircd.org> * Copyright (C) 2007 Robin Burchell <robin+git@viroteck.net> * Copyright (C) 2004-2005 Craig Edwards <craigedwards@brainbox.cc> * * This file is part of InspIRCd. InspIRCd is free software: you can * redistribute it and/or modify it under the terms of the GNU General Public * License as published by the Free Software Foundation, version 2. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include "inspircd.h" /** Handle /SANICK */ class CommandSanick : public Command { public: CommandSanick(Module* Creator) : Command(Creator,"SANICK", 2) { allow_empty_last_param = false; flags_needed = 'o'; syntax = "<nick> <newnick>"; TRANSLATE2(TR_NICK, TR_TEXT); } CmdResult Handle(User* user, const Params& parameters) CXX11_OVERRIDE { User* target = ServerInstance->FindNick(parameters[0]); /* Do local sanity checks and bails */ if (IS_LOCAL(user)) { if (target && target->server->IsULine()) { user->WriteNumeric(ERR_NOPRIVILEGES, "Cannot use an SA command on a U-lined client"); return CMD_FAILURE; } if ((!target) || (target->registered != REG_ALL)) { user->WriteNotice("*** No such nickname: '" + parameters[0] + "'"); return CMD_FAILURE; } if (!ServerInstance->IsNick(parameters[1])) { user->WriteNotice("*** Invalid nickname: '" + parameters[1] + "'"); return CMD_FAILURE; } } /* Have we hit target's server yet? */ if (target && IS_LOCAL(target)) { std::string oldnick = user->nick; std::string newnick = target->nick; if (target->ChangeNick(parameters[1])) { ServerInstance->SNO->WriteGlobalSno('a', oldnick+" used SANICK to change "+newnick+" to "+parameters[1]); } else { ServerInstance->SNO->WriteGlobalSno('a', oldnick+" failed SANICK (from "+newnick+" to "+parameters[1]+")"); } } return CMD_SUCCESS; } RouteDescriptor GetRouting(User* user, const Params& parameters) CXX11_OVERRIDE { return ROUTE_OPT_UCAST(parameters[0]); } }; class ModuleSanick : public Module { CommandSanick cmd; public: ModuleSanick() : cmd(this) { } Version GetVersion() CXX11_OVERRIDE { return Version("Provides the SANICK command, allows opers to change the nicknames of users", VF_OPTCOMMON | VF_VENDOR); } }; MODULE_INIT(ModuleSanick) �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/src/modules/m_sapart.cpp�������������������������������������������������������������0000664�0000000�0000000�00000005453�13554550454�0020123�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * InspIRCd -- Internet Relay Chat Daemon * * Copyright (C) 2007 Dennis Friis <peavey@inspircd.org> * Copyright (C) 2007 Robin Burchell <robin+git@viroteck.net> * Copyright (C) 2004-2007 Craig Edwards <craigedwards@brainbox.cc> * * This file is part of InspIRCd. InspIRCd is free software: you can * redistribute it and/or modify it under the terms of the GNU General Public * License as published by the Free Software Foundation, version 2. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include "inspircd.h" /** Handle /SAPART */ class CommandSapart : public Command { public: CommandSapart(Module* Creator) : Command(Creator,"SAPART", 2, 3) { flags_needed = 'o'; syntax = "<nick> <channel>[,<channel>]+ [:<reason>]"; TRANSLATE3(TR_NICK, TR_TEXT, TR_TEXT); } CmdResult Handle(User* user, const Params& parameters) CXX11_OVERRIDE { if (CommandParser::LoopCall(user, this, parameters, 1)) return CMD_FAILURE; User* dest = ServerInstance->FindNick(parameters[0]); Channel* channel = ServerInstance->FindChan(parameters[1]); std::string reason; if ((dest) && (dest->registered == REG_ALL) && (channel)) { if (parameters.size() > 2) reason = parameters[2]; if (dest->server->IsULine()) { user->WriteNumeric(ERR_NOPRIVILEGES, "Cannot use an SA command on a U-lined client"); return CMD_FAILURE; } if (!channel->HasUser(dest)) { user->WriteNotice("*** " + dest->nick + " is not on " + channel->name); return CMD_FAILURE; } /* For local clients, directly part them generating a PART message. For remote clients, * just return CMD_SUCCESS knowing the protocol module will route the SAPART to the users * local server and that will generate the PART instead */ if (IS_LOCAL(dest)) { channel->PartUser(dest, reason); ServerInstance->SNO->WriteGlobalSno('a', user->nick+" used SAPART to make "+dest->nick+" part "+channel->name); } return CMD_SUCCESS; } else { user->WriteNotice("*** Invalid nickname or channel"); } return CMD_FAILURE; } RouteDescriptor GetRouting(User* user, const Params& parameters) CXX11_OVERRIDE { return ROUTE_OPT_UCAST(parameters[0]); } }; class ModuleSapart : public Module { CommandSapart cmd; public: ModuleSapart() : cmd(this) { } Version GetVersion() CXX11_OVERRIDE { return Version("Provides the SAPART command, allows opers to force-part users from channels", VF_OPTCOMMON | VF_VENDOR); } }; MODULE_INIT(ModuleSapart) ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/src/modules/m_saquit.cpp�������������������������������������������������������������0000664�0000000�0000000�00000004422�13554550454�0020132�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * InspIRCd -- Internet Relay Chat Daemon * * Copyright (C) 2007 Dennis Friis <peavey@inspircd.org> * Copyright (C) 2006-2007 Robin Burchell <robin+git@viroteck.net> * Copyright (C) 2004-2005 Craig Edwards <craigedwards@brainbox.cc> * * This file is part of InspIRCd. InspIRCd is free software: you can * redistribute it and/or modify it under the terms of the GNU General Public * License as published by the Free Software Foundation, version 2. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include "inspircd.h" /** Handle /SAQUIT */ class CommandSaquit : public Command { public: CommandSaquit(Module* Creator) : Command(Creator, "SAQUIT", 2, 2) { flags_needed = 'o'; syntax = "<nick> :<reason>"; TRANSLATE2(TR_NICK, TR_TEXT); } CmdResult Handle(User* user, const Params& parameters) CXX11_OVERRIDE { User* dest = ServerInstance->FindNick(parameters[0]); if ((dest) && (dest->registered == REG_ALL)) { if (dest->server->IsULine()) { user->WriteNumeric(ERR_NOPRIVILEGES, "Cannot use an SA command on a U-lined client"); return CMD_FAILURE; } // Pass the command on, so the client's server can quit it properly. if (!IS_LOCAL(dest)) return CMD_SUCCESS; ServerInstance->SNO->WriteGlobalSno('a', user->nick+" used SAQUIT to make "+dest->nick+" quit with a reason of "+parameters[1]); ServerInstance->Users->QuitUser(dest, parameters[1]); return CMD_SUCCESS; } else { user->WriteNotice("*** Invalid nickname: '" + parameters[0] + "'"); return CMD_FAILURE; } } RouteDescriptor GetRouting(User* user, const Params& parameters) CXX11_OVERRIDE { return ROUTE_OPT_UCAST(parameters[0]); } }; class ModuleSaquit : public Module { CommandSaquit cmd; public: ModuleSaquit() : cmd(this) { } Version GetVersion() CXX11_OVERRIDE { return Version("Provides the SAQUIT command, allows opers to force-quit users", VF_OPTCOMMON | VF_VENDOR); } }; MODULE_INIT(ModuleSaquit) ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/src/modules/m_sasl.cpp���������������������������������������������������������������0000664�0000000�0000000�00000025150�13554550454�0017567�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * InspIRCd -- Internet Relay Chat Daemon * * Copyright (C) 2009-2010 Daniel De Graaf <danieldg@inspircd.org> * Copyright (C) 2008 Craig Edwards <craigedwards@brainbox.cc> * * This file is part of InspIRCd. InspIRCd is free software: you can * redistribute it and/or modify it under the terms of the GNU General Public * License as published by the Free Software Foundation, version 2. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include "inspircd.h" #include "modules/cap.h" #include "modules/account.h" #include "modules/sasl.h" #include "modules/ssl.h" #include "modules/server.h" enum { // From IRCv3 sasl-3.1 RPL_SASLSUCCESS = 903, ERR_SASLFAIL = 904, ERR_SASLTOOLONG = 905, ERR_SASLABORTED = 906, RPL_SASLMECHS = 908 }; static std::string sasl_target; class ServerTracker : public ServerProtocol::LinkEventListener { // Stop GCC warnings about the deprecated OnServerSplit event. using ServerProtocol::LinkEventListener::OnServerSplit; bool online; void Update(const Server* server, bool linked) { if (sasl_target == "*") return; if (InspIRCd::Match(server->GetName(), sasl_target)) { ServerInstance->Logs->Log(MODNAME, LOG_VERBOSE, "SASL target server \"%s\" %s", sasl_target.c_str(), (linked ? "came online" : "went offline")); online = linked; } } void OnServerLink(const Server* server) CXX11_OVERRIDE { Update(server, true); } void OnServerSplit(const Server* server, bool error) CXX11_OVERRIDE { Update(server, false); } public: ServerTracker(Module* mod) : ServerProtocol::LinkEventListener(mod) { Reset(); } void Reset() { if (sasl_target == "*") { online = true; return; } online = false; ProtocolInterface::ServerList servers; ServerInstance->PI->GetServerList(servers); for (ProtocolInterface::ServerList::const_iterator i = servers.begin(); i != servers.end(); ++i) { const ProtocolInterface::ServerInfo& server = *i; if (InspIRCd::Match(server.servername, sasl_target)) { online = true; break; } } } bool IsOnline() const { return online; } }; class SASLCap : public Cap::Capability { std::string mechlist; const ServerTracker& servertracker; bool OnRequest(LocalUser* user, bool adding) CXX11_OVERRIDE { // Servers MUST NAK any sasl capability request if the authentication layer // is unavailable. return servertracker.IsOnline(); } bool OnList(LocalUser* user) CXX11_OVERRIDE { // Servers MUST NOT advertise the sasl capability if the authentication layer // is unavailable. return servertracker.IsOnline(); } const std::string* GetValue(LocalUser* user) const CXX11_OVERRIDE { return &mechlist; } public: SASLCap(Module* mod, const ServerTracker& tracker) : Cap::Capability(mod, "sasl") , servertracker(tracker) { } void SetMechlist(const std::string& newmechlist) { if (mechlist == newmechlist) return; mechlist = newmechlist; NotifyValueChange(); } }; enum SaslState { SASL_INIT, SASL_COMM, SASL_DONE }; enum SaslResult { SASL_OK, SASL_FAIL, SASL_ABORT }; static Events::ModuleEventProvider* saslevprov; static void SendSASL(LocalUser* user, const std::string& agent, char mode, const std::vector<std::string>& parameters) { CommandBase::Params params; params.push_back(user->uuid); params.push_back(agent); params.push_back(ConvToStr(mode)); params.insert(params.end(), parameters.begin(), parameters.end()); if (!ServerInstance->PI->SendEncapsulatedData(sasl_target, "SASL", params)) { FOREACH_MOD_CUSTOM(*saslevprov, SASLEventListener, OnSASLAuth, (params)); } } static ClientProtocol::EventProvider* g_protoev; /** * Tracks SASL authentication state like charybdis does. --nenolod */ class SaslAuthenticator { private: std::string agent; LocalUser* user; SaslState state; SaslResult result; bool state_announced; void SendHostIP(UserCertificateAPI& sslapi) { std::vector<std::string> params; params.push_back(user->GetRealHost()); params.push_back(user->GetIPString()); params.push_back(sslapi && sslapi->GetCertificate(user) ? "S" : "P"); SendSASL(user, "*", 'H', params); } public: SaslAuthenticator(LocalUser* user_, const std::string& method, UserCertificateAPI& sslapi) : user(user_) , state(SASL_INIT) , state_announced(false) { SendHostIP(sslapi); std::vector<std::string> params; params.push_back(method); const std::string fp = sslapi ? sslapi->GetFingerprint(user) : ""; if (fp.size()) params.push_back(fp); SendSASL(user, "*", 'S', params); } SaslResult GetSaslResult(const std::string &result_) { if (result_ == "F") return SASL_FAIL; if (result_ == "A") return SASL_ABORT; return SASL_OK; } /* checks for and deals with a state change. */ SaslState ProcessInboundMessage(const CommandBase::Params& msg) { switch (this->state) { case SASL_INIT: this->agent = msg[0]; this->state = SASL_COMM; /* fall through */ case SASL_COMM: if (msg[0] != this->agent) return this->state; if (msg.size() < 4) return this->state; if (msg[2] == "C") { ClientProtocol::Message authmsg("AUTHENTICATE"); authmsg.PushParamRef(msg[3]); ClientProtocol::Event authevent(*g_protoev, authmsg); LocalUser* const localuser = IS_LOCAL(user); if (localuser) localuser->Send(authevent); } else if (msg[2] == "D") { this->state = SASL_DONE; this->result = this->GetSaslResult(msg[3]); } else if (msg[2] == "M") this->user->WriteNumeric(RPL_SASLMECHS, msg[3], "are available SASL mechanisms"); else ServerInstance->Logs->Log(MODNAME, LOG_DEFAULT, "Services sent an unknown SASL message \"%s\" \"%s\"", msg[2].c_str(), msg[3].c_str()); break; case SASL_DONE: break; default: ServerInstance->Logs->Log(MODNAME, LOG_DEFAULT, "WTF: SaslState is not a known state (%d)", this->state); break; } return this->state; } bool SendClientMessage(const std::vector<std::string>& parameters) { if (this->state != SASL_COMM) return true; SendSASL(this->user, this->agent, 'C', parameters); if (parameters[0].c_str()[0] == '*') { this->state = SASL_DONE; this->result = SASL_ABORT; return false; } return true; } void AnnounceState(void) { if (this->state_announced) return; switch (this->result) { case SASL_OK: this->user->WriteNumeric(RPL_SASLSUCCESS, "SASL authentication successful"); break; case SASL_ABORT: this->user->WriteNumeric(ERR_SASLABORTED, "SASL authentication aborted"); break; case SASL_FAIL: this->user->WriteNumeric(ERR_SASLFAIL, "SASL authentication failed"); break; default: break; } this->state_announced = true; } }; class CommandAuthenticate : public SplitCommand { private: // The maximum length of an AUTHENTICATE request. static const size_t MAX_AUTHENTICATE_SIZE = 400; public: SimpleExtItem<SaslAuthenticator>& authExt; Cap::Capability& cap; UserCertificateAPI sslapi; CommandAuthenticate(Module* Creator, SimpleExtItem<SaslAuthenticator>& ext, Cap::Capability& Cap) : SplitCommand(Creator, "AUTHENTICATE", 1) , authExt(ext) , cap(Cap) , sslapi(Creator) { works_before_reg = true; allow_empty_last_param = false; } CmdResult HandleLocal(LocalUser* user, const Params& parameters) CXX11_OVERRIDE { { if (!cap.get(user)) return CMD_FAILURE; if (parameters[0].find(' ') != std::string::npos || parameters[0][0] == ':') return CMD_FAILURE; if (parameters[0].length() > MAX_AUTHENTICATE_SIZE) { user->WriteNumeric(ERR_SASLTOOLONG, "SASL message too long"); return CMD_FAILURE; } SaslAuthenticator *sasl = authExt.get(user); if (!sasl) authExt.set(user, new SaslAuthenticator(user, parameters[0], sslapi)); else if (sasl->SendClientMessage(parameters) == false) // IAL abort extension --nenolod { sasl->AnnounceState(); authExt.unset(user); } } return CMD_FAILURE; } }; class CommandSASL : public Command { public: SimpleExtItem<SaslAuthenticator>& authExt; CommandSASL(Module* Creator, SimpleExtItem<SaslAuthenticator>& ext) : Command(Creator, "SASL", 2), authExt(ext) { this->flags_needed = FLAG_SERVERONLY; // should not be called by users } CmdResult Handle(User* user, const Params& parameters) CXX11_OVERRIDE { User* target = ServerInstance->FindUUID(parameters[1]); if (!target) { ServerInstance->Logs->Log(MODNAME, LOG_DEBUG, "User not found in sasl ENCAP event: %s", parameters[1].c_str()); return CMD_FAILURE; } SaslAuthenticator *sasl = authExt.get(target); if (!sasl) return CMD_FAILURE; SaslState state = sasl->ProcessInboundMessage(parameters); if (state == SASL_DONE) { sasl->AnnounceState(); authExt.unset(target); } return CMD_SUCCESS; } RouteDescriptor GetRouting(User* user, const Params& parameters) CXX11_OVERRIDE { return ROUTE_BROADCAST; } }; class ModuleSASL : public Module { SimpleExtItem<SaslAuthenticator> authExt; ServerTracker servertracker; SASLCap cap; CommandAuthenticate auth; CommandSASL sasl; Events::ModuleEventProvider sasleventprov; ClientProtocol::EventProvider protoev; public: ModuleSASL() : authExt("sasl_auth", ExtensionItem::EXT_USER, this) , servertracker(this) , cap(this, servertracker) , auth(this, authExt, cap) , sasl(this, authExt) , sasleventprov(this, "event/sasl") , protoev(this, auth.name) { saslevprov = &sasleventprov; g_protoev = &protoev; } void init() CXX11_OVERRIDE { if (!ServerInstance->Modules->Find("m_services_account.so") || !ServerInstance->Modules->Find("m_cap.so")) ServerInstance->Logs->Log(MODNAME, LOG_DEFAULT, "WARNING: m_services_account and m_cap are not loaded! m_sasl will NOT function correctly until these two modules are loaded!"); } void ReadConfig(ConfigStatus& status) CXX11_OVERRIDE { std::string target = ServerInstance->Config->ConfValue("sasl")->getString("target"); if (target.empty()) throw ModuleException("<sasl:target> must be set to the name of your services server!"); sasl_target = target; servertracker.Reset(); } void OnDecodeMetaData(Extensible* target, const std::string& extname, const std::string& extdata) CXX11_OVERRIDE { if ((target == NULL) && (extname == "saslmechlist")) cap.SetMechlist(extdata); } Version GetVersion() CXX11_OVERRIDE { return Version("Provides support for IRC Authentication Layer (aka: SASL) via AUTHENTICATE", VF_VENDOR); } }; MODULE_INIT(ModuleSASL) ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/src/modules/m_satopic.cpp������������������������������������������������������������0000664�0000000�0000000�00000003754�13554550454�0020275�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * InspIRCd -- Internet Relay Chat Daemon * * Copyright (C) 2008 Oliver Lupton <oliverlupton@gmail.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 "inspircd.h" /** Handle /SATOPIC */ class CommandSATopic : public Command { public: CommandSATopic(Module* Creator) : Command(Creator,"SATOPIC", 2, 2) { flags_needed = 'o'; syntax = "<channel> :<topic>"; } CmdResult Handle(User* user, const Params& parameters) CXX11_OVERRIDE { /* * Handles a SATOPIC request. Notifies all +s users. */ Channel* target = ServerInstance->FindChan(parameters[0]); if(target) { const std::string newTopic(parameters[1], 0, ServerInstance->Config->Limits.MaxTopic); if (target->topic == newTopic) { user->WriteNotice(InspIRCd::Format("The topic on %s is already what you are trying to change it to.", target->name.c_str())); return CMD_SUCCESS; } target->SetTopic(user, newTopic, ServerInstance->Time(), NULL); ServerInstance->SNO->WriteGlobalSno('a', user->nick + " used SATOPIC on " + target->name + ", new topic: " + newTopic); return CMD_SUCCESS; } else { user->WriteNumeric(Numerics::NoSuchChannel(parameters[0])); return CMD_FAILURE; } } }; class ModuleSATopic : public Module { CommandSATopic cmd; public: ModuleSATopic() : cmd(this) { } Version GetVersion() CXX11_OVERRIDE { return Version("Provides the SATOPIC command", VF_VENDOR); } }; MODULE_INIT(ModuleSATopic) ��������������������inspircd-3.4.0/src/modules/m_securelist.cpp���������������������������������������������������������0000664�0000000�0000000�00000006450�13554550454�0021011�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * InspIRCd -- Internet Relay Chat Daemon * * Copyright (C) 2007 Dennis Friis <peavey@inspircd.org> * Copyright (C) 2007 Robin Burchell <robin+git@viroteck.net> * Copyright (C) 2006-2007 Craig Edwards <craigedwards@brainbox.cc> * * This file is part of InspIRCd. InspIRCd is free software: you can * redistribute it and/or modify it under the terms of the GNU General Public * License as published by the Free Software Foundation, version 2. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include "inspircd.h" #include "modules/account.h" typedef std::vector<std::string> AllowList; class ModuleSecureList : public Module { AllowList allowlist; bool exemptregistered; unsigned int WaitTime; public: Version GetVersion() CXX11_OVERRIDE { return Version("Disallows the LIST command for recently connected clients to hinder spam bots", VF_VENDOR); } void ReadConfig(ConfigStatus& status) CXX11_OVERRIDE { AllowList newallows; ConfigTagList tags = ServerInstance->Config->ConfTags("securehost"); for (ConfigIter i = tags.first; i != tags.second; ++i) { std::string host = i->second->getString("exception"); if (host.empty()) throw ModuleException("<securehost:exception> is a required field at " + i->second->getTagLocation()); newallows.push_back(host); } ConfigTag* tag = ServerInstance->Config->ConfValue("securelist"); exemptregistered = tag->getBool("exemptregistered"); WaitTime = tag->getDuration("waittime", 60, 1); allowlist.swap(newallows); } /* * OnPreCommand() * Intercept the LIST command. */ ModResult OnPreCommand(std::string& command, CommandBase::Params& parameters, LocalUser* user, bool validated) CXX11_OVERRIDE { /* If the command doesnt appear to be valid, we dont want to mess with it. */ if (!validated) return MOD_RES_PASSTHRU; if ((command == "LIST") && (ServerInstance->Time() < (user->signon+WaitTime)) && (!user->IsOper())) { /* Normally wouldnt be allowed here, are they exempt? */ for (std::vector<std::string>::iterator x = allowlist.begin(); x != allowlist.end(); x++) if (InspIRCd::Match(user->MakeHost(), *x, ascii_case_insensitive_map)) return MOD_RES_PASSTHRU; const AccountExtItem* ext = GetAccountExtItem(); if (exemptregistered && ext && ext->get(user)) return MOD_RES_PASSTHRU; /* Not exempt, BOOK EM DANNO! */ user->WriteNotice("*** You cannot list within the first " + ConvToStr(WaitTime) + " seconds of connecting. Please try again later."); /* 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(RPL_LISTSTART, "Channel", "Users Name"); user->WriteNumeric(RPL_LISTEND, "End of channel list."); return MOD_RES_DENY; } return MOD_RES_PASSTHRU; } void On005Numeric(std::map<std::string, std::string>& tokens) CXX11_OVERRIDE { tokens["SECURELIST"]; } }; MODULE_INIT(ModuleSecureList) ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/src/modules/m_seenicks.cpp�����������������������������������������������������������0000664�0000000�0000000�00000002602�13554550454�0020426�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * InspIRCd -- Internet Relay Chat Daemon * * Copyright (C) 2007 Dennis Friis <peavey@inspircd.org> * Copyright (C) 2007 Robin Burchell <robin+git@viroteck.net> * Copyright (C) 2007 Craig Edwards <craigedwards@brainbox.cc> * * This file is part of InspIRCd. InspIRCd is free software: you can * redistribute it and/or modify it under the terms of the GNU General Public * License as published by the Free Software Foundation, version 2. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include "inspircd.h" class ModuleSeeNicks : public Module { public: void init() CXX11_OVERRIDE { ServerInstance->SNO->EnableSnomask('n',"NICK"); } Version GetVersion() CXX11_OVERRIDE { return Version("Provides snomasks 'n' and 'N' to see local and remote nickchanges", VF_VENDOR); } void OnUserPostNick(User* user, const std::string &oldnick) CXX11_OVERRIDE { ServerInstance->SNO->WriteToSnoMask(IS_LOCAL(user) ? 'n' : 'N',"User %s changed their nickname to %s", oldnick.c_str(), user->nick.c_str()); } }; MODULE_INIT(ModuleSeeNicks) ������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/src/modules/m_serverban.cpp����������������������������������������������������������0000664�0000000�0000000�00000002562�13554550454�0020616�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * InspIRCd -- Internet Relay Chat Daemon * * Copyright (C) 2008 Robin Burchell <robin+git@viroteck.net> * * 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 "inspircd.h" class ModuleServerBan : public Module { public: Version GetVersion() CXX11_OVERRIDE { return Version("Provides extban 's' to ban users connected to a specified server", VF_OPTCOMMON|VF_VENDOR); } ModResult OnCheckBan(User *user, Channel *c, const std::string& mask) CXX11_OVERRIDE { if ((mask.length() > 2) && (mask[0] == 's') && (mask[1] == ':')) { if (InspIRCd::Match(user->server->GetName(), mask.substr(2))) return MOD_RES_DENY; } return MOD_RES_PASSTHRU; } void On005Numeric(std::map<std::string, std::string>& tokens) CXX11_OVERRIDE { tokens["EXTBAN"].push_back('s'); } }; MODULE_INIT(ModuleServerBan) ����������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/src/modules/m_services_account.cpp���������������������������������������������������0000664�0000000�0000000�00000021350�13554550454�0022162�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * InspIRCd -- Internet Relay Chat Daemon * * Copyright (C) 2012 Shawn Smith <shawn@inspircd.org> * Copyright (C) 2009 Daniel De Graaf <danieldg@inspircd.org> * Copyright (C) 2006-2008 Robin Burchell <robin+git@viroteck.net> * Copyright (C) 2008 Pippijn van Steenhoven <pip88nl@gmail.com> * Copyright (C) 2006, 2008 Craig Edwards <craigedwards@brainbox.cc> * Copyright (C) 2007 Dennis Friis <peavey@inspircd.org> * * This file is part of InspIRCd. InspIRCd is free software: you can * redistribute it and/or modify it under the terms of the GNU General Public * License as published by the Free Software Foundation, version 2. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include "inspircd.h" #include "modules/account.h" #include "modules/callerid.h" #include "modules/ctctags.h" #include "modules/exemption.h" #include "modules/whois.h" enum { // From UnrealIRCd. RPL_WHOISREGNICK = 307, // From ircu. RPL_WHOISACCOUNT = 330, // From ircd-hybrid? ERR_NEEDREGGEDNICK = 477, // From IRCv3 sasl-3.1. RPL_LOGGEDIN = 900, RPL_LOGGEDOUT = 901 }; /** Channel mode +r - mark a channel as identified */ class Channel_r : public ModeHandler { public: Channel_r(Module* Creator) : ModeHandler(Creator, "c_registered", 'r', PARAM_NONE, MODETYPE_CHANNEL) { } ModeAction OnModeChange(User* source, User* dest, Channel* channel, std::string& parameter, bool adding) CXX11_OVERRIDE { // Only a U-lined server may add or remove the +r mode. if (!IS_LOCAL(source)) { // Only change the mode if it's not redundant if ((adding != channel->IsModeSet(this))) { channel->SetMode(this, adding); return MODEACTION_ALLOW; } } else { source->WriteNumeric(ERR_NOPRIVILEGES, "Only a server may modify the +r channel mode"); } return MODEACTION_DENY; } }; /** User mode +r - mark a user as identified */ class User_r : public ModeHandler { public: User_r(Module* Creator) : ModeHandler(Creator, "u_registered", 'r', PARAM_NONE, MODETYPE_USER) { } ModeAction OnModeChange(User* source, User* dest, Channel* channel, std::string& parameter, bool adding) CXX11_OVERRIDE { if (!IS_LOCAL(source)) { if ((adding != dest->IsModeSet(this))) { dest->SetMode(this, adding); return MODEACTION_ALLOW; } } else { source->WriteNumeric(ERR_NOPRIVILEGES, "Only a server may modify the +r user mode"); } return MODEACTION_DENY; } }; class AccountExtItemImpl : public AccountExtItem { Events::ModuleEventProvider eventprov; public: AccountExtItemImpl(Module* mod) : AccountExtItem("accountname", ExtensionItem::EXT_USER, mod) , eventprov(mod, "event/account") { } void FromInternal(Extensible* container, const std::string& value) CXX11_OVERRIDE { StringExtItem::FromInternal(container, value); } void FromNetwork(Extensible* container, const std::string& value) CXX11_OVERRIDE { StringExtItem::FromNetwork(container, value); User* user = static_cast<User*>(container); if (IS_LOCAL(user)) { if (value.empty()) { // Logged out. user->WriteNumeric(RPL_LOGGEDOUT, user->GetFullHost(), "You are now logged out"); } else { // Logged in. user->WriteNumeric(RPL_LOGGEDIN, user->GetFullHost(), value, InspIRCd::Format("You are now logged in as %s", value.c_str())); } } FOREACH_MOD_CUSTOM(eventprov, AccountEventListener, OnAccountChange, (user, value)); } }; class ModuleServicesAccount : public Module , public Whois::EventListener , public CTCTags::EventListener { private: CallerID::API calleridapi; CheckExemption::EventProvider exemptionprov; SimpleChannelModeHandler m1; SimpleChannelModeHandler m2; SimpleUserModeHandler m3; Channel_r m4; User_r m5; AccountExtItemImpl accountname; bool checking_ban; public: ModuleServicesAccount() : Whois::EventListener(this) , CTCTags::EventListener(this) , calleridapi(this) , exemptionprov(this) , m1(this, "reginvite", 'R') , m2(this, "regmoderated", 'M') , m3(this, "regdeaf", 'R') , m4(this) , m5(this) , accountname(this) , checking_ban(false) { } void On005Numeric(std::map<std::string, std::string>& tokens) CXX11_OVERRIDE { tokens["EXTBAN"].push_back('R'); tokens["EXTBAN"].push_back('U'); } /* <- :twisted.oscnet.org 330 w00t2 w00t2 w00t :is logged in as */ void OnWhois(Whois::Context& whois) CXX11_OVERRIDE { std::string* account = accountname.get(whois.GetTarget()); if (account) { whois.SendLine(RPL_WHOISACCOUNT, *account, "is logged in as"); } if (whois.GetTarget()->IsModeSet(m5)) { /* user is registered */ whois.SendLine(RPL_WHOISREGNICK, "is a registered nick"); } } void OnUserPostNick(User* user, const std::string &oldnick) CXX11_OVERRIDE { /* On nickchange, if they have +r, remove it */ if ((user->IsModeSet(m5)) && (ServerInstance->FindNickOnly(oldnick) != user)) m5.RemoveMode(user); } ModResult HandleMessage(User* user, const MessageTarget& target) { if (!IS_LOCAL(user)) return MOD_RES_PASSTHRU; std::string *account = accountname.get(user); bool is_registered = account && !account->empty(); switch (target.type) { case MessageTarget::TYPE_CHANNEL: { Channel* targchan = target.Get<Channel>(); if (!targchan->IsModeSet(m2) || is_registered) return MOD_RES_PASSTHRU; if (CheckExemption::Call(exemptionprov, user, targchan, "regmoderated") == MOD_RES_ALLOW) return MOD_RES_PASSTHRU; // User is messaging a +M channel and is not registered or exempt. user->WriteNumeric(ERR_NEEDREGGEDNICK, targchan->name, "You need to be identified to a registered account to message this channel"); return MOD_RES_DENY; break; } case MessageTarget::TYPE_USER: { User* targuser = target.Get<User>(); if (!targuser->IsModeSet(m3) || is_registered) return MOD_RES_PASSTHRU; if (calleridapi && calleridapi->IsOnAcceptList(user, targuser)) return MOD_RES_PASSTHRU; // User is messaging a +R user and is not registered or on an accept list. user->WriteNumeric(ERR_NEEDREGGEDNICK, targuser->nick, "You need to be identified to a registered account to message this user"); return MOD_RES_DENY; break; } case MessageTarget::TYPE_SERVER: break; } return MOD_RES_PASSTHRU; } ModResult OnUserPreMessage(User* user, const MessageTarget& target, MessageDetails& details) CXX11_OVERRIDE { return HandleMessage(user, target); } ModResult OnUserPreTagMessage(User* user, const MessageTarget& target, CTCTags::TagMessageDetails& details) CXX11_OVERRIDE { return HandleMessage(user, target); } ModResult OnCheckBan(User* user, Channel* chan, const std::string& mask) CXX11_OVERRIDE { if (checking_ban) return MOD_RES_PASSTHRU; if ((mask.length() > 2) && (mask[1] == ':')) { if (mask[0] == 'R') { std::string *account = accountname.get(user); if (account && InspIRCd::Match(*account, mask.substr(2))) return MOD_RES_DENY; } else if (mask[0] == 'U') { std::string *account = accountname.get(user); /* If the user is registered we don't care. */ if (account) return MOD_RES_PASSTHRU; /* If we made it this far we know the user isn't registered so just deny if it matches */ checking_ban = true; bool result = chan->CheckBan(user, mask.substr(2)); checking_ban = false; if (result) return MOD_RES_DENY; } } /* If we made it this far then the ban wasn't an ExtBan or the user we were checking for didn't match either ExtBan */ return MOD_RES_PASSTHRU; } ModResult OnUserPreJoin(LocalUser* user, Channel* chan, const std::string& cname, std::string& privs, const std::string& keygiven) CXX11_OVERRIDE { std::string *account = accountname.get(user); bool is_registered = account && !account->empty(); if (chan) { if (chan->IsModeSet(m1)) { if (!is_registered) { // joining a +R channel and not identified user->WriteNumeric(ERR_NEEDREGGEDNICK, chan->name, "You need to be identified to a registered account to join this channel"); return MOD_RES_DENY; } } } return MOD_RES_PASSTHRU; } ModResult OnSetConnectClass(LocalUser* user, ConnectClass* myclass) CXX11_OVERRIDE { if (myclass->config->getBool("requireaccount") && !accountname.get(user)) return MOD_RES_DENY; return MOD_RES_PASSTHRU; } Version GetVersion() CXX11_OVERRIDE { return Version("Provides support for ircu-style services accounts, including channel mode +R, etc", VF_OPTCOMMON|VF_VENDOR); } }; MODULE_INIT(ModuleServicesAccount) ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/src/modules/m_servprotect.cpp��������������������������������������������������������0000664�0000000�0000000�00000011457�13554550454�0021212�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * InspIRCd -- Internet Relay Chat Daemon * * Copyright (C) 2009 Daniel De Graaf <danieldg@inspircd.org> * Copyright (C) 2008 Craig Edwards <craigedwards@brainbox.cc> * Copyright (C) 2007 Robin Burchell <robin+git@viroteck.net> * * 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 "inspircd.h" #include "modules/whois.h" enum { // From AustHex. RPL_WHOISSERVICE = 310, // From UnrealIRCd. ERR_KILLDENY = 485 }; /** Handles user mode +k */ class ServProtectMode : public ModeHandler { public: ServProtectMode(Module* Creator) : ModeHandler(Creator, "servprotect", 'k', PARAM_NONE, MODETYPE_USER) { oper = true; } ModeAction OnModeChange(User* source, User* dest, Channel* channel, std::string& parameter, bool adding) CXX11_OVERRIDE { /* Because this returns MODEACTION_DENY all the time, there is only ONE * way to add this mode and that is at client introduction in the UID command, * as this calls OnModeChange for each mode but disregards the return values. * The mode cannot be manually added or removed, not even by a server or by a remote * user or uline, which prevents its (ab)use as a kiddie 'god mode' on such networks. * I'm sure if someone really wants to do that they can make a copy of this module * that does the job. It won't be me though! */ return MODEACTION_DENY; } }; class ModuleServProtectMode : public Module, public Whois::EventListener, public Whois::LineEventListener { ServProtectMode bm; public: ModuleServProtectMode() : Whois::EventListener(this) , Whois::LineEventListener(this) , bm(this) { } Version GetVersion() CXX11_OVERRIDE { return Version("Provides user mode +k to protect services from kicks, kills, and mode changes", VF_VENDOR); } void OnWhois(Whois::Context& whois) CXX11_OVERRIDE { if (whois.GetTarget()->IsModeSet(bm)) { whois.SendLine(RPL_WHOISSERVICE, "is a Network Service on " + ServerInstance->Config->Network); } } ModResult OnRawMode(User* user, Channel* chan, ModeHandler* mh, const std::string& param, bool adding) CXX11_OVERRIDE { /* Check that the mode is not a server mode, it is being removed, the user making the change is local, there is a parameter, * and the user making the change is not a uline */ if (!adding && chan && IS_LOCAL(user) && !param.empty()) { const PrefixMode* const pm = mh->IsPrefixMode(); if (!pm) return MOD_RES_PASSTHRU; /* Check if the parameter is a valid nick/uuid */ User *u = ServerInstance->FindNick(param); if (u) { Membership* memb = chan->GetUser(u); /* The target user has +k set on themselves, and you are trying to remove a privilege mode the user has set on themselves. * This includes any prefix permission mode, even those registered in other modules, e.g. +qaohv. Using ::ModeString() * here means that the number of modes is restricted to only modes the user has, limiting it to as short a loop as possible. */ if ((u->IsModeSet(bm)) && (memb) && (memb->HasMode(pm))) { /* BZZZT, Denied! */ user->WriteNumeric(ERR_CHANOPRIVSNEEDED, chan->name, InspIRCd::Format("You are not permitted to remove privileges from %s services", ServerInstance->Config->Network.c_str())); return MOD_RES_DENY; } } } /* Mode allowed */ return MOD_RES_PASSTHRU; } ModResult OnKill(User* src, User* dst, const std::string &reason) CXX11_OVERRIDE { if (src == NULL) return MOD_RES_PASSTHRU; if (dst->IsModeSet(bm)) { src->WriteNumeric(ERR_KILLDENY, InspIRCd::Format("You are not permitted to kill %s services!", ServerInstance->Config->Network.c_str())); ServerInstance->SNO->WriteGlobalSno('a', src->nick+" tried to kill service "+dst->nick+" ("+reason+")"); return MOD_RES_DENY; } return MOD_RES_PASSTHRU; } ModResult OnUserPreKick(User *src, Membership* memb, const std::string &reason) CXX11_OVERRIDE { if (memb->user->IsModeSet(bm)) { src->WriteNumeric(ERR_RESTRICTED, memb->chan->name, "You are not permitted to kick services"); return MOD_RES_DENY; } return MOD_RES_PASSTHRU; } ModResult OnWhoisLine(Whois::Context& whois, Numeric::Numeric& numeric) CXX11_OVERRIDE { return ((numeric.GetNumeric() == 319) && whois.GetTarget()->IsModeSet(bm)) ? MOD_RES_DENY : MOD_RES_PASSTHRU; } }; MODULE_INIT(ModuleServProtectMode) �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/src/modules/m_sethost.cpp������������������������������������������������������������0000664�0000000�0000000�00000004657�13554550454�0020327�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * InspIRCd -- Internet Relay Chat Daemon * * Copyright (C) 2007 Dennis Friis <peavey@inspircd.org> * Copyright (C) 2007 Robin Burchell <robin+git@viroteck.net> * Copyright (C) 2004-2006 Craig Edwards <craigedwards@brainbox.cc> * * This file is part of InspIRCd. InspIRCd is free software: you can * redistribute it and/or modify it under the terms of the GNU General Public * License as published by the Free Software Foundation, version 2. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include "inspircd.h" /** Handle /SETHOST */ class CommandSethost : public Command { public: std::bitset<UCHAR_MAX> hostmap; CommandSethost(Module* Creator) : Command(Creator,"SETHOST", 1) { allow_empty_last_param = false; flags_needed = 'o'; syntax = "<host>"; } CmdResult Handle(User* user, const Params& parameters) CXX11_OVERRIDE { if (parameters[0].length() > ServerInstance->Config->Limits.MaxHost) { user->WriteNotice("*** SETHOST: Host too long"); return CMD_FAILURE; } for (std::string::const_iterator x = parameters[0].begin(); x != parameters[0].end(); x++) { if (!hostmap.test(static_cast<unsigned char>(*x))) { user->WriteNotice("*** SETHOST: Invalid characters in hostname"); return CMD_FAILURE; } } if (user->ChangeDisplayedHost(parameters[0])) { ServerInstance->SNO->WriteGlobalSno('a', user->nick+" used SETHOST to change their displayed host to "+user->GetDisplayedHost()); return CMD_SUCCESS; } return CMD_FAILURE; } }; class ModuleSetHost : public Module { CommandSethost cmd; public: ModuleSetHost() : cmd(this) { } void ReadConfig(ConfigStatus& status) CXX11_OVERRIDE { std::string hmap = ServerInstance->Config->ConfValue("hostname")->getString("charmap", "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz.-_/0123456789"); cmd.hostmap.reset(); for (std::string::iterator n = hmap.begin(); n != hmap.end(); n++) cmd.hostmap.set(static_cast<unsigned char>(*n)); } Version GetVersion() CXX11_OVERRIDE { return Version("Provides the SETHOST command", VF_VENDOR); } }; MODULE_INIT(ModuleSetHost) ���������������������������������������������������������������������������������inspircd-3.4.0/src/modules/m_setident.cpp�����������������������������������������������������������0000664�0000000�0000000�00000003711�13554550454�0020443�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * InspIRCd -- Internet Relay Chat Daemon * * Copyright (C) 2007 Dennis Friis <peavey@inspircd.org> * Copyright (C) 2007 John Brooks <john.brooks@dereferenced.net> * Copyright (C) 2007 Robin Burchell <robin+git@viroteck.net> * Copyright (C) 2006 Oliver Lupton <oliverlupton@gmail.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 "inspircd.h" /** Handle /SETIDENT */ class CommandSetident : public Command { public: CommandSetident(Module* Creator) : Command(Creator,"SETIDENT", 1) { allow_empty_last_param = false; flags_needed = 'o'; syntax = "<ident>"; } CmdResult Handle(User* user, const Params& parameters) CXX11_OVERRIDE { if (parameters[0].size() > ServerInstance->Config->Limits.IdentMax) { user->WriteNotice("*** SETIDENT: Ident is too long"); return CMD_FAILURE; } if (!ServerInstance->IsIdent(parameters[0])) { user->WriteNotice("*** SETIDENT: Invalid characters in ident"); return CMD_FAILURE; } user->ChangeIdent(parameters[0]); ServerInstance->SNO->WriteGlobalSno('a', "%s used SETIDENT to change their ident to '%s'", user->nick.c_str(), user->ident.c_str()); return CMD_SUCCESS; } }; class ModuleSetIdent : public Module { CommandSetident cmd; public: ModuleSetIdent() : cmd(this) { } Version GetVersion() CXX11_OVERRIDE { return Version("Provides the SETIDENT command", VF_VENDOR); } }; MODULE_INIT(ModuleSetIdent) �������������������������������������������������������inspircd-3.4.0/src/modules/m_setidle.cpp������������������������������������������������������������0000664�0000000�0000000�00000004101�13554550454�0020247�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * InspIRCd -- Internet Relay Chat Daemon * * Copyright (C) 2007 Dennis Friis <peavey@inspircd.org> * Copyright (C) 2007 Robin Burchell <robin+git@viroteck.net> * Copyright (C) 2005 Craig Edwards <craigedwards@brainbox.cc> * * This file is part of InspIRCd. InspIRCd is free software: you can * redistribute it and/or modify it under the terms of the GNU General Public * License as published by the Free Software Foundation, version 2. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include "inspircd.h" enum { // InspIRCd-specific. ERR_INVALIDIDLETIME = 948, RPL_IDLETIMESET = 944 }; /** Handle /SETIDLE */ class CommandSetidle : public SplitCommand { public: CommandSetidle(Module* Creator) : SplitCommand(Creator,"SETIDLE", 1) { flags_needed = 'o'; syntax = "<duration>"; } CmdResult HandleLocal(LocalUser* user, const Params& parameters) CXX11_OVERRIDE { unsigned long idle; if (!InspIRCd::Duration(parameters[0], idle)) { user->WriteNumeric(ERR_INVALIDIDLETIME, "Invalid idle time."); return CMD_FAILURE; } user->idle_lastmsg = (ServerInstance->Time() - idle); // minor tweak - we cant have signon time shorter than our idle time! if (user->signon > user->idle_lastmsg) user->signon = user->idle_lastmsg; ServerInstance->SNO->WriteToSnoMask('a', user->nick+" used SETIDLE to set their idle time to "+ConvToStr(idle)+" seconds"); user->WriteNumeric(RPL_IDLETIMESET, "Idle time set."); return CMD_SUCCESS; } }; class ModuleSetIdle : public Module { CommandSetidle cmd; public: ModuleSetIdle() : cmd(this) { } Version GetVersion() CXX11_OVERRIDE { return Version("Provides the SETIDLE command, allows opers to set their idle time", VF_VENDOR); } }; MODULE_INIT(ModuleSetIdle) ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/src/modules/m_setname.cpp������������������������������������������������������������0000664�0000000�0000000�00000004270�13554550454�0020261�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * InspIRCd -- Internet Relay Chat Daemon * * Copyright (C) 2007 Dennis Friis <peavey@inspircd.org> * Copyright (C) 2007 Robin Burchell <robin+git@viroteck.net> * Copyright (C) 2004-2005 Craig Edwards <craigedwards@brainbox.cc> * * This file is part of InspIRCd. InspIRCd is free software: you can * redistribute it and/or modify it under the terms of the GNU General Public * License as published by the Free Software Foundation, version 2. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include "inspircd.h" class CommandSetname : public Command { public: bool notifyopers; CommandSetname(Module* Creator) : Command(Creator,"SETNAME", 1, 1) { allow_empty_last_param = false; syntax = ":<realname>"; } CmdResult Handle(User* user, const Params& parameters) CXX11_OVERRIDE { if (parameters[0].size() > ServerInstance->Config->Limits.MaxReal) { user->WriteNotice("*** SETNAME: Real name is too long"); return CMD_FAILURE; } if (user->ChangeRealName(parameters[0])) { if (notifyopers) ServerInstance->SNO->WriteGlobalSno('a', "%s used SETNAME to change their real name to '%s'", user->nick.c_str(), parameters[0].c_str()); } return CMD_SUCCESS; } }; class ModuleSetName : public Module { CommandSetname cmd; public: ModuleSetName() : cmd(this) { } void ReadConfig(ConfigStatus& status) CXX11_OVERRIDE { ConfigTag* tag = ServerInstance->Config->ConfValue("setname"); // Whether the module should only be usable by server operators. bool operonly = tag->getBool("operonly"); cmd.flags_needed = operonly ? 'o' : 0; // Whether a snotice should be sent out when a user changes their real name. cmd.notifyopers = tag->getBool("notifyopers", !operonly); } Version GetVersion() CXX11_OVERRIDE { return Version("Provides the SETNAME command", VF_VENDOR); } }; MODULE_INIT(ModuleSetName) ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/src/modules/m_sha1.cpp���������������������������������������������������������������0000664�0000000�0000000�00000017176�13554550454�0017472�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * InspIRCd -- Internet Relay Chat Daemon * * Copyright (C) 2016 Attila Molnar <attilamolnar@hush.com> * * This file is part of InspIRCd. InspIRCd is free software: you can * redistribute it and/or modify it under the terms of the GNU General Public * License as published by the Free Software Foundation, version 2. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ /* SHA-1 in C By Steve Reid <steve@edmweb.com> 100% Public Domain */ #include "inspircd.h" #include "modules/hash.h" union CHAR64LONG16 { unsigned char c[64]; uint32_t l[16]; }; inline static uint32_t rol(uint32_t value, uint32_t bits) { return (value << bits) | (value >> (32 - bits)); } // blk0() and blk() perform the initial expand. // I got the idea of expanding during the round function from SSLeay static bool big_endian; inline static uint32_t blk0(CHAR64LONG16& block, uint32_t i) { if (big_endian) return block.l[i]; else return block.l[i] = (rol(block.l[i], 24) & 0xFF00FF00) | (rol(block.l[i], 8) & 0x00FF00FF); } inline static uint32_t blk(CHAR64LONG16 &block, uint32_t i) { return block.l[i & 15] = rol(block.l[(i + 13) & 15] ^ block.l[(i + 8) & 15] ^ block.l[(i + 2) & 15] ^ block.l[i & 15],1); } // (R0+R1), R2, R3, R4 are the different operations used in SHA1 inline static void R0(CHAR64LONG16& block, uint32_t v, uint32_t &w, uint32_t x, uint32_t y, uint32_t &z, uint32_t i) { z += ((w & (x ^ y)) ^ y) + blk0(block, i) + 0x5A827999 + rol(v, 5); w = rol(w, 30); } inline static void R1(CHAR64LONG16& block, uint32_t v, uint32_t &w, uint32_t x, uint32_t y, uint32_t &z, uint32_t i) { z += ((w & (x ^ y)) ^ y) + blk(block, i) + 0x5A827999 + rol(v, 5); w = rol(w, 30); } inline static void R2(CHAR64LONG16& block, uint32_t v, uint32_t &w, uint32_t x, uint32_t y, uint32_t &z, uint32_t i) { z += (w ^ x ^ y) + blk(block, i) + 0x6ED9EBA1 + rol(v, 5); w = rol(w, 30); } inline static void R3(CHAR64LONG16& block, uint32_t v, uint32_t &w, uint32_t x, uint32_t y, uint32_t &z, uint32_t i) { z += (((w | x) & y) | (w & x)) + blk(block, i) + 0x8F1BBCDC + rol(v, 5); w = rol(w, 30); } inline static void R4(CHAR64LONG16& block, uint32_t v, uint32_t &w, uint32_t x, uint32_t y, uint32_t &z, uint32_t i) { z += (w ^ x ^ y) + blk(block, i) + 0xCA62C1D6 + rol(v, 5); w = rol(w, 30); } static const uint32_t sha1_iv[5] = { 0x67452301, 0xEFCDAB89, 0x98BADCFE, 0x10325476, 0xC3D2E1F0 }; class SHA1Context { uint32_t state[5]; uint32_t count[2]; unsigned char buffer[64]; unsigned char digest[20]; void Transform(const unsigned char buf[64]) { uint32_t a, b, c, d, e; CHAR64LONG16 block; memcpy(block.c, buf, 64); // Copy state[] to working vars a = this->state[0]; b = this->state[1]; c = this->state[2]; d = this->state[3]; e = this->state[4]; // 4 rounds of 20 operations each. Loop unrolled. R0(block, a, b, c, d, e, 0); R0(block, e, a, b, c, d, 1); R0(block, d, e, a, b, c, 2); R0(block, c, d, e, a, b, 3); R0(block, b, c, d, e, a, 4); R0(block, a, b, c, d, e, 5); R0(block, e, a, b, c, d, 6); R0(block, d, e, a, b, c, 7); R0(block, c, d, e, a, b, 8); R0(block, b, c, d, e, a, 9); R0(block, a, b, c, d, e, 10); R0(block, e, a, b, c, d, 11); R0(block, d, e, a, b, c, 12); R0(block, c, d, e, a, b, 13); R0(block, b, c, d, e, a, 14); R0(block, a, b, c, d, e, 15); R1(block, e, a, b, c, d, 16); R1(block, d, e, a, b, c, 17); R1(block, c, d, e, a, b, 18); R1(block, b, c, d, e, a, 19); R2(block, a, b, c, d, e, 20); R2(block, e, a, b, c, d, 21); R2(block, d, e, a, b, c, 22); R2(block, c, d, e, a, b, 23); R2(block, b, c, d, e, a, 24); R2(block, a, b, c, d, e, 25); R2(block, e, a, b, c, d, 26); R2(block, d, e, a, b, c, 27); R2(block, c, d, e, a, b, 28); R2(block, b, c, d, e, a, 29); R2(block, a, b, c, d, e, 30); R2(block, e, a, b, c, d, 31); R2(block, d, e, a, b, c, 32); R2(block, c, d, e, a, b, 33); R2(block, b, c, d, e, a, 34); R2(block, a, b, c, d, e, 35); R2(block, e, a, b, c, d, 36); R2(block, d, e, a, b, c, 37); R2(block, c, d, e, a, b, 38); R2(block, b, c, d, e, a, 39); R3(block, a, b, c, d, e, 40); R3(block, e, a, b, c, d, 41); R3(block, d, e, a, b, c, 42); R3(block, c, d, e, a, b, 43); R3(block, b, c, d, e, a, 44); R3(block, a, b, c, d, e, 45); R3(block, e, a, b, c, d, 46); R3(block, d, e, a, b, c, 47); R3(block, c, d, e, a, b, 48); R3(block, b, c, d, e, a, 49); R3(block, a, b, c, d, e, 50); R3(block, e, a, b, c, d, 51); R3(block, d, e, a, b, c, 52); R3(block, c, d, e, a, b, 53); R3(block, b, c, d, e, a, 54); R3(block, a, b, c, d, e, 55); R3(block, e, a, b, c, d, 56); R3(block, d, e, a, b, c, 57); R3(block, c, d, e, a, b, 58); R3(block, b, c, d, e, a, 59); R4(block, a, b, c, d, e, 60); R4(block, e, a, b, c, d, 61); R4(block, d, e, a, b, c, 62); R4(block, c, d, e, a, b, 63); R4(block, b, c, d, e, a, 64); R4(block, a, b, c, d, e, 65); R4(block, e, a, b, c, d, 66); R4(block, d, e, a, b, c, 67); R4(block, c, d, e, a, b, 68); R4(block, b, c, d, e, a, 69); R4(block, a, b, c, d, e, 70); R4(block, e, a, b, c, d, 71); R4(block, d, e, a, b, c, 72); R4(block, c, d, e, a, b, 73); R4(block, b, c, d, e, a, 74); R4(block, a, b, c, d, e, 75); R4(block, e, a, b, c, d, 76); R4(block, d, e, a, b, c, 77); R4(block, c, d, e, a, b, 78); R4(block, b, c, d, e, a, 79); // Add the working vars back into state[] this->state[0] += a; this->state[1] += b; this->state[2] += c; this->state[3] += d; this->state[4] += e; } public: SHA1Context() { for (int i = 0; i < 5; ++i) this->state[i] = sha1_iv[i]; this->count[0] = this->count[1] = 0; memset(this->buffer, 0, sizeof(this->buffer)); memset(this->digest, 0, sizeof(this->digest)); } void Update(const unsigned char* data, size_t len) { uint32_t i, j; j = (this->count[0] >> 3) & 63; if ((this->count[0] += len << 3) < (len << 3)) ++this->count[1]; this->count[1] += len >> 29; if (j + len > 63) { memcpy(&this->buffer[j], data, (i = 64 - j)); this->Transform(this->buffer); for (; i + 63 < len; i += 64) this->Transform(&data[i]); j = 0; } else i = 0; memcpy(&this->buffer[j], &data[i], len - i); } void Finalize() { uint32_t i; unsigned char finalcount[8]; for (i = 0; i < 8; ++i) finalcount[i] = static_cast<unsigned char>((this->count[i >= 4 ? 0 : 1] >> ((3 - (i & 3)) * 8)) & 255); /* Endian independent */ this->Update(reinterpret_cast<const unsigned char *>("\200"), 1); while ((this->count[0] & 504) != 448) this->Update(reinterpret_cast<const unsigned char *>("\0"), 1); this->Update(finalcount, 8); // Should cause a SHA1Transform() for (i = 0; i < 20; ++i) this->digest[i] = static_cast<unsigned char>((this->state[i>>2] >> ((3 - (i & 3)) * 8)) & 255); this->Transform(this->buffer); } std::string GetRaw() const { return std::string((const char*)digest, sizeof(digest)); } }; class SHA1HashProvider : public HashProvider { public: SHA1HashProvider(Module* mod) : HashProvider(mod, "hash/sha1", 20, 64) { } std::string GenerateRaw(const std::string& data) CXX11_OVERRIDE { SHA1Context ctx; ctx.Update(reinterpret_cast<const unsigned char*>(data.data()), data.length()); ctx.Finalize(); return ctx.GetRaw(); } }; class ModuleSHA1 : public Module { SHA1HashProvider sha1; public: ModuleSHA1() : sha1(this) { big_endian = (htonl(1337) == 1337); } Version GetVersion() CXX11_OVERRIDE { return Version("Implements SHA-1 hashing", VF_VENDOR); } }; MODULE_INIT(ModuleSHA1) ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/src/modules/m_sha256.cpp�������������������������������������������������������������0000664�0000000�0000000�00000003725�13554550454�0017641�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * InspIRCd -- Internet Relay Chat Daemon * * Copyright (C) 2009 Daniel De Graaf <danieldg@inspircd.org> * Copyright (C) 2007-2008 Robin Burchell <robin+git@viroteck.net> * Copyright (C) 2007 Dennis Friis <peavey@inspircd.org> * Copyright (C) 2006 Craig Edwards <craigedwards@brainbox.cc> * * This file is part of InspIRCd. InspIRCd is free software: you can * redistribute it and/or modify it under the terms of the GNU General Public * License as published by the Free Software Foundation, version 2. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ /// $CompilerFlags: -Ivendor_directory("sha2") /// $CompilerFlags: require_compiler("GCC") -Wno-long-long #ifdef __GNUC__ # pragma GCC diagnostic push #endif // Fix warnings about the use of `long long` on C++03. #if defined __clang__ # pragma clang diagnostic ignored "-Wc++11-long-long" #elif defined __GNUC__ # pragma GCC diagnostic ignored "-Wlong-long" #endif #include "inspircd.h" #include "modules/hash.h" #include <sha2.c> #ifdef __GNUC__ # pragma GCC diagnostic pop #endif class HashSHA256 : public HashProvider { public: std::string GenerateRaw(const std::string& data) CXX11_OVERRIDE { unsigned char bytes[SHA256_DIGEST_SIZE]; sha256((unsigned char*)data.data(), data.length(), bytes); return std::string((char*)bytes, SHA256_DIGEST_SIZE); } HashSHA256(Module* parent) : HashProvider(parent, "sha256", 32, 64) { } }; class ModuleSHA256 : public Module { HashSHA256 sha; public: ModuleSHA256() : sha(this) { } Version GetVersion() CXX11_OVERRIDE { return Version("Implements SHA-256 hashing", VF_VENDOR); } }; MODULE_INIT(ModuleSHA256) �������������������������������������������inspircd-3.4.0/src/modules/m_showfile.cpp�����������������������������������������������������������0000664�0000000�0000000�00000011735�13554550454�0020451�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * InspIRCd -- Internet Relay Chat Daemon * * Copyright (C) 2013 Attila Molnar <attilamolnar@hush.com> * * This file is part of InspIRCd. InspIRCd is free software: you can * redistribute it and/or modify it under the terms of the GNU General Public * License as published by the Free Software Foundation, version 2. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include "inspircd.h" enum { // From UnrealIRCd. RPL_RULES = 232, RPL_RULESTART = 308, RPL_RULESEND = 309, ERR_NORULES = 434 }; class CommandShowFile : public Command { enum Method { SF_MSG, SF_NOTICE, SF_NUMERIC }; std::string introtext; std::string endtext; unsigned int intronumeric; unsigned int textnumeric; unsigned int endnumeric; file_cache contents; Method method; public: CommandShowFile(Module* parent, const std::string& cmdname) : Command(parent, cmdname) { } CmdResult Handle(User* user, const Params& parameters) CXX11_OVERRIDE { if (method == SF_NUMERIC) { if (!introtext.empty() && intronumeric) user->WriteRemoteNumeric(intronumeric, introtext); for (file_cache::const_iterator i = contents.begin(); i != contents.end(); ++i) user->WriteRemoteNumeric(textnumeric, InspIRCd::Format("- %s", i->c_str())); if (!endtext.empty() && endnumeric) user->WriteRemoteNumeric(endnumeric, endtext.c_str()); } else if (IS_LOCAL(user)) { LocalUser* const localuser = IS_LOCAL(user); for (file_cache::const_iterator i = contents.begin(); i != contents.end(); ++i) { const std::string& line = *i; ClientProtocol::Messages::Privmsg msg(ClientProtocol::Messages::Privmsg::nocopy, ServerInstance->FakeClient, localuser, line, ((method == SF_MSG) ? MSG_PRIVMSG : MSG_NOTICE)); localuser->Send(ServerInstance->GetRFCEvents().privmsg, msg); } } return CMD_SUCCESS; } void UpdateSettings(ConfigTag* tag, const std::vector<std::string>& filecontents) { introtext = tag->getString("introtext", "Showing " + name); endtext = tag->getString("endtext", "End of " + name); intronumeric = tag->getUInt("intronumeric", RPL_RULESTART, 0, 999); textnumeric = tag->getUInt("numeric", RPL_RULES, 0, 999); endnumeric = tag->getUInt("endnumeric", RPL_RULESEND, 0, 999); std::string smethod = tag->getString("method"); method = SF_NUMERIC; if (smethod == "msg") method = SF_MSG; else if (smethod == "notice") method = SF_NOTICE; contents = filecontents; InspIRCd::ProcessColors(contents); } }; class ModuleShowFile : public Module { std::vector<CommandShowFile*> cmds; void ReadTag(ConfigTag* tag, std::vector<CommandShowFile*>& newcmds) { std::string cmdname = tag->getString("name"); if (cmdname.empty()) throw ModuleException("Empty value for 'name'"); std::transform(cmdname.begin(), cmdname.end(), cmdname.begin(), ::toupper); const std::string file = tag->getString("file", cmdname); if (file.empty()) throw ModuleException("Empty value for 'file'"); FileReader reader(file); CommandShowFile* sfcmd; Command* handler = ServerInstance->Parser.GetHandler(cmdname); if (handler) { // Command exists, check if it is ours if (handler->creator != this) throw ModuleException("Command " + cmdname + " already exists"); // This is our command, make sure we don't have the same entry twice sfcmd = static_cast<CommandShowFile*>(handler); if (stdalgo::isin(newcmds, sfcmd)) throw ModuleException("Command " + cmdname + " is already used in a <showfile> tag"); } else { // Command doesn't exist, create it sfcmd = new CommandShowFile(this, cmdname); ServerInstance->Modules->AddService(*sfcmd); } sfcmd->UpdateSettings(tag, reader.GetVector()); newcmds.push_back(sfcmd); } public: void ReadConfig(ConfigStatus& status) CXX11_OVERRIDE { std::vector<CommandShowFile*> newcmds; ConfigTagList tags = ServerInstance->Config->ConfTags("showfile"); for (ConfigIter i = tags.first; i != tags.second; ++i) { ConfigTag* tag = i->second; try { ReadTag(tag, newcmds); } catch (CoreException& ex) { ServerInstance->Logs->Log(MODNAME, LOG_DEFAULT, "Error: " + ex.GetReason() + " at " + tag->getTagLocation()); } } // Remove all commands that were removed from the config std::vector<CommandShowFile*> removed(cmds.size()); std::sort(newcmds.begin(), newcmds.end()); std::set_difference(cmds.begin(), cmds.end(), newcmds.begin(), newcmds.end(), removed.begin()); stdalgo::delete_all(removed); cmds.swap(newcmds); } ~ModuleShowFile() { stdalgo::delete_all(cmds); } Version GetVersion() CXX11_OVERRIDE { return Version("Provides support for showing text files to users", VF_VENDOR); } }; MODULE_INIT(ModuleShowFile) �����������������������������������inspircd-3.4.0/src/modules/m_showwhois.cpp����������������������������������������������������������0000664�0000000�0000000�00000006076�13554550454�0020665�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * InspIRCd -- Internet Relay Chat Daemon * * Copyright (C) 2009 Daniel De Graaf <danieldg@inspircd.org> * Copyright (C) 2005, 2008 Robin Burchell <robin+git@viroteck.net> * Copyright (C) 2007 Dennis Friis <peavey@inspircd.org> * Copyright (C) 2006 Craig Edwards <craigedwards@brainbox.cc> * Copyright (C) 2004 Christopher Hall <typobox43@gmail.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 "inspircd.h" #include "modules/whois.h" /** Handle user mode +W */ class SeeWhois : public SimpleUserModeHandler { public: SeeWhois(Module* Creator) : SimpleUserModeHandler(Creator, "showwhois", 'W') { } void SetOperOnly(bool operonly) { oper = operonly; } }; class WhoisNoticeCmd : public Command { public: WhoisNoticeCmd(Module* Creator) : Command(Creator,"WHOISNOTICE", 2) { flags_needed = FLAG_SERVERONLY; } void HandleFast(User* dest, User* src) { dest->WriteNotice("*** " + src->nick + " (" + src->ident + "@" + src->GetHost(dest->HasPrivPermission("users/auspex")) + ") did a /whois on you"); } CmdResult Handle(User* user, const Params& parameters) CXX11_OVERRIDE { User* dest = ServerInstance->FindNick(parameters[0]); if (!dest) return CMD_FAILURE; User* source = ServerInstance->FindNick(parameters[1]); if (IS_LOCAL(dest) && source) HandleFast(dest, source); return CMD_SUCCESS; } }; class ModuleShowwhois : public Module, public Whois::EventListener { bool ShowWhoisFromOpers; SeeWhois sw; WhoisNoticeCmd cmd; public: ModuleShowwhois() : Whois::EventListener(this) , sw(this) , cmd(this) { } void ReadConfig(ConfigStatus& status) CXX11_OVERRIDE { ConfigTag* tag = ServerInstance->Config->ConfValue("showwhois"); sw.SetOperOnly(tag->getBool("opersonly", true)); ShowWhoisFromOpers = tag->getBool("showfromopers", true); } Version GetVersion() CXX11_OVERRIDE { return Version("Provides user mode +W for opers to see when a user uses WHOIS on them", VF_OPTCOMMON|VF_VENDOR); } void OnWhois(Whois::Context& whois) CXX11_OVERRIDE { User* const source = whois.GetSource(); User* const dest = whois.GetTarget(); if (!dest->IsModeSet(sw) || whois.IsSelfWhois()) return; if (!ShowWhoisFromOpers && source->IsOper()) return; if (IS_LOCAL(dest)) { cmd.HandleFast(dest, source); } else { CommandBase::Params params; params.push_back(dest->uuid); params.push_back(source->uuid); ServerInstance->PI->SendEncapsulatedData(dest->server->GetName(), cmd.name, params); } } }; MODULE_INIT(ModuleShowwhois) ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/src/modules/m_shun.cpp���������������������������������������������������������������0000664�0000000�0000000�00000015204�13554550454�0017601�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * InspIRCd -- Internet Relay Chat Daemon * * Copyright (C) 2009 Daniel De Graaf <danieldg@inspircd.org> * Copyright (C) 2008 Robin Burchell <robin+git@viroteck.net> * Copyright (C) 2008 Craig Edwards <craigedwards@brainbox.cc> * Copyright (C) 2008 Thomas Stagner <aquanight@inspircd.org> * * This file is part of InspIRCd. InspIRCd is free software: you can * redistribute it and/or modify it under the terms of the GNU General Public * License as published by the Free Software Foundation, version 2. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include "inspircd.h" #include "xline.h" #include "modules/shun.h" #include "modules/stats.h" /** An XLineFactory specialized to generate shun pointers */ class ShunFactory : public XLineFactory { public: ShunFactory() : XLineFactory("SHUN") { } /** Generate a shun */ XLine* Generate(time_t set_time, unsigned long duration, const std::string& source, const std::string& reason, const std::string& xline_specific_mask) CXX11_OVERRIDE { return new Shun(set_time, duration, source, reason, xline_specific_mask); } bool AutoApplyToUserList(XLine* x) CXX11_OVERRIDE { return false; } }; //typedef std::vector<Shun> shunlist; class CommandShun : public Command { public: CommandShun(Module* Creator) : Command(Creator, "SHUN", 1, 3) { flags_needed = 'o'; this->syntax = "<nick!user@host> [<duration> :<reason>]"; } CmdResult Handle(User* user, const Params& parameters) CXX11_OVERRIDE { /* syntax: SHUN nick!user@host time :reason goes here */ /* 'time' is a human-readable timestring, like 2d3h2s. */ std::string target = parameters[0]; User *find = ServerInstance->FindNick(target); if ((find) && (find->registered == REG_ALL)) target = std::string("*!*@") + find->GetIPString(); if (parameters.size() == 1) { std::string reason; if (ServerInstance->XLines->DelLine(parameters[0].c_str(), "SHUN", reason, user)) { ServerInstance->SNO->WriteToSnoMask('x', "%s removed SHUN on %s: %s", user->nick.c_str(), parameters[0].c_str(), reason.c_str()); } else if (ServerInstance->XLines->DelLine(target.c_str(), "SHUN", reason, user)) { ServerInstance->SNO->WriteToSnoMask('x', "%s removed SHUN on %s: %s", user->nick.c_str(), target.c_str(), reason.c_str()); } else { user->WriteNotice("*** Shun " + parameters[0] + " not found on the list."); return CMD_FAILURE; } } else { // Adding - XXX todo make this respect <insane> tag perhaps.. unsigned long duration; std::string expr; if (parameters.size() > 2) { if (!InspIRCd::Duration(parameters[1], duration)) { user->WriteNotice("*** Invalid duration for SHUN."); return CMD_FAILURE; } expr = parameters[2]; } else { duration = 0; expr = parameters[1]; } Shun* r = new Shun(ServerInstance->Time(), duration, user->nick.c_str(), expr.c_str(), target.c_str()); if (ServerInstance->XLines->AddLine(r, user)) { if (!duration) { ServerInstance->SNO->WriteToSnoMask('x', "%s added permanent SHUN for %s: %s", user->nick.c_str(), target.c_str(), expr.c_str()); } else { ServerInstance->SNO->WriteToSnoMask('x', "%s added timed SHUN for %s, expires in %s (on %s): %s", user->nick.c_str(), target.c_str(), InspIRCd::DurationString(duration).c_str(), InspIRCd::TimeString(ServerInstance->Time() + duration).c_str(), expr.c_str()); } } else { delete r; user->WriteNotice("*** Shun for " + target + " already exists."); return CMD_FAILURE; } } return CMD_SUCCESS; } RouteDescriptor GetRouting(User* user, const Params& parameters) CXX11_OVERRIDE { if (IS_LOCAL(user)) return ROUTE_LOCALONLY; // spanningtree will send ADDLINE return ROUTE_BROADCAST; } }; class ModuleShun : public Module, public Stats::EventListener { CommandShun cmd; ShunFactory f; insp::flat_set<std::string> ShunEnabledCommands; bool NotifyOfShun; bool affectopers; public: ModuleShun() : Stats::EventListener(this) , cmd(this) { } void init() CXX11_OVERRIDE { ServerInstance->XLines->RegisterFactory(&f); } ~ModuleShun() { ServerInstance->XLines->DelAll("SHUN"); ServerInstance->XLines->UnregisterFactory(&f); } void Prioritize() CXX11_OVERRIDE { Module* alias = ServerInstance->Modules->Find("m_alias.so"); ServerInstance->Modules->SetPriority(this, I_OnPreCommand, PRIORITY_BEFORE, alias); } ModResult OnStats(Stats::Context& stats) CXX11_OVERRIDE { if (stats.GetSymbol() != 'H') return MOD_RES_PASSTHRU; ServerInstance->XLines->InvokeStats("SHUN", 223, stats); return MOD_RES_DENY; } void ReadConfig(ConfigStatus& status) CXX11_OVERRIDE { ConfigTag* tag = ServerInstance->Config->ConfValue("shun"); std::string cmds = tag->getString("enabledcommands"); std::transform(cmds.begin(), cmds.end(), cmds.begin(), ::toupper); if (cmds.empty()) cmds = "PING PONG QUIT"; ShunEnabledCommands.clear(); irc::spacesepstream dcmds(cmds); std::string thiscmd; while (dcmds.GetToken(thiscmd)) { ShunEnabledCommands.insert(thiscmd); } NotifyOfShun = tag->getBool("notifyuser", true); affectopers = tag->getBool("affectopers", false); } ModResult OnPreCommand(std::string& command, CommandBase::Params& parameters, LocalUser* user, bool validated) CXX11_OVERRIDE { if (validated) return MOD_RES_PASSTHRU; if (!ServerInstance->XLines->MatchesLine("SHUN", user)) { /* Not shunned, don't touch. */ return MOD_RES_PASSTHRU; } if (!affectopers && user->IsOper()) { /* Don't do anything if the user is an operator and affectopers isn't set */ return MOD_RES_PASSTHRU; } if (!ShunEnabledCommands.count(command)) { if (NotifyOfShun) user->WriteNotice("*** Command " + command + " not processed, as you have been blocked from issuing commands (SHUN)"); return MOD_RES_DENY; } if (command == "QUIT") { /* Allow QUIT but dont show any quit message */ parameters.clear(); } else if ((command == "PART") && (parameters.size() > 1)) { /* same for PART */ parameters.pop_back(); } /* if we're here, allow the command. */ return MOD_RES_PASSTHRU; } Version GetVersion() CXX11_OVERRIDE { return Version("Provides the SHUN command, which stops a user from executing all except configured commands", VF_VENDOR|VF_COMMON); } }; MODULE_INIT(ModuleShun) ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/src/modules/m_silence.cpp������������������������������������������������������������0000664�0000000�0000000�00000032071�13554550454�0020247�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * InspIRCd -- Internet Relay Chat Daemon * * Copyright (C) 2019 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 "inspircd.h" #include "modules/ctctags.h" enum { // From ircu? RPL_SILELIST = 271, RPL_ENDOFSILELIST = 272, ERR_SILELISTFULL = 511, // InspIRCd-specific. ERR_SILENCE = 952 }; class SilenceEntry { public: enum SilenceFlags { // Does nothing; for internal use only. SF_NONE = 0, // Exclude users who match this flags ("x"). SF_EXEMPT = 1, // 2, 4, 8, 16 are reserved for future use. // Matches a NOTICE targeted at a channel ("n"). SF_NOTICE_CHANNEL = 32, // Matches a NOTICE targeted at a user ("N"). SF_NOTICE_USER = 64, // Matches a PRIVMSG targeted at a channel ("p"). SF_PRIVMSG_CHANNEL = 128, // Matches a PRIVMSG targeted at a user ("P"). SF_PRIVMSG_USER = 256, // Matches a TAGMSG targeted at a channel ("t"). SF_TAGMSG_CHANNEL = 512, // Matches a TAGMSG targeted at a user ("T"). SF_TAGMSG_USER = 1024, // Matches a CTCP targeted at a channel ("c"). SF_CTCP_CHANNEL = 2048, // Matches a CTCP targeted at a user ("C"). SF_CTCP_USER = 4096, // Matches an invite to a channel ("i"). SF_INVITE = 8192, // The default if no flags have been specified. SF_DEFAULT = SF_NOTICE_CHANNEL | SF_NOTICE_USER | SF_PRIVMSG_CHANNEL | SF_PRIVMSG_USER | SF_TAGMSG_CHANNEL | SF_TAGMSG_USER | SF_CTCP_CHANNEL | SF_CTCP_USER | SF_INVITE }; // The flags that this mask is silenced for. uint32_t flags; // The mask which is silenced (e.g. *!*@example.com). std::string mask; SilenceEntry(uint32_t Flags, const std::string& Mask) : flags(Flags) , mask(Mask) { } bool operator <(const SilenceEntry& other) const { if (flags & SF_EXEMPT && other.flags & ~SF_EXEMPT) return true; if (other.flags & SF_EXEMPT && flags & ~SF_EXEMPT) return false; if (flags < other.flags) return true; if (other.flags < flags) return false; return mask < other.mask; } // Converts a flag list to a bitmask. static bool FlagsToBits(const std::string& flags, uint32_t& out) { out = SF_NONE; for (std::string::const_iterator flag = flags.begin(); flag != flags.end(); ++flag) { switch (*flag) { case 'C': out |= SF_CTCP_USER; break; case 'c': out |= SF_CTCP_CHANNEL; break; case 'd': out |= SF_DEFAULT; break; case 'i': out |= SF_INVITE; break; case 'N': out |= SF_NOTICE_USER; break; case 'n': out |= SF_NOTICE_CHANNEL; break; case 'P': out |= SF_PRIVMSG_USER; break; case 'p': out |= SF_PRIVMSG_CHANNEL; break; case 'T': out |= SF_TAGMSG_USER; break; case 't': out |= SF_TAGMSG_CHANNEL; break; case 'x': out |= SF_EXEMPT; break; default: out = SF_NONE; return false; } } return true; } // Converts a bitmask to a flag list. static std::string BitsToFlags(uint32_t flags) { std::string out; if (flags & SF_CTCP_USER) out.push_back('C'); if (flags & SF_CTCP_CHANNEL) out.push_back('c'); if (flags & SF_INVITE) out.push_back('i'); if (flags & SF_NOTICE_USER) out.push_back('N'); if (flags & SF_NOTICE_CHANNEL) out.push_back('n'); if (flags & SF_PRIVMSG_USER) out.push_back('P'); if (flags & SF_PRIVMSG_CHANNEL) out.push_back('p'); if (flags & SF_TAGMSG_CHANNEL) out.push_back('T'); if (flags & SF_TAGMSG_USER) out.push_back('t'); if (flags & SF_EXEMPT) out.push_back('x'); return out; } }; typedef insp::flat_set<SilenceEntry> SilenceList; class SilenceExtItem : public SimpleExtItem<SilenceList> { public: unsigned int maxsilence; SilenceExtItem(Module* Creator) : SimpleExtItem<SilenceList>("silence_list", ExtensionItem::EXT_USER, Creator) { } void FromInternal(Extensible* container, const std::string& value) CXX11_OVERRIDE { LocalUser* user = IS_LOCAL(static_cast<User*>(container)); if (!user) return; // Remove the old list and create a new one. unset(user); SilenceList* list = new SilenceList(); irc::spacesepstream ts(value); while (!ts.StreamEnd()) { // Check we have space for another entry. if (list->size() >= maxsilence) { ServerInstance->Logs->Log(MODNAME, LOG_DEBUG, "Oversized silence list received for %s: %s", user->uuid.c_str(), value.c_str()); delete list; return; } // Extract the mask and the flags. std::string mask; std::string flagstr; if (!ts.GetToken(mask) || !ts.GetToken(flagstr)) { ServerInstance->Logs->Log(MODNAME, LOG_DEBUG, "Malformed silence list received for %s: %s", user->uuid.c_str(), value.c_str()); delete list; return; } // Try to parse the flags. uint32_t flags; if (!SilenceEntry::FlagsToBits(flagstr, flags)) { ServerInstance->Logs->Log(MODNAME, LOG_DEBUG, "Malformed silence flags received for %s: %s", user->uuid.c_str(), flagstr.c_str()); delete list; return; } // Store the silence entry. list->insert(SilenceEntry(flags, mask)); } // The value was well formed. set(user, list); } std::string ToInternal(const Extensible* container, void* item) const CXX11_OVERRIDE { SilenceList* list = static_cast<SilenceList*>(item); std::string buf; for (SilenceList::const_iterator iter = list->begin(); iter != list->end(); ++iter) { if (iter != list->begin()) buf.push_back(' '); buf.append(iter->mask); buf.push_back(' '); buf.append(SilenceEntry::BitsToFlags(iter->flags)); } return buf; } }; class SilenceMessage : public ClientProtocol::Message { public: SilenceMessage(const std::string& mask, const std::string& flags) : ClientProtocol::Message("SILENCE") { PushParam(mask); PushParam(flags); } }; class CommandSilence : public SplitCommand { private: ClientProtocol::EventProvider msgprov; CmdResult AddSilence(LocalUser* user, const std::string& mask, uint32_t flags) { SilenceList* list = ext.get(user); if (list && list->size() > ext.maxsilence) { user->WriteNumeric(ERR_SILELISTFULL, mask, SilenceEntry::BitsToFlags(flags), "Your SILENCE list is full"); return CMD_FAILURE; } else if (!list) { // There is no list; create it. list = new SilenceList(); ext.set(user, list); } if (!list->insert(SilenceEntry(flags, mask)).second) { user->WriteNumeric(ERR_SILENCE, mask, SilenceEntry::BitsToFlags(flags), "The SILENCE entry you specified already exists"); return CMD_FAILURE; } SilenceMessage msg("+" + mask, SilenceEntry::BitsToFlags(flags)); user->Send(msgprov, msg); return CMD_SUCCESS; } CmdResult RemoveSilence(LocalUser* user, const std::string& mask, uint32_t flags) { SilenceList* list = ext.get(user); if (list) { for (SilenceList::iterator iter = list->begin(); iter != list->end(); ++iter) { if (!irc::equals(iter->mask, mask) || iter->flags != flags) continue; list->erase(iter); SilenceMessage msg("-" + mask, SilenceEntry::BitsToFlags(flags)); user->Send(msgprov, msg); return CMD_SUCCESS; } } user->WriteNumeric(ERR_SILENCE, mask, SilenceEntry::BitsToFlags(flags), "The SILENCE entry you specified could not be found"); return CMD_FAILURE; } CmdResult ShowSilenceList(LocalUser* user) { SilenceList* list = ext.get(user); if (list) { for (SilenceList::const_iterator iter = list->begin(); iter != list->end(); ++iter) { user->WriteNumeric(RPL_SILELIST, iter->mask, SilenceEntry::BitsToFlags(iter->flags)); } } user->WriteNumeric(RPL_ENDOFSILELIST, "End of SILENCE list"); return CMD_SUCCESS; } public: SilenceExtItem ext; CommandSilence(Module* Creator) : SplitCommand(Creator, "SILENCE") , msgprov(Creator, "SILENCE") , ext(Creator) { allow_empty_last_param = false; syntax = "[(+|-)<mask> [CcdiNnPpTtx]]"; } CmdResult HandleLocal(LocalUser* user, const Params& parameters) CXX11_OVERRIDE { if (parameters.empty()) return ShowSilenceList(user); // If neither add nor remove are specified we default to add. bool is_remove = parameters[0][0] == '-'; // If a prefix mask has been given then strip it and clean it up. std::string mask = parameters[0]; if (mask[0] == '-' || mask[0] == '+') { mask.erase(0, 1); if (mask.empty()) mask.assign("*"); ModeParser::CleanMask(mask); } // If the user specified a flags then use that. Otherwise, default to blocking // all CTCPs, invites, notices, privmsgs, and invites. uint32_t flags = SilenceEntry::SF_DEFAULT; if (parameters.size() > 1) { if (!SilenceEntry::FlagsToBits(parameters[1], flags)) { user->WriteNumeric(ERR_SILENCE, mask, parameters[1], "You specified one or more invalid SILENCE flags"); return CMD_FAILURE; } else if (flags == SilenceEntry::SF_EXEMPT) { // The user specified "x" with no other flags which does not make sense; add the "d" flag. flags |= SilenceEntry::SF_DEFAULT; } } return is_remove ? RemoveSilence(user, mask, flags) : AddSilence(user, mask, flags); } }; class ModuleSilence : public Module , public CTCTags::EventListener { private: bool exemptuline; CommandSilence cmd; ModResult BuildChannelExempts(User* source, Channel* channel, SilenceEntry::SilenceFlags flag, CUList& exemptions) { const Channel::MemberMap& members = channel->GetUsers(); for (Channel::MemberMap::const_iterator member = members.begin(); member != members.end(); ++member) { if (!CanReceiveMessage(source, member->first, flag)) exemptions.insert(member->first); } return MOD_RES_PASSTHRU; } bool CanReceiveMessage(User* source, User* target, SilenceEntry::SilenceFlags flag) { // Servers handle their own clients. if (!IS_LOCAL(target)) return true; if (exemptuline && source->server->IsULine()) return true; SilenceList* list = cmd.ext.get(target); if (!list) return true; for (SilenceList::iterator iter = list->begin(); iter != list->end(); ++iter) { if (!(iter->flags & flag)) continue; if (InspIRCd::Match(source->GetFullHost(), iter->mask)) return iter->flags & SilenceEntry::SF_EXEMPT; } return true; } public: ModuleSilence() : CTCTags::EventListener(this) , cmd(this) { } void ReadConfig(ConfigStatus& status) CXX11_OVERRIDE { ConfigTag* tag = ServerInstance->Config->ConfValue("silence"); exemptuline = tag->getBool("exemptuline", true); cmd.ext.maxsilence = tag->getUInt("maxentries", 32, 1); } void On005Numeric(std::map<std::string, std::string>& tokens) CXX11_OVERRIDE { tokens["ESILENCE"] = "CcdiNnPpTtx"; tokens["SILENCE"] = ConvToStr(cmd.ext.maxsilence); } ModResult OnUserPreInvite(User* source, User* dest, Channel* channel, time_t timeout) CXX11_OVERRIDE { return CanReceiveMessage(source, dest, SilenceEntry::SF_INVITE) ? MOD_RES_PASSTHRU : MOD_RES_DENY; } ModResult OnUserPreMessage(User* user, const MessageTarget& target, MessageDetails& details) CXX11_OVERRIDE { std::string ctcpname; bool is_ctcp = details.IsCTCP(ctcpname) && !irc::equals(ctcpname, "ACTION"); SilenceEntry::SilenceFlags flag = SilenceEntry::SF_NONE; switch (target.type) { case MessageTarget::TYPE_CHANNEL: { if (is_ctcp) flag = SilenceEntry::SF_CTCP_CHANNEL; else if (details.type == MSG_NOTICE) flag = SilenceEntry::SF_NOTICE_CHANNEL; else if (details.type == MSG_PRIVMSG) flag = SilenceEntry::SF_PRIVMSG_CHANNEL; return BuildChannelExempts(user, target.Get<Channel>(), flag, details.exemptions); break; } case MessageTarget::TYPE_USER: { if (is_ctcp) flag = SilenceEntry::SF_CTCP_USER; else if (details.type == MSG_NOTICE) flag = SilenceEntry::SF_NOTICE_USER; else if (details.type == MSG_PRIVMSG) flag = SilenceEntry::SF_PRIVMSG_USER; if (!CanReceiveMessage(user, target.Get<User>(), flag)) { details.echo_original = true; return MOD_RES_DENY; } break; } case MessageTarget::TYPE_SERVER: break; } return MOD_RES_PASSTHRU; } ModResult OnUserPreTagMessage(User* user, const MessageTarget& target, CTCTags::TagMessageDetails& details) CXX11_OVERRIDE { if (target.type == MessageTarget::TYPE_CHANNEL) return BuildChannelExempts(user, target.Get<Channel>(), SilenceEntry::SF_TAGMSG_CHANNEL, details.exemptions); if (target.type == MessageTarget::TYPE_USER && !CanReceiveMessage(user, target.Get<User>(), SilenceEntry::SF_TAGMSG_USER)) { details.echo_original = true; return MOD_RES_DENY; } return MOD_RES_PASSTHRU; } Version GetVersion() CXX11_OVERRIDE { return Version("Provides support for blocking users with the SILENCE command", VF_OPTCOMMON | VF_VENDOR); } }; MODULE_INIT(ModuleSilence) �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/src/modules/m_spanningtree/����������������������������������������������������������0000775�0000000�0000000�00000000000�13554550454�0020613�5����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/src/modules/m_spanningtree/addline.cpp�����������������������������������������������0000664�0000000�0000000�00000005122�13554550454�0022717�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * InspIRCd -- Internet Relay Chat Daemon * * Copyright (C) 2008 Robin Burchell <robin+git@viroteck.net> * * 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 "inspircd.h" #include "xline.h" #include "treeserver.h" #include "utils.h" #include "commands.h" CmdResult CommandAddLine::Handle(User* usr, Params& params) { XLineFactory* xlf = ServerInstance->XLines->GetFactory(params[0]); const std::string& setter = usr->nick; if (!xlf) { ServerInstance->SNO->WriteToSnoMask('x', "%s sent me an unknown ADDLINE type (%s).", setter.c_str(), params[0].c_str()); return CMD_FAILURE; } XLine* xl = NULL; try { xl = xlf->Generate(ServerInstance->Time(), ConvToNum<unsigned long>(params[4]), params[2], params[5], params[1]); } catch (ModuleException &e) { ServerInstance->SNO->WriteToSnoMask('x', "Unable to ADDLINE type %s from %s: %s", params[0].c_str(), setter.c_str(), e.GetReason().c_str()); return CMD_FAILURE; } xl->SetCreateTime(ConvToNum<time_t>(params[3])); if (ServerInstance->XLines->AddLine(xl, NULL)) { if (xl->duration) { ServerInstance->SNO->WriteToSnoMask('X', "%s added timed %s%s for %s, expires in %s (on %s): %s", setter.c_str(), params[0].c_str(), params[0].length() == 1 ? "-line" : "", params[1].c_str(), InspIRCd::DurationString(xl->duration).c_str(), InspIRCd::TimeString(xl->expiry).c_str(), params[5].c_str()); } else { ServerInstance->SNO->WriteToSnoMask('X', "%s added permanent %s%s on %s: %s", setter.c_str(), params[0].c_str(), params[0].length() == 1 ? "-line" : "", params[1].c_str(), params[5].c_str()); } TreeServer* remoteserver = TreeServer::Get(usr); if (!remoteserver->IsBursting()) { ServerInstance->XLines->ApplyLines(); } return CMD_SUCCESS; } else { delete xl; return CMD_FAILURE; } } CommandAddLine::Builder::Builder(XLine* xline, User* user) : CmdBuilder(user, "ADDLINE") { push(xline->type); push(xline->Displayable()); push(xline->source); push_int(xline->set_time); push_int(xline->duration); push_last(xline->reason); } ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/src/modules/m_spanningtree/away.cpp��������������������������������������������������0000664�0000000�0000000�00000002641�13554550454�0022263�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * InspIRCd -- Internet Relay Chat Daemon * * Copyright (C) 2009 Daniel De Graaf <danieldg@inspircd.org> * * This file is part of InspIRCd. InspIRCd is free software: you can * redistribute it and/or modify it under the terms of the GNU General Public * License as published by the Free Software Foundation, version 2. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include "inspircd.h" #include "main.h" #include "utils.h" #include "commands.h" CmdResult CommandAway::HandleRemote(::RemoteUser* u, Params& params) { if (!params.empty()) { if (params.size() > 1) u->awaytime = ConvToNum<time_t>(params[0]); else u->awaytime = ServerInstance->Time(); u->awaymsg = params.back(); FOREACH_MOD_CUSTOM(awayevprov, Away::EventListener, OnUserAway, (u)); } else { u->awaytime = 0; u->awaymsg.clear(); FOREACH_MOD_CUSTOM(awayevprov, Away::EventListener, OnUserBack, (u)); } return CMD_SUCCESS; } CommandAway::Builder::Builder(User* user) : CmdBuilder(user, "AWAY") { if (!user->awaymsg.empty()) push_int(user->awaytime).push_last(user->awaymsg); } �����������������������������������������������������������������������������������������������inspircd-3.4.0/src/modules/m_spanningtree/cachetimer.h����������������������������������������������0000664�0000000�0000000�00000001646�13554550454�0023077�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * InspIRCd -- Internet Relay Chat Daemon * * Copyright (C) 2008 Craig Edwards <craigedwards@brainbox.cc> * * This file is part of InspIRCd. InspIRCd is free software: you can * redistribute it and/or modify it under the terms of the GNU General Public * License as published by the Free Software Foundation, version 2. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once /** Timer that fires when we need to refresh the IP cache of servers */ class CacheRefreshTimer : public Timer { public: CacheRefreshTimer(); bool Tick(time_t TIME) CXX11_OVERRIDE; }; ������������������������������������������������������������������������������������������inspircd-3.4.0/src/modules/m_spanningtree/capab.cpp�������������������������������������������������0000664�0000000�0000000�00000035334�13554550454�0022375�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * InspIRCd -- Internet Relay Chat Daemon * * Copyright (C) 2009-2010 Daniel De Graaf <danieldg@inspircd.org> * Copyright (C) 2008 Robin Burchell <robin+git@viroteck.net> * Copyright (C) 2008 Craig Edwards <craigedwards@brainbox.cc> * * This file is part of InspIRCd. InspIRCd is free software: you can * redistribute it and/or modify it under the terms of the GNU General Public * License as published by the Free Software Foundation, version 2. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include "inspircd.h" #include "treeserver.h" #include "utils.h" #include "link.h" #include "main.h" struct CompatMod { const char* name; ModuleFlags listflag; }; static CompatMod compatmods[] = { { "m_watch.so", VF_OPTCOMMON } }; std::string TreeSocket::MyModules(int filter) { const ModuleManager::ModuleMap& modlist = ServerInstance->Modules->GetModules(); std::string capabilities; for (ModuleManager::ModuleMap::const_iterator i = modlist.begin(); i != modlist.end(); ++i) { Module* const mod = i->second; // 3.0 advertises its settings for the benefit of services // 2.0 would bork on this if (proto_version < PROTO_INSPIRCD_30 && mod->ModuleSourceFile == "m_kicknorejoin.so") continue; bool do_compat_include = false; if (proto_version < PROTO_INSPIRCD_30) { for (size_t j = 0; j < sizeof(compatmods)/sizeof(compatmods[0]); j++) { if ((compatmods[j].listflag & filter) && (mod->ModuleSourceFile == compatmods[j].name)) { do_compat_include = true; break; } } } Version v = mod->GetVersion(); if ((!do_compat_include) && (!(v.Flags & filter))) continue; capabilities.push_back(' '); capabilities.append(i->first); if (!v.link_data.empty()) { capabilities.push_back('='); capabilities.append(v.link_data); } } // If we are linked in a 2.0 server and have an ascii casemapping // advertise it as m_ascii.so from inspircd-extras if ((filter & VF_COMMON) && ServerInstance->Config->CaseMapping == "ascii" && proto_version == PROTO_INSPIRCD_20) capabilities.append(" m_ascii.so"); if (capabilities.empty()) return capabilities; return capabilities.substr(1); } std::string TreeSocket::BuildModeList(ModeType mtype) { std::vector<std::string> modes; const ModeParser::ModeHandlerMap& mhs = ServerInstance->Modes.GetModes(mtype); for (ModeParser::ModeHandlerMap::const_iterator i = mhs.begin(); i != mhs.end(); ++i) { const ModeHandler* const mh = i->second; const PrefixMode* const pm = mh->IsPrefixMode(); std::string mdesc; if (proto_version >= PROTO_INSPIRCD_30) { if (pm) mdesc.append("prefix:").append(ConvToStr(pm->GetPrefixRank())).push_back(':'); else if (mh->IsListMode()) mdesc.append("list:"); else if (mh->NeedsParam(true)) mdesc.append(mh->NeedsParam(false) ? "param:" : "param-set:"); else mdesc.append("simple:"); } mdesc.append(mh->name); mdesc.push_back('='); if (pm) { if (pm->GetPrefix()) mdesc.push_back(pm->GetPrefix()); } mdesc.push_back(mh->GetModeChar()); modes.push_back(mdesc); } std::sort(modes.begin(), modes.end()); return stdalgo::string::join(modes); } void TreeSocket::SendCapabilities(int phase) { if (capab->capab_phase >= phase) return; if (capab->capab_phase < 1 && phase >= 1) WriteLine("CAPAB START " + ConvToStr(PROTO_NEWEST)); capab->capab_phase = phase; if (phase < 2) return; const char sep = ' '; irc::sepstream modulelist(MyModules(VF_COMMON), sep); irc::sepstream optmodulelist(MyModules(VF_OPTCOMMON), sep); /* Send module names, split at 509 length */ std::string item; std::string line = "CAPAB MODULES :"; while (modulelist.GetToken(item)) { if (line.length() + item.length() + 1 > 509) { this->WriteLine(line); line = "CAPAB MODULES :"; } if (line != "CAPAB MODULES :") line.push_back(sep); line.append(item); } if (line != "CAPAB MODULES :") this->WriteLine(line); line = "CAPAB MODSUPPORT :"; while (optmodulelist.GetToken(item)) { if (line.length() + item.length() + 1 > 509) { this->WriteLine(line); line = "CAPAB MODSUPPORT :"; } if (line != "CAPAB MODSUPPORT :") line.push_back(sep); line.append(item); } if (line != "CAPAB MODSUPPORT :") this->WriteLine(line); WriteLine("CAPAB CHANMODES :" + BuildModeList(MODETYPE_CHANNEL)); WriteLine("CAPAB USERMODES :" + BuildModeList(MODETYPE_USER)); std::string extra; /* Do we have sha256 available? If so, we send a challenge */ if (ServerInstance->Modules->FindService(SERVICE_DATA, "hash/sha256")) { SetOurChallenge(ServerInstance->GenRandomStr(20)); extra = " CHALLENGE=" + this->GetOurChallenge(); } // 2.0 needs these keys. if (proto_version == PROTO_INSPIRCD_20) { extra.append(" PROTOCOL="+ConvToStr(proto_version)) .append(" MAXGECOS="+ConvToStr(ServerInstance->Config->Limits.MaxReal)) .append(" CHANMODES="+ServerInstance->Modes->GiveModeList(MODETYPE_CHANNEL)) .append(" USERMODES="+ServerInstance->Modes->GiveModeList(MODETYPE_USER)) .append(" PREFIX="+ ServerInstance->Modes->BuildPrefixes()); } this->WriteLine("CAPAB CAPABILITIES " /* Preprocessor does this one. */ ":NICKMAX="+ConvToStr(ServerInstance->Config->Limits.NickMax)+ " CHANMAX="+ConvToStr(ServerInstance->Config->Limits.ChanMax)+ " MAXMODES="+ConvToStr(ServerInstance->Config->Limits.MaxModes)+ " IDENTMAX="+ConvToStr(ServerInstance->Config->Limits.IdentMax)+ " MAXQUIT="+ConvToStr(ServerInstance->Config->Limits.MaxQuit)+ " MAXTOPIC="+ConvToStr(ServerInstance->Config->Limits.MaxTopic)+ " MAXKICK="+ConvToStr(ServerInstance->Config->Limits.MaxKick)+ " MAXREAL="+ConvToStr(ServerInstance->Config->Limits.MaxReal)+ " MAXAWAY="+ConvToStr(ServerInstance->Config->Limits.MaxAway)+ " MAXHOST="+ConvToStr(ServerInstance->Config->Limits.MaxHost)+ extra+ " CASEMAPPING="+ServerInstance->Config->CaseMapping+ // XXX: Advertise the presence or absence of m_globops in CAPAB CAPABILITIES. // Services want to know about it, and since m_globops was not marked as VF_(OPT)COMMON // in 2.0, we advertise it here to not break linking to previous versions. // Protocol version 1201 (1.2) does not have this issue because we advertise m_globops // to 1201 protocol servers irrespectively of its module flags. (ServerInstance->Modules->Find("m_globops.so") != NULL ? " GLOBOPS=1" : " GLOBOPS=0") ); this->WriteLine("CAPAB END"); } /* Isolate and return the elements that are different between two comma seperated lists */ void TreeSocket::ListDifference(const std::string &one, const std::string &two, char sep, std::string& mleft, std::string& mright) { std::set<std::string> values; irc::sepstream sepleft(one, sep); irc::sepstream sepright(two, sep); std::string item; while (sepleft.GetToken(item)) { values.insert(item); } while (sepright.GetToken(item)) { if (!values.erase(item)) { mright.push_back(sep); mright.append(item); } } for(std::set<std::string>::iterator i = values.begin(); i != values.end(); ++i) { mleft.push_back(sep); mleft.append(*i); } } bool TreeSocket::Capab(const CommandBase::Params& params) { if (params.size() < 1) { this->SendError("Invalid number of parameters for CAPAB - Mismatched version"); return false; } if (params[0] == "START") { capab->ModuleList.clear(); capab->OptModuleList.clear(); capab->CapKeys.clear(); if (params.size() > 1) proto_version = ConvToNum<unsigned int>(params[1]); if (proto_version < PROTO_OLDEST) { SendError("CAPAB negotiation failed: Server is using protocol version " + (proto_version ? ConvToStr(proto_version) : "1201 or older") + " which is too old to link with this server (protocol versions " + ConvToStr(PROTO_OLDEST) + " to " + ConvToStr(PROTO_NEWEST) + " are supported)"); return false; } // We don't support the 2.1 protocol. if (proto_version == PROTO_INSPIRCD_21_A0 || proto_version == PROTO_INSPIRCD_21_B2) { SendError("CAPAB negotiation failed: InspIRCd 2.1 beta is not supported"); return false; } SendCapabilities(2); } else if (params[0] == "END") { std::string reason; /* Compare ModuleList and check CapKeys */ if ((this->capab->ModuleList != this->MyModules(VF_COMMON)) && (this->capab->ModuleList.length())) { std::string diffIneed, diffUneed; ListDifference(this->capab->ModuleList, this->MyModules(VF_COMMON), ' ', diffIneed, diffUneed); if (diffIneed.length() || diffUneed.length()) { reason = "Modules incorrectly matched on these servers."; if (diffIneed.length()) reason += " Not loaded here:" + diffIneed; if (diffUneed.length()) reason += " Not loaded there:" + diffUneed; this->SendError("CAPAB negotiation failed: "+reason); return false; } } if (this->capab->OptModuleList != this->MyModules(VF_OPTCOMMON) && this->capab->OptModuleList.length()) { std::string diffIneed, diffUneed; ListDifference(this->capab->OptModuleList, this->MyModules(VF_OPTCOMMON), ' ', diffIneed, diffUneed); if (diffIneed.length() || diffUneed.length()) { if (Utils->AllowOptCommon) { ServerInstance->SNO->WriteToSnoMask('l', "Optional module lists do not match, some commands may not work globally.%s%s%s%s", diffIneed.length() ? " Not loaded here:" : "", diffIneed.c_str(), diffUneed.length() ? " Not loaded there:" : "", diffUneed.c_str()); } else { reason = "Optional modules incorrectly matched on these servers and <options:allowmismatch> is not enabled."; if (diffIneed.length()) reason += " Not loaded here:" + diffIneed; if (diffUneed.length()) reason += " Not loaded there:" + diffUneed; this->SendError("CAPAB negotiation failed: "+reason); return false; } } } if (!capab->ChanModes.empty()) { if (capab->ChanModes != BuildModeList(MODETYPE_CHANNEL)) { std::string diffIneed, diffUneed; ListDifference(capab->ChanModes, BuildModeList(MODETYPE_CHANNEL), ' ', diffIneed, diffUneed); if (diffIneed.length() || diffUneed.length()) { reason = "Channel modes not matched on these servers."; if (diffIneed.length()) reason += " Not loaded here:" + diffIneed; if (diffUneed.length()) reason += " Not loaded there:" + diffUneed; } } } else if (proto_version == PROTO_INSPIRCD_20) { if (this->capab->CapKeys.find("CHANMODES") != this->capab->CapKeys.end()) { if (this->capab->CapKeys.find("CHANMODES")->second != ServerInstance->Modes->GiveModeList(MODETYPE_CHANNEL)) reason = "One or more of the channel modes on the remote server are invalid on this server."; } else if (this->capab->CapKeys.find("PREFIX") != this->capab->CapKeys.end()) { if (this->capab->CapKeys.find("PREFIX")->second != ServerInstance->Modes->BuildPrefixes()) reason = "One or more of the prefixes on the remote server are invalid on this server."; } } if (!reason.empty()) { this->SendError("CAPAB negotiation failed: " + reason); return false; } if (!capab->UserModes.empty()) { if (capab->UserModes != BuildModeList(MODETYPE_USER)) { std::string diffIneed, diffUneed; ListDifference(capab->UserModes, BuildModeList(MODETYPE_USER), ' ', diffIneed, diffUneed); if (diffIneed.length() || diffUneed.length()) { reason = "User modes not matched on these servers."; if (diffIneed.length()) reason += " Not loaded here:" + diffIneed; if (diffUneed.length()) reason += " Not loaded there:" + diffUneed; } } } else if (proto_version == PROTO_INSPIRCD_20 && this->capab->CapKeys.find("USERMODES") != this->capab->CapKeys.end()) { if (this->capab->CapKeys.find("USERMODES")->second != ServerInstance->Modes->GiveModeList(MODETYPE_USER)) reason = "One or more of the user modes on the remote server are invalid on this server."; } if (!reason.empty()) { this->SendError("CAPAB negotiation failed: " + reason); return false; } if (this->capab->CapKeys.find("CASEMAPPING") != this->capab->CapKeys.end()) { const std::string casemapping = this->capab->CapKeys.find("CASEMAPPING")->second; if (casemapping != ServerInstance->Config->CaseMapping) { reason = "The casemapping of the remote server differs to that of the local server." " Local casemapping: " + ServerInstance->Config->CaseMapping + " Remote casemapping: " + casemapping; this->SendError("CAPAB negotiation failed: " + reason); return false; } } /* Challenge response, store their challenge for our password */ std::map<std::string,std::string>::iterator n = this->capab->CapKeys.find("CHALLENGE"); if ((n != this->capab->CapKeys.end()) && (ServerInstance->Modules->FindService(SERVICE_DATA, "hash/sha256"))) { /* Challenge-response is on now */ this->SetTheirChallenge(n->second); if (!this->GetTheirChallenge().empty() && (this->LinkState == CONNECTING)) { this->SendCapabilities(2); this->WriteLine("SERVER "+ServerInstance->Config->ServerName+" "+this->MakePass(capab->link->SendPass, capab->theirchallenge)+" 0 "+ServerInstance->Config->GetSID()+" :"+ServerInstance->Config->ServerDesc); } } else { // They didn't specify a challenge or we don't have sha256, we use plaintext if (this->LinkState == CONNECTING) { this->SendCapabilities(2); this->WriteLine("SERVER "+ServerInstance->Config->ServerName+" "+capab->link->SendPass+" 0 "+ServerInstance->Config->GetSID()+" :"+ServerInstance->Config->ServerDesc); } } } else if ((params[0] == "MODULES") && (params.size() == 2)) { if (!capab->ModuleList.length()) { capab->ModuleList = params[1]; } else { capab->ModuleList.push_back(' '); capab->ModuleList.append(params[1]); } } else if ((params[0] == "MODSUPPORT") && (params.size() == 2)) { if (!capab->OptModuleList.length()) { capab->OptModuleList = params[1]; } else { capab->OptModuleList.push_back(' '); capab->OptModuleList.append(params[1]); } } else if ((params[0] == "CHANMODES") && (params.size() == 2)) { capab->ChanModes = params[1]; } else if ((params[0] == "USERMODES") && (params.size() == 2)) { capab->UserModes = params[1]; } else if ((params[0] == "CAPABILITIES") && (params.size() == 2)) { irc::spacesepstream capabs(params[1]); std::string item; while (capabs.GetToken(item)) { /* Process each key/value pair */ std::string::size_type equals = item.find('='); if (equals != std::string::npos) { std::string var(item, 0, equals); std::string value(item, equals+1); capab->CapKeys[var] = value; } } } return true; } ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/src/modules/m_spanningtree/commandbuilder.h������������������������������������������0000664�0000000�0000000�00000007443�13554550454�0023761�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * InspIRCd -- Internet Relay Chat Daemon * * Copyright (C) 2013 Attila Molnar <attilamolnar@hush.com> * * This file is part of InspIRCd. InspIRCd is free software: you can * redistribute it and/or modify it under the terms of the GNU General Public * License as published by the Free Software Foundation, version 2. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include "utils.h" class TreeServer; class CmdBuilder { protected: /** The raw message contents. */ std::string content; /** Tags which have been added to this message. */ ClientProtocol::TagMap tags; /** The size of tags within the contents. */ size_t tagsize; /** Fires the ServerProtocol::MessageEventListener::OnBuildMessage event for a server target. */ void FireEvent(Server* target, const char* cmd, ClientProtocol::TagMap& taglist); /** Fires the ServerProtocol::MessageEventListener::OnBuildMessage event for a user target. */ void FireEvent(User* target, const char* cmd, ClientProtocol::TagMap& taglist); /** Updates the tag string within the buffer. */ void UpdateTags(); public: CmdBuilder(const char* cmd) : content(1, ':') , tagsize(0) { content.append(ServerInstance->Config->GetSID()); push(cmd); FireEvent(ServerInstance->FakeClient->server, cmd, tags); } CmdBuilder(TreeServer* src, const char* cmd) : content(1, ':') , tagsize(0) { content.append(src->GetId()); push(cmd); FireEvent(src, cmd, tags); } CmdBuilder(User* src, const char* cmd) : content(1, ':') , tagsize(0) { content.append(src->uuid); push(cmd); if (InspIRCd::IsSID(src->uuid)) FireEvent(src->server, cmd, tags); else FireEvent(src, cmd, tags); } CmdBuilder& push_raw(const std::string& s) { content.append(s); return *this; } CmdBuilder& push_raw(const char* s) { content.append(s); return *this; } CmdBuilder& push_raw(char c) { content.push_back(c); return *this; } template <typename T> CmdBuilder& push_raw_int(T i) { content.append(ConvToStr(i)); return *this; } template <typename InputIterator> CmdBuilder& push_raw(InputIterator first, InputIterator last) { content.append(first, last); return *this; } CmdBuilder& push(const std::string& s) { content.push_back(' '); content.append(s); return *this; } CmdBuilder& push(const char* s) { content.push_back(' '); content.append(s); return *this; } CmdBuilder& push(char c) { content.push_back(' '); content.push_back(c); return *this; } template <typename T> CmdBuilder& push_int(T i) { content.push_back(' '); content.append(ConvToStr(i)); return *this; } CmdBuilder& push_last(const std::string& s) { content.push_back(' '); content.push_back(':'); content.append(s); return *this; } CmdBuilder& push_tags(ClientProtocol::TagMap newtags) { // It has to be this way around so new tags get priority. newtags.insert(tags.begin(), tags.end()); std::swap(tags, newtags); UpdateTags(); return *this; } template<typename T> CmdBuilder& insert(const T& cont) { for (typename T::const_iterator i = cont.begin(); i != cont.end(); ++i) push(*i); return *this; } const std::string& str() const { return content; } operator const std::string&() const { return str(); } void Broadcast() const { Utils->DoOneToMany(*this); } void Forward(TreeServer* omit) const { Utils->DoOneToAllButSender(*this, omit); } void Unicast(User* target) const { Utils->DoOneToOne(*this, target->server); } }; �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/src/modules/m_spanningtree/commands.h������������������������������������������������0000664�0000000�0000000�00000032052�13554550454�0022567�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * InspIRCd -- Internet Relay Chat Daemon * * Copyright (C) 2010 Daniel De Graaf <danieldg@inspircd.org> * * This file is part of InspIRCd. InspIRCd is free software: you can * redistribute it and/or modify it under the terms of the GNU General Public * License as published by the Free Software Foundation, version 2. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include "servercommand.h" #include "commandbuilder.h" #include "remoteuser.h" #include "modules/away.h" namespace SpanningTree { class CommandAway; class CommandNick; class CommandPing; class CommandPong; class CommandServer; } using SpanningTree::CommandAway; using SpanningTree::CommandNick; using SpanningTree::CommandPing; using SpanningTree::CommandPong; using SpanningTree::CommandServer; /** Handle /RCONNECT */ class CommandRConnect : public Command { public: CommandRConnect(Module* Creator); CmdResult Handle(User* user, const Params& parameters) CXX11_OVERRIDE; RouteDescriptor GetRouting(User* user, const Params& parameters) CXX11_OVERRIDE; }; class CommandRSQuit : public Command { public: CommandRSQuit(Module* Creator); CmdResult Handle(User* user, const Params& parameters) CXX11_OVERRIDE; RouteDescriptor GetRouting(User* user, const Params& parameters) CXX11_OVERRIDE; }; class CommandMap : public Command { public: CommandMap(Module* Creator); CmdResult Handle(User* user, const Params& parameters) CXX11_OVERRIDE; RouteDescriptor GetRouting(User* user, const Params& parameters) CXX11_OVERRIDE; }; class CommandSVSJoin : public ServerCommand { public: CommandSVSJoin(Module* Creator) : ServerCommand(Creator, "SVSJOIN", 2) { } CmdResult Handle(User* user, Params& params) CXX11_OVERRIDE; RouteDescriptor GetRouting(User* user, const Params& parameters) CXX11_OVERRIDE; }; class CommandSVSPart : public ServerCommand { public: CommandSVSPart(Module* Creator) : ServerCommand(Creator, "SVSPART", 2) { } CmdResult Handle(User* user, Params& params) CXX11_OVERRIDE; RouteDescriptor GetRouting(User* user, const Params& parameters) CXX11_OVERRIDE; }; class CommandSVSNick : public ServerCommand { public: CommandSVSNick(Module* Creator) : ServerCommand(Creator, "SVSNICK", 3) { } CmdResult Handle(User* user, Params& params) CXX11_OVERRIDE; RouteDescriptor GetRouting(User* user, const Params& parameters) CXX11_OVERRIDE; }; class CommandMetadata : public ServerCommand { public: CommandMetadata(Module* Creator) : ServerCommand(Creator, "METADATA", 2) { } CmdResult Handle(User* user, Params& params) CXX11_OVERRIDE; class Builder : public CmdBuilder { public: Builder(User* user, const std::string& key, const std::string& val); Builder(Channel* chan, const std::string& key, const std::string& val); Builder(const std::string& key, const std::string& val); }; }; class CommandUID : public ServerOnlyServerCommand<CommandUID> { public: CommandUID(Module* Creator) : ServerOnlyServerCommand<CommandUID>(Creator, "UID", 10) { } CmdResult HandleServer(TreeServer* server, CommandBase::Params& params); class Builder : public CmdBuilder { public: Builder(User* user); }; }; class CommandOpertype : public UserOnlyServerCommand<CommandOpertype> { public: CommandOpertype(Module* Creator) : UserOnlyServerCommand<CommandOpertype>(Creator, "OPERTYPE", 1) { } CmdResult HandleRemote(RemoteUser* user, Params& params); class Builder : public CmdBuilder { public: Builder(User* user); }; }; class TreeSocket; class FwdFJoinBuilder; class CommandFJoin : public ServerCommand { /** Remove all modes from a channel, including statusmodes (+qaovh etc), simplemodes, parameter modes. * This does not update the timestamp of the target channel, this must be done seperately. */ static void RemoveStatus(Channel* c); /** * Lowers the TS on the given channel: removes all modes, unsets all extensions, * clears the topic and removes all pending invites. * @param chan The target channel whose TS to lower * @param TS The new TS to set * @param newname The new name of the channel; must be the same or a case change of the current name */ static void LowerTS(Channel* chan, time_t TS, const std::string& newname); void ProcessModeUUIDPair(const std::string& item, TreeServer* sourceserver, Channel* chan, Modes::ChangeList* modechangelist, FwdFJoinBuilder& fwdfjoin); public: CommandFJoin(Module* Creator) : ServerCommand(Creator, "FJOIN", 3) { } CmdResult Handle(User* user, Params& params) CXX11_OVERRIDE; RouteDescriptor GetRouting(User* user, const Params& parameters) CXX11_OVERRIDE { return ROUTE_LOCALONLY; } class Builder : public CmdBuilder { /** Maximum possible Membership::Id length in decimal digits, used for determining whether a user will fit into * a message or not */ static const size_t membid_max_digits = 20; static const size_t maxline = 510; std::string::size_type pos; protected: void add(Membership* memb, std::string::const_iterator mbegin, std::string::const_iterator mend); bool has_room(std::string::size_type nummodes) const; public: Builder(Channel* chan, TreeServer* source = Utils->TreeRoot); void add(Membership* memb) { add(memb, memb->modes.begin(), memb->modes.end()); } bool has_room(Membership* memb) const { return has_room(memb->modes.size()); } void clear(); const std::string& finalize(); }; }; class CommandFMode : public ServerCommand { public: CommandFMode(Module* Creator) : ServerCommand(Creator, "FMODE", 3) { } CmdResult Handle(User* user, Params& params) CXX11_OVERRIDE; }; class CommandFTopic : public ServerCommand { public: CommandFTopic(Module* Creator) : ServerCommand(Creator, "FTOPIC", 4, 5) { } CmdResult Handle(User* user, Params& params) CXX11_OVERRIDE; class Builder : public CmdBuilder { public: Builder(Channel* chan); Builder(User* user, Channel* chan); }; }; class CommandFHost : public UserOnlyServerCommand<CommandFHost> { public: CommandFHost(Module* Creator) : UserOnlyServerCommand<CommandFHost>(Creator, "FHOST", 1) { } CmdResult HandleRemote(RemoteUser* user, Params& params); }; class CommandFIdent : public UserOnlyServerCommand<CommandFIdent> { public: CommandFIdent(Module* Creator) : UserOnlyServerCommand<CommandFIdent>(Creator, "FIDENT", 1) { } CmdResult HandleRemote(RemoteUser* user, Params& params); }; class CommandFName : public UserOnlyServerCommand<CommandFName> { public: CommandFName(Module* Creator) : UserOnlyServerCommand<CommandFName>(Creator, "FNAME", 1) { } CmdResult HandleRemote(RemoteUser* user, Params& params); }; class CommandIJoin : public UserOnlyServerCommand<CommandIJoin> { public: CommandIJoin(Module* Creator) : UserOnlyServerCommand<CommandIJoin>(Creator, "IJOIN", 2) { } CmdResult HandleRemote(RemoteUser* user, Params& params); }; class CommandResync : public ServerOnlyServerCommand<CommandResync> { public: CommandResync(Module* Creator) : ServerOnlyServerCommand<CommandResync>(Creator, "RESYNC", 1) { } CmdResult HandleServer(TreeServer* server, Params& parameters); RouteDescriptor GetRouting(User* user, const Params& parameters) CXX11_OVERRIDE { return ROUTE_LOCALONLY; } }; class SpanningTree::CommandAway : public UserOnlyServerCommand<SpanningTree::CommandAway> { private: Away::EventProvider awayevprov; public: CommandAway(Module* Creator) : UserOnlyServerCommand<SpanningTree::CommandAway>(Creator, "AWAY", 0, 2) , awayevprov(Creator) { } CmdResult HandleRemote(::RemoteUser* user, Params& parameters); class Builder : public CmdBuilder { public: Builder(User* user); }; }; class XLine; class CommandAddLine : public ServerCommand { public: CommandAddLine(Module* Creator) : ServerCommand(Creator, "ADDLINE", 6, 6) { } CmdResult Handle(User* user, Params& parameters) CXX11_OVERRIDE; class Builder : public CmdBuilder { public: Builder(XLine* xline, User* user = ServerInstance->FakeClient); }; }; class CommandDelLine : public ServerCommand { public: CommandDelLine(Module* Creator) : ServerCommand(Creator, "DELLINE", 2, 2) { } CmdResult Handle(User* user, Params& parameters) CXX11_OVERRIDE; }; class CommandEncap : public ServerCommand { public: CommandEncap(Module* Creator) : ServerCommand(Creator, "ENCAP", 2) { } CmdResult Handle(User* user, Params& parameters) CXX11_OVERRIDE; RouteDescriptor GetRouting(User* user, const Params& parameters) CXX11_OVERRIDE; }; class CommandIdle : public UserOnlyServerCommand<CommandIdle> { public: CommandIdle(Module* Creator) : UserOnlyServerCommand<CommandIdle>(Creator, "IDLE", 1) { } CmdResult HandleRemote(RemoteUser* user, Params& parameters); RouteDescriptor GetRouting(User* user, const Params& parameters) CXX11_OVERRIDE { return ROUTE_UNICAST(parameters[0]); } }; class SpanningTree::CommandNick : public UserOnlyServerCommand<SpanningTree::CommandNick> { public: CommandNick(Module* Creator) : UserOnlyServerCommand<SpanningTree::CommandNick>(Creator, "NICK", 2) { } CmdResult HandleRemote(::RemoteUser* user, Params& parameters); }; class SpanningTree::CommandPing : public ServerCommand { public: CommandPing(Module* Creator) : ServerCommand(Creator, "PING", 1) { } CmdResult Handle(User* user, Params& parameters) CXX11_OVERRIDE; RouteDescriptor GetRouting(User* user, const Params& parameters) CXX11_OVERRIDE { return ROUTE_UNICAST(parameters[0]); } }; class SpanningTree::CommandPong : public ServerOnlyServerCommand<SpanningTree::CommandPong> { public: CommandPong(Module* Creator) : ServerOnlyServerCommand<SpanningTree::CommandPong>(Creator, "PONG", 1) { } CmdResult HandleServer(TreeServer* server, Params& parameters); RouteDescriptor GetRouting(User* user, const Params& parameters) CXX11_OVERRIDE { return ROUTE_UNICAST(parameters[0]); } }; class DllExport CommandSave : public ServerCommand { public: /** Timestamp of the uuid nick of all users who collided and got their nick changed to uuid */ static const time_t SavedTimestamp = 100; CommandSave(Module* Creator) : ServerCommand(Creator, "SAVE", 2) { } CmdResult Handle(User* user, Params& parameters) CXX11_OVERRIDE; }; class SpanningTree::CommandServer : public ServerOnlyServerCommand<SpanningTree::CommandServer> { static void HandleExtra(TreeServer* newserver, Params& params); public: CommandServer(Module* Creator) : ServerOnlyServerCommand<SpanningTree::CommandServer>(Creator, "SERVER", 3) { } CmdResult HandleServer(TreeServer* server, Params& parameters); class Builder : public CmdBuilder { void push_property(const char* key, const std::string& val) { push(key).push_raw('=').push_raw(val); } public: Builder(TreeServer* server); }; }; class CommandSQuit : public ServerOnlyServerCommand<CommandSQuit> { public: CommandSQuit(Module* Creator) : ServerOnlyServerCommand<CommandSQuit>(Creator, "SQUIT", 2) { } CmdResult HandleServer(TreeServer* server, Params& parameters); }; class CommandSNONotice : public ServerCommand { public: CommandSNONotice(Module* Creator) : ServerCommand(Creator, "SNONOTICE", 2) { } CmdResult Handle(User* user, Params& parameters) CXX11_OVERRIDE; }; class CommandEndBurst : public ServerOnlyServerCommand<CommandEndBurst> { public: CommandEndBurst(Module* Creator) : ServerOnlyServerCommand<CommandEndBurst>(Creator, "ENDBURST") { } CmdResult HandleServer(TreeServer* server, Params& parameters); }; class CommandSInfo : public ServerOnlyServerCommand<CommandSInfo> { public: CommandSInfo(Module* Creator) : ServerOnlyServerCommand<CommandSInfo>(Creator, "SINFO", 2) { } CmdResult HandleServer(TreeServer* server, Params& parameters); class Builder : public CmdBuilder { public: Builder(TreeServer* server, const char* type, const std::string& value); }; }; class CommandNum : public ServerOnlyServerCommand<CommandNum> { public: CommandNum(Module* Creator) : ServerOnlyServerCommand<CommandNum>(Creator, "NUM", 3) { } CmdResult HandleServer(TreeServer* server, Params& parameters); RouteDescriptor GetRouting(User* user, const Params& parameters) CXX11_OVERRIDE; class Builder : public CmdBuilder { public: Builder(SpanningTree::RemoteUser* target, const Numeric::Numeric& numeric); }; }; class SpanningTreeCommands { public: CommandSVSJoin svsjoin; CommandSVSPart svspart; CommandSVSNick svsnick; CommandMetadata metadata; CommandUID uid; CommandOpertype opertype; CommandFJoin fjoin; CommandIJoin ijoin; CommandResync resync; CommandFMode fmode; CommandFTopic ftopic; CommandFHost fhost; CommandFIdent fident; CommandFName fname; SpanningTree::CommandAway away; CommandAddLine addline; CommandDelLine delline; CommandEncap encap; CommandIdle idle; SpanningTree::CommandNick nick; SpanningTree::CommandPing ping; SpanningTree::CommandPong pong; CommandSave save; SpanningTree::CommandServer server; CommandSQuit squit; CommandSNONotice snonotice; CommandEndBurst endburst; CommandSInfo sinfo; CommandNum num; SpanningTreeCommands(ModuleSpanningTree* module); }; ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/src/modules/m_spanningtree/compat.cpp������������������������������������������������0000664�0000000�0000000�00000042257�13554550454�0022614�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * InspIRCd -- Internet Relay Chat Daemon * * 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 * 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 "inspircd.h" #include "main.h" #include "treesocket.h" #include "treeserver.h" static std::string newline("\n"); void TreeSocket::WriteLineNoCompat(const std::string& line) { ServerInstance->Logs->Log(MODNAME, LOG_RAWIO, "S[%d] O %s", this->GetFd(), line.c_str()); this->WriteData(line); this->WriteData(newline); } void TreeSocket::WriteLine(const std::string& original_line) { if (LinkState == CONNECTED) { if (proto_version != PROTO_NEWEST) { std::string line = original_line; std::string::size_type a = line.find(' '); if (line[0] == '@') { // The line contains tags which the 1202 protocol can't handle. line.erase(0, a + 1); a = line.find(' '); } std::string::size_type b = line.find(' ', a + 1); std::string command(line, a + 1, b-a-1); // now try to find a translation entry if (proto_version < PROTO_INSPIRCD_30) { if (command == "IJOIN") { // Convert // :<uid> IJOIN <chan> <membid> [<ts> [<flags>]] // to // :<sid> FJOIN <chan> <ts> + [<flags>],<uuid> std::string::size_type c = line.find(' ', b + 1); if (c == std::string::npos) return; std::string::size_type d = line.find(' ', c + 1); // Erase membership id first line.erase(c, d-c); if (d == std::string::npos) { // No TS or modes in the command // :22DAAAAAB IJOIN #chan const std::string channame(line, b+1, c-b-1); Channel* chan = ServerInstance->FindChan(channame); if (!chan) return; line.push_back(' '); line.append(ConvToStr(chan->age)); line.append(" + ,"); } else { d = line.find(' ', c + 1); if (d == std::string::npos) { // TS present, no modes // :22DAAAAAC IJOIN #chan 12345 line.append(" + ,"); } else { // Both TS and modes are present // :22DAAAAAC IJOIN #chan 12345 ov std::string::size_type e = line.find(' ', d + 1); if (e != std::string::npos) line.erase(e); line.insert(d, " +"); line.push_back(','); } } // Move the uuid to the end and replace the I with an F line.append(line.substr(1, 9)); line.erase(4, 6); line[5] = 'F'; } else if (command == "RESYNC") return; else if (command == "METADATA") { // Drop TS for channel METADATA, translate METADATA operquit into an OPERQUIT command // :sid METADATA #target TS extname ... // A B C D if (b == std::string::npos) return; std::string::size_type c = line.find(' ', b + 1); if (c == std::string::npos) return; std::string::size_type d = line.find(' ', c + 1); if (d == std::string::npos) return; if (line[b + 1] == '#') { // We're sending channel metadata line.erase(c, d-c); } else if (!line.compare(c, d-c, " operquit", 9)) { // ":22D METADATA 22DAAAAAX operquit :message" -> ":22DAAAAAX OPERQUIT :message" line = ":" + line.substr(b+1, c-b) + "OPERQUIT" + line.substr(d); } } else if (command == "FTOPIC") { // Drop channel TS for FTOPIC // :sid FTOPIC #target TS TopicTS setter :newtopic // A B C D E F // :uid FTOPIC #target TS TopicTS :newtopic // A B C D E if (b == std::string::npos) return; std::string::size_type c = line.find(' ', b + 1); if (c == std::string::npos) return; std::string::size_type d = line.find(' ', c + 1); if (d == std::string::npos) return; std::string::size_type e = line.find(' ', d + 1); if (line[e+1] == ':') { line.erase(c, e-c); line.erase(a+1, 1); } else line.erase(c, d-c); } else if ((command == "PING") || (command == "PONG")) { // :22D PING 20D if (line.length() < 13) return; // Insert the source SID (and a space) between the command and the first parameter line.insert(10, line.substr(1, 4)); } else if (command == "OPERTYPE") { std::string::size_type colon = line.find(':', b); if (colon != std::string::npos) { for (std::string::iterator i = line.begin()+colon; i != line.end(); ++i) { if (*i == ' ') *i = '_'; } line.erase(colon, 1); } } else if (command == "INVITE") { // :22D INVITE 22DAAAAAN #chan TS ExpirationTime // A B C D E if (b == std::string::npos) return; std::string::size_type c = line.find(' ', b + 1); if (c == std::string::npos) return; std::string::size_type d = line.find(' ', c + 1); if (d == std::string::npos) return; std::string::size_type e = line.find(' ', d + 1); // If there is no expiration time then everything will be erased from 'd' line.erase(d, e-d); } else if (command == "FJOIN") { // Strip membership ids // :22D FJOIN #chan 1234 +f 4:3 :o,22DAAAAAB:15 o,22DAAAAAA:15 // :22D FJOIN #chan 1234 +f 4:3 o,22DAAAAAB:15 // :22D FJOIN #chan 1234 +Pf 4:3 : // If the last parameter is prefixed by a colon then it's a userlist which may have 0 or more users; // if it isn't, then it is a single member std::string::size_type spcolon = line.find(" :"); if (spcolon != std::string::npos) { spcolon++; // Loop while there is a ':' in the userlist, this is never true if the channel is empty std::string::size_type pos = std::string::npos; while ((pos = line.rfind(':', pos-1)) > spcolon) { // Find the next space after the ':' std::string::size_type sp = line.find(' ', pos); // Erase characters between the ':' and the next space after it, including the ':' but not the space; // if there is no next space, everything will be erased between pos and the end of the line line.erase(pos, sp-pos); } } else { // Last parameter is a single member std::string::size_type sp = line.rfind(' '); std::string::size_type colon = line.find(':', sp); line.erase(colon); } } else if (command == "KICK") { // Strip membership id if the KICK has one if (b == std::string::npos) return; std::string::size_type c = line.find(' ', b + 1); if (c == std::string::npos) return; std::string::size_type d = line.find(' ', c + 1); if ((d < line.size()-1) && (original_line[d+1] != ':')) { // There is a third parameter which doesn't begin with a colon, erase it std::string::size_type e = line.find(' ', d + 1); line.erase(d, e-d); } } else if (command == "SINFO") { // :22D SINFO version :InspIRCd-3.0 // A B C std::string::size_type c = line.find(' ', b + 1); if (c == std::string::npos) return; // Only translating SINFO version, discard everything else if (line.compare(b, 9, " version ", 9)) return; line = line.substr(0, 5) + "VERSION" + line.substr(c); } else if (command == "SERVER") { // :001 SERVER inspircd.test 002 [<anything> ...] :description // A B C std::string::size_type c = line.find(' ', b + 1); if (c == std::string::npos) return; std::string::size_type d = c + 4; std::string::size_type spcolon = line.find(" :", d); if (spcolon == std::string::npos) return; line.erase(d, spcolon-d); line.insert(c, " * 0"); if (burstsent) { WriteLineNoCompat(line); // Synthesize a :<newserver> BURST <time> message spcolon = line.find(" :"); TreeServer* const source = Utils->FindServerID(line.substr(spcolon-3, 3)); if (!source) return; line = CmdBuilder(source, "BURST").push_int(ServerInstance->Time()).str(); } } else if (command == "NUM") { // :<sid> NUM <numeric source sid> <target uuid> <3 digit number> <params> // Translate to // :<sid> PUSH <target uuid> :<numeric source name> <3 digit number> <target nick> <params> TreeServer* const numericsource = Utils->FindServerID(line.substr(9, 3)); if (!numericsource) return; // The nick of the target is necessary for building the PUSH message User* const target = ServerInstance->FindUUID(line.substr(13, UIDGenerator::UUID_LENGTH)); if (!target) return; std::string push = InspIRCd::Format(":%.*s PUSH %s ::%s %.*s %s", 3, line.c_str()+1, target->uuid.c_str(), numericsource->GetName().c_str(), 3, line.c_str()+23, target->nick.c_str()); push.append(line, 26, std::string::npos); push.swap(line); } else if (command == "TAGMSG") { // Drop IRCv3 tag messages as v2 has no message tag support. return; } } WriteLineNoCompat(line); return; } } WriteLineNoCompat(original_line); } namespace { bool InsertCurrentChannelTS(CommandBase::Params& params, unsigned int chanindex = 0, unsigned int pos = 1) { Channel* chan = ServerInstance->FindChan(params[chanindex]); if (!chan) return false; // Insert the current TS of the channel after the pos-th parameter params.insert(params.begin()+pos, ConvToStr(chan->age)); return true; } } bool TreeSocket::PreProcessOldProtocolMessage(User*& who, std::string& cmd, CommandBase::Params& params) { if ((cmd == "METADATA") && (params.size() >= 3) && (params[0][0] == '#')) { // :20D METADATA #channel extname :extdata return InsertCurrentChannelTS(params); } else if ((cmd == "FTOPIC") && (params.size() >= 4)) { // :20D FTOPIC #channel 100 Attila :topic text return InsertCurrentChannelTS(params); } else if ((cmd == "PING") || (cmd == "PONG")) { if (params.size() == 1) { // If it's a PING with 1 parameter, reply with a PONG now, if it's a PONG with 1 parameter (weird), do nothing if (cmd[1] == 'I') this->WriteData(":" + ServerInstance->Config->GetSID() + " PONG " + params[0] + newline); // Don't process this message further return false; } // :20D PING 20D 22D // :20D PONG 20D 22D // Drop the first parameter params.erase(params.begin()); // If the target is a server name, translate it to a SID if (!InspIRCd::IsSID(params[0])) { TreeServer* server = Utils->FindServer(params[0]); if (!server) { // We've no idea what this is, log and stop processing ServerInstance->Logs->Log(MODNAME, LOG_DEFAULT, "Received a " + cmd + " with an unknown target: \"" + params[0] + "\", command dropped"); return false; } params[0] = server->GetId(); } } else if ((cmd == "GLINE") || (cmd == "KLINE") || (cmd == "ELINE") || (cmd == "ZLINE") || (cmd == "QLINE")) { // Fix undocumented protocol usage: translate GLINE, ZLINE, etc. into ADDLINE or DELLINE if ((params.size() != 1) && (params.size() != 3)) return false; CommandBase::Params p; p.push_back(cmd.substr(0, 1)); p.push_back(params[0]); if (params.size() == 3) { cmd = "ADDLINE"; p.push_back(who->nick); p.push_back(ConvToStr(ServerInstance->Time())); p.push_back(ConvToStr(InspIRCd::Duration(params[1]))); p.push_back(params[2]); } else cmd = "DELLINE"; params.swap(p); } else if (cmd == "SVSMODE") { cmd = "MODE"; } else if (cmd == "OPERQUIT") { // Translate OPERQUIT into METADATA if (params.empty()) return false; cmd = "METADATA"; params.insert(params.begin(), who->uuid); params.insert(params.begin()+1, "operquit"); who = MyRoot->ServerUser; } else if ((cmd == "TOPIC") && (params.size() >= 2)) { // :20DAAAAAC TOPIC #chan :new topic cmd = "FTOPIC"; if (!InsertCurrentChannelTS(params)) return false; params.insert(params.begin()+2, ConvToStr(ServerInstance->Time())); } else if (cmd == "MODENOTICE") { // MODENOTICE is always supported by 2.0 but it's optional in 3.0. params.insert(params.begin(), "*"); params.insert(params.begin()+1, cmd); cmd = "ENCAP"; } else if (cmd == "RULES") { return false; } else if (cmd == "INVITE") { // :20D INVITE 22DAAABBB #chan // :20D INVITE 22DAAABBB #chan 123456789 // Insert channel timestamp after the channel name; the 3rd parameter, if there, is the invite expiration time return InsertCurrentChannelTS(params, 1, 2); } else if (cmd == "VERSION") { // :20D VERSION :InspIRCd-2.0 // change to // :20D SINFO version :InspIRCd-2.0 cmd = "SINFO"; params.insert(params.begin(), "version"); } else if (cmd == "JOIN") { // 2.0 allows and forwards legacy JOINs but we don't, so translate them to FJOINs before processing if ((params.size() != 1) || (IS_SERVER(who))) return false; // Huh? cmd = "FJOIN"; Channel* chan = ServerInstance->FindChan(params[0]); params.push_back(ConvToStr(chan ? chan->age : ServerInstance->Time())); params.push_back("+"); params.push_back(","); params.back().append(who->uuid); who = TreeServer::Get(who)->ServerUser; } else if ((cmd == "FMODE") && (params.size() >= 2)) { // Translate user mode changes with timestamp to MODE if (params[0][0] != '#') { User* user = ServerInstance->FindUUID(params[0]); if (!user) return false; // Emulate the old nonsensical behavior if (user->age < ServerCommand::ExtractTS(params[1])) return false; cmd = "MODE"; params.erase(params.begin()+1); } } else if ((cmd == "SERVER") && (params.size() > 4)) { // This does not affect the initial SERVER line as it is sent before the link state is CONNECTED // :20D SERVER <name> * 0 <sid> <desc> // change to // :20D SERVER <name> <sid> <desc> params[1].swap(params[3]); params.erase(params.begin()+2, params.begin()+4); // If the source of this SERVER message or any of its parents are bursting, then new servers it // introduces are not bursting. bool bursting = false; for (TreeServer* server = TreeServer::Get(who); server; server = server->GetParent()) { if (server->IsBursting()) { bursting = true; break; } } if (!bursting) params.insert(params.begin()+2, "burst=" + ConvToStr(((uint64_t)ServerInstance->Time())*1000)); } else if (cmd == "BURST") { // A server is introducing another one, drop unnecessary BURST return false; } else if (cmd == "SVSWATCH") { // SVSWATCH was removed because nothing was using it, but better be sure return false; } else if (cmd == "SVSSILENCE") { // SVSSILENCE was removed because nothing was using it, but better be sure return false; } else if (cmd == "PUSH") { if ((params.size() != 2) || (!this->MyRoot)) return false; // Huh? irc::tokenstream ts(params.back()); std::string srcstr; ts.GetMiddle(srcstr); srcstr.erase(0, 1); std::string token; ts.GetMiddle(token); // See if it's a numeric being sent to the target via PUSH unsigned int numeric_number = 0; if (token.length() == 3) numeric_number = ConvToNum<unsigned int>(token); if ((numeric_number > 0) && (numeric_number < 1000)) { // It's a numeric, translate to NUM // srcstr must be a valid server name TreeServer* const numericsource = Utils->FindServer(srcstr); if (!numericsource) { ServerInstance->Logs->Log(MODNAME, LOG_DEBUG, "Unable to translate PUSH numeric %s to user %s from 1202 protocol server %s: source \"%s\" doesn't exist", token.c_str(), params[0].c_str(), this->MyRoot->GetName().c_str(), srcstr.c_str()); return false; } cmd = "NUM"; // Second parameter becomes the target uuid params[0].swap(params[1]); // Replace first param (now the PUSH payload, not needed) with the source sid params[0] = numericsource->GetId(); params.push_back(InspIRCd::Format("%03u", numeric_number)); // Ignore the nickname in the numeric in PUSH ts.GetMiddle(token); // Rest of the tokens are the numeric parameters, add them to NUM while (ts.GetTrailing(token)) params.push_back(token); } else if ((token == "PRIVMSG") || (token == "NOTICE")) { // Command is a PRIVMSG/NOTICE cmd.swap(token); // Check if the PRIVMSG/NOTICE target is a nickname ts.GetMiddle(token); if (token.c_str()[0] == '#') { ServerInstance->Logs->Log(MODNAME, LOG_DEBUG, "Unable to translate PUSH %s to user %s from 1202 protocol server %s, target \"%s\"", cmd.c_str(), params[0].c_str(), this->MyRoot->GetName().c_str(), token.c_str()); return false; } // Replace second parameter with the message ts.GetTrailing(params[1]); } else { ServerInstance->Logs->Log(MODNAME, LOG_DEFAULT, "Unable to translate PUSH to user %s from 1202 protocol server %s", params[0].c_str(), this->MyRoot->GetName().c_str()); return false; } return true; } return true; // Passthru } �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/src/modules/m_spanningtree/delline.cpp�����������������������������������������������0000664�0000000�0000000�00000002454�13554550454�0022740�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * InspIRCd -- Internet Relay Chat Daemon * * Copyright (C) 2008 Robin Burchell <robin+git@viroteck.net> * * 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 "inspircd.h" #include "xline.h" #include "commands.h" CmdResult CommandDelLine::Handle(User* user, Params& params) { const std::string& setter = user->nick; std::string reason; // XLineManager::DelLine() returns true if the xline existed, false if it didn't if (ServerInstance->XLines->DelLine(params[1].c_str(), params[0], reason, user)) { ServerInstance->SNO->WriteToSnoMask('X', "%s removed %s%s on %s: %s", setter.c_str(), params[0].c_str(), params[0].length() == 1 ? "-line" : "", params[1].c_str(), reason.c_str()); return CMD_SUCCESS; } return CMD_FAILURE; } ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/src/modules/m_spanningtree/encap.cpp�������������������������������������������������0000664�0000000�0000000�00000003503�13554550454�0022406�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * InspIRCd -- Internet Relay Chat Daemon * * Copyright (C) 2008 Craig Edwards <craigedwards@brainbox.cc> * * This file is part of InspIRCd. InspIRCd is free software: you can * redistribute it and/or modify it under the terms of the GNU General Public * License as published by the Free Software Foundation, version 2. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include "inspircd.h" #include "commands.h" #include "main.h" /** ENCAP */ CmdResult CommandEncap::Handle(User* user, Params& params) { if (ServerInstance->Config->GetSID() == params[0] || InspIRCd::Match(ServerInstance->Config->ServerName, params[0])) { CommandBase::Params plist(params.begin() + 2, params.end()); // XXX: Workaround for SVS* commands provided by spanningtree not being registered in the core if ((params[1] == "SVSNICK") || (params[1] == "SVSJOIN") || (params[1] == "SVSPART")) { ServerCommand* const scmd = Utils->Creator->CmdManager.GetHandler(params[1]); if (scmd) scmd->Handle(user, plist); return CMD_SUCCESS; } Command* cmd = NULL; ServerInstance->Parser.CallHandler(params[1], plist, user, &cmd); // Discard return value, ENCAP shall succeed even if the command does not exist if ((cmd) && (cmd->force_manual_route)) return CMD_FAILURE; } return CMD_SUCCESS; } RouteDescriptor CommandEncap::GetRouting(User* user, const Params& params) { if (params[0].find_first_of("*?") != std::string::npos) return ROUTE_BROADCAST; return ROUTE_UNICAST(params[0]); } ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/src/modules/m_spanningtree/fjoin.cpp�������������������������������������������������0000664�0000000�0000000�00000031527�13554550454�0022434�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * InspIRCd -- Internet Relay Chat Daemon * * Copyright (C) 2009-2010 Daniel De Graaf <danieldg@inspircd.org> * Copyright (C) 2008 Robin Burchell <robin+git@viroteck.net> * Copyright (C) 2008 Dennis Friis <peavey@inspircd.org> * Copyright (C) 2008 Craig Edwards <craigedwards@brainbox.cc> * * This file is part of InspIRCd. InspIRCd is free software: you can * redistribute it and/or modify it under the terms of the GNU General Public * License as published by the Free Software Foundation, version 2. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include "inspircd.h" #include "commands.h" #include "treeserver.h" #include "treesocket.h" /** FJOIN builder for rebuilding incoming FJOINs and splitting them up into multiple messages if necessary */ class FwdFJoinBuilder : public CommandFJoin::Builder { TreeServer* const sourceserver; public: FwdFJoinBuilder(Channel* chan, TreeServer* server) : CommandFJoin::Builder(chan, server) , sourceserver(server) { } void add(Membership* memb, std::string::const_iterator mbegin, std::string::const_iterator mend); }; /** FJOIN, almost identical to TS6 SJOIN, except for nicklist handling. */ CmdResult CommandFJoin::Handle(User* srcuser, Params& params) { /* 1.1+ FJOIN works as follows: * * Each FJOIN is sent along with a timestamp, and the side with the lowest * timestamp 'wins'. From this point on we will refer to this side as the * winner. The side with the higher timestamp loses, from this point on we * will call this side the loser or losing side. This should be familiar to * anyone who's dealt with dreamforge or TS6 before. * * When two sides of a split heal and this occurs, the following things * will happen: * * If the timestamps are exactly equal, both sides merge their privilages * and users, as in InspIRCd 1.0 and ircd2.8. The channels have not been * re-created during a split, this is safe to do. * * If the timestamps are NOT equal, the losing side removes all of its * modes from the channel, before introducing new users into the channel * which are listed in the FJOIN command's parameters. The losing side then * LOWERS its timestamp value of the channel to match that of the winning * side, and the modes of the users of the winning side are merged in with * the losing side. * * The winning side on the other hand will ignore all user modes from the * losing side, so only its own modes get applied. Life is simple for those * who succeed at internets. :-) * * Outside of netbursts, the winning side also resyncs the losing side if it * detects that the other side recreated the channel. * * Syntax: * :<sid> FJOIN <chan> <TS> <modes> :[<member> [<member> ...]] * The last parameter is a list consisting of zero or more channel members * (permanent channels may have zero users). Each entry on the list is in the * following format: * [[<modes>,]<uuid>[:<membid>] * <modes> is a concatenation of the mode letters the user has on the channel * (e.g.: "ov" if the user is opped and voiced). The order of the mode letters * are not important but if a server ecounters an unknown mode letter, it will * drop the link to avoid desync. * * InspIRCd 2.0 and older required a comma before the uuid even if the user * had no prefix modes on the channel, InspIRCd 3.0 and later does not require * a comma in this case anymore. * * <membid> is a positive integer representing the id of the membership. * If not present (in FJOINs coming from pre-1205 servers), 0 is assumed. * * Forwarding: * FJOIN messages are forwarded with the new TS and modes. Prefix modes of * members on the losing side are not forwarded. * This is required to only have one server on each side of the network who * decides the fate of a channel during a network merge. Otherwise, if the * clock of a server is slightly off it may make a different decision than * the rest of the network and desync. * The prefix modes are always forwarded as-is, or not at all. * One incoming FJOIN may result in more than one FJOIN being generated * and forwarded mainly due to compatibility reasons with non-InspIRCd * servers that don't handle more than 512 char long lines. * * Forwarding examples: * Existing channel #chan with TS 1000, modes +n. * Incoming: :220 FJOIN #chan 1000 +t :o,220AAAAAB:0 * Forwarded: :220 FJOIN #chan 1000 +nt :o,220AAAAAB:0 * Merge modes and forward the result. Forward their prefix modes as well. * * Existing channel #chan with TS 1000, modes +nt. * Incoming: :220 FJOIN #CHAN 2000 +i :ov,220AAAAAB:0 o,220AAAAAC:20 * Forwarded: :220 FJOIN #chan 1000 +nt :,220AAAAAB:0 ,220AAAAAC:20 * Drop their modes, forward our modes and TS, use our channel name * capitalization. Don't forward prefix modes. * */ time_t TS = ServerCommand::ExtractTS(params[1]); const std::string& channel = params[0]; Channel* chan = ServerInstance->FindChan(channel); bool apply_other_sides_modes = true; TreeServer* const sourceserver = TreeServer::Get(srcuser); if (!chan) { chan = new Channel(channel, TS); } else { time_t ourTS = chan->age; if (TS != ourTS) { ServerInstance->Logs->Log(MODNAME, LOG_DEBUG, "Merge FJOIN received for %s, ourTS: %lu, TS: %lu, difference: %ld", chan->name.c_str(), (unsigned long)ourTS, (unsigned long)TS, (long)(ourTS - TS)); /* If our TS is less than theirs, we dont accept their modes */ if (ourTS < TS) { // If the source server isn't bursting then this FJOIN is the result of them recreating the channel with a higher TS. // This happens if the last user on the channel hops and before the PART propagates a user on another server joins. Fix it by doing a resync. // Servers behind us won't react this way because the forwarded FJOIN will have the correct TS. if (!sourceserver->IsBursting()) { ServerInstance->Logs->Log(MODNAME, LOG_DEBUG, "Server %s recreated channel %s with higher TS, resyncing", sourceserver->GetName().c_str(), chan->name.c_str()); sourceserver->GetSocket()->SyncChannel(chan); } apply_other_sides_modes = false; } else if (ourTS > TS) { // Our TS is greater than theirs, remove all modes, extensions, etc. from the channel LowerTS(chan, TS, channel); // XXX: If the channel does not exist in the chan hash at this point, create it so the remote modes can be applied on it. // This happens to 0-user permanent channels on the losing side, because those are removed (from the chan hash, then // deleted later) as soon as the permchan mode is removed from them. if (ServerInstance->FindChan(channel) == NULL) { chan = new Channel(channel, TS); } } } } // Apply their channel modes if we have to Modes::ChangeList modechangelist; if (apply_other_sides_modes) { ServerInstance->Modes.ModeParamsToChangeList(srcuser, MODETYPE_CHANNEL, params, modechangelist, 2, params.size() - 1); ServerInstance->Modes->Process(srcuser, chan, NULL, modechangelist, ModeParser::MODE_LOCALONLY | ModeParser::MODE_MERGE); // Reuse for prefix modes modechangelist.clear(); } // Build a new FJOIN for forwarding. Put the correct TS in it and the current modes of the channel // after applying theirs. If they lost, the prefix modes from their message are not forwarded. FwdFJoinBuilder fwdfjoin(chan, sourceserver); // Process every member in the message irc::spacesepstream users(params.back()); std::string item; Modes::ChangeList* modechangelistptr = (apply_other_sides_modes ? &modechangelist : NULL); while (users.GetToken(item)) { ProcessModeUUIDPair(item, sourceserver, chan, modechangelistptr, fwdfjoin); } fwdfjoin.finalize(); fwdfjoin.Forward(sourceserver->GetRoute()); // Set prefix modes on their users if we lost the FJOIN or had equal TS if (apply_other_sides_modes) ServerInstance->Modes->Process(srcuser, chan, NULL, modechangelist, ModeParser::MODE_LOCALONLY); return CMD_SUCCESS; } void CommandFJoin::ProcessModeUUIDPair(const std::string& item, TreeServer* sourceserver, Channel* chan, Modes::ChangeList* modechangelist, FwdFJoinBuilder& fwdfjoin) { std::string::size_type comma = item.find(','); // Comma not required anymore if the user has no modes const std::string::size_type ubegin = (comma == std::string::npos ? 0 : comma+1); std::string uuid(item, ubegin, UIDGenerator::UUID_LENGTH); User* who = ServerInstance->FindUUID(uuid); if (!who) { // Probably KILLed, ignore return; } TreeSocket* src_socket = sourceserver->GetSocket(); /* Check that the user's 'direction' is correct */ TreeServer* route_back_again = TreeServer::Get(who); if (route_back_again->GetSocket() != src_socket) { return; } std::string::const_iterator modeendit = item.begin(); // End of the "ov" mode string /* Check if the user received at least one mode */ if ((modechangelist) && (comma != std::string::npos)) { modeendit += comma; /* Iterate through the modes and see if they are valid here, if so, apply */ for (std::string::const_iterator i = item.begin(); i != modeendit; ++i) { ModeHandler* mh = ServerInstance->Modes->FindMode(*i, MODETYPE_CHANNEL); if (!mh) throw ProtocolException("Unrecognised mode '" + std::string(1, *i) + "'"); /* Add any modes this user had to the mode stack */ modechangelist->push_add(mh, who->nick); } } Membership* memb = chan->ForceJoin(who, NULL, sourceserver->IsBursting()); if (!memb) { // User was already on the channel, forward because of the modes they potentially got memb = chan->GetUser(who); if (memb) fwdfjoin.add(memb, item.begin(), modeendit); return; } // Assign the id to the new Membership Membership::Id membid = 0; const std::string::size_type colon = item.rfind(':'); if (colon != std::string::npos) membid = Membership::IdFromString(item.substr(colon+1)); memb->id = membid; // Add member to fwdfjoin with prefix modes fwdfjoin.add(memb, item.begin(), modeendit); } void CommandFJoin::RemoveStatus(Channel* c) { Modes::ChangeList changelist; const ModeParser::ModeHandlerMap& mhs = ServerInstance->Modes->GetModes(MODETYPE_CHANNEL); for (ModeParser::ModeHandlerMap::const_iterator i = mhs.begin(); i != mhs.end(); ++i) { ModeHandler* mh = i->second; // Add the removal of this mode to the changelist. This handles all kinds of modes, including prefix modes. mh->RemoveMode(c, changelist); } ServerInstance->Modes->Process(ServerInstance->FakeClient, c, NULL, changelist, ModeParser::MODE_LOCALONLY); } void CommandFJoin::LowerTS(Channel* chan, time_t TS, const std::string& newname) { if (Utils->AnnounceTSChange) chan->WriteNotice(InspIRCd::Format("Creation time of %s changed from %s to %s", newname.c_str(), InspIRCd::TimeString(chan->age).c_str(), InspIRCd::TimeString(TS).c_str())); // While the name is equal in case-insensitive compare, it might differ in case; use the remote version chan->name = newname; chan->age = TS; // Clear all modes CommandFJoin::RemoveStatus(chan); // Unset all extensions chan->FreeAllExtItems(); // Clear the topic chan->SetTopic(ServerInstance->FakeClient, std::string(), 0); chan->setby.clear(); } CommandFJoin::Builder::Builder(Channel* chan, TreeServer* source) : CmdBuilder(source, "FJOIN") { push(chan->name).push_int(chan->age).push_raw(" +"); pos = str().size(); push_raw(chan->ChanModes(true)).push_raw(" :"); } void CommandFJoin::Builder::add(Membership* memb, std::string::const_iterator mbegin, std::string::const_iterator mend) { push_raw(mbegin, mend).push_raw(',').push_raw(memb->user->uuid); push_raw(':').push_raw_int(memb->id); push_raw(' '); } bool CommandFJoin::Builder::has_room(std::string::size_type nummodes) const { return ((str().size() + nummodes + UIDGenerator::UUID_LENGTH + 2 + membid_max_digits + 1) <= maxline); } void CommandFJoin::Builder::clear() { content.erase(pos); push_raw(" :"); } const std::string& CommandFJoin::Builder::finalize() { if (*content.rbegin() == ' ') content.erase(content.size()-1); return str(); } void FwdFJoinBuilder::add(Membership* memb, std::string::const_iterator mbegin, std::string::const_iterator mend) { // Pseudoserver compatibility: // Some pseudoservers do not handle lines longer than 512 so we split long FJOINs into multiple messages. // The forwarded FJOIN can end up being longer than the original one if we have more modes set and won, for example. // Check if the member fits into the current message. If not, send it and prepare a new one. if (!has_room(std::distance(mbegin, mend))) { finalize(); Forward(sourceserver); clear(); } // Add the member and their modes exactly as they sent them CommandFJoin::Builder::add(memb, mbegin, mend); } �������������������������������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/src/modules/m_spanningtree/fmode.cpp�������������������������������������������������0000664�0000000�0000000�00000003507�13554550454�0022416�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * InspIRCd -- Internet Relay Chat Daemon * * Copyright (C) 2009-2010 Daniel De Graaf <danieldg@inspircd.org> * Copyright (C) 2008 Robin Burchell <robin+git@viroteck.net> * * 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 "inspircd.h" #include "commands.h" /** FMODE command - channel mode change with timestamp checks */ CmdResult CommandFMode::Handle(User* who, Params& params) { time_t TS = ServerCommand::ExtractTS(params[1]); Channel* const chan = ServerInstance->FindChan(params[0]); if (!chan) // Channel doesn't exist return CMD_FAILURE; // Extract the TS of the channel in question time_t ourTS = chan->age; /* If the TS is greater than ours, we drop the mode and don't pass it anywhere. */ if (TS > ourTS) return CMD_FAILURE; /* TS is equal or less: apply the mode change locally and forward the message */ // Turn modes into a Modes::ChangeList; may have more elements than max modes Modes::ChangeList changelist; ServerInstance->Modes.ModeParamsToChangeList(who, MODETYPE_CHANNEL, params, changelist, 2); ModeParser::ModeProcessFlag flags = ModeParser::MODE_LOCALONLY; if ((TS == ourTS) && IS_SERVER(who)) flags |= ModeParser::MODE_MERGE; ServerInstance->Modes->Process(who, chan, NULL, changelist, flags); return CMD_SUCCESS; } �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/src/modules/m_spanningtree/ftopic.cpp������������������������������������������������0000664�0000000�0000000�00000005514�13554550454�0022610�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * InspIRCd -- Internet Relay Chat Daemon * * Copyright (C) 2010 Daniel De Graaf <danieldg@inspircd.org> * Copyright (C) 2008 Robin Burchell <robin+git@viroteck.net> * * 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 "inspircd.h" #include "commands.h" /** FTOPIC command */ CmdResult CommandFTopic::Handle(User* user, Params& params) { Channel* c = ServerInstance->FindChan(params[0]); if (!c) return CMD_FAILURE; if (c->age < ServerCommand::ExtractTS(params[1])) // Our channel TS is older, nothing to do return CMD_FAILURE; // Channel::topicset is initialized to 0 on channel creation, so their ts will always win if we never had a topic time_t ts = ServerCommand::ExtractTS(params[2]); if (ts < c->topicset) return CMD_FAILURE; // The topic text is always the last parameter const std::string& newtopic = params.back(); // If there is a setter in the message use that, otherwise use the message source const std::string& setter = ((params.size() > 4) ? params[3] : (ServerInstance->Config->FullHostInTopic ? user->GetFullHost() : user->nick)); /* * If the topics were updated at the exact same second, accept * the remote only when it's "bigger" than ours as defined by * string comparision, so non-empty topics always overridde * empty topics if their timestamps are equal * * Similarly, if the topic texts are equal too, keep one topic * setter and discard the other */ if (ts == c->topicset) { // Discard if their topic text is "smaller" if (c->topic > newtopic) return CMD_FAILURE; // If the texts are equal in addition to the timestamps, decide which setter to keep if ((c->topic == newtopic) && (c->setby >= setter)) return CMD_FAILURE; } c->SetTopic(user, newtopic, ts, &setter); return CMD_SUCCESS; } // Used when bursting and in reply to RESYNC, contains topic setter as the 4th parameter CommandFTopic::Builder::Builder(Channel* chan) : CmdBuilder("FTOPIC") { push(chan->name); push_int(chan->age); push_int(chan->topicset); push(chan->setby); push_last(chan->topic); } // Used when changing the topic, the setter is the message source CommandFTopic::Builder::Builder(User* user, Channel* chan) : CmdBuilder(user, "FTOPIC") { push(chan->name); push_int(chan->age); push_int(chan->topicset); push_last(chan->topic); } ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/src/modules/m_spanningtree/hmac.cpp��������������������������������������������������0000664�0000000�0000000�00000006771�13554550454�0022242�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * InspIRCd -- Internet Relay Chat Daemon * * Copyright (C) 2009-2010 Daniel De Graaf <danieldg@inspircd.org> * Copyright (C) 2008 Robin Burchell <robin+git@viroteck.net> * * 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 "inspircd.h" #include "modules/hash.h" #include "modules/ssl.h" #include "main.h" #include "link.h" #include "treesocket.h" const std::string& TreeSocket::GetOurChallenge() { return capab->ourchallenge; } void TreeSocket::SetOurChallenge(const std::string &c) { capab->ourchallenge = c; } const std::string& TreeSocket::GetTheirChallenge() { return capab->theirchallenge; } void TreeSocket::SetTheirChallenge(const std::string &c) { capab->theirchallenge = c; } std::string TreeSocket::MakePass(const std::string &password, const std::string &challenge) { /* This is a simple (maybe a bit hacky?) HMAC algorithm, thanks to jilles for * suggesting the use of HMAC to secure the password against various attacks. * * Note: If an sha256 provider is not available, we MUST fall back to plaintext with no * HMAC challenge/response. */ HashProvider* sha256 = ServerInstance->Modules->FindDataService<HashProvider>("hash/sha256"); if (sha256 && !challenge.empty()) return "AUTH:" + BinToBase64(sha256->hmac(password, challenge)); if (!challenge.empty() && !sha256) ServerInstance->Logs->Log(MODNAME, LOG_DEFAULT, "Not authenticating to server using SHA256/HMAC because we don't have an SHA256 provider (e.g. m_sha256) loaded!"); return password; } bool TreeSocket::ComparePass(const Link& link, const std::string &theirs) { capab->auth_fingerprint = !link.Fingerprint.empty(); capab->auth_challenge = !capab->ourchallenge.empty() && !capab->theirchallenge.empty(); std::string fp = SSLClientCert::GetFingerprint(this); if (capab->auth_fingerprint) { /* Require fingerprint to exist and match */ if (link.Fingerprint != fp) { ServerInstance->SNO->WriteToSnoMask('l',"Invalid SSL certificate fingerprint on link %s: need \"%s\" got \"%s\"", link.Name.c_str(), link.Fingerprint.c_str(), fp.c_str()); SendError("Invalid SSL certificate fingerprint " + fp + " - expected " + link.Fingerprint); return false; } } if (capab->auth_challenge) { std::string our_hmac = MakePass(link.RecvPass, capab->ourchallenge); // Use the timing-safe compare function to compare the hashes if (!InspIRCd::TimingSafeCompare(our_hmac, theirs)) return false; } else { // Use the timing-safe compare function to compare the passwords if (!InspIRCd::TimingSafeCompare(link.RecvPass, theirs)) return false; } // Tell opers to set up fingerprint verification if it's not already set up and the SSL mod gave us a fingerprint // this time if ((!capab->auth_fingerprint) && (!fp.empty())) { ServerInstance->SNO->WriteToSnoMask('l', "SSL certificate fingerprint for link %s is \"%s\". " "You can improve security by specifying this in <link:fingerprint>.", link.Name.c_str(), fp.c_str()); } return true; } �������inspircd-3.4.0/src/modules/m_spanningtree/idle.cpp��������������������������������������������������0000664�0000000�0000000�00000004025�13554550454�0022235�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * InspIRCd -- Internet Relay Chat Daemon * * Copyright (C) 2011 Adam <Adam@anope.org> * * This file is part of InspIRCd. InspIRCd is free software: you can * redistribute it and/or modify it under the terms of the GNU General Public * License as published by the Free Software Foundation, version 2. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include "inspircd.h" #include "utils.h" #include "commands.h" CmdResult CommandIdle::HandleRemote(RemoteUser* issuer, Params& params) { /** * There are two forms of IDLE: request and reply. Requests have one parameter, * replies have more than one. * * If this is a request, 'issuer' did a /whois and its server wants to learn the * idle time of the user in params[0]. * * If this is a reply, params[0] is the user who did the whois and params.back() is * the number of seconds 'issuer' has been idle. */ User* target = ServerInstance->FindUUID(params[0]); if ((!target) || (target->registered != REG_ALL)) return CMD_FAILURE; LocalUser* localtarget = IS_LOCAL(target); if (!localtarget) { // Forward to target's server return CMD_SUCCESS; } if (params.size() >= 2) { ServerInstance->Parser.CallHandler("WHOIS", params, issuer); } else { // A server is asking us the idle time of our user unsigned int idle; if (localtarget->idle_lastmsg >= ServerInstance->Time()) // Possible case when our clock ticked backwards idle = 0; else idle = ((unsigned int) (ServerInstance->Time() - localtarget->idle_lastmsg)); CmdBuilder reply(target, "IDLE"); reply.push(issuer->uuid); reply.push(ConvToStr(target->signon)); reply.push(ConvToStr(idle)); reply.Unicast(issuer); } return CMD_SUCCESS; } �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/src/modules/m_spanningtree/ijoin.cpp�������������������������������������������������0000664�0000000�0000000�00000004456�13554550454�0022440�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * InspIRCd -- Internet Relay Chat Daemon * * Copyright (C) 2012-2013 Attila Molnar <attilamolnar@hush.com> * * This file is part of InspIRCd. InspIRCd is free software: you can * redistribute it and/or modify it under the terms of the GNU General Public * License as published by the Free Software Foundation, version 2. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include "inspircd.h" #include "commands.h" #include "utils.h" #include "treeserver.h" #include "treesocket.h" CmdResult CommandIJoin::HandleRemote(RemoteUser* user, Params& params) { Channel* chan = ServerInstance->FindChan(params[0]); if (!chan) { // Desync detected, recover // Ignore the join and send RESYNC, this will result in the remote server sending all channel data to us ServerInstance->Logs->Log(MODNAME, LOG_DEBUG, "Received IJOIN for nonexistent channel: " + params[0]); CmdBuilder("RESYNC").push(params[0]).Unicast(user); return CMD_FAILURE; } bool apply_modes; if (params.size() > 3) { time_t RemoteTS = ServerCommand::ExtractTS(params[2]); apply_modes = (RemoteTS <= chan->age); } else apply_modes = false; // Join the user and set the membership id to what they sent Membership* memb = chan->ForceJoin(user, apply_modes ? &params[3] : NULL); if (!memb) return CMD_FAILURE; memb->id = Membership::IdFromString(params[1]); return CMD_SUCCESS; } CmdResult CommandResync::HandleServer(TreeServer* server, CommandBase::Params& params) { ServerInstance->Logs->Log(MODNAME, LOG_DEBUG, "Resyncing " + params[0]); Channel* chan = ServerInstance->FindChan(params[0]); if (!chan) { // This can happen for a number of reasons, safe to ignore ServerInstance->Logs->Log(MODNAME, LOG_DEBUG, "Channel does not exist"); return CMD_FAILURE; } if (!server->IsLocal()) throw ProtocolException("RESYNC from a server that is not directly connected"); // Send all known information about the channel server->GetSocket()->SyncChannel(chan); return CMD_SUCCESS; } ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/src/modules/m_spanningtree/link.h����������������������������������������������������0000664�0000000�0000000�00000002633�13554550454�0021725�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * InspIRCd -- Internet Relay Chat Daemon * * Copyright (C) 2007 Dennis Friis <peavey@inspircd.org> * Copyright (C) 2007 Craig Edwards <craigedwards@brainbox.cc> * * This file is part of InspIRCd. InspIRCd is free software: you can * redistribute it and/or modify it under the terms of the GNU General Public * License as published by the Free Software Foundation, version 2. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once class Link : public refcountbase { public: reference<ConfigTag> tag; std::string Name; std::string IPAddr; unsigned int Port; std::string SendPass; std::string RecvPass; std::string Fingerprint; std::vector<std::string> AllowMasks; bool HiddenFromStats; std::string Hook; unsigned int Timeout; std::string Bind; bool Hidden; Link(ConfigTag* Tag) : tag(Tag) {} }; class Autoconnect : public refcountbase { public: reference<ConfigTag> tag; std::vector<std::string> servers; unsigned long Period; time_t NextConnectTime; /** Negative == inactive */ int position; Autoconnect(ConfigTag* Tag) : tag(Tag) {} }; �����������������������������������������������������������������������������������������������������inspircd-3.4.0/src/modules/m_spanningtree/main.cpp��������������������������������������������������0000664�0000000�0000000�00000060426�13554550454�0022253�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * InspIRCd -- Internet Relay Chat Daemon * * Copyright (C) 2009-2010 Daniel De Graaf <danieldg@inspircd.org> * Copyright (C) 2007-2009 Craig Edwards <craigedwards@brainbox.cc> * Copyright (C) 2007-2008 Robin Burchell <robin+git@viroteck.net> * Copyright (C) 2008 Thomas Stagner <aquanight@inspircd.org> * Copyright (C) 2007 Dennis Friis <peavey@inspircd.org> * * This file is part of InspIRCd. InspIRCd is free software: you can * redistribute it and/or modify it under the terms of the GNU General Public * License as published by the Free Software Foundation, version 2. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include "inspircd.h" #include "socket.h" #include "xline.h" #include "iohook.h" #include "resolvers.h" #include "main.h" #include "utils.h" #include "treeserver.h" #include "link.h" #include "treesocket.h" #include "commands.h" #include "translate.h" ModuleSpanningTree::ModuleSpanningTree() : Away::EventListener(this) , Stats::EventListener(this) , CTCTags::EventListener(this) , rconnect(this) , rsquit(this) , map(this) , commands(this) , currmembid(0) , broadcasteventprov(this, "event/server-broadcast") , linkeventprov(this, "event/server-link") , messageeventprov(this, "event/server-message") , synceventprov(this, "event/server-sync") , sslapi(this) , DNS(this, "DNS") , tagevprov(this, "event/messagetag") , loopCall(false) { } SpanningTreeCommands::SpanningTreeCommands(ModuleSpanningTree* module) : svsjoin(module), svspart(module), svsnick(module), metadata(module), uid(module), opertype(module), fjoin(module), ijoin(module), resync(module), fmode(module), ftopic(module), fhost(module), fident(module), fname(module), away(module), addline(module), delline(module), encap(module), idle(module), nick(module), ping(module), pong(module), save(module), server(module), squit(module), snonotice(module), endburst(module), sinfo(module), num(module) { } namespace { void SetLocalUsersServer(Server* newserver) { // Does not change the server of quitting users because those are not in the list ServerInstance->FakeClient->server = newserver; const UserManager::LocalList& list = ServerInstance->Users.GetLocalUsers(); for (UserManager::LocalList::const_iterator i = list.begin(); i != list.end(); ++i) (*i)->server = newserver; } void ResetMembershipIds() { // Set all membership ids to 0 const UserManager::LocalList& list = ServerInstance->Users.GetLocalUsers(); for (UserManager::LocalList::iterator i = list.begin(); i != list.end(); ++i) { LocalUser* user = *i; for (User::ChanList::iterator j = user->chans.begin(); j != user->chans.end(); ++j) (*j)->id = 0; } } } void ModuleSpanningTree::init() { ServerInstance->SNO->EnableSnomask('l', "LINK"); ResetMembershipIds(); Utils = new SpanningTreeUtilities(this); Utils->TreeRoot = new TreeServer; ServerInstance->PI = &protocolinterface; delete ServerInstance->FakeClient->server; SetLocalUsersServer(Utils->TreeRoot); } void ModuleSpanningTree::ShowLinks(TreeServer* Current, User* user, int hops) { std::string Parent = Utils->TreeRoot->GetName(); if (Current->GetParent()) { Parent = Current->GetParent()->GetName(); } const TreeServer::ChildServers& children = Current->GetChildren(); for (TreeServer::ChildServers::const_iterator i = children.begin(); i != children.end(); ++i) { TreeServer* server = *i; if ((server->Hidden) || ((Utils->HideULines) && (server->IsULine()))) { if (user->IsOper()) { ShowLinks(server, user, hops+1); } } else { ShowLinks(server, user, hops+1); } } /* Don't display the line if its a uline, hide ulines is on, and the user isnt an oper */ if ((Utils->HideULines) && (Current->IsULine()) && (!user->IsOper())) return; /* Or if the server is hidden and they're not an oper */ else if ((Current->Hidden) && (!user->IsOper())) return; user->WriteNumeric(RPL_LINKS, Current->GetName(), (((Utils->FlatLinks) && (!user->IsOper())) ? ServerInstance->Config->ServerName : Parent), InspIRCd::Format("%d %s", (((Utils->FlatLinks) && (!user->IsOper())) ? 0 : hops), Current->GetDesc().c_str())); } void ModuleSpanningTree::HandleLinks(const CommandBase::Params& parameters, User* user) { ShowLinks(Utils->TreeRoot,user,0); user->WriteNumeric(RPL_ENDOFLINKS, '*', "End of /LINKS list."); } void ModuleSpanningTree::ConnectServer(Autoconnect* a, bool on_timer) { if (!a) return; for(unsigned int j=0; j < a->servers.size(); j++) { if (Utils->FindServer(a->servers[j])) { // found something in this block. Should the server fail, // we want to start at the start of the list, not in the // middle where we left off a->position = -1; return; } } if (on_timer && a->position >= 0) return; if (!on_timer && a->position < 0) return; a->position++; while (a->position < (int)a->servers.size()) { Link* x = Utils->FindLink(a->servers[a->position]); if (x) { ServerInstance->SNO->WriteToSnoMask('l', "AUTOCONNECT: Auto-connecting server \002%s\002", x->Name.c_str()); ConnectServer(x, a); return; } a->position++; } // Autoconnect chain has been fully iterated; start at the beginning on the // next AutoConnectServers run a->position = -1; } void ModuleSpanningTree::ConnectServer(Link* x, Autoconnect* y) { if (InspIRCd::Match(ServerInstance->Config->ServerName, x->Name, ascii_case_insensitive_map)) { ServerInstance->SNO->WriteToSnoMask('l', "CONNECT: Not connecting to myself."); return; } irc::sockets::sockaddrs sa; if (x->IPAddr.find('/') != std::string::npos) { if (!irc::sockets::isunix(x->IPAddr) || !irc::sockets::untosa(x->IPAddr, sa)) { // We don't use the family() != AF_UNSPEC check below for UNIX sockets as // that results in a DNS lookup. ServerInstance->SNO->WriteToSnoMask('l', "CONNECT: Error connecting \002%s\002: %s is not a UNIX socket!", x->Name.c_str(), x->IPAddr.c_str()); return; } } else { // If this fails then the IP sa will be AF_UNSPEC. irc::sockets::aptosa(x->IPAddr, x->Port, sa); } /* Do we already have an IP? If so, no need to resolve it. */ if (sa.family() != AF_UNSPEC) { // Create a TreeServer object that will start connecting immediately in the background TreeSocket* newsocket = new TreeSocket(x, y, sa); if (newsocket->GetFd() > -1) { /* Handled automatically on success */ } else { ServerInstance->SNO->WriteToSnoMask('l', "CONNECT: Error connecting \002%s\002: %s.", x->Name.c_str(), newsocket->getError().c_str()); ServerInstance->GlobalCulls.AddItem(newsocket); } } else if (!DNS) { ServerInstance->SNO->WriteToSnoMask('l', "CONNECT: Error connecting \002%s\002: Hostname given and core_dns is not loaded, unable to resolve.", x->Name.c_str()); } else { // Guess start_type from bindip aftype DNS::QueryType start_type = DNS::QUERY_AAAA; irc::sockets::sockaddrs bind; if ((!x->Bind.empty()) && (irc::sockets::aptosa(x->Bind, 0, bind))) { if (bind.family() == AF_INET) start_type = DNS::QUERY_A; } ServernameResolver* snr = new ServernameResolver(*DNS, x->IPAddr, x, start_type, y); try { DNS->Process(snr); } catch (DNS::Exception& e) { delete snr; ServerInstance->SNO->WriteToSnoMask('l', "CONNECT: Error connecting \002%s\002: %s.",x->Name.c_str(), e.GetReason().c_str()); ConnectServer(y, false); } } } void ModuleSpanningTree::AutoConnectServers(time_t curtime) { for (std::vector<reference<Autoconnect> >::iterator i = Utils->AutoconnectBlocks.begin(); i < Utils->AutoconnectBlocks.end(); ++i) { Autoconnect* x = *i; if (curtime >= x->NextConnectTime) { x->NextConnectTime = curtime + x->Period; ConnectServer(x, true); } } } void ModuleSpanningTree::DoConnectTimeout(time_t curtime) { SpanningTreeUtilities::TimeoutList::iterator i = Utils->timeoutlist.begin(); while (i != Utils->timeoutlist.end()) { TreeSocket* s = i->first; std::pair<std::string, unsigned int> p = i->second; SpanningTreeUtilities::TimeoutList::iterator me = i; i++; if (s->GetLinkState() == DYING) { Utils->timeoutlist.erase(me); s->Close(); } else if (curtime > s->age + p.second) { ServerInstance->SNO->WriteToSnoMask('l',"CONNECT: Error connecting \002%s\002 (timeout of %u seconds)",p.first.c_str(),p.second); Utils->timeoutlist.erase(me); s->Close(); } } } ModResult ModuleSpanningTree::HandleVersion(const CommandBase::Params& parameters, User* user) { // We've already confirmed that !parameters.empty(), so this is safe TreeServer* found = Utils->FindServerMask(parameters[0]); if (found) { if (found == Utils->TreeRoot) { // Pass to default VERSION handler. return MOD_RES_PASSTHRU; } // If an oper wants to see the version then show the full version string instead of the normal, // but only if it is non-empty. // If it's empty it might be that the server is still syncing (full version hasn't arrived yet) // or the server is a 2.0 server and does not send a full version. bool showfull = ((user->IsOper()) && (!found->GetFullVersion().empty())); Numeric::Numeric numeric(RPL_VERSION); irc::tokenstream tokens(showfull ? found->GetFullVersion() : found->GetVersion()); for (std::string token; tokens.GetTrailing(token); ) numeric.push(token); user->WriteNumeric(numeric); } else { user->WriteNumeric(ERR_NOSUCHSERVER, parameters[0], "No such server"); } return MOD_RES_DENY; } ModResult ModuleSpanningTree::HandleConnect(const CommandBase::Params& parameters, User* user) { for (std::vector<reference<Link> >::iterator i = Utils->LinkBlocks.begin(); i < Utils->LinkBlocks.end(); i++) { Link* x = *i; if (InspIRCd::Match(x->Name, parameters[0], ascii_case_insensitive_map)) { if (InspIRCd::Match(ServerInstance->Config->ServerName, x->Name, ascii_case_insensitive_map)) { user->WriteRemoteNotice(InspIRCd::Format("*** CONNECT: Server \002%s\002 is ME, not connecting.", x->Name.c_str())); return MOD_RES_DENY; } TreeServer* CheckDupe = Utils->FindServer(x->Name); if (!CheckDupe) { user->WriteRemoteNotice(InspIRCd::Format("*** CONNECT: Connecting to server: \002%s\002 (%s:%d)", x->Name.c_str(), (x->HiddenFromStats ? "<hidden>" : x->IPAddr.c_str()), x->Port)); ConnectServer(x); return MOD_RES_DENY; } else { user->WriteRemoteNotice(InspIRCd::Format("*** CONNECT: Server \002%s\002 already exists on the network and is connected via \002%s\002", x->Name.c_str(), CheckDupe->GetParent()->GetName().c_str())); return MOD_RES_DENY; } } } user->WriteRemoteNotice(InspIRCd::Format("*** CONNECT: No server matching \002%s\002 could be found in the config file.", parameters[0].c_str())); return MOD_RES_DENY; } void ModuleSpanningTree::OnUserInvite(User* source, User* dest, Channel* channel, time_t expiry, unsigned int notifyrank, CUList& notifyexcepts) { if (IS_LOCAL(source)) { CmdBuilder params(source, "INVITE"); params.push(dest->uuid); params.push(channel->name); params.push_int(channel->age); params.push(ConvToStr(expiry)); params.Broadcast(); } } ModResult ModuleSpanningTree::OnPreTopicChange(User* user, Channel* chan, const std::string& topic) { // XXX: Deny topic changes if the current topic set time is the current time or is in the future because // other servers will drop our FTOPIC. This restriction will be removed when the protocol is updated. if ((chan->topicset >= ServerInstance->Time()) && (Utils->serverlist.size() > 1)) { user->WriteNumeric(ERR_CHANOPRIVSNEEDED, chan->name, "Retry topic change later"); return MOD_RES_DENY; } return MOD_RES_PASSTHRU; } void ModuleSpanningTree::OnPostTopicChange(User* user, Channel* chan, const std::string &topic) { // Drop remote events on the floor. if (!IS_LOCAL(user)) return; CommandFTopic::Builder(user, chan).Broadcast(); } void ModuleSpanningTree::OnUserPostMessage(User* user, const MessageTarget& target, const MessageDetails& details) { if (!IS_LOCAL(user)) return; const char* message_type = (details.type == MSG_PRIVMSG ? "PRIVMSG" : "NOTICE"); switch (target.type) { case MessageTarget::TYPE_USER: { User* d = target.Get<User>(); if (!IS_LOCAL(d)) { CmdBuilder params(user, message_type); params.push_tags(details.tags_out); params.push(d->uuid); params.push_last(details.text); params.Unicast(d); } break; } case MessageTarget::TYPE_CHANNEL: { Utils->SendChannelMessage(user, target.Get<Channel>(), details.text, target.status, details.tags_out, details.exemptions, message_type); break; } case MessageTarget::TYPE_SERVER: { const std::string* serverglob = target.Get<std::string>(); CmdBuilder par(user, message_type); par.push_tags(details.tags_out); par.push(*serverglob); par.push_last(details.text); par.Broadcast(); break; } } } void ModuleSpanningTree::OnUserPostTagMessage(User* user, const MessageTarget& target, const CTCTags::TagMessageDetails& details) { if (!IS_LOCAL(user)) return; switch (target.type) { case MessageTarget::TYPE_USER: { User* d = target.Get<User>(); if (!IS_LOCAL(d)) { CmdBuilder params(user, "TAGMSG"); params.push_tags(details.tags_out); params.push(d->uuid); params.Unicast(d); } break; } case MessageTarget::TYPE_CHANNEL: { Utils->SendChannelMessage(user, target.Get<Channel>(), "", target.status, details.tags_out, details.exemptions, "TAGMSG"); break; } case MessageTarget::TYPE_SERVER: { const std::string* serverglob = target.Get<std::string>(); CmdBuilder par(user, "TAGMSG"); par.push_tags(details.tags_out); par.push(*serverglob); par.Broadcast(); break; } } } void ModuleSpanningTree::OnBackgroundTimer(time_t curtime) { AutoConnectServers(curtime); DoConnectTimeout(curtime); } void ModuleSpanningTree::OnUserConnect(LocalUser* user) { if (user->quitting) return; // Create the lazy ssl_cert metadata for this user if not already created. if (sslapi) sslapi->GetCertificate(user); CommandUID::Builder(user).Broadcast(); if (user->IsOper()) CommandOpertype::Builder(user).Broadcast(); for(Extensible::ExtensibleStore::const_iterator i = user->GetExtList().begin(); i != user->GetExtList().end(); i++) { ExtensionItem* item = i->first; std::string value = item->ToNetwork(user, i->second); if (!value.empty()) ServerInstance->PI->SendMetaData(user, item->name, value); } Utils->TreeRoot->UserCount++; } void ModuleSpanningTree::OnUserJoin(Membership* memb, bool sync, bool created_by_local, CUList& excepts) { // Only do this for local users if (!IS_LOCAL(memb->user)) return; // Assign the current membership id to the new Membership and increase it memb->id = currmembid++; if (created_by_local) { CommandFJoin::Builder params(memb->chan); params.add(memb); params.finalize(); params.Broadcast(); } else { CmdBuilder params(memb->user, "IJOIN"); params.push(memb->chan->name); params.push_int(memb->id); if (!memb->modes.empty()) { params.push(ConvToStr(memb->chan->age)); params.push(memb->modes); } params.Broadcast(); } } void ModuleSpanningTree::OnChangeHost(User* user, const std::string &newhost) { if (user->registered != REG_ALL || !IS_LOCAL(user)) return; CmdBuilder(user, "FHOST").push(newhost).Broadcast(); } void ModuleSpanningTree::OnChangeRealName(User* user, const std::string& real) { if (user->registered != REG_ALL || !IS_LOCAL(user)) return; CmdBuilder(user, "FNAME").push_last(real).Broadcast(); } void ModuleSpanningTree::OnChangeIdent(User* user, const std::string &ident) { if ((user->registered != REG_ALL) || (!IS_LOCAL(user))) return; CmdBuilder(user, "FIDENT").push(ident).Broadcast(); } void ModuleSpanningTree::OnUserPart(Membership* memb, std::string &partmessage, CUList& excepts) { if (IS_LOCAL(memb->user)) { CmdBuilder params(memb->user, "PART"); params.push(memb->chan->name); if (!partmessage.empty()) params.push_last(partmessage); params.Broadcast(); } } void ModuleSpanningTree::OnUserQuit(User* user, const std::string &reason, const std::string &oper_message) { if (IS_LOCAL(user)) { if (oper_message != reason) ServerInstance->PI->SendMetaData(user, "operquit", oper_message); CmdBuilder(user, "QUIT").push_last(reason).Broadcast(); } else { // Hide the message if one of the following is true: // - User is being quit due to a netsplit and quietbursts is on // - Server is a silent uline TreeServer* server = TreeServer::Get(user); bool hide = (((server->IsDead()) && (Utils->quiet_bursts)) || (server->IsSilentULine())); if (!hide) { ServerInstance->SNO->WriteToSnoMask('Q', "Client exiting on server %s: %s (%s) [%s]", user->server->GetName().c_str(), user->GetFullRealHost().c_str(), user->GetIPString().c_str(), oper_message.c_str()); } } // Regardless, update the UserCount TreeServer::Get(user)->UserCount--; } void ModuleSpanningTree::OnUserPostNick(User* user, const std::string &oldnick) { if (IS_LOCAL(user)) { // The nick TS is updated by the core, we don't do it CmdBuilder params(user, "NICK"); params.push(user->nick); params.push(ConvToStr(user->age)); params.Broadcast(); } else if (!loopCall) { ServerInstance->Logs->Log(MODNAME, LOG_DEFAULT, "WARNING: Changed nick of remote user %s from %s to %s TS %lu by ourselves!", user->uuid.c_str(), oldnick.c_str(), user->nick.c_str(), (unsigned long) user->age); } } void ModuleSpanningTree::OnUserKick(User* source, Membership* memb, const std::string &reason, CUList& excepts) { if ((!IS_LOCAL(source)) && (source != ServerInstance->FakeClient)) return; CmdBuilder params(source, "KICK"); params.push(memb->chan->name); params.push(memb->user->uuid); // If a remote user is being kicked by us then send the membership id in the kick too if (!IS_LOCAL(memb->user)) params.push_int(memb->id); params.push_last(reason); params.Broadcast(); } void ModuleSpanningTree::OnPreRehash(User* user, const std::string &parameter) { ServerInstance->Logs->Log(MODNAME, LOG_DEBUG, "OnPreRehash called with param %s", parameter.c_str()); // Send out to other servers if (!parameter.empty() && parameter[0] != '-') { CmdBuilder params(user ? user : ServerInstance->FakeClient, "REHASH"); params.push(parameter); params.Forward(user ? TreeServer::Get(user)->GetRoute() : NULL); } } void ModuleSpanningTree::ReadConfig(ConfigStatus& status) { // Did this rehash change the description of this server? const std::string& newdesc = ServerInstance->Config->ServerDesc; if (newdesc != Utils->TreeRoot->GetDesc()) { // Broadcast a SINFO desc message to let the network know about the new description. This is the description // string that is sent in the SERVER message initially and shown for example in WHOIS. // We don't need to update the field itself in the Server object - the core does that. CommandSInfo::Builder(Utils->TreeRoot, "desc", newdesc).Broadcast(); } // Re-read config stuff try { Utils->ReadConfiguration(); } catch (ModuleException& e) { // Refresh the IP cache anyway, so servers read before the error will be allowed to connect Utils->RefreshIPCache(); // Always warn local opers with snomask +l, also warn globally (snomask +L) if the rehash was issued by a remote user std::string msg = "Error in configuration: "; msg.append(e.GetReason()); ServerInstance->SNO->WriteToSnoMask('l', msg); if (status.srcuser && !IS_LOCAL(status.srcuser)) ServerInstance->PI->SendSNONotice('L', msg); } } void ModuleSpanningTree::OnLoadModule(Module* mod) { std::string data; data.push_back('+'); data.append(mod->ModuleSourceFile); Version v = mod->GetVersion(); if (!v.link_data.empty()) { data.push_back('='); data.append(v.link_data); } ServerInstance->PI->SendMetaData("modules", data); } void ModuleSpanningTree::OnUnloadModule(Module* mod) { if (!Utils) return; ServerInstance->PI->SendMetaData("modules", "-" + mod->ModuleSourceFile); if (mod == this) { // We are being unloaded, inform modules about all servers splitting which cannot be done later when the servers are actually disconnected const server_hash& servers = Utils->serverlist; for (server_hash::const_iterator i = servers.begin(); i != servers.end(); ++i) { TreeServer* server = i->second; if (!server->IsRoot()) FOREACH_MOD_CUSTOM(GetLinkEventProvider(), ServerProtocol::LinkEventListener, OnServerSplit, (server, false)); } return; } // Some other module is being unloaded. If it provides an IOHook we use, we must close that server connection now. restart: // Close all connections which use an IO hook provided by this module const TreeServer::ChildServers& list = Utils->TreeRoot->GetChildren(); for (TreeServer::ChildServers::const_iterator i = list.begin(); i != list.end(); ++i) { TreeSocket* sock = (*i)->GetSocket(); if (sock->GetModHook(mod)) { sock->SendError("SSL module unloaded"); sock->Close(); // XXX: The list we're iterating is modified by TreeServer::SQuit() which is called by Close() goto restart; } } for (SpanningTreeUtilities::TimeoutList::const_iterator i = Utils->timeoutlist.begin(); i != Utils->timeoutlist.end(); ++i) { TreeSocket* sock = i->first; if (sock->GetModHook(mod)) sock->Close(); } } void ModuleSpanningTree::OnOper(User* user, const std::string &opertype) { if (user->registered != REG_ALL || !IS_LOCAL(user)) return; // Note: The protocol does not allow direct umode +o; // sending OPERTYPE infers +o modechange locally. CommandOpertype::Builder(user).Broadcast(); } void ModuleSpanningTree::OnAddLine(User* user, XLine *x) { if (!x->IsBurstable() || loopCall || (user && !IS_LOCAL(user))) return; if (!user) user = ServerInstance->FakeClient; CommandAddLine::Builder(x, user).Broadcast(); } void ModuleSpanningTree::OnDelLine(User* user, XLine *x) { if (!x->IsBurstable() || loopCall || (user && !IS_LOCAL(user))) return; if (!user) user = ServerInstance->FakeClient; CmdBuilder params(user, "DELLINE"); params.push(x->type); params.push(x->Displayable()); params.Broadcast(); } void ModuleSpanningTree::OnUserAway(User* user) { if (IS_LOCAL(user)) CommandAway::Builder(user).Broadcast(); } void ModuleSpanningTree::OnUserBack(User* user) { if (IS_LOCAL(user)) CommandAway::Builder(user).Broadcast(); } void ModuleSpanningTree::OnMode(User* source, User* u, Channel* c, const Modes::ChangeList& modes, ModeParser::ModeProcessFlag processflags) { if (processflags & ModeParser::MODE_LOCALONLY) return; if (u) { if (u->registered != REG_ALL) return; CmdBuilder params(source, "MODE"); params.push(u->uuid); params.push(ClientProtocol::Messages::Mode::ToModeLetters(modes)); params.push_raw(Translate::ModeChangeListToParams(modes.getlist())); params.Broadcast(); } else { CmdBuilder params(source, "FMODE"); params.push(c->name); params.push_int(c->age); params.push(ClientProtocol::Messages::Mode::ToModeLetters(modes)); params.push_raw(Translate::ModeChangeListToParams(modes.getlist())); params.Broadcast(); } } void ModuleSpanningTree::OnShutdown(const std::string& reason) { const TreeServer::ChildServers& children = Utils->TreeRoot->GetChildren(); while (!children.empty()) children.front()->SQuit(reason, true); } CullResult ModuleSpanningTree::cull() { if (Utils) Utils->cull(); return this->Module::cull(); } ModuleSpanningTree::~ModuleSpanningTree() { ServerInstance->PI = &ServerInstance->DefaultProtocolInterface; Server* newsrv = new Server(ServerInstance->Config->GetSID(), ServerInstance->Config->ServerName, ServerInstance->Config->ServerDesc); SetLocalUsersServer(newsrv); delete Utils; } Version ModuleSpanningTree::GetVersion() { return Version("Allows servers to be linked", VF_VENDOR); } /* It is IMPORTANT that m_spanningtree is the last module in the chain * so that any activity it sees is FINAL, e.g. we arent going to send out * a NICK message before m_cloaking has finished putting the +x on the user, * etc etc. * Therefore, we set our priority to PRIORITY_LAST to make sure we end up at the END of * the module call queue. */ void ModuleSpanningTree::Prioritize() { ServerInstance->Modules->SetPriority(this, PRIORITY_LAST); ServerInstance->Modules.SetPriority(this, I_OnPreTopicChange, PRIORITY_FIRST); } MODULE_INIT(ModuleSpanningTree) ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/src/modules/m_spanningtree/main.h����������������������������������������������������0000664�0000000�0000000�00000017474�13554550454�0021725�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * InspIRCd -- Internet Relay Chat Daemon * * Copyright (C) 2009 Daniel De Graaf <danieldg@inspircd.org> * Copyright (C) 2008 Thomas Stagner <aquanight@inspircd.org> * Copyright (C) 2007-2008 Craig Edwards <craigedwards@brainbox.cc> * Copyright (C) 2007 Robin Burchell <robin+git@viroteck.net> * Copyright (C) 2007 Dennis Friis <peavey@inspircd.org> * * This file is part of InspIRCd. InspIRCd is free software: you can * redistribute it and/or modify it under the terms of the GNU General Public * License as published by the Free Software Foundation, version 2. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include "inspircd.h" #include "event.h" #include "modules/dns.h" #include "modules/ssl.h" #include "modules/stats.h" #include "modules/ctctags.h" #include "modules/server.h" #include "servercommand.h" #include "commands.h" #include "protocolinterface.h" /** An enumeration of all known protocol versions. * * If you introduce new protocol versions please document them here: * https://docs.inspircd.org/spanningtree/changes */ enum ProtocolVersion { /** The linking protocol version introduced in InspIRCd v2.0. */ PROTO_INSPIRCD_20 = 1202, /** The linking protocol version introduced in InspIRCd v2.1 alpha 0. */ PROTO_INSPIRCD_21_A0 = 1203, /** The linking protocol version introduced in InspIRCd v2.1 beta 2. */ PROTO_INSPIRCD_21_B2 = 1204, /** The linking protocol version introduced in InspIRCd v3.0. */ PROTO_INSPIRCD_30 = 1205, /** The oldest version of the protocol that we support. */ PROTO_OLDEST = PROTO_INSPIRCD_20, /** The newest version of the protocol that we support. */ PROTO_NEWEST = PROTO_INSPIRCD_30 }; /** Forward declarations */ class SpanningTreeUtilities; class CacheRefreshTimer; class TreeServer; class Link; class Autoconnect; /** This is the main class for the spanningtree module */ class ModuleSpanningTree : public Module , public Away::EventListener , public Stats::EventListener , public CTCTags::EventListener { /** Client to server commands, registered in the core */ CommandRConnect rconnect; CommandRSQuit rsquit; CommandMap map; /** Server to server only commands, not registered in the core */ SpanningTreeCommands commands; /** Next membership id assigned when a local user joins a channel */ Membership::Id currmembid; /** The specialized ProtocolInterface that is assigned to ServerInstance->PI on load */ SpanningTreeProtocolInterface protocolinterface; /** Event provider for our broadcast events. */ Events::ModuleEventProvider broadcasteventprov; /** Event provider for our link events. */ Events::ModuleEventProvider linkeventprov; /** Event provider for our message events. */ Events::ModuleEventProvider messageeventprov; /** Event provider for our sync events. */ Events::ModuleEventProvider synceventprov; /** API for accessing user SSL certificates. */ UserCertificateAPI sslapi; public: dynamic_reference<DNS::Manager> DNS; /** Event provider for message tags. */ Events::ModuleEventProvider tagevprov; ServerCommandManager CmdManager; /** Set to true if inside a spanningtree call, to prevent sending * xlines and other things back to their source */ bool loopCall; /** Constructor */ ModuleSpanningTree(); void init() CXX11_OVERRIDE; /** Shows /LINKS */ void ShowLinks(TreeServer* Current, User* user, int hops); /** Handle LINKS command */ void HandleLinks(const CommandBase::Params& parameters, User* user); /** Handle SQUIT */ ModResult HandleSquit(const CommandBase::Params& parameters, User* user); /** Handle remote WHOIS */ ModResult HandleRemoteWhois(const CommandBase::Params& parameters, User* user); /** Connect a server locally */ void ConnectServer(Link* x, Autoconnect* y = NULL); /** Connect the next autoconnect server */ void ConnectServer(Autoconnect* y, bool on_timer); /** Check if any servers are due to be autoconnected */ void AutoConnectServers(time_t curtime); /** Check if any connecting servers should timeout */ void DoConnectTimeout(time_t curtime); /** Handle remote VERSON */ ModResult HandleVersion(const CommandBase::Params& parameters, User* user); /** Handle CONNECT */ ModResult HandleConnect(const CommandBase::Params& parameters, User* user); /** Retrieves the event provider for broadcast events. */ const Events::ModuleEventProvider& GetBroadcastEventProvider() const { return broadcasteventprov; } /** Retrieves the event provider for link events. */ const Events::ModuleEventProvider& GetLinkEventProvider() const { return linkeventprov; } /** Retrieves the event provider for message events. */ const Events::ModuleEventProvider& GetMessageEventProvider() const { return messageeventprov; } /** Retrieves the event provider for sync events. */ const Events::ModuleEventProvider& GetSyncEventProvider() const { return synceventprov; } /** ** *** MODULE EVENTS *** **/ ModResult OnPreCommand(std::string& command, CommandBase::Params& parameters, LocalUser* user, bool validated) CXX11_OVERRIDE; void OnPostCommand(Command*, const CommandBase::Params& parameters, LocalUser* user, CmdResult result, bool loop) CXX11_OVERRIDE; void OnUserConnect(LocalUser* source) CXX11_OVERRIDE; void OnUserInvite(User* source, User* dest, Channel* channel, time_t timeout, unsigned int notifyrank, CUList& notifyexcepts) CXX11_OVERRIDE; ModResult OnPreTopicChange(User* user, Channel* chan, const std::string& topic) CXX11_OVERRIDE; void OnPostTopicChange(User* user, Channel* chan, const std::string &topic) CXX11_OVERRIDE; void OnUserPostMessage(User* user, const MessageTarget& target, const MessageDetails& details) CXX11_OVERRIDE; void OnUserPostTagMessage(User* user, const MessageTarget& target, const CTCTags::TagMessageDetails& details) CXX11_OVERRIDE; void OnBackgroundTimer(time_t curtime) CXX11_OVERRIDE; void OnUserJoin(Membership* memb, bool sync, bool created, CUList& excepts) CXX11_OVERRIDE; void OnChangeHost(User* user, const std::string &newhost) CXX11_OVERRIDE; void OnChangeRealName(User* user, const std::string& real) CXX11_OVERRIDE; void OnChangeIdent(User* user, const std::string &ident) CXX11_OVERRIDE; void OnUserPart(Membership* memb, std::string &partmessage, CUList& excepts) CXX11_OVERRIDE; void OnUserQuit(User* user, const std::string &reason, const std::string &oper_message) CXX11_OVERRIDE; void OnUserPostNick(User* user, const std::string &oldnick) CXX11_OVERRIDE; void OnUserKick(User* source, Membership* memb, const std::string &reason, CUList& excepts) CXX11_OVERRIDE; void OnPreRehash(User* user, const std::string &parameter) CXX11_OVERRIDE; void ReadConfig(ConfigStatus& status) CXX11_OVERRIDE; void OnOper(User* user, const std::string &opertype) CXX11_OVERRIDE; void OnAddLine(User *u, XLine *x) CXX11_OVERRIDE; void OnDelLine(User *u, XLine *x) CXX11_OVERRIDE; ModResult OnStats(Stats::Context& stats) CXX11_OVERRIDE; void OnUserAway(User* user) CXX11_OVERRIDE; void OnUserBack(User* user) CXX11_OVERRIDE; void OnLoadModule(Module* mod) CXX11_OVERRIDE; void OnUnloadModule(Module* mod) CXX11_OVERRIDE; ModResult OnAcceptConnection(int newsock, ListenSocket* from, irc::sockets::sockaddrs* client, irc::sockets::sockaddrs* server) CXX11_OVERRIDE; void OnMode(User* source, User* u, Channel* c, const Modes::ChangeList& modes, ModeParser::ModeProcessFlag processflags) CXX11_OVERRIDE; void OnShutdown(const std::string& reason) CXX11_OVERRIDE; CullResult cull() CXX11_OVERRIDE; ~ModuleSpanningTree(); Version GetVersion() CXX11_OVERRIDE; void Prioritize() CXX11_OVERRIDE; }; ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/src/modules/m_spanningtree/metadata.cpp����������������������������������������������0000664�0000000�0000000�00000005323�13554550454�0023102�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * InspIRCd -- Internet Relay Chat Daemon * * Copyright (C) 2010 Daniel De Graaf <danieldg@inspircd.org> * Copyright (C) 2008 Robin Burchell <robin+git@viroteck.net> * * 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 "inspircd.h" #include "commands.h" CmdResult CommandMetadata::Handle(User* srcuser, Params& params) { if (params[0] == "*") { std::string value = params.size() < 3 ? "" : params[2]; FOREACH_MOD(OnDecodeMetaData, (NULL,params[1],value)); return CMD_SUCCESS; } if (params[0][0] == '#') { // Channel METADATA has an additional parameter: the channel TS // :22D METADATA #channel 12345 extname :extdata if (params.size() < 3) throw ProtocolException("Insufficient parameters for channel METADATA"); Channel* c = ServerInstance->FindChan(params[0]); if (!c) return CMD_FAILURE; time_t ChanTS = ServerCommand::ExtractTS(params[1]); if (c->age < ChanTS) // Their TS is newer than ours, discard this command and do not propagate return CMD_FAILURE; std::string value = params.size() < 4 ? "" : params[3]; ExtensionItem* item = ServerInstance->Extensions.GetItem(params[2]); if ((item) && (item->type == ExtensionItem::EXT_CHANNEL)) item->FromNetwork(c, value); FOREACH_MOD(OnDecodeMetaData, (c,params[2],value)); } else { User* u = ServerInstance->FindUUID(params[0]); if (u) { ExtensionItem* item = ServerInstance->Extensions.GetItem(params[1]); std::string value = params.size() < 3 ? "" : params[2]; if ((item) && (item->type == ExtensionItem::EXT_USER)) item->FromNetwork(u, value); FOREACH_MOD(OnDecodeMetaData, (u,params[1],value)); } } return CMD_SUCCESS; } CommandMetadata::Builder::Builder(User* user, const std::string& key, const std::string& val) : CmdBuilder("METADATA") { push(user->uuid); push(key); push_last(val); } CommandMetadata::Builder::Builder(Channel* chan, const std::string& key, const std::string& val) : CmdBuilder("METADATA") { push(chan->name); push_int(chan->age); push(key); push_last(val); } CommandMetadata::Builder::Builder(const std::string& key, const std::string& val) : CmdBuilder("METADATA") { push("*"); push(key); push_last(val); } �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/src/modules/m_spanningtree/misccommands.cpp������������������������������������������0000664�0000000�0000000�00000004753�13554550454�0024005�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * InspIRCd -- Internet Relay Chat Daemon * * Copyright (C) 2013 Attila Molnar <attilamolnar@hush.com> * Copyright (C) 2007-2008, 2012 Robin Burchell <robin+git@viroteck.net> * Copyright (C) 2009-2010 Daniel De Graaf <danieldg@inspircd.org> * Copyright (C) 2007-2008 Craig Edwards <craigedwards@brainbox.cc> * Copyright (C) 2008 Pippijn van Steenhoven <pip88nl@gmail.com> * Copyright (C) 2008 Thomas Stagner <aquanight@inspircd.org> * Copyright (C) 2007 Dennis Friis <peavey@inspircd.org> * * This file is part of InspIRCd. InspIRCd is free software: you can * redistribute it and/or modify it under the terms of the GNU General Public * License as published by the Free Software Foundation, version 2. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include "inspircd.h" #include "main.h" #include "commands.h" #include "treeserver.h" void CmdBuilder::FireEvent(Server* target, const char* cmd, ClientProtocol::TagMap& taglist) { FOREACH_MOD_CUSTOM(Utils->Creator->GetMessageEventProvider(), ServerProtocol::MessageEventListener, OnBuildMessage, (target, cmd, taglist)); UpdateTags(); } void CmdBuilder::FireEvent(User* target, const char* cmd, ClientProtocol::TagMap& taglist) { FOREACH_MOD_CUSTOM(Utils->Creator->GetMessageEventProvider(), ServerProtocol::MessageEventListener, OnBuildMessage, (target, cmd, taglist)); UpdateTags(); } void CmdBuilder::UpdateTags() { std::string taglist; if (!tags.empty()) { char separator = '@'; for (ClientProtocol::TagMap::const_iterator iter = tags.begin(); iter != tags.end(); ++iter) { taglist.push_back(separator); separator = ';'; taglist.append(iter->first); if (!iter->second.value.empty()) { taglist.push_back('='); taglist.append(iter->second.value); } } taglist.push_back(' '); } content.replace(0, tagsize, taglist); tagsize = taglist.length(); } CmdResult CommandSNONotice::Handle(User* user, Params& params) { ServerInstance->SNO->WriteToSnoMask(params[0][0], "From " + user->nick + ": " + params[1]); return CMD_SUCCESS; } CmdResult CommandEndBurst::HandleServer(TreeServer* server, Params& params) { server->FinishBurst(); return CMD_SUCCESS; } ���������������������inspircd-3.4.0/src/modules/m_spanningtree/netburst.cpp����������������������������������������������0000664�0000000�0000000�00000022007�13554550454�0023166�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * InspIRCd -- Internet Relay Chat Daemon * * Copyright (C) 2009 Daniel De Graaf <danieldg@inspircd.org> * Copyright (C) 2008 Robin Burchell <robin+git@viroteck.net> * Copyright (C) 2008 Craig Edwards <craigedwards@brainbox.cc> * * This file is part of InspIRCd. InspIRCd is free software: you can * redistribute it and/or modify it under the terms of the GNU General Public * License as published by the Free Software Foundation, version 2. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include "inspircd.h" #include "xline.h" #include "listmode.h" #include "treesocket.h" #include "treeserver.h" #include "main.h" #include "commands.h" /** * Creates FMODE messages, used only when syncing channels */ class FModeBuilder : public CmdBuilder { static const size_t maxline = 480; std::string params; unsigned int modes; std::string::size_type startpos; public: FModeBuilder(Channel* chan) : CmdBuilder("FMODE"), modes(0) { push(chan->name).push_int(chan->age).push_raw(" +"); startpos = str().size(); } /** Add a mode to the message */ void push_mode(const char modeletter, const std::string& mask) { push_raw(modeletter); params.push_back(' '); params.append(mask); modes++; } /** Remove all modes from the message */ void clear() { content.erase(startpos); params.clear(); modes = 0; } /** Prepare the message for sending, next mode can only be added after clear() */ const std::string& finalize() { return push_raw(params); } /** Returns true if the given mask can be added to the message, false if the message * has no room for the mask */ bool has_room(const std::string& mask) const { return ((str().size() + params.size() + mask.size() + 2 <= maxline) && (modes < ServerInstance->Config->Limits.MaxModes)); } /** Returns true if this message is empty (has no modes) */ bool empty() const { return (modes == 0); } }; struct TreeSocket::BurstState { SpanningTreeProtocolInterface::Server server; BurstState(TreeSocket* sock) : server(sock) { } }; /** This function is called when we want to send a netburst to a local * server. There is a set order we must do this, because for example * users require their servers to exist, and channels require their * users to exist. You get the idea. */ void TreeSocket::DoBurst(TreeServer* s) { ServerInstance->SNO->WriteToSnoMask('l',"Bursting to \002%s\002 (Authentication: %s%s).", s->GetName().c_str(), capab->auth_fingerprint ? "SSL certificate fingerprint and " : "", capab->auth_challenge ? "challenge-response" : "plaintext password"); this->CleanNegotiationInfo(); this->WriteLine(CmdBuilder("BURST").push_int(ServerInstance->Time())); // Introduce all servers behind us this->SendServers(Utils->TreeRoot, s); BurstState bs(this); // Introduce all users this->SendUsers(bs); // Sync all channels const chan_hash& chans = ServerInstance->GetChans(); for (chan_hash::const_iterator i = chans.begin(); i != chans.end(); ++i) SyncChannel(i->second, bs); // Send all xlines this->SendXLines(); FOREACH_MOD_CUSTOM(Utils->Creator->GetSyncEventProvider(), ServerProtocol::SyncEventListener, OnSyncNetwork, (bs.server)); this->WriteLine(CmdBuilder("ENDBURST")); ServerInstance->SNO->WriteToSnoMask('l',"Finished bursting to \002"+ s->GetName()+"\002."); this->burstsent = true; } void TreeSocket::SendServerInfo(TreeServer* from) { // Send public version string this->WriteLine(CommandSInfo::Builder(from, "version", from->GetVersion())); // Send full version string that contains more information and is shown to opers this->WriteLine(CommandSInfo::Builder(from, "fullversion", from->GetFullVersion())); // Send the raw version string that just contains the base info this->WriteLine(CommandSInfo::Builder(from, "rawversion", from->GetRawVersion())); } /** Recursively send the server tree. * This is used during network burst to inform the other server * (and any of ITS servers too) of what servers we know about. * If at any point any of these servers already exist on the other * end, our connection may be terminated. */ void TreeSocket::SendServers(TreeServer* Current, TreeServer* s) { SendServerInfo(Current); const TreeServer::ChildServers& children = Current->GetChildren(); for (TreeServer::ChildServers::const_iterator i = children.begin(); i != children.end(); ++i) { TreeServer* recursive_server = *i; if (recursive_server != s) { this->WriteLine(CommandServer::Builder(recursive_server)); /* down to next level */ this->SendServers(recursive_server, s); } } } /** Send one or more FJOINs for a channel of users. * If the length of a single line is too long, it is split over multiple lines. */ void TreeSocket::SendFJoins(Channel* c) { CommandFJoin::Builder fjoin(c); const Channel::MemberMap& ulist = c->GetUsers(); for (Channel::MemberMap::const_iterator i = ulist.begin(); i != ulist.end(); ++i) { Membership* memb = i->second; if (!fjoin.has_room(memb)) { // No room for this user, send the line and prepare a new one this->WriteLine(fjoin.finalize()); fjoin.clear(); } fjoin.add(memb); } this->WriteLine(fjoin.finalize()); } /** Send all XLines we know about */ void TreeSocket::SendXLines() { std::vector<std::string> types = ServerInstance->XLines->GetAllTypes(); for (std::vector<std::string>::const_iterator it = types.begin(); it != types.end(); ++it) { /* Expired lines are removed in XLineManager::GetAll() */ XLineLookup* lookup = ServerInstance->XLines->GetAll(*it); /* lookup cannot be NULL in this case but a check won't hurt */ if (lookup) { for (LookupIter i = lookup->begin(); i != lookup->end(); ++i) { /* Is it burstable? this is better than an explicit check for type 'K'. * We break the loop as NONE of the items in this group are worth iterating. */ if (!i->second->IsBurstable()) break; this->WriteLine(CommandAddLine::Builder(i->second)); } } } } void TreeSocket::SendListModes(Channel* chan) { FModeBuilder fmode(chan); const ModeParser::ListModeList& listmodes = ServerInstance->Modes->GetListModes(); for (ModeParser::ListModeList::const_iterator i = listmodes.begin(); i != listmodes.end(); ++i) { ListModeBase* mh = *i; ListModeBase::ModeList* list = mh->GetList(chan); if (!list) continue; // Add all items on the list to the FMODE, send it whenever it becomes too long const char modeletter = mh->GetModeChar(); for (ListModeBase::ModeList::const_iterator j = list->begin(); j != list->end(); ++j) { const std::string& mask = j->mask; if (!fmode.has_room(mask)) { // No room for this mask, send the current line as-is then add the mask to a // new, empty FMODE message this->WriteLine(fmode.finalize()); fmode.clear(); } fmode.push_mode(modeletter, mask); } } if (!fmode.empty()) this->WriteLine(fmode.finalize()); } /** Send channel users, topic, modes and global metadata */ void TreeSocket::SyncChannel(Channel* chan, BurstState& bs) { SendFJoins(chan); // If the topic was ever set, send it, even if it's empty now // because a new empty topic should override an old non-empty topic if (chan->topicset != 0) this->WriteLine(CommandFTopic::Builder(chan)); SendListModes(chan); for (Extensible::ExtensibleStore::const_iterator i = chan->GetExtList().begin(); i != chan->GetExtList().end(); i++) { ExtensionItem* item = i->first; std::string value = item->ToNetwork(chan, i->second); if (!value.empty()) this->WriteLine(CommandMetadata::Builder(chan, item->name, value)); } FOREACH_MOD_CUSTOM(Utils->Creator->GetSyncEventProvider(), ServerProtocol::SyncEventListener, OnSyncChannel, (chan, bs.server)); } void TreeSocket::SyncChannel(Channel* chan) { BurstState bs(this); SyncChannel(chan, bs); } /** Send all users and their state, including oper and away status and global metadata */ void TreeSocket::SendUsers(BurstState& bs) { const user_hash& users = ServerInstance->Users->GetUsers(); for (user_hash::const_iterator u = users.begin(); u != users.end(); ++u) { User* user = u->second; if (user->registered != REG_ALL) continue; this->WriteLine(CommandUID::Builder(user)); if (user->IsOper()) this->WriteLine(CommandOpertype::Builder(user)); if (user->IsAway()) this->WriteLine(CommandAway::Builder(user)); const Extensible::ExtensibleStore& exts = user->GetExtList(); for (Extensible::ExtensibleStore::const_iterator i = exts.begin(); i != exts.end(); ++i) { ExtensionItem* item = i->first; std::string value = item->ToNetwork(u->second, i->second); if (!value.empty()) this->WriteLine(CommandMetadata::Builder(user, item->name, value)); } FOREACH_MOD_CUSTOM(Utils->Creator->GetSyncEventProvider(), ServerProtocol::SyncEventListener, OnSyncUser, (user, bs.server)); } } �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/src/modules/m_spanningtree/nick.cpp��������������������������������������������������0000664�0000000�0000000�00000004542�13554550454�0022250�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * InspIRCd -- Internet Relay Chat Daemon * * Copyright (C) 2013 Attila Molnar <attilamolnar@hush.com> * Copyright (C) 2007-2008, 2012 Robin Burchell <robin+git@viroteck.net> * Copyright (C) 2009-2010 Daniel De Graaf <danieldg@inspircd.org> * Copyright (C) 2007-2008 Craig Edwards <craigedwards@brainbox.cc> * Copyright (C) 2008 Pippijn van Steenhoven <pip88nl@gmail.com> * Copyright (C) 2008 Thomas Stagner <aquanight@inspircd.org> * Copyright (C) 2007 Dennis Friis <peavey@inspircd.org> * * This file is part of InspIRCd. InspIRCd is free software: you can * redistribute it and/or modify it under the terms of the GNU General Public * License as published by the Free Software Foundation, version 2. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include "inspircd.h" #include "main.h" #include "utils.h" #include "commands.h" #include "treeserver.h" CmdResult CommandNick::HandleRemote(::RemoteUser* user, Params& params) { if ((isdigit(params[0][0])) && (params[0] != user->uuid)) throw ProtocolException("Attempted to change nick to an invalid or non-matching UUID"); // Timestamp of the new nick time_t newts = ServerCommand::ExtractTS(params[1]); /* * On nick messages, check that the nick doesn't already exist here. * If it does, perform collision logic. */ User* x = ServerInstance->FindNickOnly(params[0]); if ((x) && (x != user) && (x->registered == REG_ALL)) { // 'x' is the already existing user using the same nick as params[0] // 'user' is the user trying to change nick to the in use nick bool they_change = Utils->DoCollision(x, TreeServer::Get(user), newts, user->ident, user->GetIPString(), user->uuid, "NICK"); if (they_change) { // Remote client lost, or both lost, rewrite this nick change as a change to uuid before // calling ChangeNick() and forwarding the message params[0] = user->uuid; params[1] = ConvToStr(CommandSave::SavedTimestamp); newts = CommandSave::SavedTimestamp; } } user->ChangeNick(params[0], newts); return CMD_SUCCESS; } ��������������������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/src/modules/m_spanningtree/nickcollide.cpp�������������������������������������������0000664�0000000�0000000�00000010465�13554550454�0023605�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * InspIRCd -- Internet Relay Chat Daemon * * Copyright (C) 2009 Daniel De Graaf <danieldg@inspircd.org> * Copyright (C) 2008 Robin Burchell <robin+git@viroteck.net> * * 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 "inspircd.h" #include "treesocket.h" #include "treeserver.h" #include "utils.h" #include "commandbuilder.h" #include "commands.h" /* * Yes, this function looks a little ugly. * However, in some circumstances we may not have a User, so we need to do things this way. * Returns true if remote or both lost, false otherwise. * Sends SAVEs as appropriate and forces nick change of the user 'u' if our side loses or if both lose. * Does not change the nick of the user that is trying to claim the nick of 'u', i.e. the "remote" user. */ bool SpanningTreeUtilities::DoCollision(User* u, TreeServer* server, time_t remotets, const std::string& remoteident, const std::string& remoteip, const std::string& remoteuid, const char* collidecmd) { // At this point we're sure that a collision happened, increment the counter regardless of who wins ServerInstance->stats.Collisions++; /* * Under old protocol rules, we would have had to kill both clients. * Really, this sucks. * These days, we have UID. And, so what we do is, force nick change client(s) * involved according to timestamp rules. * * RULES: * user@ip equal: * Force nick change on OLDER timestamped client * user@ip differ: * Force nick change on NEWER timestamped client * TS EQUAL: * FNC both. * * This stops abusive use of collisions, simplifies problems with loops, and so on. * -- w00t */ bool bChangeLocal = true; bool bChangeRemote = true; // If the timestamps are not equal only one of the users has to change nick, // otherwise both have to change const time_t localts = u->age; if (remotets != localts) { /* first, let's see if ident@host matches. */ const std::string& localident = u->ident; const std::string& localip = u->GetIPString(); bool SamePerson = (localident == remoteident) && (localip == remoteip); /* * if ident@ip is equal, and theirs is newer, or * ident@ip differ, and ours is newer */ if((SamePerson && remotets < localts) || (!SamePerson && remotets > localts)) { // Only remote needs to change bChangeLocal = false; } else { // Only ours needs to change bChangeRemote = false; } } ServerInstance->Logs->Log(MODNAME, LOG_DEBUG, "Nick collision on \"%s\" caused by %s: %s/%lu/%s@%s %d <-> %s/%lu/%s@%s %d", u->nick.c_str(), collidecmd, u->uuid.c_str(), (unsigned long)localts, u->ident.c_str(), u->GetIPString().c_str(), bChangeLocal, remoteuid.c_str(), (unsigned long)remotets, remoteident.c_str(), remoteip.c_str(), bChangeRemote); /* * Send SAVE and accept the losing client with its UID (as we know the SAVE will * not fail under any circumstances -- UIDs are netwide exclusive). * * This means that each side of a collide will generate one extra NICK back to where * they have just linked (and where it got the SAVE from), however, it will * be dropped harmlessly as it will come in as :928AAAB NICK 928AAAB, and we already * have 928AAAB's nick set to that. * -- w00t */ if (bChangeLocal) { /* * Local-side nick needs to change. Just in case we are hub, and * this "local" nick is actually behind us, send a SAVE out. */ CmdBuilder params("SAVE"); params.push(u->uuid); params.push(ConvToStr(u->age)); params.Broadcast(); u->ChangeNick(u->uuid, CommandSave::SavedTimestamp); } if (bChangeRemote) { /* * Remote side needs to change. If this happens, we modify the UID or NICK and * send back a SAVE to the source. */ CmdBuilder("SAVE").push(remoteuid).push_int(remotets).Unicast(server->ServerUser); } return bChangeRemote; } �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/src/modules/m_spanningtree/num.cpp���������������������������������������������������0000664�0000000�0000000�00000004061�13554550454�0022117�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * InspIRCd -- Internet Relay Chat Daemon * * Copyright (C) 2016 Attila Molnar <attilamolnar@hush.com> * * This file is part of InspIRCd. InspIRCd is free software: you can * redistribute it and/or modify it under the terms of the GNU General Public * License as published by the Free Software Foundation, version 2. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include "inspircd.h" #include "utils.h" #include "commands.h" #include "remoteuser.h" CmdResult CommandNum::HandleServer(TreeServer* server, CommandBase::Params& params) { User* const target = ServerInstance->FindUUID(params[1]); if (!target) return CMD_FAILURE; LocalUser* const localtarget = IS_LOCAL(target); if (!localtarget) return CMD_SUCCESS; Numeric::Numeric numeric(ConvToNum<unsigned int>(params[2])); // Passing NULL is ok, in that case the numeric source becomes this server numeric.SetServer(Utils->FindServerID(params[0])); numeric.GetParams().insert(numeric.GetParams().end(), params.begin()+3, params.end()); localtarget->WriteNumeric(numeric); return CMD_SUCCESS; } RouteDescriptor CommandNum::GetRouting(User* user, const Params& params) { return ROUTE_UNICAST(params[1]); } CommandNum::Builder::Builder(SpanningTree::RemoteUser* target, const Numeric::Numeric& numeric) : CmdBuilder("NUM") { TreeServer* const server = (numeric.GetServer() ? (static_cast<TreeServer*>(numeric.GetServer())) : Utils->TreeRoot); push(server->GetId()).push(target->uuid).push(InspIRCd::Format("%03u", numeric.GetNumeric())); const CommandBase::Params& params = numeric.GetParams(); if (!params.empty()) { for (CommandBase::Params::const_iterator i = params.begin(); i != params.end()-1; ++i) push(*i); push_last(params.back()); } } �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/src/modules/m_spanningtree/opertype.cpp����������������������������������������������0000664�0000000�0000000�00000004213�13554550454�0023166�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * InspIRCd -- Internet Relay Chat Daemon * * Copyright (C) 2010 Daniel De Graaf <danieldg@inspircd.org> * Copyright (C) 2008 Robin Burchell <robin+git@viroteck.net> * * 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 "inspircd.h" #include "commands.h" #include "treeserver.h" #include "utils.h" /** Because the core won't let users or even SERVERS set +o, * we use the OPERTYPE command to do this. */ CmdResult CommandOpertype::HandleRemote(RemoteUser* u, CommandBase::Params& params) { const std::string& opertype = params[0]; if (!u->IsOper()) ServerInstance->Users->all_opers.push_back(u); ModeHandler* opermh = ServerInstance->Modes->FindMode('o', MODETYPE_USER); if (opermh) u->SetMode(opermh, true); ServerConfig::OperIndex::const_iterator iter = ServerInstance->Config->OperTypes.find(opertype); if (iter != ServerInstance->Config->OperTypes.end()) u->oper = iter->second; else u->oper = new OperInfo(opertype); if (Utils->quiet_bursts) { /* * If quiet bursts are enabled, and server is bursting or silent uline (i.e. services), * then do nothing. -- w00t */ TreeServer* remoteserver = TreeServer::Get(u); if (remoteserver->IsBehindBursting() || remoteserver->IsSilentULine()) return CMD_SUCCESS; } ServerInstance->SNO->WriteToSnoMask('O', "From %s: User %s (%s@%s) is now a server operator of type %s", u->server->GetName().c_str(), u->nick.c_str(),u->ident.c_str(), u->GetRealHost().c_str(), opertype.c_str()); return CMD_SUCCESS; } CommandOpertype::Builder::Builder(User* user) : CmdBuilder(user, "OPERTYPE") { push_last(user->oper->name); } �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/src/modules/m_spanningtree/override_map.cpp������������������������������������������0000664�0000000�0000000�00000014437�13554550454�0024004�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * InspIRCd -- Internet Relay Chat Daemon * * Copyright (C) 2014 Adam <Adam@anope.org> * Copyright (C) 2009 Daniel De Graaf <danieldg@inspircd.org> * Copyright (C) 2007-2008 Craig Edwards <craigedwards@brainbox.cc> * Copyright (C) 2008 Robin Burchell <robin+git@viroteck.net> * * 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 "inspircd.h" #include "main.h" #include "utils.h" #include "treeserver.h" #include "commands.h" CommandMap::CommandMap(Module* Creator) : Command(Creator, "MAP", 0, 1) { Penalty = 2; } static inline bool IsHidden(User* user, TreeServer* server) { if (!user->IsOper()) { if (server->Hidden) return true; if (Utils->HideULines && server->IsULine()) return true; } return false; } // Calculate the map depth the servers go, and the longest server name static void GetDepthAndLen(TreeServer* current, unsigned int depth, unsigned int& max_depth, unsigned int& max_len) { if (depth > max_depth) max_depth = depth; if (current->GetName().length() > max_len) max_len = current->GetName().length(); const TreeServer::ChildServers& servers = current->GetChildren(); for (TreeServer::ChildServers::const_iterator i = servers.begin(); i != servers.end(); ++i) { TreeServer* child = *i; GetDepthAndLen(child, depth + 1, max_depth, max_len); } } static std::vector<std::string> GetMap(User* user, TreeServer* current, unsigned int max_len, unsigned int depth) { float percent = 0; const user_hash& users = ServerInstance->Users->GetUsers(); if (!users.empty()) { // If there are no users, WHO THE HELL DID THE /MAP?!?!?! percent = current->UserCount * 100.0 / users.size(); } std::string buffer = current->GetName(); if (user->IsOper()) { buffer += " (" + current->GetId(); const std::string& cur_vers = current->GetRawVersion(); if (!cur_vers.empty()) buffer += " " + cur_vers; buffer += ")"; } // Pad with spaces until its at max len, max_len must always be >= my names length buffer.append(max_len - current->GetName().length(), ' '); buffer += InspIRCd::Format("%5d [%5.2f%%]", current->UserCount, percent); if (user->IsOper()) { time_t secs_up = ServerInstance->Time() - current->age; buffer += " [Up: " + InspIRCd::DurationString(secs_up) + (current->rtt == 0 ? "]" : " Lag: " + ConvToStr(current->rtt) + "ms]"); } std::vector<std::string> map; map.push_back(buffer); const TreeServer::ChildServers& servers = current->GetChildren(); for (TreeServer::ChildServers::const_iterator i = servers.begin(); i != servers.end(); ++i) { TreeServer* child = *i; if (IsHidden(user, child)) continue; bool last = true; for (TreeServer::ChildServers::const_iterator j = i + 1; last && j != servers.end(); ++j) if (!IsHidden(user, *j)) last = false; unsigned int next_len; if (user->IsOper() || !Utils->FlatLinks) { // This child is indented by us, so remove the depth from the max length to align the users properly next_len = max_len - 2; } else { // This user can not see depth, so max_len remains constant next_len = max_len; } // Build the map for this child std::vector<std::string> child_map = GetMap(user, child, next_len, depth + 1); for (std::vector<std::string>::const_iterator j = child_map.begin(); j != child_map.end(); ++j) { const char* prefix; if (user->IsOper() || !Utils->FlatLinks) { // If this server is not the root child if (j != child_map.begin()) { // If this child is not my last child, then add | // to be able to "link" the next server in my list to me, and to indent this childs servers if (!last) prefix = "| "; // Otherwise this is my last child, so just use a space as theres nothing else linked to me below this else prefix = " "; } // If we get here, this server must be the root child else { // If this is the last child, it gets a `- if (last) prefix = "`-"; // Otherwise this isn't the last child, so it gets |- else prefix = "|-"; } } else // User can't see depth, so use no prefix prefix = ""; // Add line to the map map.push_back(prefix + *j); } } return map; } CmdResult CommandMap::Handle(User* user, const Params& parameters) { if (parameters.size() > 0) { // Remote MAP, the target server is the 1st parameter TreeServer* s = Utils->FindServerMask(parameters[0]); if (!s) { user->WriteNumeric(ERR_NOSUCHSERVER, parameters[0], "No such server"); return CMD_FAILURE; } if (!s->IsRoot()) return CMD_SUCCESS; } // Max depth and max server name length unsigned int max_depth = 0; unsigned int max_len = 0; GetDepthAndLen(Utils->TreeRoot, 0, max_depth, max_len); unsigned int max; if (user->IsOper() || !Utils->FlatLinks) { // Each level of the map is indented by 2 characters, making the max possible line (max_depth * 2) + max_len max = (max_depth * 2) + max_len; } else { // This user can't see any depth max = max_len; } std::vector<std::string> map = GetMap(user, Utils->TreeRoot, max, 0); for (std::vector<std::string>::const_iterator i = map.begin(); i != map.end(); ++i) user->WriteRemoteNumeric(RPL_MAP, *i); size_t totusers = ServerInstance->Users->GetUsers().size(); float avg_users = (float) totusers / Utils->serverlist.size(); user->WriteRemoteNumeric(RPL_MAPUSERS, InspIRCd::Format("%u server%s and %u user%s, average %.2f users per server", (unsigned int)Utils->serverlist.size(), (Utils->serverlist.size() > 1 ? "s" : ""), (unsigned int)totusers, (totusers > 1 ? "s" : ""), avg_users)); user->WriteRemoteNumeric(RPL_ENDMAP, "End of /MAP"); return CMD_SUCCESS; } RouteDescriptor CommandMap::GetRouting(User* user, const Params& parameters) { if (!parameters.empty()) return ROUTE_UNICAST(parameters[0]); return ROUTE_LOCALONLY; } ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/src/modules/m_spanningtree/override_squit.cpp����������������������������������������0000664�0000000�0000000�00000003253�13554550454�0024366�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * InspIRCd -- Internet Relay Chat Daemon * * Copyright (C) 2007 Craig Edwards <craigedwards@brainbox.cc> * * This file is part of InspIRCd. InspIRCd is free software: you can * redistribute it and/or modify it under the terms of the GNU General Public * License as published by the Free Software Foundation, version 2. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include "inspircd.h" #include "socket.h" #include "main.h" #include "utils.h" #include "treeserver.h" #include "treesocket.h" ModResult ModuleSpanningTree::HandleSquit(const CommandBase::Params& parameters, User* user) { TreeServer* s = Utils->FindServerMask(parameters[0]); if (s) { if (s->IsRoot()) { user->WriteNotice("*** SQUIT: Foolish mortal, you cannot make a server SQUIT itself! (" + parameters[0] + " matches local server name)"); return MOD_RES_DENY; } if (s->IsLocal()) { ServerInstance->SNO->WriteToSnoMask('l',"SQUIT: Server \002%s\002 removed from network by %s",parameters[0].c_str(),user->nick.c_str()); s->SQuit("Server quit by " + user->GetFullRealHost()); } else { user->WriteNotice("*** SQUIT may not be used to remove remote servers. Please use RSQUIT instead."); } } else { user->WriteNotice("*** SQUIT: The server \002" + parameters[0] + "\002 does not exist on the network."); } return MOD_RES_DENY; } �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/src/modules/m_spanningtree/override_stats.cpp����������������������������������������0000664�0000000�0000000�00000003502�13554550454�0024354�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * InspIRCd -- Internet Relay Chat Daemon * * Copyright (C) 2010 Daniel De Graaf <danieldg@inspircd.org> * Copyright (C) 2007 Craig Edwards <craigedwards@brainbox.cc> * * This file is part of InspIRCd. InspIRCd is free software: you can * redistribute it and/or modify it under the terms of the GNU General Public * License as published by the Free Software Foundation, version 2. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include "inspircd.h" #include "main.h" #include "utils.h" #include "link.h" ModResult ModuleSpanningTree::OnStats(Stats::Context& stats) { if ((stats.GetSymbol() == 'c') || (stats.GetSymbol() == 'n')) { for (std::vector<reference<Link> >::iterator i = Utils->LinkBlocks.begin(); i != Utils->LinkBlocks.end(); ++i) { Link* L = *i; std::string ipaddr = "*@"; if (L->HiddenFromStats) ipaddr.append("<hidden>"); else ipaddr.append(L->IPAddr); const std::string hook = (L->Hook.empty() ? "plaintext" : L->Hook); stats.AddRow(213, stats.GetSymbol(), ipaddr, '*', L->Name, L->Port, hook); if (stats.GetSymbol() == 'c') stats.AddRow(244, 'H', '*', '*', L->Name); } return MOD_RES_DENY; } else if (stats.GetSymbol() == 'U') { ConfigTagList tags = ServerInstance->Config->ConfTags("uline"); for (ConfigIter i = tags.first; i != tags.second; ++i) { std::string name = i->second->getString("server"); if (!name.empty()) stats.AddRow(248, 'U', name); } return MOD_RES_DENY; } return MOD_RES_PASSTHRU; } ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/src/modules/m_spanningtree/override_whois.cpp����������������������������������������0000664�0000000�0000000�00000002424�13554550454�0024351�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * InspIRCd -- Internet Relay Chat Daemon * * Copyright (C) 2007 Craig Edwards <craigedwards@brainbox.cc> * * This file is part of InspIRCd. InspIRCd is free software: you can * redistribute it and/or modify it under the terms of the GNU General Public * License as published by the Free Software Foundation, version 2. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include "inspircd.h" #include "main.h" #include "commandbuilder.h" ModResult ModuleSpanningTree::HandleRemoteWhois(const CommandBase::Params& parameters, User* user) { User* remote = ServerInstance->FindNickOnly(parameters[1]); if (remote && !IS_LOCAL(remote)) { CmdBuilder(user, "IDLE").push(remote->uuid).Unicast(remote); return MOD_RES_DENY; } else if (!remote) { user->WriteNumeric(Numerics::NoSuchNick(parameters[0])); user->WriteNumeric(RPL_ENDOFWHOIS, parameters[0], "End of /WHOIS list."); return MOD_RES_DENY; } return MOD_RES_PASSTHRU; } ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/src/modules/m_spanningtree/ping.cpp��������������������������������������������������0000664�0000000�0000000�00000002252�13554550454�0022255�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * InspIRCd -- Internet Relay Chat Daemon * * Copyright (C) 2008 Robin Burchell <robin+git@viroteck.net> * * 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 "inspircd.h" #include "utils.h" #include "treeserver.h" #include "commands.h" #include "utils.h" CmdResult CommandPing::Handle(User* user, Params& params) { if (params[0] == ServerInstance->Config->GetSID()) { // PING for us, reply with a PONG CmdBuilder reply("PONG"); reply.push(user->uuid); if (params.size() >= 2) // If there is a second parameter, append it reply.push(params[1]); reply.Unicast(user); } return CMD_SUCCESS; } ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/src/modules/m_spanningtree/pingtimer.cpp���������������������������������������������0000664�0000000�0000000�00000005737�13554550454�0023331�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * InspIRCd -- Internet Relay Chat Daemon * * Copyright (C) 2015 Attila Molnar <attilamolnar@hush.com> * * This file is part of InspIRCd. InspIRCd is free software: you can * redistribute it and/or modify it under the terms of the GNU General Public * License as published by the Free Software Foundation, version 2. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include "inspircd.h" #include "pingtimer.h" #include "treeserver.h" #include "commandbuilder.h" PingTimer::PingTimer(TreeServer* ts) : Timer(Utils->PingFreq) , server(ts) , state(PS_SENDPING) { } PingTimer::State PingTimer::TickInternal() { // Timer expired, take next action based on what happened last time if (state == PS_SENDPING) { // Last ping was answered, send next ping server->GetSocket()->WriteLine(CmdBuilder("PING").push(server->GetId())); LastPingMsec = ServerInstance->Time() * 1000 + (ServerInstance->Time_ns() / 1000000); // Warn next unless warnings are disabled. If they are, jump straight to timeout. if (Utils->PingWarnTime) return PS_WARN; else return PS_TIMEOUT; } else if (state == PS_WARN) { // No pong arrived in PingWarnTime seconds, send a warning to opers ServerInstance->SNO->WriteToSnoMask('l', "Server \002%s\002 has not responded to PING for %d seconds, high latency.", server->GetName().c_str(), GetInterval()); return PS_TIMEOUT; } else // PS_TIMEOUT { // They didn't answer the last ping, if they are locally connected, get rid of them if (server->IsLocal()) { TreeSocket* sock = server->GetSocket(); sock->SendError("Ping timeout"); sock->Close(); } // If the server is non-locally connected, don't do anything until we get a PONG. // This is to avoid pinging the server and warning opers more than once. // If they do answer eventually, we will move to the PS_SENDPING state and ping them again. return PS_IDLE; } } void PingTimer::SetState(State newstate) { state = newstate; // Set when should the next Tick() happen based on the state if (state == PS_SENDPING) SetInterval(Utils->PingFreq); else if (state == PS_WARN) SetInterval(Utils->PingWarnTime); else if (state == PS_TIMEOUT) SetInterval(Utils->PingFreq - Utils->PingWarnTime); // If state == PS_IDLE, do not set the timer, see above why } bool PingTimer::Tick(time_t currtime) { if (server->IsDead()) return false; SetState(TickInternal()); return false; } void PingTimer::OnPong() { // Calculate RTT long ts = ServerInstance->Time() * 1000 + (ServerInstance->Time_ns() / 1000000); server->rtt = ts - LastPingMsec; // Change state to send ping next, also reschedules the timer appropriately SetState(PS_SENDPING); } ���������������������������������inspircd-3.4.0/src/modules/m_spanningtree/pingtimer.h�����������������������������������������������0000664�0000000�0000000�00000003616�13554550454�0022770�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * InspIRCd -- Internet Relay Chat Daemon * * Copyright (C) 2015 Attila Molnar <attilamolnar@hush.com> * * This file is part of InspIRCd. InspIRCd is free software: you can * redistribute it and/or modify it under the terms of the GNU General Public * License as published by the Free Software Foundation, version 2. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once class TreeServer; /** Handles PINGing servers and killing them on timeout */ class PingTimer : public Timer { enum State { /** Send PING next */ PS_SENDPING, /** Warn opers next */ PS_WARN, /** Kill the server next due to ping timeout */ PS_TIMEOUT, /** Do nothing */ PS_IDLE }; /** Server the timer is interacting with */ TreeServer* const server; /** What to do when the timer ticks next */ State state; /** Last ping time in milliseconds, used to calculate round trip time */ unsigned long LastPingMsec; /** Update internal state and reschedule timer according to the new state * @param newstate State to change to */ void SetState(State newstate); /** Process timer tick event * @return State to change to */ State TickInternal(); /** Called by the TimerManager when the timer expires * @param currtime Time now * @return Always false, we reschedule ourselves instead */ bool Tick(time_t currtime) CXX11_OVERRIDE; public: /** Construct the timer. This doesn't schedule the timer. * @param server TreeServer to interact with */ PingTimer(TreeServer* server); /** Register a PONG from the server */ void OnPong(); }; ������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/src/modules/m_spanningtree/pong.cpp��������������������������������������������������0000664�0000000�0000000�00000002351�13554550454�0022263�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * InspIRCd -- Internet Relay Chat Daemon * * Copyright (C) 2008 Robin Burchell <robin+git@viroteck.net> * * 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 "inspircd.h" #include "utils.h" #include "treeserver.h" #include "commands.h" #include "utils.h" CmdResult CommandPong::HandleServer(TreeServer* server, CommandBase::Params& params) { if (server->IsBursting()) { ServerInstance->SNO->WriteGlobalSno('l', "Server \002%s\002 has not finished burst, forcing end of burst (send ENDBURST!)", server->GetName().c_str()); server->FinishBurst(); } if (params[0] == ServerInstance->Config->GetSID()) { // PONG for us server->OnPong(); } return CMD_SUCCESS; } ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/src/modules/m_spanningtree/postcommand.cpp�������������������������������������������0000664�0000000�0000000�00000010114�13554550454�0023640�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * InspIRCd -- Internet Relay Chat Daemon * * Copyright (C) 2009 Daniel De Graaf <danieldg@inspircd.org> * Copyright (C) 2007 Craig Edwards <craigedwards@brainbox.cc> * * This file is part of InspIRCd. InspIRCd is free software: you can * redistribute it and/or modify it under the terms of the GNU General Public * License as published by the Free Software Foundation, version 2. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include "inspircd.h" #include "main.h" #include "utils.h" #include "treeserver.h" #include "commandbuilder.h" void ModuleSpanningTree::OnPostCommand(Command* command, const CommandBase::Params& parameters, LocalUser* user, CmdResult result, bool loop) { if (result == CMD_SUCCESS) Utils->RouteCommand(NULL, command, parameters, user); } void SpanningTreeUtilities::RouteCommand(TreeServer* origin, CommandBase* thiscmd, const CommandBase::Params& parameters, User* user) { const std::string& command = thiscmd->name; RouteDescriptor routing = thiscmd->GetRouting(user, parameters); if (routing.type == ROUTE_TYPE_LOCALONLY) return; const bool encap = ((routing.type == ROUTE_TYPE_OPT_BCAST) || (routing.type == ROUTE_TYPE_OPT_UCAST)); CmdBuilder params(user, encap ? "ENCAP" : command.c_str()); params.push_tags(parameters.GetTags()); TreeServer* sdest = NULL; if (routing.type == ROUTE_TYPE_OPT_BCAST) { params.push('*'); params.push(command); } else if (routing.type == ROUTE_TYPE_UNICAST || routing.type == ROUTE_TYPE_OPT_UCAST) { sdest = static_cast<TreeServer*>(routing.server); if (!sdest) { // Assume the command handler already validated routing.serverdest and have only returned success if the target is something that the // user executing the command is allowed to look up e.g. target is not an uuid if user is local. sdest = FindRouteTarget(routing.serverdest); if (!sdest) { ServerInstance->Logs->Log(MODNAME, LOG_DEFAULT, "Trying to route %s%s to nonexistent server %s", (encap ? "ENCAP " : ""), command.c_str(), routing.serverdest.c_str()); return; } } if (encap) { params.push(sdest->GetId()); params.push(command); } } else { Module* srcmodule = thiscmd->creator; Version ver = srcmodule->GetVersion(); if (!(ver.Flags & (VF_COMMON | VF_CORE)) && srcmodule != Creator) { ServerInstance->Logs->Log(MODNAME, LOG_DEFAULT, "Routed command %s from non-VF_COMMON module %s", command.c_str(), srcmodule->ModuleSourceFile.c_str()); return; } } std::string output_text = CommandParser::TranslateUIDs(thiscmd->translation, parameters, true, thiscmd); params.push(output_text); if (routing.type == ROUTE_TYPE_MESSAGE) { char pfx = 0; std::string dest = routing.serverdest; if (ServerInstance->Modes->FindPrefix(dest[0])) { pfx = dest[0]; dest.erase(dest.begin()); } if (dest[0] == '#') { Channel* c = ServerInstance->FindChan(dest); if (!c) return; // TODO OnBuildExemptList hook was here CUList exempts; std::string message; if (parameters.size() >= 2) message.assign(parameters[1]); SendChannelMessage(user, c, message, pfx, parameters.GetTags(), exempts, command.c_str(), origin ? origin->GetSocket() : NULL); } else if (dest[0] == '$') { params.Forward(origin); } else { // user target? User* d = ServerInstance->FindNick(dest); if (!d || IS_LOCAL(d)) return; TreeServer* tsd = TreeServer::Get(d)->GetRoute(); if (tsd == origin) // huh? no routing stuff around in a circle, please. return; params.Unicast(d); } } else if (routing.type == ROUTE_TYPE_BROADCAST || routing.type == ROUTE_TYPE_OPT_BCAST) { params.Forward(origin); } else if (routing.type == ROUTE_TYPE_UNICAST || routing.type == ROUTE_TYPE_OPT_UCAST) { params.Unicast(sdest->ServerUser); } } ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/src/modules/m_spanningtree/precommand.cpp��������������������������������������������0000664�0000000�0000000�00000003147�13554550454�0023451�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * InspIRCd -- Internet Relay Chat Daemon * * Copyright (C) 2008 Thomas Stagner <aquanight@inspircd.org> * Copyright (C) 2007 Craig Edwards <craigedwards@brainbox.cc> * * This file is part of InspIRCd. InspIRCd is free software: you can * redistribute it and/or modify it under the terms of the GNU General Public * License as published by the Free Software Foundation, version 2. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include "inspircd.h" #include "main.h" ModResult ModuleSpanningTree::OnPreCommand(std::string &command, CommandBase::Params& parameters, LocalUser *user, bool validated) { /* If the command doesnt appear to be valid, we dont want to mess with it. */ if (!validated) return MOD_RES_PASSTHRU; if (command == "CONNECT") { return this->HandleConnect(parameters,user); } else if (command == "SQUIT") { return this->HandleSquit(parameters,user); } else if (command == "LINKS") { this->HandleLinks(parameters,user); return MOD_RES_DENY; } else if (command == "WHOIS") { if (parameters.size() > 1) { // remote whois return this->HandleRemoteWhois(parameters,user); } } else if ((command == "VERSION") && (parameters.size() > 0)) { return this->HandleVersion(parameters,user); } return MOD_RES_PASSTHRU; } �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/src/modules/m_spanningtree/protocolinterface.cpp�������������������������������������0000664�0000000�0000000�00000010213�13554550454�0025036�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * InspIRCd -- Internet Relay Chat Daemon * * Copyright (C) 2009 Daniel De Graaf <danieldg@inspircd.org> * Copyright (C) 2008 Craig Edwards <craigedwards@brainbox.cc> * * This file is part of InspIRCd. InspIRCd is free software: you can * redistribute it and/or modify it under the terms of the GNU General Public * License as published by the Free Software Foundation, version 2. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include "inspircd.h" #include "utils.h" #include "treeserver.h" #include "protocolinterface.h" #include "commands.h" /* * For documentation on this class, see include/protocol.h. */ void SpanningTreeProtocolInterface::GetServerList(ServerList& sl) { for (server_hash::iterator i = Utils->serverlist.begin(); i != Utils->serverlist.end(); i++) { ServerInfo ps; ps.servername = i->second->GetName(); TreeServer* s = i->second->GetParent(); ps.parentname = s ? s->GetName() : ""; ps.usercount = i->second->UserCount; ps.opercount = i->second->OperCount; ps.description = i->second->GetDesc(); ps.latencyms = i->second->rtt; sl.push_back(ps); } } bool SpanningTreeProtocolInterface::SendEncapsulatedData(const std::string& targetmask, const std::string& cmd, const CommandBase::Params& params, User* source) { if (!source) source = ServerInstance->FakeClient; CmdBuilder encap(source, "ENCAP"); // Are there any wildcards in the target string? if (targetmask.find_first_of("*?") != std::string::npos) { // Yes, send the target string as-is; servers will decide whether or not it matches them encap.push(targetmask).push(cmd).insert(params).Broadcast(); } else { // No wildcards which means the target string has to be the name of a known server TreeServer* server = Utils->FindServer(targetmask); if (!server) return false; // Use the SID of the target in the message instead of the server name encap.push(server->GetId()).push(cmd).insert(params).Unicast(server->ServerUser); } return true; } void SpanningTreeProtocolInterface::BroadcastEncap(const std::string& cmd, const CommandBase::Params& params, User* source, User* omit) { if (!source) source = ServerInstance->FakeClient; // If omit is non-NULL we pass the route belonging to the user to Forward(), // otherwise we pass NULL, which is equivalent to Broadcast() TreeServer* server = (omit ? TreeServer::Get(omit)->GetRoute() : NULL); CmdBuilder(source, "ENCAP * ").push_raw(cmd).insert(params).Forward(server); } void SpanningTreeProtocolInterface::SendMetaData(User* u, const std::string& key, const std::string& data) { CommandMetadata::Builder(u, key, data).Broadcast(); } void SpanningTreeProtocolInterface::SendMetaData(Channel* c, const std::string& key, const std::string& data) { CommandMetadata::Builder(c, key, data).Broadcast(); } void SpanningTreeProtocolInterface::SendMetaData(const std::string& key, const std::string& data) { CommandMetadata::Builder(key, data).Broadcast(); } void SpanningTreeProtocolInterface::Server::SendMetaData(const std::string& key, const std::string& data) { sock->WriteLine(CommandMetadata::Builder(key, data)); } void SpanningTreeProtocolInterface::SendSNONotice(char snomask, const std::string &text) { CmdBuilder("SNONOTICE").push(snomask).push_last(text).Broadcast(); } void SpanningTreeProtocolInterface::SendMessage(Channel* target, char status, const std::string& text, MessageType msgtype) { const char* cmd = (msgtype == MSG_PRIVMSG ? "PRIVMSG" : "NOTICE"); CUList exempt_list; ClientProtocol::TagMap tags; Utils->SendChannelMessage(ServerInstance->FakeClient, target, text, status, tags, exempt_list, cmd); } void SpanningTreeProtocolInterface::SendMessage(User* target, const std::string& text, MessageType msgtype) { CmdBuilder p(msgtype == MSG_PRIVMSG ? "PRIVMSG" : "NOTICE"); p.push(target->uuid); p.push_last(text); p.Unicast(target); } �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/src/modules/m_spanningtree/protocolinterface.h���������������������������������������0000664�0000000�0000000�00000003577�13554550454�0024522�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * InspIRCd -- Internet Relay Chat Daemon * * Copyright (C) 2008 Craig Edwards <craigedwards@brainbox.cc> * * This file is part of InspIRCd. InspIRCd is free software: you can * redistribute it and/or modify it under the terms of the GNU General Public * License as published by the Free Software Foundation, version 2. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once class SpanningTreeProtocolInterface : public ProtocolInterface { public: class Server : public ProtocolInterface::Server { TreeSocket* const sock; public: Server(TreeSocket* s) : sock(s) { } void SendMetaData(const std::string& key, const std::string& data) CXX11_OVERRIDE; }; bool SendEncapsulatedData(const std::string& targetmask, const std::string& cmd, const CommandBase::Params& params, User* source) CXX11_OVERRIDE; void BroadcastEncap(const std::string& cmd, const CommandBase::Params& params, User* source, User* omit) CXX11_OVERRIDE; void SendMetaData(User* user, const std::string& key, const std::string& data) CXX11_OVERRIDE; void SendMetaData(Channel* chan, const std::string& key, const std::string& data) CXX11_OVERRIDE; void SendMetaData(const std::string& key, const std::string& data) CXX11_OVERRIDE; void SendSNONotice(char snomask, const std::string& text) CXX11_OVERRIDE; void SendMessage(Channel* target, char status, const std::string& text, MessageType msgtype) CXX11_OVERRIDE; void SendMessage(User* target, const std::string& text, MessageType msgtype) CXX11_OVERRIDE; void GetServerList(ServerList& sl) CXX11_OVERRIDE; }; ���������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/src/modules/m_spanningtree/rconnect.cpp����������������������������������������������0000664�0000000�0000000�00000005154�13554550454�0023137�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * InspIRCd -- Internet Relay Chat Daemon * * Copyright (C) 2007 Dennis Friis <peavey@inspircd.org> * Copyright (C) 2007 Craig Edwards <craigedwards@brainbox.cc> * * This file is part of InspIRCd. InspIRCd is free software: you can * redistribute it and/or modify it under the terms of the GNU General Public * License as published by the Free Software Foundation, version 2. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include "inspircd.h" #include "main.h" #include "utils.h" #include "commands.h" CommandRConnect::CommandRConnect (Module* Creator) : Command(Creator, "RCONNECT", 2) { flags_needed = 'o'; syntax = "<remote-server-mask> <target-server-mask>"; } CmdResult CommandRConnect::Handle(User* user, const Params& parameters) { /* First see if the server which is being asked to connect to another server in fact exists */ if (!Utils->FindServerMask(parameters[0])) { user->WriteRemoteNotice(InspIRCd::Format("*** RCONNECT: Server \002%s\002 isn't connected to the network!", parameters[0].c_str())); return CMD_FAILURE; } /* Is this aimed at our server? */ if (InspIRCd::Match(ServerInstance->Config->ServerName,parameters[0])) { /* Yes, initiate the given connect */ ServerInstance->SNO->WriteToSnoMask('l',"Remote CONNECT from %s matching \002%s\002, connecting server \002%s\002",user->nick.c_str(),parameters[0].c_str(),parameters[1].c_str()); CommandBase::Params para; para.push_back(parameters[1]); ((ModuleSpanningTree*)(Module*)creator)->HandleConnect(para, user); } else { /* It's not aimed at our server, but if the request originates from our user * acknowledge that we sent the request. * * It's possible that we're asking a server for something that makes no sense * (e.g. connect to itself or to an already connected server), but we don't check * for those conditions here, as ModuleSpanningTree::HandleConnect() (which will run * on the target) does all the checking and error reporting. */ if (IS_LOCAL(user)) { user->WriteNotice("*** RCONNECT: Sending remote connect to \002 " + parameters[0] + "\002 to connect server \002" + parameters[1] + "\002."); } } return CMD_SUCCESS; } RouteDescriptor CommandRConnect::GetRouting(User* user, const Params& parameters) { return ROUTE_UNICAST(parameters[0]); } ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/src/modules/m_spanningtree/remoteuser.cpp��������������������������������������������0000664�0000000�0000000�00000002016�13554550454�0023510�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * InspIRCd -- Internet Relay Chat Daemon * * Copyright (C) 2016 Attila Molnar <attilamolnar@hush.com> * * This file is part of InspIRCd. InspIRCd is free software: you can * redistribute it and/or modify it under the terms of the GNU General Public * License as published by the Free Software Foundation, version 2. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include "inspircd.h" #include "main.h" #include "remoteuser.h" SpanningTree::RemoteUser::RemoteUser(const std::string& uid, Server* srv) : ::RemoteUser(uid, srv) { } void SpanningTree::RemoteUser::WriteRemoteNumeric(const Numeric::Numeric& numeric) { CommandNum::Builder(this, numeric).Unicast(this); } ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/src/modules/m_spanningtree/remoteuser.h����������������������������������������������0000664�0000000�0000000�00000001725�13554550454�0023163�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * InspIRCd -- Internet Relay Chat Daemon * * Copyright (C) 2016 Attila Molnar <attilamolnar@hush.com> * * This file is part of InspIRCd. InspIRCd is free software: you can * redistribute it and/or modify it under the terms of the GNU General Public * License as published by the Free Software Foundation, version 2. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once namespace SpanningTree { class RemoteUser; } class SpanningTree::RemoteUser : public ::RemoteUser { public: RemoteUser(const std::string& uid, Server* srv); void WriteRemoteNumeric(const Numeric::Numeric& numeric) CXX11_OVERRIDE; }; �������������������������������������������inspircd-3.4.0/src/modules/m_spanningtree/resolvers.cpp���������������������������������������������0000664�0000000�0000000�00000011464�13554550454�0023351�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * InspIRCd -- Internet Relay Chat Daemon * * Copyright (C) 2007 Dennis Friis <peavey@inspircd.org> * Copyright (C) 2007 Craig Edwards <craigedwards@brainbox.cc> * * This file is part of InspIRCd. InspIRCd is free software: you can * redistribute it and/or modify it under the terms of the GNU General Public * License as published by the Free Software Foundation, version 2. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include "inspircd.h" #include "cachetimer.h" #include "resolvers.h" #include "main.h" #include "utils.h" #include "treeserver.h" #include "link.h" #include "treesocket.h" /** This class is used to resolve server hostnames during /connect and autoconnect. * As of 1.1, the resolver system is seperated out from BufferedSocket, so we must do this * resolver step first ourselves if we need it. This is totally nonblocking, and will * callback to OnLookupComplete or OnError when completed. Once it has completed we * will have an IP address which we can then use to continue our connection. */ ServernameResolver::ServernameResolver(DNS::Manager* mgr, const std::string& hostname, Link* x, DNS::QueryType qt, Autoconnect* myac) : DNS::Request(mgr, Utils->Creator, hostname, qt) , query(qt), host(hostname), MyLink(x), myautoconnect(myac) { } void ServernameResolver::OnLookupComplete(const DNS::Query *r) { const DNS::ResourceRecord* const ans_record = r->FindAnswerOfType(this->question.type); if (!ans_record) { OnError(r); return; } irc::sockets::sockaddrs sa; if (!irc::sockets::aptosa(ans_record->rdata, MyLink->Port, sa)) { // We had a result but it wasn't a valid IPv4/IPv6. OnError(r); return; } /* Initiate the connection, now that we have an IP to use. * Passing a hostname directly to BufferedSocket causes it to * just bail and set its FD to -1. */ TreeServer* CheckDupe = Utils->FindServer(MyLink->Name); if (!CheckDupe) /* Check that nobody tried to connect it successfully while we were resolving */ { TreeSocket* newsocket = new TreeSocket(MyLink, myautoconnect, sa); if (newsocket->GetFd() > -1) { /* We're all OK */ } else { /* Something barfed, show the opers */ ServerInstance->SNO->WriteToSnoMask('l', "CONNECT: Error connecting \002%s\002: %s.", MyLink->Name.c_str(), newsocket->getError().c_str()); ServerInstance->GlobalCulls.AddItem(newsocket); } } } void ServernameResolver::OnError(const DNS::Query *r) { if (r->error == DNS::ERROR_UNLOADED) { // We're being unloaded, skip the snotice and ConnectServer() below to prevent autoconnect creating new sockets return; } if (query == DNS::QUERY_AAAA) { ServernameResolver* snr = new ServernameResolver(this->manager, host, MyLink, DNS::QUERY_A, myautoconnect); try { this->manager->Process(snr); return; } catch (DNS::Exception &) { delete snr; } } ServerInstance->SNO->WriteToSnoMask('l', "CONNECT: Error connecting \002%s\002: Unable to resolve hostname - %s", MyLink->Name.c_str(), this->manager->GetErrorStr(r->error).c_str()); Utils->Creator->ConnectServer(myautoconnect, false); } SecurityIPResolver::SecurityIPResolver(Module* me, DNS::Manager* mgr, const std::string& hostname, Link* x, DNS::QueryType qt) : DNS::Request(mgr, me, hostname, qt) , MyLink(x), mine(me), host(hostname), query(qt) { } void SecurityIPResolver::OnLookupComplete(const DNS::Query *r) { for (std::vector<reference<Link> >::iterator i = Utils->LinkBlocks.begin(); i != Utils->LinkBlocks.end(); ++i) { Link* L = *i; if (L->IPAddr == host) { for (std::vector<DNS::ResourceRecord>::const_iterator j = r->answers.begin(); j != r->answers.end(); ++j) { const DNS::ResourceRecord& ans_record = *j; if (ans_record.type == this->question.type) Utils->ValidIPs.push_back(ans_record.rdata); } break; } } } void SecurityIPResolver::OnError(const DNS::Query *r) { // This can be called because of us being unloaded but we don't have to do anything differently if (query == DNS::QUERY_AAAA) { SecurityIPResolver* res = new SecurityIPResolver(mine, this->manager, host, MyLink, DNS::QUERY_A); try { this->manager->Process(res); return; } catch (DNS::Exception &) { delete res; } } ServerInstance->Logs->Log(MODNAME, LOG_DEFAULT, "Could not resolve IP associated with Link '%s': %s", MyLink->Name.c_str(), this->manager->GetErrorStr(r->error).c_str()); } CacheRefreshTimer::CacheRefreshTimer() : Timer(3600, true) { } bool CacheRefreshTimer::Tick(time_t TIME) { Utils->RefreshIPCache(); return true; } ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/src/modules/m_spanningtree/resolvers.h�����������������������������������������������0000664�0000000�0000000�00000004144�13554550454�0023013�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * InspIRCd -- Internet Relay Chat Daemon * * Copyright (C) 2007 Dennis Friis <peavey@inspircd.org> * Copyright (C) 2007 Craig Edwards <craigedwards@brainbox.cc> * * This file is part of InspIRCd. InspIRCd is free software: you can * redistribute it and/or modify it under the terms of the GNU General Public * License as published by the Free Software Foundation, version 2. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include "inspircd.h" #include "modules/dns.h" #include "utils.h" #include "link.h" /** Handle resolving of server IPs for the cache */ class SecurityIPResolver : public DNS::Request { private: reference<Link> MyLink; Module* mine; std::string host; DNS::QueryType query; public: SecurityIPResolver(Module* me, DNS::Manager* mgr, const std::string& hostname, Link* x, DNS::QueryType qt); void OnLookupComplete(const DNS::Query *r) CXX11_OVERRIDE; void OnError(const DNS::Query *q) CXX11_OVERRIDE; }; /** This class is used to resolve server hostnames during /connect and autoconnect. * As of 1.1, the resolver system is seperated out from BufferedSocket, so we must do this * resolver step first ourselves if we need it. This is totally nonblocking, and will * callback to OnLookupComplete or OnError when completed. Once it has completed we * will have an IP address which we can then use to continue our connection. */ class ServernameResolver : public DNS::Request { private: DNS::QueryType query; std::string host; reference<Link> MyLink; reference<Autoconnect> myautoconnect; public: ServernameResolver(DNS::Manager* mgr, const std::string& hostname, Link* x, DNS::QueryType qt, Autoconnect* myac); void OnLookupComplete(const DNS::Query *r) CXX11_OVERRIDE; void OnError(const DNS::Query *q) CXX11_OVERRIDE; }; ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/src/modules/m_spanningtree/rsquit.cpp������������������������������������������������0000664�0000000�0000000�00000004226�13554550454�0022652�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * InspIRCd -- Internet Relay Chat Daemon * * Copyright (C) 2008 Robin Burchell <robin+git@viroteck.net> * Copyright (C) 2007 Dennis Friis <peavey@inspircd.org> * * This file is part of InspIRCd. InspIRCd is free software: you can * redistribute it and/or modify it under the terms of the GNU General Public * License as published by the Free Software Foundation, version 2. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include "inspircd.h" #include "main.h" #include "utils.h" #include "treeserver.h" #include "commands.h" CommandRSQuit::CommandRSQuit(Module* Creator) : Command(Creator, "RSQUIT", 1) { flags_needed = 'o'; syntax = "<target-server-mask> [:<reason>]"; } CmdResult CommandRSQuit::Handle(User* user, const Params& parameters) { TreeServer *server_target; // Server to squit server_target = Utils->FindServerMask(parameters[0]); if (!server_target) { user->WriteRemoteNotice(InspIRCd::Format("*** RSQUIT: Server \002%s\002 isn't connected to the network!", parameters[0].c_str())); return CMD_FAILURE; } if (server_target->IsRoot()) { user->WriteRemoteNotice(InspIRCd::Format("*** RSQUIT: Foolish mortal, you cannot make a server SQUIT itself! (%s matches local server name)", parameters[0].c_str())); return CMD_FAILURE; } if (server_target->IsLocal()) { // We have been asked to remove server_target. const char* reason = parameters.size() == 2 ? parameters[1].c_str() : "No reason"; ServerInstance->SNO->WriteToSnoMask('l',"RSQUIT: Server \002%s\002 removed from network by %s (%s)", parameters[0].c_str(), user->nick.c_str(), reason); server_target->SQuit("Server quit by " + user->GetFullRealHost() + " (" + reason + ")"); } return CMD_SUCCESS; } RouteDescriptor CommandRSQuit::GetRouting(User* user, const Params& parameters) { return ROUTE_UNICAST(parameters[0]); } ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/src/modules/m_spanningtree/save.cpp��������������������������������������������������0000664�0000000�0000000�00000002207�13554550454�0022256�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * InspIRCd -- Internet Relay Chat Daemon * * Copyright (C) 2009 Daniel De Graaf <danieldg@inspircd.org> * * This file is part of InspIRCd. InspIRCd is free software: you can * redistribute it and/or modify it under the terms of the GNU General Public * License as published by the Free Software Foundation, version 2. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include "inspircd.h" #include "utils.h" #include "treesocket.h" #include "commands.h" /** * SAVE command - force nick change to UID on timestamp match */ CmdResult CommandSave::Handle(User* user, Params& params) { User* u = ServerInstance->FindUUID(params[0]); if (!u) return CMD_FAILURE; time_t ts = ConvToNum<time_t>(params[1]); if (u->age == ts) u->ChangeNick(u->uuid, SavedTimestamp); return CMD_SUCCESS; } �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/src/modules/m_spanningtree/server.cpp������������������������������������������������0000664�0000000�0000000�00000017517�13554550454�0022640�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * InspIRCd -- Internet Relay Chat Daemon * * Copyright (C) 2009-2010 Daniel De Graaf <danieldg@inspircd.org> * Copyright (C) 2008 Robin Burchell <robin+git@viroteck.net> * * 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 "inspircd.h" #include "modules/ssl.h" #include "main.h" #include "utils.h" #include "link.h" #include "treeserver.h" #include "treesocket.h" #include "commands.h" /* * Some server somewhere in the network introducing another server. * -- w */ CmdResult CommandServer::HandleServer(TreeServer* ParentOfThis, Params& params) { const std::string& servername = params[0]; const std::string& sid = params[1]; const std::string& description = params.back(); TreeSocket* socket = ParentOfThis->GetSocket(); if (!InspIRCd::IsSID(sid)) { socket->SendError("Invalid format server ID: "+sid+"!"); return CMD_FAILURE; } TreeServer* CheckDupe = Utils->FindServer(servername); if (CheckDupe) { socket->SendError("Server "+servername+" already exists!"); ServerInstance->SNO->WriteToSnoMask('L', "Server \002"+CheckDupe->GetName()+"\002 being introduced from \002" + ParentOfThis->GetName() + "\002 denied, already exists. Closing link with " + ParentOfThis->GetName()); return CMD_FAILURE; } CheckDupe = Utils->FindServer(sid); if (CheckDupe) { socket->SendError("Server ID "+sid+" already exists! You may want to specify the server ID for the server manually with <server:id> so they do not conflict."); ServerInstance->SNO->WriteToSnoMask('L', "Server \002"+servername+"\002 being introduced from \002" + ParentOfThis->GetName() + "\002 denied, server ID already exists on the network. Closing link with " + ParentOfThis->GetName()); return CMD_FAILURE; } TreeServer* route = ParentOfThis->GetRoute(); Link* lnk = Utils->FindLink(route->GetName()); TreeServer* Node = new TreeServer(servername, description, sid, ParentOfThis, ParentOfThis->GetSocket(), lnk ? lnk->Hidden : false); HandleExtra(Node, params); ServerInstance->SNO->WriteToSnoMask('L', "Server \002"+ParentOfThis->GetName()+"\002 introduced server \002"+servername+"\002 ("+description+")"); return CMD_SUCCESS; } void CommandServer::HandleExtra(TreeServer* newserver, Params& params) { for (CommandBase::Params::const_iterator i = params.begin() + 2; i != params.end() - 1; ++i) { const std::string& prop = *i; std::string::size_type p = prop.find('='); std::string key = prop; std::string val; if (p != std::string::npos) { key.erase(p); val.assign(prop, p+1, std::string::npos); } if (irc::equals(key, "burst")) newserver->BeginBurst(ConvToNum<uint64_t>(val)); else if (irc::equals(key, "hidden")) newserver->Hidden = ConvToNum<bool>(val); } } Link* TreeSocket::AuthRemote(const CommandBase::Params& params) { if (params.size() < 5) { SendError("Protocol error - Not enough parameters for SERVER command"); return NULL; } const std::string& sname = params[0]; const std::string& password = params[1]; const std::string& sid = params[3]; const std::string& description = params.back(); this->SendCapabilities(2); if (!ServerInstance->IsSID(sid)) { this->SendError("Invalid format server ID: "+sid+"!"); return NULL; } for (std::vector<reference<Link> >::iterator i = Utils->LinkBlocks.begin(); i < Utils->LinkBlocks.end(); i++) { Link* x = *i; if (!InspIRCd::Match(sname, x->Name)) continue; if (!ComparePass(*x, password)) { ServerInstance->SNO->WriteToSnoMask('l', "Invalid password on link: %s", x->Name.c_str()); continue; } if (!CheckDuplicate(sname, sid)) return NULL; ServerInstance->SNO->WriteToSnoMask('l', "Verified server connection " + linkID + " ("+description+")"); const SSLIOHook* const ssliohook = SSLIOHook::IsSSL(this); if (ssliohook) { std::string ciphersuite; ssliohook->GetCiphersuite(ciphersuite); ServerInstance->SNO->WriteToSnoMask('l', "Negotiated ciphersuite %s on link %s", ciphersuite.c_str(), x->Name.c_str()); } return x; } this->SendError("Mismatched server name or password (check the other server's snomask output for details - e.g. user mode +s +Ll)"); ServerInstance->SNO->WriteToSnoMask('l', "Server connection from \002"+sname+"\002 denied, invalid link credentials"); return NULL; } /* * This is used after the other side of a connection has accepted our credentials. * They are then introducing themselves to us, BEFORE either of us burst. -- w */ bool TreeSocket::Outbound_Reply_Server(CommandBase::Params& params) { const Link* x = AuthRemote(params); if (x) { /* * They're in WAIT_AUTH_2 (having accepted our credentials). * Set our state to CONNECTED (since everything's peachy so far) and send our * netburst to them, which will trigger their CONNECTED state, and BURST in reply. * * While we're at it, create a treeserver object so we know about them. * -- w */ FinishAuth(params[0], params[3], params.back(), x->Hidden); return true; } return false; } bool TreeSocket::CheckDuplicate(const std::string& sname, const std::string& sid) { // Check if the server name is not in use by a server that's already fully connected TreeServer* CheckDupe = Utils->FindServer(sname); if (CheckDupe) { std::string pname = CheckDupe->GetParent() ? CheckDupe->GetParent()->GetName() : "<ourself>"; SendError("Server "+sname+" already exists on server "+pname+"!"); ServerInstance->SNO->WriteToSnoMask('l', "Server connection from \002"+sname+"\002 denied, already exists on server "+pname); return false; } // Check if the id is not in use by a server that's already fully connected ServerInstance->Logs->Log(MODNAME, LOG_DEBUG, "Looking for dupe SID %s", sid.c_str()); CheckDupe = Utils->FindServerID(sid); if (CheckDupe) { this->SendError("Server ID "+CheckDupe->GetId()+" already exists on server "+CheckDupe->GetName()+"! You may want to specify the server ID for the server manually with <server:id> so they do not conflict."); ServerInstance->SNO->WriteToSnoMask('l', "Server connection from \002"+sname+"\002 denied, server ID '"+CheckDupe->GetId()+ "' already exists on server "+CheckDupe->GetName()); return false; } return true; } /* * Someone else is attempting to connect to us if this is called. Validate their credentials etc. * -- w */ bool TreeSocket::Inbound_Server(CommandBase::Params& params) { const Link* x = AuthRemote(params); if (x) { // Save these for later, so when they accept our credentials (indicated by BURST) we remember them this->capab->hidden = x->Hidden; this->capab->sid = params[3]; this->capab->description = params.back(); this->capab->name = params[0]; // Send our details: Our server name and description and hopcount of 0, // along with the sendpass from this block. this->WriteLine("SERVER "+ServerInstance->Config->ServerName+" "+this->MakePass(x->SendPass, this->GetTheirChallenge())+" 0 "+ServerInstance->Config->GetSID()+" :"+ServerInstance->Config->ServerDesc); // move to the next state, we are now waiting for THEM. this->LinkState = WAIT_AUTH_2; return true; } return false; } CommandServer::Builder::Builder(TreeServer* server) : CmdBuilder(server->GetParent(), "SERVER") { push(server->GetName()); push(server->GetId()); if (server->IsBursting()) push_property("burst", ConvToStr(server->StartBurst)); push_property("hidden", ConvToStr(server->Hidden)); push_last(server->GetDesc()); } ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/src/modules/m_spanningtree/servercommand.cpp�����������������������������������������0000664�0000000�0000000�00000003424�13554550454�0024167�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * InspIRCd -- Internet Relay Chat Daemon * * Copyright (C) 2013 Attila Molnar <attilamolnar@hush.com> * * This file is part of InspIRCd. InspIRCd is free software: you can * redistribute it and/or modify it under the terms of the GNU General Public * License as published by the Free Software Foundation, version 2. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include "inspircd.h" #include "main.h" #include "servercommand.h" ServerCommand::ServerCommand(Module* Creator, const std::string& Name, unsigned int MinParams, unsigned int MaxParams) : CommandBase(Creator, Name, MinParams, MaxParams) { } void ServerCommand::RegisterService() { ModuleSpanningTree* st = static_cast<ModuleSpanningTree*>(static_cast<Module*>(creator)); st->CmdManager.AddCommand(this); } RouteDescriptor ServerCommand::GetRouting(User* user, const Params& parameters) { // Broadcast server-to-server commands unless overridden return ROUTE_BROADCAST; } time_t ServerCommand::ExtractTS(const std::string& tsstr) { time_t TS = ConvToNum<time_t>(tsstr); if (!TS) throw ProtocolException("Invalid TS"); return TS; } ServerCommand* ServerCommandManager::GetHandler(const std::string& command) const { ServerCommandMap::const_iterator it = commands.find(command); if (it != commands.end()) return it->second; return NULL; } bool ServerCommandManager::AddCommand(ServerCommand* cmd) { return commands.insert(std::make_pair(cmd->name, cmd)).second; } ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/src/modules/m_spanningtree/servercommand.h�������������������������������������������0000664�0000000�0000000�00000006744�13554550454�0023644�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * InspIRCd -- Internet Relay Chat Daemon * * Copyright (C) 2013 Attila Molnar <attilamolnar@hush.com> * * This file is part of InspIRCd. InspIRCd is free software: you can * redistribute it and/or modify it under the terms of the GNU General Public * License as published by the Free Software Foundation, version 2. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include "utils.h" #include "treeserver.h" class ProtocolException : public ModuleException { public: ProtocolException(const std::string& msg) : ModuleException("Protocol violation: " + msg) { } }; /** Base class for server-to-server commands that may have a (remote) user source or server source. */ class ServerCommand : public CommandBase { public: ServerCommand(Module* Creator, const std::string& Name, unsigned int MinPara = 0, unsigned int MaxPara = 0); /** Register this object in the ServerCommandManager */ void RegisterService() CXX11_OVERRIDE; virtual CmdResult Handle(User* user, Params& parameters) = 0; RouteDescriptor GetRouting(User* user, const Params& parameters) CXX11_OVERRIDE; /** * Extract the TS from a string. * @param tsstr The string containing the TS. * @return The raw timestamp value. * This function throws a ProtocolException if it considers the TS invalid. Note that the detection of * invalid timestamps is not designed to be bulletproof, only some cases - like "0" - trigger an exception. */ static time_t ExtractTS(const std::string& tsstr); }; /** Base class for server-to-server command handlers which are only valid if their source is a user. * When a server sends a command of this type and the source is a server (sid), the link is aborted. */ template <class T> class UserOnlyServerCommand : public ServerCommand { public: UserOnlyServerCommand(Module* Creator, const std::string& Name, unsigned int MinPara = 0, unsigned int MaxPara = 0) : ServerCommand(Creator, Name, MinPara, MaxPara) { } CmdResult Handle(User* user, Params& parameters) CXX11_OVERRIDE { RemoteUser* remoteuser = IS_REMOTE(user); if (!remoteuser) throw ProtocolException("Invalid source"); return static_cast<T*>(this)->HandleRemote(remoteuser, parameters); } }; /** Base class for server-to-server command handlers which are only valid if their source is a server. * When a server sends a command of this type and the source is a user (uuid), the link is aborted. */ template <class T> class ServerOnlyServerCommand : public ServerCommand { public: ServerOnlyServerCommand(Module* Creator, const std::string& Name, unsigned int MinPara = 0, unsigned int MaxPara = 0) : ServerCommand(Creator, Name, MinPara, MaxPara) { } CmdResult Handle(User* user, CommandBase::Params& parameters) CXX11_OVERRIDE { if (!IS_SERVER(user)) throw ProtocolException("Invalid source"); TreeServer* server = TreeServer::Get(user); return static_cast<T*>(this)->HandleServer(server, parameters); } }; class ServerCommandManager { typedef TR1NS::unordered_map<std::string, ServerCommand*> ServerCommandMap; ServerCommandMap commands; public: ServerCommand* GetHandler(const std::string& command) const; bool AddCommand(ServerCommand* cmd); }; ����������������������������inspircd-3.4.0/src/modules/m_spanningtree/sinfo.cpp�������������������������������������������������0000664�0000000�0000000�00000003125�13554550454�0022436�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * InspIRCd -- Internet Relay Chat Daemon * * Copyright (C) 2014 Attila Molnar <attilamolnar@hush.com> * * This file is part of InspIRCd. InspIRCd is free software: you can * redistribute it and/or modify it under the terms of the GNU General Public * License as published by the Free Software Foundation, version 2. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include "inspircd.h" #include "treeserver.h" #include "commands.h" CmdResult CommandSInfo::HandleServer(TreeServer* server, CommandBase::Params& params) { const std::string& key = params.front(); const std::string& value = params.back(); if (key == "fullversion") { server->SetFullVersion(value); } else if (key == "version") { server->SetVersion(value); } else if (key == "rawversion") { server->SetRawVersion(value); } else if (key == "desc") { // Only sent when the description of a server changes because of a rehash; not sent on burst ServerInstance->Logs->Log(MODNAME, LOG_DEFAULT, "Server description of " + server->GetName() + " changed: " + value); server->SetDesc(value); } return CMD_SUCCESS; } CommandSInfo::Builder::Builder(TreeServer* server, const char* key, const std::string& val) : CmdBuilder(server, "SINFO") { push(key).push_last(val); } �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/src/modules/m_spanningtree/svsjoin.cpp�����������������������������������������������0000664�0000000�0000000�00000003076�13554550454�0023020�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * InspIRCd -- Internet Relay Chat Daemon * * Copyright (C) 2010 Daniel De Graaf <danieldg@inspircd.org> * Copyright (C) 2008 Robin Burchell <robin+git@viroteck.net> * * 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 "inspircd.h" #include "commands.h" CmdResult CommandSVSJoin::Handle(User* user, Params& parameters) { // Check for valid channel name if (!ServerInstance->IsChannel(parameters[1])) return CMD_FAILURE; // Check target exists User* u = ServerInstance->FindUUID(parameters[0]); if (!u) return CMD_FAILURE; /* only join if it's local, otherwise just pass it on! */ LocalUser* localuser = IS_LOCAL(u); if (localuser) { bool override = false; std::string key; if (parameters.size() >= 3) { key = parameters[2]; if (key.empty()) override = true; } Channel::JoinUser(localuser, parameters[1], override, key); } return CMD_SUCCESS; } RouteDescriptor CommandSVSJoin::GetRouting(User* user, const Params& parameters) { return ROUTE_OPT_UCAST(parameters[0]); } ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/src/modules/m_spanningtree/svsnick.cpp�����������������������������������������������0000664�0000000�0000000�00000005300�13554550454�0022775�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * InspIRCd -- Internet Relay Chat Daemon * * Copyright (C) 2010 Daniel De Graaf <danieldg@inspircd.org> * Copyright (C) 2008 Robin Burchell <robin+git@viroteck.net> * * 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 "inspircd.h" #include "main.h" #include "commands.h" CmdResult CommandSVSNick::Handle(User* user, Params& parameters) { User* u = ServerInstance->FindNick(parameters[0]); if (u && IS_LOCAL(u)) { // The 4th parameter is optional and it is the expected nick TS of the target user. If this parameter is // present and it doesn't match the user's nick TS, the SVSNICK is not acted upon. // This makes it possible to detect the case when services wants to change the nick of a user, but the // user changes their nick before the SVSNICK arrives, making the SVSNICK nick change (usually to a guest nick) // unnecessary. Consider the following for example: // // 1. test changes nick to Attila which is protected by services // 2. Services SVSNICKs the user to Guest12345 // 3. Attila changes nick to Attila_ which isn't protected by services // 4. SVSNICK arrives // 5. Attila_ gets his nick changed to Guest12345 unnecessarily // // In this case when the SVSNICK is processed the target has already changed their nick to something // which isn't protected, so changing the nick again to a Guest nick is not desired. // However, if the expected nick TS parameter is present in the SVSNICK then the nick change in step 5 // won't happen because the timestamps won't match. if (parameters.size() > 3) { time_t ExpectedTS = ConvToNum<time_t>(parameters[3]); if (u->age != ExpectedTS) return CMD_FAILURE; // Ignore SVSNICK } std::string nick = parameters[1]; if (isdigit(nick[0])) nick = u->uuid; time_t NickTS = ConvToNum<time_t>(parameters[2]); if (NickTS <= 0) return CMD_FAILURE; if (!u->ChangeNick(nick, NickTS)) { // Changing to 'nick' failed (it may already be in use), change to the uuid u->ChangeNick(u->uuid); } } return CMD_SUCCESS; } RouteDescriptor CommandSVSNick::GetRouting(User* user, const Params& parameters) { return ROUTE_OPT_UCAST(parameters[0]); } ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/src/modules/m_spanningtree/svspart.cpp�����������������������������������������������0000664�0000000�0000000�00000002530�13554550454�0023021�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * InspIRCd -- Internet Relay Chat Daemon * * Copyright (C) 2010 Daniel De Graaf <danieldg@inspircd.org> * Copyright (C) 2008 Robin Burchell <robin+git@viroteck.net> * * 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 "inspircd.h" #include "commands.h" CmdResult CommandSVSPart::Handle(User* user, Params& parameters) { User* u = ServerInstance->FindUUID(parameters[0]); if (!u) return CMD_FAILURE; Channel* c = ServerInstance->FindChan(parameters[1]); if (!c) return CMD_FAILURE; if (IS_LOCAL(u)) { std::string reason = (parameters.size() == 3) ? parameters[2] : "Services forced part"; c->PartUser(u, reason); } return CMD_SUCCESS; } RouteDescriptor CommandSVSPart::GetRouting(User* user, const Params& parameters) { return ROUTE_OPT_UCAST(parameters[0]); } ������������������������������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/src/modules/m_spanningtree/translate.cpp���������������������������������������������0000664�0000000�0000000�00000002436�13554550454�0023321�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * InspIRCd -- Internet Relay Chat Daemon * * Copyright (C) 2014 Attila Molnar <attilamolnar@hush.com> * * This file is part of InspIRCd. InspIRCd is free software: you can * redistribute it and/or modify it under the terms of the GNU General Public * License as published by the Free Software Foundation, version 2. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include "inspircd.h" #include "translate.h" std::string Translate::ModeChangeListToParams(const Modes::ChangeList::List& modes) { std::string ret; for (Modes::ChangeList::List::const_iterator i = modes.begin(); i != modes.end(); ++i) { const Modes::Change& item = *i; ModeHandler* mh = item.mh; if (!mh->NeedsParam(item.adding)) continue; ret.push_back(' '); if (mh->IsPrefixMode()) { User* target = ServerInstance->FindNick(item.param); if (target) { ret.append(target->uuid); continue; } } ret.append(item.param); } return ret; } ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/src/modules/m_spanningtree/translate.h�����������������������������������������������0000664�0000000�0000000�00000002116�13554550454�0022761�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * InspIRCd -- Internet Relay Chat Daemon * * Copyright (C) 2014 Attila Molnar <attilamolnar@hush.com> * * This file is part of InspIRCd. InspIRCd is free software: you can * redistribute it and/or modify it under the terms of the GNU General Public * License as published by the Free Software Foundation, version 2. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once namespace Translate { /** Generate a list of mode parameters suitable for FMODE/MODE from a Modes::ChangeList::List * @param modes List of mode changes * @return List of mode parameters built from the input. Does not include the modes themselves, * only the parameters. */ std::string ModeChangeListToParams(const Modes::ChangeList::List& modes); } ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/src/modules/m_spanningtree/treeserver.cpp��������������������������������������������0000664�0000000�0000000�00000024032�13554550454�0023506�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * InspIRCd -- Internet Relay Chat Daemon * * Copyright (C) 2009 Daniel De Graaf <danieldg@inspircd.org> * Copyright (C) 2007-2008 Craig Edwards <craigedwards@brainbox.cc> * Copyright (C) 2008 Robin Burchell <robin+git@viroteck.net> * Copyright (C) 2007 Dennis Friis <peavey@inspircd.org> * * This file is part of InspIRCd. InspIRCd is free software: you can * redistribute it and/or modify it under the terms of the GNU General Public * License as published by the Free Software Foundation, version 2. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include "inspircd.h" #include "xline.h" #include "main.h" #include "utils.h" #include "treeserver.h" /** We use this constructor only to create the 'root' item, Utils->TreeRoot, which * represents our own server. Therefore, it has no route, no parent, and * no socket associated with it. Its version string is our own local version. */ TreeServer::TreeServer() : Server(ServerInstance->Config->GetSID(), ServerInstance->Config->ServerName, ServerInstance->Config->ServerDesc) , Parent(NULL), Route(NULL) , VersionString(ServerInstance->GetVersionString()) , fullversion(ServerInstance->GetVersionString(true)) , rawversion(INSPIRCD_VERSION) , Socket(NULL) , behind_bursting(0) , isdead(false) , pingtimer(this) , ServerUser(ServerInstance->FakeClient) , age(ServerInstance->Time()) , UserCount(ServerInstance->Users.LocalUserCount()) , OperCount(0) , rtt(0) , StartBurst(0) , Hidden(false) { AddHashEntry(); } /** When we create a new server, we call this constructor to initialize it. * This constructor initializes the server's Route and Parent, and sets up * the ping timer for the server. */ TreeServer::TreeServer(const std::string& Name, const std::string& Desc, const std::string& Sid, TreeServer* Above, TreeSocket* Sock, bool Hide) : Server(Sid, Name, Desc) , Parent(Above) , Socket(Sock) , behind_bursting(Parent->behind_bursting) , isdead(false) , pingtimer(this) , ServerUser(new FakeUser(id, this)) , age(ServerInstance->Time()) , UserCount(0) , OperCount(0) , rtt(0) , StartBurst(0) , Hidden(Hide) { ServerInstance->Logs->Log(MODNAME, LOG_DEBUG, "New server %s behind_bursting %u", GetName().c_str(), behind_bursting); CheckULine(); ServerInstance->Timers.AddTimer(&pingtimer); /* find the 'route' for this server (e.g. the one directly connected * to the local server, which we can use to reach it) * * In the following example, consider we have just added a TreeServer * class for server G on our network, of which we are server A. * To route traffic to G (marked with a *) we must send the data to * B (marked with a +) so this algorithm initializes the 'Route' * value to point at whichever server traffic must be routed through * to get here. If we were to try this algorithm with server B, * the Route pointer would point at its own object ('this'). * * A * / \ * + B C * / \ \ * D E F * / \ * * G H * * We only run this algorithm when a server is created, as * the routes remain constant while ever the server exists, and * do not need to be re-calculated. */ Route = Above; if (Route == Utils->TreeRoot) { Route = this; } else { while (this->Route->GetParent() != Utils->TreeRoot) { this->Route = Route->GetParent(); } } /* Because recursive code is slow and takes a lot of resources, * we store two representations of the server tree. The first * is a recursive structure where each server references its * children and its parent, which is used for netbursts and * netsplits to dump the whole dataset to the other server, * and the second is used for very fast lookups when routing * messages and is instead a hash_map, where each item can * be referenced by its server name. The AddHashEntry() * call below automatically inserts each TreeServer class * into the hash_map as it is created. There is a similar * maintainance call in the destructor to tidy up deleted * servers. */ this->AddHashEntry(); Parent->Children.push_back(this); FOREACH_MOD_CUSTOM(Utils->Creator->GetLinkEventProvider(), ServerProtocol::LinkEventListener, OnServerLink, (this)); } void TreeServer::BeginBurst(uint64_t startms) { behind_bursting++; uint64_t now = ServerInstance->Time() * 1000 + (ServerInstance->Time_ns() / 1000000); // If the start time is in the future (clocks are not synced) then use current time if ((!startms) || (startms > now)) startms = now; this->StartBurst = startms; ServerInstance->Logs->Log(MODNAME, LOG_DEBUG, "Server %s started bursting at time %s behind_bursting %u", GetId().c_str(), ConvToStr(startms).c_str(), behind_bursting); } void TreeServer::FinishBurstInternal() { // Check is needed because 1202 protocol servers don't send the bursting state of a server, so servers // introduced during a netburst may later send ENDBURST which would normally decrease this counter if (behind_bursting > 0) behind_bursting--; ServerInstance->Logs->Log(MODNAME, LOG_DEBUG, "FinishBurstInternal() %s behind_bursting %u", GetName().c_str(), behind_bursting); for (ChildServers::const_iterator i = Children.begin(); i != Children.end(); ++i) { TreeServer* child = *i; child->FinishBurstInternal(); } } void TreeServer::FinishBurst() { ServerInstance->XLines->ApplyLines(); uint64_t ts = ServerInstance->Time() * 1000 + (ServerInstance->Time_ns() / 1000000); unsigned long bursttime = ts - this->StartBurst; ServerInstance->SNO->WriteToSnoMask(Parent == Utils->TreeRoot ? 'l' : 'L', "Received end of netburst from \002%s\002 (burst time: %lu %s)", GetName().c_str(), (bursttime > 10000 ? bursttime / 1000 : bursttime), (bursttime > 10000 ? "secs" : "msecs")); FOREACH_MOD_CUSTOM(Utils->Creator->GetLinkEventProvider(), ServerProtocol::LinkEventListener, OnServerBurst, (this)); StartBurst = 0; FinishBurstInternal(); } void TreeServer::SQuitChild(TreeServer* server, const std::string& reason, bool error) { stdalgo::erase(Children, server); if (IsRoot()) { // Server split from us, generate a SQUIT message and broadcast it ServerInstance->SNO->WriteGlobalSno('l', "Server \002" + server->GetName() + "\002 split: " + reason); CmdBuilder("SQUIT").push(server->GetId()).push_last(reason).Broadcast(); } else { ServerInstance->SNO->WriteToSnoMask('L', "Server \002" + server->GetName() + "\002 split from server \002" + GetName() + "\002 with reason: " + reason); } unsigned int num_lost_servers = 0; server->SQuitInternal(num_lost_servers, error); const std::string quitreason = GetName() + " " + server->GetName(); unsigned int num_lost_users = QuitUsers(quitreason); ServerInstance->SNO->WriteToSnoMask(IsRoot() ? 'l' : 'L', "Netsplit complete, lost \002%u\002 user%s on \002%u\002 server%s.", num_lost_users, num_lost_users != 1 ? "s" : "", num_lost_servers, num_lost_servers != 1 ? "s" : ""); // No-op if the socket is already closed (i.e. it called us) if (server->IsLocal()) server->GetSocket()->Close(); // Add the server to the cull list, the servers behind it are handled by cull() and the destructor ServerInstance->GlobalCulls.AddItem(server); } void TreeServer::SQuitInternal(unsigned int& num_lost_servers, bool error) { ServerInstance->Logs->Log(MODNAME, LOG_DEBUG, "Server %s lost in split", GetName().c_str()); for (ChildServers::const_iterator i = Children.begin(); i != Children.end(); ++i) { TreeServer* server = *i; server->SQuitInternal(num_lost_servers, error); } // Mark server as dead isdead = true; num_lost_servers++; RemoveHash(); if (!Utils->Creator->dying) FOREACH_MOD_CUSTOM(Utils->Creator->GetLinkEventProvider(), ServerProtocol::LinkEventListener, OnServerSplit, (this, error)); } unsigned int TreeServer::QuitUsers(const std::string& reason) { std::string publicreason = Utils->HideSplits ? "*.net *.split" : reason; const user_hash& users = ServerInstance->Users->GetUsers(); unsigned int original_size = users.size(); for (user_hash::const_iterator i = users.begin(); i != users.end(); ) { User* user = i->second; // Increment the iterator now because QuitUser() removes the user from the container ++i; TreeServer* server = TreeServer::Get(user); if (server->IsDead()) ServerInstance->Users->QuitUser(user, publicreason, &reason); } return original_size - users.size(); } void TreeServer::CheckULine() { uline = silentuline = false; ConfigTagList tags = ServerInstance->Config->ConfTags("uline"); for (ConfigIter i = tags.first; i != tags.second; ++i) { ConfigTag* tag = i->second; std::string server = tag->getString("server"); if (!strcasecmp(server.c_str(), GetName().c_str())) { if (this->IsRoot()) { ServerInstance->Logs->Log(MODNAME, LOG_DEFAULT, "Servers should not uline themselves (at " + tag->getTagLocation() + ")"); return; } uline = true; silentuline = tag->getBool("silent"); break; } } } /** This method is used to add the server to the * maps for linear searches. It is only called * by the constructors. */ void TreeServer::AddHashEntry() { Utils->serverlist[GetName()] = this; Utils->sidlist[GetId()] = this; } CullResult TreeServer::cull() { // Recursively cull all servers that are under us in the tree for (ChildServers::const_iterator i = Children.begin(); i != Children.end(); ++i) { TreeServer* server = *i; server->cull(); } if (!IsRoot()) ServerUser->cull(); return classbase::cull(); } TreeServer::~TreeServer() { // Recursively delete all servers that are under us in the tree first for (ChildServers::const_iterator i = Children.begin(); i != Children.end(); ++i) delete *i; // Delete server user unless it's us if (!IsRoot()) delete ServerUser; } void TreeServer::RemoveHash() { Utils->sidlist.erase(GetId()); Utils->serverlist.erase(GetName()); } ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/src/modules/m_spanningtree/treeserver.h����������������������������������������������0000664�0000000�0000000�00000020203�13554550454�0023147�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * InspIRCd -- Internet Relay Chat Daemon * * Copyright (C) 2008 Robin Burchell <robin+git@viroteck.net> * Copyright (C) 2007 Dennis Friis <peavey@inspircd.org> * Copyright (C) 2007 Craig Edwards <craigedwards@brainbox.cc> * * This file is part of InspIRCd. InspIRCd is free software: you can * redistribute it and/or modify it under the terms of the GNU General Public * License as published by the Free Software Foundation, version 2. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include "treesocket.h" #include "pingtimer.h" /** Each server in the tree is represented by one class of * type TreeServer. A locally connected TreeServer can * have a class of type TreeSocket associated with it, for * remote servers, the TreeSocket entry will be NULL. * Each server also maintains a pointer to its parent * (NULL if this server is ours, at the top of the tree) * and a pointer to its "Route" (see the comments in the * constructors below), and also a dynamic list of pointers * to its children which can be iterated recursively * if required. Creating or deleting objects of type i* TreeServer automatically maintains the hash_map of * TreeServer items, deleting and inserting them as they * are created and destroyed. */ class TreeServer : public Server { TreeServer* Parent; /* Parent entry */ TreeServer* Route; /* Route entry */ std::vector<TreeServer*> Children; /* List of child objects */ std::string VersionString; /* Version string or empty string */ /** Full version string including patch version and other info */ std::string fullversion; std::string rawversion; TreeSocket* Socket; /* Socket used to communicate with this server */ /** Counter counting how many servers are bursting in front of this server, including * this server. Set to parents' value on construction then it is increased if the * server itself starts bursting. Decreased when a server on the path to this server * finishes burst. */ unsigned int behind_bursting; /** True if this server has been lost in a split and is awaiting destruction */ bool isdead; /** Timer handling PINGing the server and killing it on timeout */ PingTimer pingtimer; /** This method is used to add this TreeServer to the * hash maps. It is only called by the constructors. */ void AddHashEntry(); /** Used by SQuit logic to recursively remove servers */ void SQuitInternal(unsigned int& num_lost_servers, bool error); /** Remove the reference to this server from the hash maps */ void RemoveHash(); public: typedef std::vector<TreeServer*> ChildServers; FakeUser* const ServerUser; /* User representing this server */ const time_t age; unsigned int UserCount; /* How many users are on this server? [note: doesn't care about +i] */ unsigned int OperCount; /* How many opers are on this server? */ /** We use this constructor only to create the 'root' item, Utils->TreeRoot, which * represents our own server. Therefore, it has no route, no parent, and * no socket associated with it. Its version string is our own local version. */ TreeServer(); /** When we create a new server, we call this constructor to initialize it. * This constructor initializes the server's Route and Parent, and sets up * its ping counters so that it will be pinged one minute from now. */ TreeServer(const std::string& Name, const std::string& Desc, const std::string& id, TreeServer* Above, TreeSocket* Sock, bool Hide); /** SQuit a server connected to this server, removing the given server and all servers behind it * @param server Server to squit, must be directly below this server * @param reason Reason for quitting the server, sent to opers and other servers * @param error Whether the server is being squit because of an error. */ void SQuitChild(TreeServer* server, const std::string& reason, bool error = false); /** SQuit this server, removing this server and all servers behind it * @param reason Reason for quitting the server, sent to opers and other servers * @param error Whether the server is being squit because of an error. */ void SQuit(const std::string& reason, bool error = false) { GetParent()->SQuitChild(this, reason, error); } static unsigned int QuitUsers(const std::string& reason); /** Get route. * The 'route' is defined as the locally- * connected server which can be used to reach this server. */ TreeServer* GetRoute() const { return Route; } /** Returns true if this server is the tree root (i.e.: us) */ bool IsRoot() const { return (this->Parent == NULL); } /** Returns true if this server is locally connected */ bool IsLocal() const { return (this->Route == this); } /** Returns true if the server is awaiting destruction * @return True if the server is waiting to be culled and deleted, false otherwise */ bool IsDead() const { return isdead; } /** Get server version string */ const std::string& GetVersion() const { return VersionString; } /** Get the full version string of this server * @return The full version string of this server, including patch version and other info */ const std::string& GetFullVersion() const { return fullversion; } /** Get the raw version string of this server */ const std::string& GetRawVersion() const { return rawversion; } /** Round trip time of last ping */ unsigned long rtt; /** When we received BURST from this server, used to calculate total burst time at ENDBURST. */ uint64_t StartBurst; /** True if this server is hidden */ bool Hidden; /** Get the TreeSocket pointer for local servers. * For remote servers, this returns NULL. */ TreeSocket* GetSocket() const { return Socket; } /** Get the parent server. * For the root node, this returns NULL. */ TreeServer* GetParent() const { return Parent; } /** Set the server version string */ void SetVersion(const std::string& verstr) { VersionString = verstr; } /** Set the full version string * @param verstr The version string to set */ void SetFullVersion(const std::string& verstr) { fullversion = verstr; } /** Set the raw version string */ void SetRawVersion(const std::string& verstr) { rawversion = verstr; } /** Sets the description of this server. Called when the description of a remote server changes * and we are notified about it. * @param descstr The description to set */ void SetDesc(const std::string& descstr) { description = descstr; } /** Return all child servers */ const ChildServers& GetChildren() const { return Children; } /** Marks a server as having finished bursting and performs appropriate actions. */ void FinishBurst(); /** Recursive call for child servers */ void FinishBurstInternal(); /** (Re)check the uline state of this server */ void CheckULine(); /** Get the bursting state of this server * @return True if this server is bursting, false if it isn't */ bool IsBursting() const { return (StartBurst != 0); } /** Check whether this server is behind a bursting server or is itself bursting. * This can tell whether a user is on a part of the network that is still bursting. * @return True if this server is bursting or is behind a server that is bursting, false if it isn't */ bool IsBehindBursting() const { return (behind_bursting != 0); } /** Set the bursting state of the server * @param startms Time the server started bursting, if 0 or omitted, use current time */ void BeginBurst(uint64_t startms = 0); /** Register a PONG from the server */ void OnPong() { pingtimer.OnPong(); } CullResult cull() CXX11_OVERRIDE; /** Destructor, deletes ServerUser unless IsRoot() */ ~TreeServer(); /** Returns the TreeServer the given user is connected to * @param user The user whose server to return * @return The TreeServer this user is connected to. */ static TreeServer* Get(User* user) { return static_cast<TreeServer*>(user->server); } }; ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/src/modules/m_spanningtree/treesocket.h����������������������������������������������0000664�0000000�0000000�00000027710�13554550454�0023143�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * InspIRCd -- Internet Relay Chat Daemon * * Copyright (C) 2009-2010 Daniel De Graaf <danieldg@inspircd.org> * Copyright (C) 2008 Robin Burchell <robin+git@viroteck.net> * Copyright (C) 2007 Dennis Friis <peavey@inspircd.org> * Copyright (C) 2007 Craig Edwards <craigedwards@brainbox.cc> * * This file is part of InspIRCd. InspIRCd is free software: you can * redistribute it and/or modify it under the terms of the GNU General Public * License as published by the Free Software Foundation, version 2. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include "inspircd.h" #include "utils.h" /* * The server list in InspIRCd is maintained as two structures * which hold the data in different ways. Most of the time, we * want to very quicky obtain three pieces of information: * * (1) The information on a server * (2) The information on the server we must send data through * to actually REACH the server we're after * (3) Potentially, the child/parent objects of this server * * The InspIRCd spanning protocol provides easy access to these * by storing the data firstly in a recursive structure, where * each item references its parent item, and a dynamic list * of child items, and another structure which stores the items * hashed, linearly. This means that if we want to find a server * by name quickly, we can look it up in the hash, avoiding * any O(n) lookups. If however, during a split or sync, we want * to apply an operation to a server, and any of its child objects * we can resort to recursion to walk the tree structure. * Any socket can have one of five states at any one time. * * CONNECTING: indicates an outbound socket which is * waiting to be writeable. * WAIT_AUTH_1: indicates the socket is outbound and * has successfully connected, but has not * yet sent and received SERVER strings. * WAIT_AUTH_2: indicates that the socket is inbound * but has not yet sent and received * SERVER strings. * CONNECTED: represents a fully authorized, fully * connected server. * DYING: represents a server that has had an error. */ enum ServerState { CONNECTING, WAIT_AUTH_1, WAIT_AUTH_2, CONNECTED, DYING }; struct CapabData { reference<Link> link; /* Link block used for this connection */ reference<Autoconnect> ac; /* Autoconnect used to cause this connection, if any */ std::string ModuleList; /* Required module list of other server from CAPAB */ std::string OptModuleList; /* Optional module list of other server from CAPAB */ std::string ChanModes; std::string UserModes; std::map<std::string,std::string> CapKeys; /* CAPAB keys from other server */ std::string ourchallenge; /* Challenge sent for challenge/response */ std::string theirchallenge; /* Challenge recv for challenge/response */ int capab_phase; /* Have sent CAPAB already */ bool auth_fingerprint; /* Did we auth using SSL certificate fingerprint */ bool auth_challenge; /* Did we auth using challenge/response */ // Data saved from incoming SERVER command, for later use when our credentials have been accepted by the other party std::string description; std::string sid; std::string name; bool hidden; }; /** Every SERVER connection inbound or outbound is represented by an object of * type TreeSocket. During setup, the object can be found in Utils->timeoutlist; * after setup, MyRoot will have been created as a child of Utils->TreeRoot */ class TreeSocket : public BufferedSocket { struct BurstState; std::string linkID; /* Description for this link */ ServerState LinkState; /* Link state */ CapabData* capab; /* Link setup data (held until burst is sent) */ TreeServer* MyRoot; /* The server we are talking to */ unsigned int proto_version; /* Remote protocol version */ /** True if we've sent our burst. * This only changes the behavior of message translation for 1202 protocol servers and it can be * removed once 1202 support is dropped. */ bool burstsent; /** Checks if the given servername and sid are both free */ bool CheckDuplicate(const std::string& servername, const std::string& sid); /** Send all ListModeBase modes set on the channel */ void SendListModes(Channel* chan); /** Send all known information about a channel */ void SyncChannel(Channel* chan, BurstState& bs); /** Send all users and their oper state, away state and metadata */ void SendUsers(BurstState& bs); /** Send all additional info about the given server to this server */ void SendServerInfo(TreeServer* from); /** Find the User source of a command given a prefix and a command string. * This connection must be fully up when calling this function. * @param prefix Prefix string to find the source User object for. Can be a sid, a uuid or a server name. * @param command The command whose source to find. This is required because certain commands (like mode * changes and kills) must be processed even if their claimed source doesn't exist. If the given command is * such a command and the source does not exist, the function returns a valid FakeUser that can be used to * to process the command with. * @return The command source to use when processing the command or NULL if the source wasn't found. * Note that the direction of the returned source is not verified. */ User* FindSource(const std::string& prefix, const std::string& command); /** Finish the authentication phase of this connection. * Change the state of the connection to CONNECTED, create a TreeServer object for the server on the * other end of the connection using the details provided in the parameters, and finally send a burst. * @param remotename Name of the remote server * @param remotesid SID of the remote server * @param remotedesc Description of the remote server * @param hidden True if the remote server is hidden according to the configuration */ void FinishAuth(const std::string& remotename, const std::string& remotesid, const std::string& remotedesc, bool hidden); /** Authenticate the remote server. * Validate the parameters and find the link block that matches the remote server. In case of an error, * an appropriate snotice is generated, an ERROR message is sent and the connection is closed. * Failing to find a matching link block counts as an error. * @param params Parameters they sent in the SERVER command * @return Link block for the remote server, or NULL if an error occurred */ Link* AuthRemote(const CommandBase::Params& params); /** Write a line on this socket with a new line character appended, skipping all translation for old protocols * @param line Line to write without a new line character at the end */ void WriteLineNoCompat(const std::string& line); public: const time_t age; /** Because most of the I/O gubbins are encapsulated within * BufferedSocket, we just call the superclass constructor for * most of the action, and append a few of our own values * to it. */ TreeSocket(Link* link, Autoconnect* myac, const irc::sockets::sockaddrs& sa); /** When a listening socket gives us a new file descriptor, * we must associate it with a socket without creating a new * connection. This constructor is used for this purpose. */ TreeSocket(int newfd, ListenSocket* via, irc::sockets::sockaddrs* client, irc::sockets::sockaddrs* server); /** Get link state */ ServerState GetLinkState() const { return LinkState; } /** Get challenge set in our CAPAB for challenge/response */ const std::string& GetOurChallenge(); /** Get challenge set in our CAPAB for challenge/response */ void SetOurChallenge(const std::string &c); /** Get challenge set in their CAPAB for challenge/response */ const std::string& GetTheirChallenge(); /** Get challenge set in their CAPAB for challenge/response */ void SetTheirChallenge(const std::string &c); /** Compare two passwords based on authentication scheme */ bool ComparePass(const Link& link, const std::string &theirs); /** Clean up information used only during server negotiation */ void CleanNegotiationInfo(); CullResult cull() CXX11_OVERRIDE; /** Destructor */ ~TreeSocket(); /** Construct a password, optionally hashed with the other side's * challenge string */ std::string MakePass(const std::string &password, const std::string &challenge); /** When an outbound connection finishes connecting, we receive * this event, and must send our SERVER string to the other * side. If the other side is happy, as outlined in the server * to server docs on the inspircd.org site, the other side * will then send back its own server string. */ void OnConnected() CXX11_OVERRIDE; /** Handle socket error event */ void OnError(BufferedSocketError e) CXX11_OVERRIDE; /** Sends an error to the remote server, and displays it locally to show * that it was sent. */ void SendError(const std::string &errormessage); /** Recursively send the server tree with distances as hops. * This is used during network burst to inform the other server * (and any of ITS servers too) of what servers we know about. */ void SendServers(TreeServer* Current, TreeServer* s); /** Returns module list as a string, filtered by filter * @param filter a module version bitmask, such as VF_COMMON or VF_OPTCOMMON */ std::string MyModules(int filter); /** Returns mode list as a string, filtered by type. * @param type The type of modes to return. */ std::string BuildModeList(ModeType type); /** Send my capabilities to the remote side */ void SendCapabilities(int phase); /* Isolate and return the elements that are different between two lists */ void ListDifference(const std::string &one, const std::string &two, char sep, std::string& mleft, std::string& mright); bool Capab(const CommandBase::Params& params); /** Send one or more FJOINs for a channel of users. * If the length of a single line is more than 480-NICKMAX * in length, it is split over multiple lines. */ void SendFJoins(Channel* c); /** Send G-, Q-, Z- and E-lines */ void SendXLines(); /** Send all known information about a channel */ void SyncChannel(Channel* chan); /** This function is called when we want to send a netburst to a local * server. There is a set order we must do this, because for example * users require their servers to exist, and channels require their * users to exist. You get the idea. */ void DoBurst(TreeServer* s); /** This function is called when we receive data from a remote * server. */ void OnDataReady() CXX11_OVERRIDE; /** Send one or more complete lines down the socket */ void WriteLine(const std::string& line); /** Handle ERROR command */ void Error(CommandBase::Params& params); /** (local) -> SERVER */ bool Outbound_Reply_Server(CommandBase::Params& params); /** (local) <- SERVER */ bool Inbound_Server(CommandBase::Params& params); /** Handle IRC line split */ void Split(const std::string& line, std::string& tags, std::string& prefix, std::string& command, CommandBase::Params& params); /** Process complete line from buffer */ void ProcessLine(std::string &line); /** Process message tags received from a remote server. */ void ProcessTag(User* source, const std::string& tag, ClientProtocol::TagMap& tags); /** Process a message for a fully connected server. */ void ProcessConnectedLine(std::string& tags, std::string& prefix, std::string& command, CommandBase::Params& params); /** Handle socket timeout from connect() */ void OnTimeout() CXX11_OVERRIDE; /** Handle server quit on close */ void Close() CXX11_OVERRIDE; /** Fixes messages coming from old servers so the new command handlers understand them */ bool PreProcessOldProtocolMessage(User*& who, std::string& cmd, CommandBase::Params& params); }; ��������������������������������������������������������inspircd-3.4.0/src/modules/m_spanningtree/treesocket1.cpp�������������������������������������������0000664�0000000�0000000�00000015205�13554550454�0023553�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * InspIRCd -- Internet Relay Chat Daemon * * Copyright (C) 2009-2010 Daniel De Graaf <danieldg@inspircd.org> * Copyright (C) 2007-2008 Robin Burchell <robin+git@viroteck.net> * Copyright (C) 2007 Craig Edwards <craigedwards@brainbox.cc> * Copyright (C) 2007 Dennis Friis <peavey@inspircd.org> * * This file is part of InspIRCd. InspIRCd is free software: you can * redistribute it and/or modify it under the terms of the GNU General Public * License as published by the Free Software Foundation, version 2. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include "inspircd.h" #include "iohook.h" #include "main.h" #include "utils.h" #include "treeserver.h" #include "link.h" #include "treesocket.h" #include "commands.h" /** Constructor for outgoing connections. * Because most of the I/O gubbins are encapsulated within * BufferedSocket, we just call DoConnect() for most of the action, * and only do minor initialization tasks ourselves. */ TreeSocket::TreeSocket(Link* link, Autoconnect* myac, const irc::sockets::sockaddrs& dest) : linkID(link->Name), LinkState(CONNECTING), MyRoot(NULL), proto_version(0) , burstsent(false), age(ServerInstance->Time()) { capab = new CapabData; capab->link = link; capab->ac = myac; capab->capab_phase = 0; irc::sockets::sockaddrs bind; memset(&bind, 0, sizeof(bind)); if (!link->Bind.empty() && (dest.family() == AF_INET || dest.family() == AF_INET6)) { if (!irc::sockets::aptosa(link->Bind, 0, bind)) { state = I_ERROR; SetError("Bind address '" + link->Bind + "' is not a valid IPv4 or IPv6 address"); TreeSocket::OnError(I_ERR_BIND); return; } else if (bind.family() != dest.family()) { state = I_ERROR; SetError("Bind address '" + bind.addr() + "' is not the same address family as destination address '" + dest.addr() + "'"); TreeSocket::OnError(I_ERR_BIND); return; } } DoConnect(dest, bind, link->Timeout); Utils->timeoutlist[this] = std::pair<std::string, unsigned int>(linkID, link->Timeout); SendCapabilities(1); } /** Constructor for incoming connections */ TreeSocket::TreeSocket(int newfd, ListenSocket* via, irc::sockets::sockaddrs* client, irc::sockets::sockaddrs* server) : BufferedSocket(newfd) , linkID("inbound from " + client->addr()), LinkState(WAIT_AUTH_1), MyRoot(NULL), proto_version(0) , burstsent(false), age(ServerInstance->Time()) { capab = new CapabData; capab->capab_phase = 0; for (ListenSocket::IOHookProvList::iterator i = via->iohookprovs.begin(); i != via->iohookprovs.end(); ++i) { ListenSocket::IOHookProvRef& iohookprovref = *i; if (!iohookprovref) continue; iohookprovref->OnAccept(this, client, server); // IOHook could have encountered a fatal error, e.g. if the TLS ClientHello was already in the queue and there was no common TLS version if (!getError().empty()) { TreeSocket::OnError(I_ERR_OTHER); return; } } SendCapabilities(1); Utils->timeoutlist[this] = std::pair<std::string, unsigned int>(linkID, 30); } void TreeSocket::CleanNegotiationInfo() { // connect is good, reset the autoconnect block (if used) if (capab->ac) capab->ac->position = -1; delete capab; capab = NULL; } CullResult TreeSocket::cull() { Utils->timeoutlist.erase(this); if (capab && capab->ac) Utils->Creator->ConnectServer(capab->ac, false); return this->BufferedSocket::cull(); } TreeSocket::~TreeSocket() { delete capab; } /** When an outbound connection finishes connecting, we receive * this event, and must do CAPAB negotiation with the other * side. If the other side is happy, as outlined in the server * to server docs on the inspircd.org site, the other side * will then send back its own SERVER string eventually. */ void TreeSocket::OnConnected() { if (this->LinkState == CONNECTING) { if (!capab->link->Hook.empty()) { ServiceProvider* prov = ServerInstance->Modules->FindService(SERVICE_IOHOOK, capab->link->Hook); if (!prov) { SetError("Could not find hook '" + capab->link->Hook + "' for connection to " + linkID); return; } static_cast<IOHookProvider*>(prov)->OnConnect(this); } ServerInstance->SNO->WriteGlobalSno('l', "Connection to \002%s\002[%s] started.", linkID.c_str(), (capab->link->HiddenFromStats ? "<hidden>" : capab->link->IPAddr.c_str())); this->SendCapabilities(1); } } void TreeSocket::OnError(BufferedSocketError e) { ServerInstance->SNO->WriteGlobalSno('l', "Connection to '\002%s\002' failed with error: %s", linkID.c_str(), getError().c_str()); LinkState = DYING; Close(); } void TreeSocket::SendError(const std::string &errormessage) { WriteLine("ERROR :"+errormessage); DoWrite(); LinkState = DYING; SetError(errormessage); } CmdResult CommandSQuit::HandleServer(TreeServer* server, CommandBase::Params& params) { TreeServer* quitting = Utils->FindServer(params[0]); if (!quitting) { ServerInstance->Logs->Log(MODNAME, LOG_DEFAULT, "Squit from unknown server"); return CMD_FAILURE; } CmdResult ret = CMD_SUCCESS; if (quitting == server) { ret = CMD_FAILURE; server = server->GetParent(); } else if (quitting->GetParent() != server) throw ProtocolException("Attempted to SQUIT a non-directly connected server or the parent"); server->SQuitChild(quitting, params[1]); // XXX: Return CMD_FAILURE when servers SQUIT themselves (i.e. :00S SQUIT 00S :Shutting down) // to stop this message from being forwarded. // The squit logic generates a SQUIT message with our sid as the source and sends it to the // remaining servers. return ret; } /** This function is called when we receive data from a remote * server. */ void TreeSocket::OnDataReady() { Utils->Creator->loopCall = true; std::string line; while (GetNextLine(line)) { std::string::size_type rline = line.find('\r'); if (rline != std::string::npos) line.erase(rline); if (line.find('\0') != std::string::npos) { SendError("Read null character from socket"); break; } try { ProcessLine(line); } catch (CoreException& ex) { ServerInstance->Logs->Log(MODNAME, LOG_DEFAULT, "Error while processing: " + line); ServerInstance->Logs->Log(MODNAME, LOG_DEFAULT, ex.GetReason()); SendError(ex.GetReason() + " - check the log file for details"); } if (!getError().empty()) break; } if (LinkState != CONNECTED && recvq.length() > 4096) SendError("RecvQ overrun (line too long)"); Utils->Creator->loopCall = false; } �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/src/modules/m_spanningtree/treesocket2.cpp�������������������������������������������0000664�0000000�0000000�00000032460�13554550454�0023556�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * InspIRCd -- Internet Relay Chat Daemon * * Copyright (C) 2007-2008, 2012 Robin Burchell <robin+git@viroteck.net> * Copyright (C) 2009-2010 Daniel De Graaf <danieldg@inspircd.org> * Copyright (C) 2007-2008 Craig Edwards <craigedwards@brainbox.cc> * Copyright (C) 2008 Pippijn van Steenhoven <pip88nl@gmail.com> * Copyright (C) 2008 Thomas Stagner <aquanight@inspircd.org> * Copyright (C) 2007 Dennis Friis <peavey@inspircd.org> * * This file is part of InspIRCd. InspIRCd is free software: you can * redistribute it and/or modify it under the terms of the GNU General Public * License as published by the Free Software Foundation, version 2. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include "inspircd.h" #include "main.h" #include "utils.h" #include "treeserver.h" #include "treesocket.h" #include "resolvers.h" #include "commands.h" /* Handle ERROR command */ void TreeSocket::Error(CommandBase::Params& params) { std::string msg = params.size() ? params[0] : ""; SetError("received ERROR " + msg); } void TreeSocket::Split(const std::string& line, std::string& tags, std::string& prefix, std::string& command, CommandBase::Params& params) { std::string token; irc::tokenstream tokens(line); if (!tokens.GetMiddle(token)) return; if (token[0] == '@') { if (token.length() <= 1) { this->SendError("BUG: Received a message with empty tags: " + line); return; } tags.assign(token, 1, std::string::npos); if (!tokens.GetMiddle(token)) { this->SendError("BUG: Received a message with no command: " + line); return; } } if (token[0] == ':') { if (token.length() <= 1) { this->SendError("BUG: Received a message with an empty prefix: " + line); return; } prefix.assign(token, 1, std::string::npos); if (!tokens.GetMiddle(token)) { this->SendError("BUG: Received a message with no command: " + line); return; } } command.assign(token); while (tokens.GetTrailing(token)) params.push_back(token); } void TreeSocket::ProcessLine(std::string &line) { std::string tags; std::string prefix; std::string command; CommandBase::Params params; ServerInstance->Logs->Log(MODNAME, LOG_RAWIO, "S[%d] I %s", this->GetFd(), line.c_str()); Split(line, tags, prefix, command, params); if (command.empty()) return; switch (this->LinkState) { case WAIT_AUTH_1: /* * State WAIT_AUTH_1: * Waiting for SERVER command from remote server. Server initiating * the connection sends the first SERVER command, listening server * replies with theirs if its happy, then if the initiator is happy, * it starts to send its net sync, which starts the merge, otherwise * it sends an ERROR. */ if (command == "PASS") { /* * Ignore this silently. Some services packages insist on sending PASS, even * when it is not required (i.e. by us). We have to ignore this here, otherwise * as it's an unknown command (effectively), it will cause the connection to be * closed, which probably isn't what people want. -- w00t */ } else if (command == "SERVER") { this->Inbound_Server(params); } else if (command == "ERROR") { this->Error(params); } else if (command == "USER") { this->SendError("Client connections to this port are prohibited."); } else if (command == "CAPAB") { this->Capab(params); } else { this->SendError("Invalid command in negotiation phase: " + command); } break; case WAIT_AUTH_2: /* * State WAIT_AUTH_2: * We have sent SERVER to the other side of the connection. Now we're waiting for them to start BURST. * The other option at this stage of things, of course, is for them to close our connection thanks * to invalid credentials.. -- w */ if (command == "SERVER") { /* * Connection is either attempting to re-auth itself (stupid) or sending netburst without sending BURST. * Both of these aren't allowable, so block them here. -- w */ this->SendError("You may not re-authenticate or commence netburst without sending BURST."); } else if (command == "BURST") { if (!params.empty()) { time_t them = ConvToNum<time_t>(params[0]); time_t delta = them - ServerInstance->Time(); if ((delta < -60) || (delta > 60)) { ServerInstance->SNO->WriteGlobalSno('l', "\002ERROR\002: Your clocks are off by %ld seconds (this is more than one minute). Link aborted, \002PLEASE SYNC YOUR CLOCKS!\002", labs((long)delta)); SendError("Your clocks are out by "+ConvToStr(labs((long)delta))+" seconds (this is more than one minute). Link aborted, PLEASE SYNC YOUR CLOCKS!"); return; } else if ((delta < -15) || (delta > 15)) { ServerInstance->SNO->WriteGlobalSno('l', "\002WARNING\002: Your clocks are off by %ld seconds. Please consider syncing your clocks.", labs((long)delta)); } } // Check for duplicate server name/sid again, it's possible that a new // server was introduced while we were waiting for them to send BURST. // (we do not reserve their server name/sid when they send SERVER, we do it now) if (!CheckDuplicate(capab->name, capab->sid)) return; FinishAuth(capab->name, capab->sid, capab->description, capab->hidden); } else if (command == "ERROR") { this->Error(params); } else if (command == "CAPAB") { this->Capab(params); } break; case CONNECTING: /* * State CONNECTING: * We're connecting (OUTGOING) to another server. They are in state WAIT_AUTH_1 until they verify * our credentials, when they proceed into WAIT_AUTH_2 and send SERVER to us. We then send BURST * + our netburst, which will put them into CONNECTED state. -- w */ if (command == "SERVER") { // Our credentials have been accepted, send netburst. (this puts US into the CONNECTED state) this->Outbound_Reply_Server(params); } else if (command == "ERROR") { this->Error(params); } else if (command == "CAPAB") { this->Capab(params); } break; case CONNECTED: /* * State CONNECTED: * Credentials have been exchanged, we've gotten their 'BURST' (or sent ours). * Anything from here on should be accepted a little more reasonably. */ this->ProcessConnectedLine(tags, prefix, command, params); break; case DYING: break; } } User* TreeSocket::FindSource(const std::string& prefix, const std::string& command) { // Empty prefix means the source is the directly connected server that sent this command if (prefix.empty()) return MyRoot->ServerUser; if (prefix.size() == 3) { // Prefix looks like a sid TreeServer* server = Utils->FindServerID(prefix); if (server) return server->ServerUser; } else { // If the prefix string is a uuid FindUUID() returns the appropriate User object User* user = ServerInstance->FindUUID(prefix); if (user) return user; } // Some implementations wrongly send a server name as prefix occasionally, handle that too for now TreeServer* const server = Utils->FindServer(prefix); if (server) return server->ServerUser; /* It is important that we don't close the link here, unknown prefix can occur * due to various race conditions such as the KILL message for a user somehow * crossing the users QUIT further upstream from the server. Thanks jilles! */ if ((prefix.length() == UIDGenerator::UUID_LENGTH) && (isdigit(prefix[0])) && ((command == "FMODE") || (command == "MODE") || (command == "KICK") || (command == "TOPIC") || (command == "KILL") || (command == "ADDLINE") || (command == "DELLINE"))) { /* Special case, we cannot drop these commands as they've been committed already on a * part of the network by the time we receive them, so in this scenario pretend the * command came from a server to avoid desync. */ TreeServer* const usersserver = Utils->FindServerID(prefix.substr(0, 3)); if (usersserver) return usersserver->ServerUser; return this->MyRoot->ServerUser; } // Unknown prefix return NULL; } void TreeSocket::ProcessTag(User* source, const std::string& tag, ClientProtocol::TagMap& tags) { std::string tagkey; std::string tagval; const std::string::size_type p = tag.find('='); if (p != std::string::npos) { // Tag has a value tagkey.assign(tag, 0, p); tagval.assign(tag, p + 1, std::string::npos); } else { tagkey.assign(tag); } const Events::ModuleEventProvider::SubscriberList& list = Utils->Creator->tagevprov.GetSubscribers(); for (Events::ModuleEventProvider::SubscriberList::const_iterator i = list.begin(); i != list.end(); ++i) { ClientProtocol::MessageTagProvider* const tagprov = static_cast<ClientProtocol::MessageTagProvider*>(*i); const ModResult res = tagprov->OnProcessTag(source, tagkey, tagval); if (res == MOD_RES_ALLOW) tags.insert(std::make_pair(tagkey, ClientProtocol::MessageTagData(tagprov, tagval))); else if (res == MOD_RES_DENY) break; } } void TreeSocket::ProcessConnectedLine(std::string& taglist, std::string& prefix, std::string& command, CommandBase::Params& params) { User* who = FindSource(prefix, command); if (!who) { ServerInstance->Logs->Log(MODNAME, LOG_DEBUG, "Command '%s' from unknown prefix '%s'! Dropping entire command.", command.c_str(), prefix.c_str()); return; } /* * Check for fake direction here, and drop any instances that are found. * What is fake direction? Imagine the following server setup: * 0AA <-> 0AB <-> 0AC * Fake direction would be 0AC sending a message to 0AB claiming to be from * 0AA, or something similar. Basically, a message taking a path that *cannot* * be correct. * * When would this be seen? * Well, hopefully never. It could be caused by race conditions, bugs, or * "miscreant" servers, though, so let's check anyway. -- w * * We also check here for totally invalid prefixes (prefixes that are neither * a valid SID or a valid UUID, so that invalid UUID or SID never makes it * to the higher level functions. -- B */ TreeServer* const server = TreeServer::Get(who); if (server->GetSocket() != this) { ServerInstance->Logs->Log(MODNAME, LOG_DEBUG, "Protocol violation: Fake direction '%s' from connection '%s'", prefix.c_str(), linkID.c_str()); return; } // Translate commands coming from servers using an older protocol if (proto_version < PROTO_NEWEST) { if (!PreProcessOldProtocolMessage(who, command, params)) return; } ServerCommand* scmd = Utils->Creator->CmdManager.GetHandler(command); CommandBase* cmdbase = scmd; Command* cmd = NULL; if (!scmd) { // Not a special server-to-server command cmd = ServerInstance->Parser.GetHandler(command); if (!cmd) { if (command == "ERROR") { this->Error(params); return; } else if (command == "BURST") { // This is sent even when there is no need for it, drop it here for now return; } throw ProtocolException("Unknown command: " + command); } cmdbase = cmd; } if (params.size() < cmdbase->min_params) throw ProtocolException("Insufficient parameters"); if ((!params.empty()) && (params.back().empty()) && (!cmdbase->allow_empty_last_param)) { // the last param is empty and the command handler doesn't allow that, check if there will be enough params if we drop the last if (params.size()-1 < cmdbase->min_params) return; params.pop_back(); } CmdResult res; ClientProtocol::TagMap tags; std::string tag; irc::sepstream tagstream(taglist, ';'); while (tagstream.GetToken(tag)) ProcessTag(who, tag, tags); CommandBase::Params newparams(params, tags); if (scmd) res = scmd->Handle(who, newparams); else { res = cmd->Handle(who, newparams); if (res == CMD_INVALID) throw ProtocolException("Error in command handler"); } if (res == CMD_SUCCESS) Utils->RouteCommand(server->GetRoute(), cmdbase, newparams, who); } void TreeSocket::OnTimeout() { ServerInstance->SNO->WriteGlobalSno('l', "CONNECT: Connection to \002%s\002 timed out.", linkID.c_str()); } void TreeSocket::Close() { if (fd < 0) return; ServerInstance->GlobalCulls.AddItem(this); this->BufferedSocket::Close(); SetError("Remote host closed connection"); // Connection closed. // If the connection is fully up (state CONNECTED) // then propogate a netsplit to all peers. if (MyRoot) MyRoot->SQuit(getError(), true); ServerInstance->SNO->WriteGlobalSno('l', "Connection to '\002%s\002' failed.", linkID.c_str()); time_t server_uptime = ServerInstance->Time() - this->age; if (server_uptime) { std::string timestr = InspIRCd::DurationString(server_uptime); ServerInstance->SNO->WriteGlobalSno('l', "Connection to '\002%s\002' was established for %s", linkID.c_str(), timestr.c_str()); } } void TreeSocket::FinishAuth(const std::string& remotename, const std::string& remotesid, const std::string& remotedesc, bool hidden) { this->LinkState = CONNECTED; Utils->timeoutlist.erase(this); linkID = remotename; MyRoot = new TreeServer(remotename, remotedesc, remotesid, Utils->TreeRoot, this, hidden); // Mark the server as bursting MyRoot->BeginBurst(); this->DoBurst(MyRoot); CommandServer::Builder(MyRoot).Forward(MyRoot); } ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/src/modules/m_spanningtree/uid.cpp���������������������������������������������������0000664�0000000�0000000�00000013512�13554550454�0022102�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * InspIRCd -- Internet Relay Chat Daemon * * Copyright (C) 2010 Daniel De Graaf <danieldg@inspircd.org> * Copyright (C) 2008 Robin Burchell <robin+git@viroteck.net> * Copyright (C) 2008 Craig Edwards <craigedwards@brainbox.cc> * * This file is part of InspIRCd. InspIRCd is free software: you can * redistribute it and/or modify it under the terms of the GNU General Public * License as published by the Free Software Foundation, version 2. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include "inspircd.h" #include "commands.h" #include "utils.h" #include "treeserver.h" #include "remoteuser.h" CmdResult CommandUID::HandleServer(TreeServer* remoteserver, CommandBase::Params& params) { /** * 0 1 2 3 4 5 6 7 8 9 (n-1) * UID uuid age nick host dhost ident ip.string signon +modes (modepara) :real */ time_t age_t = ServerCommand::ExtractTS(params[1]); time_t signon = ServerCommand::ExtractTS(params[7]); std::string empty; const std::string& modestr = params[8]; // Check if the length of the uuid is correct and confirm the sid portion of the uuid matches the sid of the server introducing the user if (params[0].length() != UIDGenerator::UUID_LENGTH || params[0].compare(0, 3, remoteserver->GetId())) throw ProtocolException("Bogus UUID"); // Sanity check on mode string: must begin with '+' if (modestr[0] != '+') throw ProtocolException("Invalid mode string"); // See if there is a nick collision User* collideswith = ServerInstance->FindNickOnly(params[2]); if ((collideswith) && (collideswith->registered != REG_ALL)) { // User that the incoming user is colliding with is not fully registered, we force nick change the // unregistered user to their uuid and tell them what happened LocalUser* const localuser = static_cast<LocalUser*>(collideswith); localuser->OverruleNick(); } else if (collideswith) { // The user on this side is registered, handle the collision bool they_change = Utils->DoCollision(collideswith, remoteserver, age_t, params[5], params[6], params[0], "UID"); if (they_change) { // The client being introduced needs to change nick to uuid, change the nick in the message before // processing/forwarding it. Also change the nick TS to CommandSave::SavedTimestamp. age_t = CommandSave::SavedTimestamp; params[1] = ConvToStr(CommandSave::SavedTimestamp); params[2] = params[0]; } } /* For remote users, we pass the UUID they sent to the constructor. * If the UUID already exists User::User() throws an exception which causes this connection to be closed. */ RemoteUser* _new = new SpanningTree::RemoteUser(params[0], remoteserver); ServerInstance->Users->clientlist[params[2]] = _new; _new->nick = params[2]; _new->ChangeRealHost(params[3], false); _new->ChangeDisplayedHost(params[4]); _new->ident = params[5]; _new->ChangeRealName(params.back()); _new->registered = REG_ALL; _new->signon = signon; _new->age = age_t; unsigned int paramptr = 9; for (std::string::const_iterator v = modestr.begin(); v != modestr.end(); ++v) { // Accept more '+' chars, for now if (*v == '+') continue; /* For each mode thats set, find the mode handler and set it on the new user */ ModeHandler* mh = ServerInstance->Modes->FindMode(*v, MODETYPE_USER); if (!mh) throw ProtocolException("Unrecognised mode '" + std::string(1, *v) + "'"); if (mh->NeedsParam(true)) { if (paramptr >= params.size() - 1) throw ProtocolException("Out of parameters while processing modes"); std::string mp = params[paramptr++]; /* IMPORTANT NOTE: * All modes are assumed to succeed here as they are being set by a remote server. * Modes CANNOT FAIL here. If they DO fail, then the failure is ignored. This is important * to note as all but one modules currently cannot ever fail in this situation, except for * m_servprotect which specifically works this way to prevent the mode being set ANYWHERE * but here, at client introduction. You may safely assume this behaviour is standard and * will not change in future versions if you want to make use of this protective behaviour * yourself. */ mh->OnModeChange(_new, _new, NULL, mp, true); } else mh->OnModeChange(_new, _new, NULL, empty, true); _new->SetMode(mh, true); } _new->SetClientIP(params[6]); ServerInstance->Users->AddClone(_new); remoteserver->UserCount++; bool dosend = true; if ((Utils->quiet_bursts && remoteserver->IsBehindBursting()) || _new->server->IsSilentULine()) dosend = false; if (dosend) ServerInstance->SNO->WriteToSnoMask('C',"Client connecting at %s: %s (%s) [%s]", remoteserver->GetName().c_str(), _new->GetFullRealHost().c_str(), _new->GetIPString().c_str(), _new->GetRealName().c_str()); FOREACH_MOD(OnPostConnect, (_new)); return CMD_SUCCESS; } CmdResult CommandFHost::HandleRemote(RemoteUser* src, Params& params) { src->ChangeDisplayedHost(params[0]); return CMD_SUCCESS; } CmdResult CommandFIdent::HandleRemote(RemoteUser* src, Params& params) { src->ChangeIdent(params[0]); return CMD_SUCCESS; } CmdResult CommandFName::HandleRemote(RemoteUser* src, Params& params) { src->ChangeRealName(params[0]); return CMD_SUCCESS; } CommandUID::Builder::Builder(User* user) : CmdBuilder(TreeServer::Get(user), "UID") { push(user->uuid); push_int(user->age); push(user->nick); push(user->GetRealHost()); push(user->GetDisplayedHost()); push(user->ident); push(user->GetIPString()); push_int(user->signon); push(user->GetModeLetters(true)); push_last(user->GetRealName()); } ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/src/modules/m_spanningtree/utils.cpp�������������������������������������������������0000664�0000000�0000000�00000027475�13554550454�0022476�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * InspIRCd -- Internet Relay Chat Daemon * * Copyright (C) 2009 Daniel De Graaf <danieldg@inspircd.org> * Copyright (C) 2007-2009 Craig Edwards <craigedwards@brainbox.cc> * Copyright (C) 2008 Robin Burchell <robin+git@viroteck.net> * Copyright (C) 2007 Dennis Friis <peavey@inspircd.org> * * This file is part of InspIRCd. InspIRCd is free software: you can * redistribute it and/or modify it under the terms of the GNU General Public * License as published by the Free Software Foundation, version 2. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include "inspircd.h" #include "main.h" #include "utils.h" #include "treeserver.h" #include "treesocket.h" #include "resolvers.h" #include "commandbuilder.h" SpanningTreeUtilities* Utils = NULL; ModResult ModuleSpanningTree::OnAcceptConnection(int newsock, ListenSocket* from, irc::sockets::sockaddrs* client, irc::sockets::sockaddrs* server) { if (!stdalgo::string::equalsci(from->bind_tag->getString("type"), "servers")) return MOD_RES_PASSTHRU; std::string incomingip = client->addr(); for (std::vector<std::string>::iterator i = Utils->ValidIPs.begin(); i != Utils->ValidIPs.end(); i++) { if (*i == "*" || *i == incomingip || irc::sockets::cidr_mask(*i).match(*client)) { /* we don't need to do anything with the pointer, creating it stores it in the necessary places */ new TreeSocket(newsock, from, client, server); return MOD_RES_ALLOW; } } ServerInstance->SNO->WriteToSnoMask('l', "Server connection from %s denied (no link blocks with that IP address)", incomingip.c_str()); return MOD_RES_DENY; } TreeServer* SpanningTreeUtilities::FindServer(const std::string &ServerName) { if (InspIRCd::IsSID(ServerName)) return this->FindServerID(ServerName); server_hash::iterator iter = serverlist.find(ServerName); if (iter != serverlist.end()) { return iter->second; } else { return NULL; } } /** Find the first server matching a given glob mask. * We iterate over the list and match each one until we get a hit. */ TreeServer* SpanningTreeUtilities::FindServerMask(const std::string &ServerName) { for (server_hash::iterator i = serverlist.begin(); i != serverlist.end(); i++) { if (InspIRCd::Match(i->first,ServerName)) return i->second; } return NULL; } TreeServer* SpanningTreeUtilities::FindServerID(const std::string &id) { server_hash::iterator iter = sidlist.find(id); if (iter != sidlist.end()) return iter->second; else return NULL; } TreeServer* SpanningTreeUtilities::FindRouteTarget(const std::string& target) { TreeServer* const server = FindServer(target); if (server) return server; User* const user = ServerInstance->FindNick(target); if (user) return TreeServer::Get(user); return NULL; } SpanningTreeUtilities::SpanningTreeUtilities(ModuleSpanningTree* C) : Creator(C), TreeRoot(NULL) , PingFreq(60) // XXX: TreeServer constructor reads this and TreeRoot is created before the config is read, so init it to something (value doesn't matter) to avoid a valgrind warning in TimerManager on unload { ServerInstance->Timers.AddTimer(&RefreshTimer); } CullResult SpanningTreeUtilities::cull() { const TreeServer::ChildServers& children = TreeRoot->GetChildren(); while (!children.empty()) { TreeSocket* sock = children.front()->GetSocket(); sock->Close(); } for(TimeoutList::iterator i = timeoutlist.begin(); i != timeoutlist.end(); ++i) { TreeSocket* s = i->first; s->Close(); } TreeRoot->cull(); return classbase::cull(); } SpanningTreeUtilities::~SpanningTreeUtilities() { delete TreeRoot; } // Returns a list of DIRECT servers for a specific channel void SpanningTreeUtilities::GetListOfServersForChannel(Channel* c, TreeSocketSet& list, char status, const CUList& exempt_list) { unsigned int minrank = 0; if (status) { PrefixMode* mh = ServerInstance->Modes->FindPrefix(status); if (mh) minrank = mh->GetPrefixRank(); } TreeServer::ChildServers children = TreeRoot->GetChildren(); const Channel::MemberMap& ulist = c->GetUsers(); for (Channel::MemberMap::const_iterator i = ulist.begin(); i != ulist.end(); ++i) { if (IS_LOCAL(i->first)) continue; if (minrank && i->second->getRank() < minrank) continue; if (exempt_list.find(i->first) == exempt_list.end()) { TreeServer* best = TreeServer::Get(i->first); list.insert(best->GetSocket()); TreeServer::ChildServers::iterator citer = std::find(children.begin(), children.end(), best); if (citer != children.end()) children.erase(citer); } } // Check whether the servers which do not have users in the channel might need this message. This // is used to keep the chanhistory module synchronised between servers. for (TreeServer::ChildServers::const_iterator i = children.begin(); i != children.end(); ++i) { ModResult result; FIRST_MOD_RESULT_CUSTOM(Creator->GetBroadcastEventProvider(), ServerProtocol::BroadcastEventListener, OnBroadcastMessage, result, (c, *i)); if (result == MOD_RES_ALLOW) list.insert((*i)->GetSocket()); } } void SpanningTreeUtilities::DoOneToAllButSender(const CmdBuilder& params, TreeServer* omitroute) { const std::string& FullLine = params.str(); const TreeServer::ChildServers& children = TreeRoot->GetChildren(); for (TreeServer::ChildServers::const_iterator i = children.begin(); i != children.end(); ++i) { TreeServer* Route = *i; // Send the line if the route isn't the path to the one to be omitted if (Route != omitroute) { Route->GetSocket()->WriteLine(FullLine); } } } void SpanningTreeUtilities::DoOneToOne(const CmdBuilder& params, Server* server) { TreeServer* ts = static_cast<TreeServer*>(server); TreeSocket* sock = ts->GetSocket(); if (sock) sock->WriteLine(params); } void SpanningTreeUtilities::RefreshIPCache() { ValidIPs.clear(); for (std::vector<reference<Link> >::iterator i = LinkBlocks.begin(); i != LinkBlocks.end(); ++i) { Link* L = *i; if (!L->Port) { ServerInstance->Logs->Log(MODNAME, LOG_DEFAULT, "Ignoring a link block without a port."); /* Invalid link block */ continue; } ValidIPs.insert(ValidIPs.end(), L->AllowMasks.begin(), L->AllowMasks.end()); irc::sockets::sockaddrs dummy; bool ipvalid = irc::sockets::aptosa(L->IPAddr, L->Port, dummy); if ((L->IPAddr == "*") || (ipvalid)) ValidIPs.push_back(L->IPAddr); else if (this->Creator->DNS) { SecurityIPResolver* sr = new SecurityIPResolver(Creator, *this->Creator->DNS, L->IPAddr, L, DNS::QUERY_AAAA); try { this->Creator->DNS->Process(sr); } catch (DNS::Exception &) { delete sr; } } } } void SpanningTreeUtilities::ReadConfiguration() { ConfigTag* security = ServerInstance->Config->ConfValue("security"); ConfigTag* options = ServerInstance->Config->ConfValue("options"); FlatLinks = security->getBool("flatlinks"); HideULines = security->getBool("hideulines"); HideSplits = security->getBool("hidesplits"); AnnounceTSChange = options->getBool("announcets"); AllowOptCommon = options->getBool("allowmismatch"); quiet_bursts = ServerInstance->Config->ConfValue("performance")->getBool("quietbursts"); PingWarnTime = options->getDuration("pingwarning", 15); PingFreq = options->getDuration("serverpingfreq", 60, 1); if (PingWarnTime >= PingFreq) PingWarnTime = 0; AutoconnectBlocks.clear(); LinkBlocks.clear(); ConfigTagList tags = ServerInstance->Config->ConfTags("link"); for(ConfigIter i = tags.first; i != tags.second; ++i) { ConfigTag* tag = i->second; reference<Link> L = new Link(tag); irc::spacesepstream sep = tag->getString("allowmask"); for (std::string s; sep.GetToken(s);) L->AllowMasks.push_back(s); L->Name = tag->getString("name"); L->IPAddr = tag->getString("ipaddr"); L->Port = tag->getUInt("port", 0); L->SendPass = tag->getString("sendpass", tag->getString("password")); L->RecvPass = tag->getString("recvpass", tag->getString("password")); L->Fingerprint = tag->getString("fingerprint"); L->HiddenFromStats = tag->getBool("statshidden"); L->Timeout = tag->getDuration("timeout", 30); L->Hook = tag->getString("ssl"); L->Bind = tag->getString("bind"); L->Hidden = tag->getBool("hidden"); if (L->Name.empty()) throw ModuleException("Invalid configuration, found a link tag without a name!" + (!L->IPAddr.empty() ? " IP address: "+L->IPAddr : "")); if (L->Name.find('.') == std::string::npos) throw ModuleException("The link name '"+L->Name+"' is invalid as it must contain at least one '.' character"); if (L->Name.length() > ServerInstance->Config->Limits.MaxHost) throw ModuleException("The link name '"+L->Name+"' is invalid as it is longer than " + ConvToStr(ServerInstance->Config->Limits.MaxHost) + " characters"); if (L->RecvPass.empty()) throw ModuleException("Invalid configuration for server '"+L->Name+"', recvpass not defined"); if (L->SendPass.empty()) throw ModuleException("Invalid configuration for server '"+L->Name+"', sendpass not defined"); if ((L->SendPass.find(' ') != std::string::npos) || (L->RecvPass.find(' ') != std::string::npos)) throw ModuleException("Link block '" + L->Name + "' has a password set that contains a space character which is invalid"); if ((L->SendPass[0] == ':') || (L->RecvPass[0] == ':')) throw ModuleException("Link block '" + L->Name + "' has a password set that begins with a colon (:) which is invalid"); if (L->IPAddr.empty()) { L->IPAddr = "*"; ServerInstance->Logs->Log(MODNAME, LOG_DEFAULT, "Configuration warning: Link block '" + L->Name + "' has no IP defined! This will allow any IP to connect as this server, and MAY not be what you want."); } if (!L->Port && L->IPAddr.find('/') == std::string::npos) ServerInstance->Logs->Log(MODNAME, LOG_DEFAULT, "Configuration warning: Link block '" + L->Name + "' has no port defined, you will not be able to /connect it."); L->Fingerprint.erase(std::remove(L->Fingerprint.begin(), L->Fingerprint.end(), ':'), L->Fingerprint.end()); LinkBlocks.push_back(L); } tags = ServerInstance->Config->ConfTags("autoconnect"); for(ConfigIter i = tags.first; i != tags.second; ++i) { ConfigTag* tag = i->second; reference<Autoconnect> A = new Autoconnect(tag); A->Period = tag->getDuration("period", 60, 1); A->NextConnectTime = ServerInstance->Time() + A->Period; A->position = -1; irc::spacesepstream ss(tag->getString("server")); std::string server; while (ss.GetToken(server)) { A->servers.push_back(server); } if (A->servers.empty()) { throw ModuleException("Invalid configuration for autoconnect, server cannot be empty!"); } AutoconnectBlocks.push_back(A); } for (server_hash::const_iterator i = serverlist.begin(); i != serverlist.end(); ++i) i->second->CheckULine(); RefreshIPCache(); } Link* SpanningTreeUtilities::FindLink(const std::string& name) { for (std::vector<reference<Link> >::iterator i = LinkBlocks.begin(); i != LinkBlocks.end(); ++i) { Link* x = *i; if (InspIRCd::Match(x->Name, name, ascii_case_insensitive_map)) { return x; } } return NULL; } void SpanningTreeUtilities::SendChannelMessage(User* source, Channel* target, const std::string& text, char status, const ClientProtocol::TagMap& tags, const CUList& exempt_list, const char* message_type, TreeSocket* omit) { CmdBuilder msg(source, message_type); msg.push_tags(tags); msg.push_raw(' '); if (status != 0) msg.push_raw(status); msg.push_raw(target->name); if (!text.empty()) msg.push_last(text); TreeSocketSet list; this->GetListOfServersForChannel(target, list, status, exempt_list); for (TreeSocketSet::iterator i = list.begin(); i != list.end(); ++i) { TreeSocket* Sock = *i; if (Sock != omit) Sock->WriteLine(msg); } } ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/src/modules/m_spanningtree/utils.h���������������������������������������������������0000664�0000000�0000000�00000012371�13554550454�0022130�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * InspIRCd -- Internet Relay Chat Daemon * * Copyright (C) 2009 Daniel De Graaf <danieldg@inspircd.org> * Copyright (C) 2008 Robin Burchell <robin+git@viroteck.net> * Copyright (C) 2007 Dennis Friis <peavey@inspircd.org> * Copyright (C) 2007 Craig Edwards <craigedwards@brainbox.cc> * * This file is part of InspIRCd. InspIRCd is free software: you can * redistribute it and/or modify it under the terms of the GNU General Public * License as published by the Free Software Foundation, version 2. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include "inspircd.h" #include "cachetimer.h" class TreeServer; class TreeSocket; class Link; class Autoconnect; class ModuleSpanningTree; class SpanningTreeUtilities; class CmdBuilder; extern SpanningTreeUtilities* Utils; /** Associative container type, mapping server names/ids to TreeServers */ typedef TR1NS::unordered_map<std::string, TreeServer*, irc::insensitive, irc::StrHashComp> server_hash; /** Contains helper functions and variables for this module, * and keeps them out of the global namespace */ class SpanningTreeUtilities : public classbase { CacheRefreshTimer RefreshTimer; public: typedef std::set<TreeSocket*> TreeSocketSet; typedef std::map<TreeSocket*, std::pair<std::string, unsigned int> > TimeoutList; /** Creator module */ ModuleSpanningTree* Creator; /** Flatten links and /MAP for non-opers */ bool FlatLinks; /** True if we're going to hide netsplits as *.net *.split for non-opers */ bool HideSplits; /** Hide U-Lined servers in /MAP and /LINKS */ bool HideULines; /** Announce TS changes to channels on merge */ bool AnnounceTSChange; /** Allow modules marked as VF_OPTCOMMON to be mismatched when linking */ bool AllowOptCommon; /** Make snomasks +CQ quiet during bursts and splits */ bool quiet_bursts; /* Number of seconds that a server can go without ping * before opers are warned of high latency. */ unsigned int PingWarnTime; /** This variable represents the root of the server tree */ TreeServer *TreeRoot; /** IPs allowed to link to us */ std::vector<std::string> ValidIPs; /** Hash of currently connected servers by name */ server_hash serverlist; /** Hash of currently known server ids */ server_hash sidlist; /** List of all outgoing sockets and their timeouts */ TimeoutList timeoutlist; /** Holds the data from the <link> tags in the conf */ std::vector<reference<Link> > LinkBlocks; /** Holds the data from the <autoconnect> tags in the conf */ std::vector<reference<Autoconnect> > AutoconnectBlocks; /** Ping frequency of server to server links */ unsigned int PingFreq; /** Initialise utility class */ SpanningTreeUtilities(ModuleSpanningTree* Creator); /** Prepare for class destruction */ CullResult cull() CXX11_OVERRIDE; /** Destroy class and free listeners etc */ ~SpanningTreeUtilities(); void RouteCommand(TreeServer* origin, CommandBase* cmd, const CommandBase::Params& parameters, User* user); /** Send a message from this server to one other local or remote */ void DoOneToOne(const CmdBuilder& params, Server* target); /** Send a message from this server to all but one other, local or remote */ void DoOneToAllButSender(const CmdBuilder& params, TreeServer* omit); /** Send a message from this server to all others */ void DoOneToMany(const CmdBuilder& params); /** Read the spanningtree module's tags from the config file */ void ReadConfiguration(); /** Handle nick collision */ bool DoCollision(User* u, TreeServer* server, time_t remotets, const std::string& remoteident, const std::string& remoteip, const std::string& remoteuid, const char* collidecmd); /** Compile a list of servers which contain members of channel c */ void GetListOfServersForChannel(Channel* c, TreeSocketSet& list, char status, const CUList& exempt_list); /** Find a server by name or SID */ TreeServer* FindServer(const std::string &ServerName); /** Find server by SID */ TreeServer* FindServerID(const std::string &id); /** Find a server based on a target string. * @param target Target string where a command should be routed to. May be a server name, a sid, a nickname or a uuid. */ TreeServer* FindRouteTarget(const std::string& target); /** Find a server by glob mask */ TreeServer* FindServerMask(const std::string &ServerName); /** Find a link tag from a server name */ Link* FindLink(const std::string& name); /** Refresh the IP cache used for allowing inbound connections */ void RefreshIPCache(); /** Sends a PRIVMSG or a NOTICE to a channel obeying an exempt list and an optional prefix */ void SendChannelMessage(User* source, Channel* target, const std::string& text, char status, const ClientProtocol::TagMap& tags, const CUList& exempt_list, const char* message_type, TreeSocket* omit = NULL); }; inline void SpanningTreeUtilities::DoOneToMany(const CmdBuilder& params) { DoOneToAllButSender(params, NULL); } �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/src/modules/m_sqlauth.cpp������������������������������������������������������������0000664�0000000�0000000�00000014064�13554550454�0020310�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * InspIRCd -- Internet Relay Chat Daemon * * 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 * 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 "inspircd.h" #include "modules/sql.h" #include "modules/hash.h" #include "modules/ssl.h" enum AuthState { AUTH_STATE_NONE = 0, AUTH_STATE_BUSY = 1, AUTH_STATE_FAIL = 2 }; class AuthQuery : public SQL::Query { public: const std::string uid; LocalIntExt& pendingExt; bool verbose; const std::string& kdf; const std::string& pwcolumn; AuthQuery(Module* me, const std::string& u, LocalIntExt& e, bool v, const std::string& kd, const std::string& pwcol) : SQL::Query(me) , uid(u) , pendingExt(e) , verbose(v) , kdf(kd) , pwcolumn(pwcol) { } void OnResult(SQL::Result& res) CXX11_OVERRIDE { LocalUser* user = IS_LOCAL(ServerInstance->FindUUID(uid)); if (!user) return; if (res.Rows()) { if (!kdf.empty()) { HashProvider* hashprov = ServerInstance->Modules->FindDataService<HashProvider>("hash/" + kdf); if (!hashprov) { if (verbose) ServerInstance->SNO->WriteGlobalSno('a', "Forbidden connection from %s (a provider for %s was not loaded)", user->GetFullRealHost().c_str(), kdf.c_str()); pendingExt.set(user, AUTH_STATE_FAIL); return; } size_t colindex = 0; if (!pwcolumn.empty() && !res.HasColumn(pwcolumn, colindex)) { if (verbose) ServerInstance->SNO->WriteGlobalSno('a', "Forbidden connection from %s (the column specified (%s) was not returned)", user->GetFullRealHost().c_str(), pwcolumn.c_str()); pendingExt.set(user, AUTH_STATE_FAIL); return; } SQL::Row row; while (res.GetRow(row)) { if (hashprov->Compare(user->password, row[colindex])) { pendingExt.set(user, AUTH_STATE_NONE); return; } } if (verbose) ServerInstance->SNO->WriteGlobalSno('a', "Forbidden connection from %s (password from the SQL query did not match the user provided password)", user->GetFullRealHost().c_str()); pendingExt.set(user, AUTH_STATE_FAIL); return; } pendingExt.set(user, AUTH_STATE_NONE); } else { if (verbose) ServerInstance->SNO->WriteGlobalSno('a', "Forbidden connection from %s (SQL query returned no matches)", user->GetFullRealHost().c_str()); pendingExt.set(user, AUTH_STATE_FAIL); } } void OnError(SQL::Error& error) CXX11_OVERRIDE { User* user = ServerInstance->FindNick(uid); if (!user) return; pendingExt.set(user, AUTH_STATE_FAIL); if (verbose) ServerInstance->SNO->WriteGlobalSno('a', "Forbidden connection from %s (SQL query failed: %s)", user->GetFullRealHost().c_str(), error.ToString()); } }; class ModuleSQLAuth : public Module { LocalIntExt pendingExt; dynamic_reference<SQL::Provider> SQL; UserCertificateAPI sslapi; std::string freeformquery; std::string killreason; std::string allowpattern; bool verbose; std::vector<std::string> hash_algos; std::string kdf; std::string pwcolumn; public: ModuleSQLAuth() : pendingExt("sqlauth-wait", ExtensionItem::EXT_USER, this) , SQL(this, "SQL") , sslapi(this) { } void ReadConfig(ConfigStatus& status) CXX11_OVERRIDE { ConfigTag* conf = ServerInstance->Config->ConfValue("sqlauth"); std::string dbid = conf->getString("dbid"); if (dbid.empty()) SQL.SetProvider("SQL"); else SQL.SetProvider("SQL/" + dbid); freeformquery = conf->getString("query"); killreason = conf->getString("killreason"); allowpattern = conf->getString("allowpattern"); verbose = conf->getBool("verbose"); kdf = conf->getString("kdf"); pwcolumn = conf->getString("column"); hash_algos.clear(); irc::commasepstream algos(conf->getString("hash", "md5,sha256")); std::string algo; while (algos.GetToken(algo)) hash_algos.push_back(algo); } ModResult OnUserRegister(LocalUser* user) CXX11_OVERRIDE { // Note this is their initial (unresolved) connect block ConfigTag* tag = user->MyClass->config; if (!tag->getBool("usesqlauth", true)) return MOD_RES_PASSTHRU; if (!allowpattern.empty() && InspIRCd::Match(user->nick,allowpattern)) return MOD_RES_PASSTHRU; if (pendingExt.get(user)) return MOD_RES_PASSTHRU; if (!SQL) { ServerInstance->SNO->WriteGlobalSno('a', "Forbidden connection from %s (SQL database not present)", user->GetFullRealHost().c_str()); ServerInstance->Users->QuitUser(user, killreason); return MOD_RES_PASSTHRU; } pendingExt.set(user, AUTH_STATE_BUSY); SQL::ParamMap userinfo; SQL::PopulateUserInfo(user, userinfo); userinfo["pass"] = user->password; userinfo["certfp"] = sslapi ? sslapi->GetFingerprint(user) : ""; for (std::vector<std::string>::const_iterator it = hash_algos.begin(); it != hash_algos.end(); ++it) { HashProvider* hashprov = ServerInstance->Modules->FindDataService<HashProvider>("hash/" + *it); if (hashprov && !hashprov->IsKDF()) userinfo[*it + "pass"] = hashprov->Generate(user->password); } SQL->Submit(new AuthQuery(this, user->uuid, pendingExt, verbose, kdf, pwcolumn), freeformquery, userinfo); return MOD_RES_PASSTHRU; } ModResult OnCheckReady(LocalUser* user) CXX11_OVERRIDE { switch (pendingExt.get(user)) { case AUTH_STATE_NONE: return MOD_RES_PASSTHRU; case AUTH_STATE_BUSY: return MOD_RES_DENY; case AUTH_STATE_FAIL: ServerInstance->Users->QuitUser(user, killreason); return MOD_RES_DENY; } return MOD_RES_PASSTHRU; } Version GetVersion() CXX11_OVERRIDE { return Version("Allow/deny connections based upon an arbitrary SQL table", VF_VENDOR); } }; MODULE_INIT(ModuleSQLAuth) ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/src/modules/m_sqloper.cpp������������������������������������������������������������0000664�0000000�0000000�00000017030�13554550454�0020310�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * InspIRCd -- Internet Relay Chat Daemon * * Copyright (C) 2017 Dylan Frank <b00mx0r@aureus.pw> * 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 * 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 "inspircd.h" #include "modules/sql.h" class OperQuery : public SQL::Query { public: // This variable will store all the OPER blocks from the DB std::vector<std::string>& my_blocks; /** We want to store the username and password if this is called during an /OPER, as we're responsible for /OPER post-DB fetch * Note: uid will be empty if this DB update was not called as a result of a user command (i.e. /REHASH) */ const std::string uid, username, password; OperQuery(Module* me, std::vector<std::string>& mb, const std::string& u, const std::string& un, const std::string& pw) : SQL::Query(me) , my_blocks(mb) , uid(u) , username(un) , password(pw) { } OperQuery(Module* me, std::vector<std::string>& mb) : SQL::Query(me) , my_blocks(mb) { } void OnResult(SQL::Result& res) CXX11_OVERRIDE { ServerConfig::OperIndex& oper_blocks = ServerInstance->Config->oper_blocks; // Remove our previous blocks from oper_blocks for a clean update for (std::vector<std::string>::const_iterator i = my_blocks.begin(); i != my_blocks.end(); ++i) { oper_blocks.erase(*i); } my_blocks.clear(); SQL::Row row; // Iterate through DB results to create oper blocks from sqloper rows while (res.GetRow(row)) { std::vector<std::string> cols; res.GetCols(cols); // Create the oper tag as if we were the conf file. ConfigItems* items; reference<ConfigTag> tag = ConfigTag::create("oper", MODNAME, 0, items); /** Iterate through each column in the SQLOpers table. An infinite number of fields can be specified. * Column 'x' with cell value 'y' will be the same as x=y in an OPER block in opers.conf. */ for (unsigned int i=0; i < cols.size(); ++i) { if (!row[i].IsNull()) (*items)[cols[i]] = row[i]; } const std::string name = tag->getString("name"); // Skip both duplicate sqloper blocks and sqloper blocks that attempt to override conf blocks. if (oper_blocks.find(name) != oper_blocks.end()) continue; const std::string type = tag->getString("type"); ServerConfig::OperIndex::iterator tblk = ServerInstance->Config->OperTypes.find(type); if (tblk == ServerInstance->Config->OperTypes.end()) { ServerInstance->Logs->Log(MODNAME, LOG_DEFAULT, "Sqloper block " + name + " has missing type " + type); ServerInstance->SNO->WriteGlobalSno('a', "m_sqloper: Oper block %s has missing type %s", name.c_str(), type.c_str()); continue; } OperInfo* ifo = new OperInfo(type); ifo->type_block = tblk->second->type_block; ifo->oper_block = tag; ifo->class_blocks.assign(tblk->second->class_blocks.begin(), tblk->second->class_blocks.end()); oper_blocks[name] = ifo; my_blocks.push_back(name); row.clear(); } // If this was done as a result of /OPER and not a config read if (!uid.empty()) { // Now that we've updated the DB, call any other /OPER hooks and then call /OPER OperExec(); } } void OnError(SQL::Error& error) CXX11_OVERRIDE { ServerInstance->Logs->Log(MODNAME, LOG_DEFAULT, "query failed (%s)", error.ToString()); ServerInstance->SNO->WriteGlobalSno('a', "m_sqloper: Failed to update blocks from database"); if (!uid.empty()) { // Fallback. We don't want to block a netadmin from /OPER OperExec(); } } // Call /oper after placing all blocks from the SQL table into the config->oper_blocks list. void OperExec() { User* user = ServerInstance->FindNick(uid); LocalUser* localuser = IS_LOCAL(user); // This should never be true if (!localuser) return; Command* oper_command = ServerInstance->Parser.GetHandler("OPER"); if (oper_command) { CommandBase::Params params; params.push_back(username); params.push_back(password); // Begin callback to other modules (i.e. sslinfo) now that we completed the DB fetch ModResult MOD_RESULT; std::string origin = "OPER"; FIRST_MOD_RESULT(OnPreCommand, MOD_RESULT, (origin, params, localuser, true)); if (MOD_RESULT == MOD_RES_DENY) return; // Now handle /OPER. ClientProtocol::TagMap tags; oper_command->Handle(user, CommandBase::Params(params, tags)); } else { ServerInstance->Logs->Log(MODNAME, LOG_SPARSE, "BUG: WHAT?! Why do we have no OPER command?!"); } } }; class ModuleSQLOper : public Module { // Whether OperQuery is running bool active; std::string query; // Stores oper blocks from DB std::vector<std::string> my_blocks; dynamic_reference<SQL::Provider> SQL; public: ModuleSQLOper() : active(false) , SQL(this, "SQL") { } void ReadConfig(ConfigStatus& status) CXX11_OVERRIDE { // Clear list of our blocks, as ConfigReader just wiped them anyway my_blocks.clear(); ConfigTag* tag = ServerInstance->Config->ConfValue("sqloper"); std::string dbid = tag->getString("dbid"); if (dbid.empty()) SQL.SetProvider("SQL"); else SQL.SetProvider("SQL/" + dbid); query = tag->getString("query", "SELECT * FROM ircd_opers WHERE active=1;"); // Update sqloper list from the database. GetOperBlocks(); } ~ModuleSQLOper() { // Remove all oper blocks that were from the DB for (std::vector<std::string>::const_iterator i = my_blocks.begin(); i != my_blocks.end(); ++i) { ServerInstance->Config->oper_blocks.erase(*i); } } ModResult OnPreCommand(std::string& command, CommandBase::Params& parameters, LocalUser* user, bool validated) CXX11_OVERRIDE { // If we are not in the middle of an existing /OPER and someone is trying to oper-up if (validated && command == "OPER" && parameters.size() >= 2 && !active) { if (SQL) { GetOperBlocks(user->uuid, parameters[0], parameters[1]); /** We need to reload oper blocks from the DB before other * hooks can run (i.e. sslinfo). We will re-call /OPER later. */ return MOD_RES_DENY; } ServerInstance->Logs->Log(MODNAME, LOG_DEFAULT, "database not present"); } else if (active) { active = false; } // There is either no DB or we successfully reloaded oper blocks return MOD_RES_PASSTHRU; } // The one w/o params is for non-/OPER DB updates, such as a rehash. void GetOperBlocks() { SQL->Submit(new OperQuery(this, my_blocks), query); } void GetOperBlocks(const std::string u, const std::string& un, const std::string& pw) { active = true; // Call to SQL query to fetch oper list from SQL table. SQL->Submit(new OperQuery(this, my_blocks, u, un, pw), query); } void Prioritize() CXX11_OVERRIDE { /** Run before other /OPER hooks that expect populated blocks, i.e. sslinfo or a TOTP module. * We issue a DENY first, and will re-run OnPreCommand later to trigger the other hooks post-DB update. */ ServerInstance->Modules.SetPriority(this, I_OnPreCommand, PRIORITY_FIRST); } Version GetVersion() CXX11_OVERRIDE { return Version("Allows storage of oper credentials in an SQL table", VF_VENDOR); } }; MODULE_INIT(ModuleSQLOper) ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/src/modules/m_sslinfo.cpp������������������������������������������������������������0000664�0000000�0000000�00000023266�13554550454�0020310�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * InspIRCd -- Internet Relay Chat Daemon * * 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 * 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 "inspircd.h" #include "modules/ssl.h" #include "modules/webirc.h" #include "modules/whois.h" #include "modules/who.h" enum { // From oftc-hybrid. RPL_WHOISCERTFP = 276, // From UnrealIRCd. RPL_WHOISSECURE = 671 }; class SSLCertExt : public ExtensionItem { public: SSLCertExt(Module* parent) : ExtensionItem("ssl_cert", ExtensionItem::EXT_USER, parent) { } ssl_cert* get(const Extensible* item) const { return static_cast<ssl_cert*>(get_raw(item)); } void set(Extensible* item, ssl_cert* value) { value->refcount_inc(); ssl_cert* old = static_cast<ssl_cert*>(set_raw(item, value)); if (old && old->refcount_dec()) delete old; } void unset(Extensible* container) { free(container, unset_raw(container)); } std::string ToNetwork(const Extensible* container, void* item) const CXX11_OVERRIDE { return static_cast<ssl_cert*>(item)->GetMetaLine(); } void FromNetwork(Extensible* container, const std::string& value) CXX11_OVERRIDE { ssl_cert* cert = new ssl_cert; set(container, cert); std::stringstream s(value); std::string v; getline(s,v,' '); cert->invalid = (v.find('v') != std::string::npos); cert->trusted = (v.find('T') != std::string::npos); cert->revoked = (v.find('R') != std::string::npos); cert->unknownsigner = (v.find('s') != std::string::npos); if (v.find('E') != std::string::npos) { getline(s,cert->error,'\n'); } else { getline(s,cert->fingerprint,' '); getline(s,cert->dn,' '); getline(s,cert->issuer,'\n'); } } void free(Extensible* container, void* item) CXX11_OVERRIDE { ssl_cert* old = static_cast<ssl_cert*>(item); if (old && old->refcount_dec()) delete old; } }; class UserCertificateAPIImpl : public UserCertificateAPIBase { public: LocalIntExt nosslext; SSLCertExt sslext; UserCertificateAPIImpl(Module* mod) : UserCertificateAPIBase(mod) , nosslext("no_ssl_cert", ExtensionItem::EXT_USER, mod) , sslext(mod) { } ssl_cert* GetCertificate(User* user) CXX11_OVERRIDE { ssl_cert* cert = sslext.get(user); if (cert) return cert; LocalUser* luser = IS_LOCAL(user); if (!luser || nosslext.get(luser)) return NULL; cert = SSLClientCert::GetCertificate(&luser->eh); if (!cert) return NULL; SetCertificate(user, cert); return cert; } void SetCertificate(User* user, ssl_cert* cert) CXX11_OVERRIDE { ServerInstance->Logs->Log(MODNAME, LOG_DEBUG, "Setting SSL certificate for %s: %s", user->GetFullHost().c_str(), cert->GetMetaLine().c_str()); sslext.set(user, cert); } }; class CommandSSLInfo : public Command { public: UserCertificateAPIImpl sslapi; CommandSSLInfo(Module* Creator) : Command(Creator, "SSLINFO", 1) , sslapi(Creator) { this->syntax = "<nick>"; } CmdResult Handle(User* user, const Params& parameters) CXX11_OVERRIDE { User* target = ServerInstance->FindNickOnly(parameters[0]); if ((!target) || (target->registered != REG_ALL)) { user->WriteNumeric(Numerics::NoSuchNick(parameters[0])); return CMD_FAILURE; } bool operonlyfp = ServerInstance->Config->ConfValue("sslinfo")->getBool("operonly"); if (operonlyfp && !user->IsOper() && target != user) { user->WriteNotice("*** You cannot view SSL certificate information for other users"); return CMD_FAILURE; } ssl_cert* cert = sslapi.GetCertificate(target); if (!cert) { user->WriteNotice("*** No SSL certificate for this user"); } else if (cert->GetError().length()) { user->WriteNotice("*** No SSL certificate information for this user (" + cert->GetError() + ")."); } else { user->WriteNotice("*** Distinguished Name: " + cert->GetDN()); user->WriteNotice("*** Issuer: " + cert->GetIssuer()); user->WriteNotice("*** Key Fingerprint: " + cert->GetFingerprint()); } return CMD_SUCCESS; } }; class ModuleSSLInfo : public Module , public WebIRC::EventListener , public Whois::EventListener , public Who::EventListener { private: CommandSSLInfo cmd; bool MatchFP(ssl_cert* const cert, const std::string& fp) const { return irc::spacesepstream(fp).Contains(cert->GetFingerprint()); } public: ModuleSSLInfo() : WebIRC::EventListener(this) , Whois::EventListener(this) , Who::EventListener(this) , cmd(this) { } Version GetVersion() CXX11_OVERRIDE { return Version("SSL Certificate Utilities", VF_VENDOR); } void OnWhois(Whois::Context& whois) CXX11_OVERRIDE { ssl_cert* cert = cmd.sslapi.GetCertificate(whois.GetTarget()); if (cert) { whois.SendLine(RPL_WHOISSECURE, "is using a secure connection"); bool operonlyfp = ServerInstance->Config->ConfValue("sslinfo")->getBool("operonly"); if ((!operonlyfp || whois.IsSelfWhois() || whois.GetSource()->IsOper()) && !cert->fingerprint.empty()) whois.SendLine(RPL_WHOISCERTFP, InspIRCd::Format("has client certificate fingerprint %s", cert->fingerprint.c_str())); } } ModResult OnWhoLine(const Who::Request& request, LocalUser* source, User* user, Membership* memb, Numeric::Numeric& numeric) CXX11_OVERRIDE { size_t flag_index; if (!request.GetFieldIndex('f', flag_index)) return MOD_RES_PASSTHRU; ssl_cert* cert = cmd.sslapi.GetCertificate(user); if (cert) numeric.GetParams()[flag_index].push_back('s'); return MOD_RES_PASSTHRU; } ModResult OnPreCommand(std::string& command, CommandBase::Params& parameters, LocalUser* user, bool validated) CXX11_OVERRIDE { if ((command == "OPER") && (validated)) { ServerConfig::OperIndex::const_iterator i = ServerInstance->Config->oper_blocks.find(parameters[0]); if (i != ServerInstance->Config->oper_blocks.end()) { OperInfo* ifo = i->second; ssl_cert* cert = cmd.sslapi.GetCertificate(user); if (ifo->oper_block->getBool("sslonly") && !cert) { user->WriteNumeric(ERR_NOOPERHOST, "This oper login requires an SSL connection."); user->CommandFloodPenalty += 10000; return MOD_RES_DENY; } std::string fingerprint; if (ifo->oper_block->readString("fingerprint", fingerprint) && (!cert || !MatchFP(cert, fingerprint))) { user->WriteNumeric(ERR_NOOPERHOST, "This oper login requires a matching SSL certificate fingerprint."); user->CommandFloodPenalty += 10000; return MOD_RES_DENY; } } } // Let core handle it for extra stuff return MOD_RES_PASSTHRU; } void OnPostConnect(User* user) CXX11_OVERRIDE { LocalUser* const localuser = IS_LOCAL(user); if (!localuser) return; const SSLIOHook* const ssliohook = SSLIOHook::IsSSL(&localuser->eh); if (!ssliohook || cmd.sslapi.nosslext.get(localuser)) return; ssl_cert* const cert = ssliohook->GetCertificate(); { std::string text = "*** You are connected to "; if (!ssliohook->GetServerName(text)) text.append(ServerInstance->Config->ServerName); text.append(" using SSL cipher '"); ssliohook->GetCiphersuite(text); text.push_back('\''); if ((cert) && (!cert->GetFingerprint().empty())) text.append(" and your SSL certificate fingerprint is ").append(cert->GetFingerprint()); user->WriteNotice(text); } if (!cert) return; // find an auto-oper block for this user for (ServerConfig::OperIndex::const_iterator i = ServerInstance->Config->oper_blocks.begin(); i != ServerInstance->Config->oper_blocks.end(); ++i) { OperInfo* ifo = i->second; std::string fp = ifo->oper_block->getString("fingerprint"); if (MatchFP(cert, fp) && ifo->oper_block->getBool("autologin")) user->Oper(ifo); } } ModResult OnSetConnectClass(LocalUser* user, ConnectClass* myclass) CXX11_OVERRIDE { ssl_cert* cert = cmd.sslapi.GetCertificate(user); bool ok = true; if (myclass->config->getString("requiressl") == "trusted") { ok = (cert && cert->IsCAVerified()); ServerInstance->Logs->Log("CONNECTCLASS", LOG_DEBUG, "Class requires a trusted SSL cert. Client %s one.", (ok ? "has" : "does not have")); } else if (myclass->config->getBool("requiressl")) { ok = (cert != NULL); ServerInstance->Logs->Log("CONNECTCLASS", LOG_DEBUG, "Class requires SSL. Client %s using SSL.", (ok ? "is" : "is not")); } if (!ok) return MOD_RES_DENY; return MOD_RES_PASSTHRU; } void OnWebIRCAuth(LocalUser* user, const WebIRC::FlagMap* flags) CXX11_OVERRIDE { // We are only interested in connection flags. If none have been // given then we have nothing to do. if (!flags) return; // We only care about the tls connection flag if the connection // between the gateway and the server is secure. if (!cmd.sslapi.GetCertificate(user)) return; WebIRC::FlagMap::const_iterator iter = flags->find("secure"); if (iter == flags->end()) { // If this is not set then the connection between the client and // the gateway is not secure. cmd.sslapi.nosslext.set(user, 1); cmd.sslapi.sslext.unset(user); return; } // Create a fake ssl_cert for the user. ssl_cert* cert = new ssl_cert; cert->error = "WebIRC users can not specify valid certs yet"; cert->invalid = true; cert->revoked = true; cert->trusted = false; cert->unknownsigner = true; cmd.sslapi.SetCertificate(user, cert); } }; MODULE_INIT(ModuleSSLInfo) ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/src/modules/m_sslmodes.cpp�����������������������������������������������������������0000664�0000000�0000000�00000014457�13554550454�0020466�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * InspIRCd -- Internet Relay Chat Daemon * * Copyright (C) 2013 Shawn Smith <shawn@inspircd.org> * Copyright (C) 2009 Daniel De Graaf <danieldg@inspircd.org> * Copyright (C) 2007 Robin Burchell <robin+git@viroteck.net> * Copyright (C) 2007 Dennis Friis <peavey@inspircd.org> * Copyright (C) 2006 Craig Edwards <craigedwards@brainbox.cc> * Copyright (C) 2006 Oliver Lupton <oliverlupton@gmail.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 "inspircd.h" #include "modules/ctctags.h" #include "modules/ssl.h" enum { // From UnrealIRCd. ERR_SECUREONLYCHAN = 489, ERR_ALLMUSTSSL = 490 }; /** Handle channel mode +z */ class SSLMode : public ModeHandler { private: UserCertificateAPI& API; public: SSLMode(Module* Creator, UserCertificateAPI& api) : ModeHandler(Creator, "sslonly", 'z', PARAM_NONE, MODETYPE_CHANNEL) , API(api) { } ModeAction OnModeChange(User* source, User* dest, Channel* channel, std::string& parameter, bool adding) CXX11_OVERRIDE { if (adding) { if (!channel->IsModeSet(this)) { if (IS_LOCAL(source)) { if (!API) { source->WriteNumeric(ERR_ALLMUSTSSL, channel->name, "Unable to determine whether all members of the channel are connected via SSL"); return MODEACTION_DENY; } unsigned long nonssl = 0; const Channel::MemberMap& userlist = channel->GetUsers(); for (Channel::MemberMap::const_iterator i = userlist.begin(); i != userlist.end(); ++i) { ssl_cert* cert = API->GetCertificate(i->first); if (!cert && !i->first->server->IsULine()) nonssl++; } if (nonssl) { source->WriteNumeric(ERR_ALLMUSTSSL, channel->name, InspIRCd::Format("All members of the channel must be connected via SSL (%lu/%lu are non-SSL)", nonssl, static_cast<unsigned long>(userlist.size()))); return MODEACTION_DENY; } } channel->SetMode(this, true); return MODEACTION_ALLOW; } else { return MODEACTION_DENY; } } else { if (channel->IsModeSet(this)) { channel->SetMode(this, false); return MODEACTION_ALLOW; } return MODEACTION_DENY; } } }; /** Handle user mode +z */ class SSLModeUser : public ModeHandler { private: UserCertificateAPI& API; public: SSLModeUser(Module* Creator, UserCertificateAPI& api) : ModeHandler(Creator, "sslqueries", 'z', PARAM_NONE, MODETYPE_USER) , API(api) { if (!ServerInstance->Config->ConfValue("sslmodes")->getBool("enableumode")) DisableAutoRegister(); } ModeAction OnModeChange(User* user, User* dest, Channel* channel, std::string& parameter, bool adding) CXX11_OVERRIDE { if (adding) { if (!dest->IsModeSet(this)) { if (!API || !API->GetCertificate(user)) return MODEACTION_DENY; dest->SetMode(this, true); return MODEACTION_ALLOW; } } else { if (dest->IsModeSet(this)) { dest->SetMode(this, false); return MODEACTION_ALLOW; } } return MODEACTION_DENY; } }; class ModuleSSLModes : public Module , public CTCTags::EventListener { private: UserCertificateAPI api; SSLMode sslm; SSLModeUser sslquery; public: ModuleSSLModes() : CTCTags::EventListener(this) , api(this) , sslm(this, api) , sslquery(this, api) { } ModResult OnUserPreJoin(LocalUser* user, Channel* chan, const std::string& cname, std::string& privs, const std::string& keygiven) CXX11_OVERRIDE { if(chan && chan->IsModeSet(sslm)) { if (!api) { user->WriteNumeric(ERR_SECUREONLYCHAN, cname, "Cannot join channel; unable to determine if you are an SSL user (+z is set)"); return MOD_RES_DENY; } if (!api->GetCertificate(user)) { user->WriteNumeric(ERR_SECUREONLYCHAN, cname, "Cannot join channel; SSL users only (+z is set)"); return MOD_RES_DENY; } } return MOD_RES_PASSTHRU; } ModResult HandleMessage(User* user, const MessageTarget& msgtarget) { if (msgtarget.type != MessageTarget::TYPE_USER) return MOD_RES_PASSTHRU; User* target = msgtarget.Get<User>(); /* If one or more of the parties involved is a ulined service, we wont stop it. */ if (user->server->IsULine() || target->server->IsULine()) return MOD_RES_PASSTHRU; /* If the target is +z */ if (target->IsModeSet(sslquery)) { if (!api || !api->GetCertificate(user)) { /* The sending user is not on an SSL connection */ user->WriteNumeric(ERR_CANTSENDTOUSER, target->nick, "You are not permitted to send private messages to this user (+z is set)"); return MOD_RES_DENY; } } /* If the user is +z */ else if (user->IsModeSet(sslquery)) { if (!api || !api->GetCertificate(target)) { user->WriteNumeric(ERR_CANTSENDTOUSER, target->nick, "You must remove user mode 'z' before you are able to send private messages to a non-SSL user."); return MOD_RES_DENY; } } return MOD_RES_PASSTHRU; } ModResult OnUserPreMessage(User* user, const MessageTarget& target, MessageDetails& details) CXX11_OVERRIDE { return HandleMessage(user, target); } ModResult OnUserPreTagMessage(User* user, const MessageTarget& target, CTCTags::TagMessageDetails& details) CXX11_OVERRIDE { return HandleMessage(user, target); } ModResult OnCheckBan(User *user, Channel *c, const std::string& mask) CXX11_OVERRIDE { if ((mask.length() > 2) && (mask[0] == 'z') && (mask[1] == ':')) { const std::string fp = api ? api->GetFingerprint(user) : ""; if (!fp.empty() && InspIRCd::Match(fp, mask.substr(2))) return MOD_RES_DENY; } return MOD_RES_PASSTHRU; } void On005Numeric(std::map<std::string, std::string>& tokens) CXX11_OVERRIDE { tokens["EXTBAN"].push_back('z'); } Version GetVersion() CXX11_OVERRIDE { return Version("Provides user and channel mode +z to allow for SSL-only channels, queries and notices", VF_VENDOR); } }; MODULE_INIT(ModuleSSLModes) �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/src/modules/m_starttls.cpp�����������������������������������������������������������0000664�0000000�0000000�00000005532�13554550454�0020507�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * InspIRCd -- Internet Relay Chat Daemon * * Copyright (C) 2014 Adam <Adam@anope.org> * * This file is part of InspIRCd. InspIRCd is free software: you can * redistribute it and/or modify it under the terms of the GNU General Public * License as published by the Free Software Foundation, version 2. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include "inspircd.h" #include "modules/ssl.h" #include "modules/cap.h" // From IRCv3 tls-3.1 enum { RPL_STARTTLS = 670, ERR_STARTTLS = 691 }; class CommandStartTLS : public SplitCommand { dynamic_reference_nocheck<IOHookProvider>& ssl; public: CommandStartTLS(Module* mod, dynamic_reference_nocheck<IOHookProvider>& s) : SplitCommand(mod, "STARTTLS") , ssl(s) { works_before_reg = true; } CmdResult HandleLocal(LocalUser* user, const Params& parameters) CXX11_OVERRIDE { if (!ssl) { user->WriteNumeric(ERR_STARTTLS, "STARTTLS is not enabled"); return CMD_FAILURE; } if (user->registered == REG_ALL) { user->WriteNumeric(ERR_STARTTLS, "STARTTLS is not permitted after client registration is complete"); return CMD_FAILURE; } if (user->eh.GetIOHook()) { user->WriteNumeric(ERR_STARTTLS, "STARTTLS failure"); return CMD_FAILURE; } user->WriteNumeric(RPL_STARTTLS, "STARTTLS successful, go ahead with TLS handshake"); /* We need to flush the write buffer prior to adding the IOHook, * otherwise we'll be sending this line inside the SSL session - which * won't start its handshake until the client gets this line. Currently, * we assume the write will not block here; this is usually safe, as * STARTTLS is sent very early on in the registration phase, where the * user hasn't built up much sendq. Handling a blocked write here would * be very annoying. */ user->eh.DoWrite(); ssl->OnAccept(&user->eh, NULL, NULL); return CMD_SUCCESS; } }; class ModuleStartTLS : public Module { CommandStartTLS starttls; Cap::Capability tls; dynamic_reference_nocheck<IOHookProvider> ssl; public: ModuleStartTLS() : starttls(this, ssl) , tls(this, "tls") , ssl(this, "ssl") { } void ReadConfig(ConfigStatus& status) CXX11_OVERRIDE { ConfigTag* conf = ServerInstance->Config->ConfValue("starttls"); std::string newprovider = conf->getString("provider"); if (newprovider.empty()) ssl.SetProvider("ssl"); else ssl.SetProvider("ssl/" + newprovider); } Version GetVersion() CXX11_OVERRIDE { return Version("Provides the STARTTLS command", VF_VENDOR); } }; MODULE_INIT(ModuleStartTLS) ����������������������������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/src/modules/m_stripcolor.cpp���������������������������������������������������������0000664�0000000�0000000�00000005200�13554550454�0021017�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * InspIRCd -- Internet Relay Chat Daemon * * Copyright (C) 2004, 2008 Craig Edwards <craigedwards@brainbox.cc> * Copyright (C) 2007 Dennis Friis <peavey@inspircd.org> * Copyright (C) 2007 Robin Burchell <robin+git@viroteck.net> * * 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 "inspircd.h" #include "modules/exemption.h" class ModuleStripColor : public Module { CheckExemption::EventProvider exemptionprov; SimpleChannelModeHandler csc; SimpleUserModeHandler usc; public: ModuleStripColor() : exemptionprov(this) , csc(this, "stripcolor", 'S') , usc(this, "u_stripcolor", 'S') { } void On005Numeric(std::map<std::string, std::string>& tokens) CXX11_OVERRIDE { tokens["EXTBAN"].push_back('S'); } ModResult OnUserPreMessage(User* user, const MessageTarget& target, MessageDetails& details) CXX11_OVERRIDE { if (!IS_LOCAL(user)) return MOD_RES_PASSTHRU; bool active = false; switch (target.type) { case MessageTarget::TYPE_USER: { User* t = target.Get<User>(); active = t->IsModeSet(usc); break; } case MessageTarget::TYPE_CHANNEL: { Channel* t = target.Get<Channel>(); ModResult res = CheckExemption::Call(exemptionprov, user, t, "stripcolor"); if (res == MOD_RES_ALLOW) return MOD_RES_PASSTHRU; active = !t->GetExtBanStatus(user, 'S').check(!t->IsModeSet(csc)); break; } case MessageTarget::TYPE_SERVER: break; } if (active) { InspIRCd::StripColor(details.text); } return MOD_RES_PASSTHRU; } void OnUserPart(Membership* memb, std::string& partmessage, CUList& except_list) CXX11_OVERRIDE { User* user = memb->user; Channel* channel = memb->chan; if (!IS_LOCAL(user)) return; if (channel->GetExtBanStatus(user, 'S').check(!user->IsModeSet(csc))) { ModResult res = CheckExemption::Call(exemptionprov, user, channel, "stripcolor"); if (res != MOD_RES_ALLOW) InspIRCd::StripColor(partmessage); } } Version GetVersion() CXX11_OVERRIDE { return Version("Provides channel mode +S, strip ansi color", VF_VENDOR); } }; MODULE_INIT(ModuleStripColor) ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/src/modules/m_svshold.cpp������������������������������������������������������������0000664�0000000�0000000�00000013316�13554550454�0020310�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * InspIRCd -- Internet Relay Chat Daemon * * Copyright (C) 2006-2008 Robin Burchell <robin+git@viroteck.net> * Copyright (C) 2008 Pippijn van Steenhoven <pip88nl@gmail.com> * Copyright (C) 2006-2008 Dennis Friis <peavey@inspircd.org> * Copyright (C) 2006 Craig Edwards <craigedwards@brainbox.cc> * * This file is part of InspIRCd. InspIRCd is free software: you can * redistribute it and/or modify it under the terms of the GNU General Public * License as published by the Free Software Foundation, version 2. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include "inspircd.h" #include "xline.h" #include "modules/stats.h" namespace { bool silent; } /** Holds a SVSHold item */ class SVSHold : public XLine { public: std::string nickname; SVSHold(time_t s_time, unsigned long d, const std::string& src, const std::string& re, const std::string& nick) : XLine(s_time, d, src, re, "SVSHOLD") { this->nickname = nick; } bool Matches(User* u) CXX11_OVERRIDE { if (u->nick == nickname) return true; return false; } bool Matches(const std::string& s) CXX11_OVERRIDE { return InspIRCd::Match(s, nickname); } void DisplayExpiry() CXX11_OVERRIDE { if (!silent) { ServerInstance->SNO->WriteToSnoMask('x', "Removing expired SVSHOLD %s (set by %s %s ago): %s", nickname.c_str(), source.c_str(), InspIRCd::DurationString(ServerInstance->Time() - set_time).c_str(), reason.c_str()); } } const std::string& Displayable() CXX11_OVERRIDE { return nickname; } }; /** An XLineFactory specialized to generate SVSHOLD pointers */ class SVSHoldFactory : public XLineFactory { public: SVSHoldFactory() : XLineFactory("SVSHOLD") { } /** Generate an SVSHOLD */ XLine* Generate(time_t set_time, unsigned long duration, const std::string& source, const std::string& reason, const std::string& xline_specific_mask) CXX11_OVERRIDE { return new SVSHold(set_time, duration, source, reason, xline_specific_mask); } bool AutoApplyToUserList(XLine* x) CXX11_OVERRIDE { return false; } }; /** Handle /SVSHold */ class CommandSvshold : public Command { public: CommandSvshold(Module* Creator) : Command(Creator, "SVSHOLD", 1) { flags_needed = 'o'; this->syntax = "<nick> [<duration> :<reason>]"; } CmdResult Handle(User* user, const Params& parameters) CXX11_OVERRIDE { /* syntax: svshold nickname time :reason goes here */ /* 'time' is a human-readable timestring, like 2d3h2s. */ if (!user->server->IsULine()) { /* don't allow SVSHOLD from non-ulined clients */ return CMD_FAILURE; } if (parameters.size() == 1) { std::string reason; if (ServerInstance->XLines->DelLine(parameters[0].c_str(), "SVSHOLD", reason, user)) { if (!silent) ServerInstance->SNO->WriteToSnoMask('x', "%s removed SVSHOLD on %s: %s", user->nick.c_str(), parameters[0].c_str(), reason.c_str()); } else { user->WriteNotice("*** SVSHOLD " + parameters[0] + " not found on the list."); } } else { if (parameters.size() < 3) return CMD_FAILURE; unsigned long duration; if (!InspIRCd::Duration(parameters[1], duration)) { user->WriteNotice("*** Invalid duration for SVSHOLD."); return CMD_FAILURE; } SVSHold* r = new SVSHold(ServerInstance->Time(), duration, user->nick.c_str(), parameters[2].c_str(), parameters[0].c_str()); if (ServerInstance->XLines->AddLine(r, user)) { if (silent) return CMD_SUCCESS; if (!duration) { ServerInstance->SNO->WriteGlobalSno('x', "%s added permanent SVSHOLD for %s: %s", user->nick.c_str(), parameters[0].c_str(), parameters[2].c_str()); } else { ServerInstance->SNO->WriteGlobalSno('x', "%s added timed SVSHOLD for %s, expires in %s (on %s): %s", user->nick.c_str(), parameters[0].c_str(), InspIRCd::DurationString(duration).c_str(), InspIRCd::TimeString(ServerInstance->Time() + duration).c_str(), parameters[2].c_str()); } } else { delete r; return CMD_FAILURE; } } return CMD_SUCCESS; } RouteDescriptor GetRouting(User* user, const Params& parameters) CXX11_OVERRIDE { return ROUTE_BROADCAST; } }; class ModuleSVSHold : public Module, public Stats::EventListener { CommandSvshold cmd; SVSHoldFactory s; public: ModuleSVSHold() : Stats::EventListener(this) , cmd(this) { } void init() CXX11_OVERRIDE { ServerInstance->XLines->RegisterFactory(&s); } void ReadConfig(ConfigStatus& status) CXX11_OVERRIDE { ConfigTag* tag = ServerInstance->Config->ConfValue("svshold"); silent = tag->getBool("silent", true); } ModResult OnStats(Stats::Context& stats) CXX11_OVERRIDE { if (stats.GetSymbol() != 'S') return MOD_RES_PASSTHRU; ServerInstance->XLines->InvokeStats("SVSHOLD", 210, stats); return MOD_RES_DENY; } ModResult OnUserPreNick(LocalUser* user, const std::string& newnick) CXX11_OVERRIDE { XLine *rl = ServerInstance->XLines->MatchesLine("SVSHOLD", newnick); if (rl) { user->WriteNumeric(ERR_ERRONEUSNICKNAME, newnick, InspIRCd::Format("Services reserved nickname: %s", rl->reason.c_str())); return MOD_RES_DENY; } return MOD_RES_PASSTHRU; } ~ModuleSVSHold() { ServerInstance->XLines->DelAll("SVSHOLD"); ServerInstance->XLines->UnregisterFactory(&s); } Version GetVersion() CXX11_OVERRIDE { return Version("Implements SVSHOLD, like Q-lines, but can only be added/removed by Services", VF_COMMON | VF_VENDOR); } }; MODULE_INIT(ModuleSVSHold) ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/src/modules/m_swhois.cpp�������������������������������������������������������������0000664�0000000�0000000�00000011402�13554550454�0020134�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * InspIRCd -- Internet Relay Chat Daemon * * Copyright (C) 2009 Daniel De Graaf <danieldg@inspircd.org> * Copyright (C) 2008 Pippijn van Steenhoven <pip88nl@gmail.com> * Copyright (C) 2007 Robin Burchell <robin+git@viroteck.net> * Copyright (C) 2007 Dennis Friis <peavey@inspircd.org> * Copyright (C) 2006-2007 John Brooks <john.brooks@dereferenced.net> * Copyright (C) 2005-2006 Craig Edwards <craigedwards@brainbox.cc> * Copyright (C) 2006 Oliver Lupton <oliverlupton@gmail.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 "inspircd.h" #include "modules/whois.h" enum { // From UnrealIRCd. RPL_WHOISSPECIAL = 320 }; /** Handle /SWHOIS */ class CommandSwhois : public Command { public: LocalIntExt operblock; StringExtItem swhois; CommandSwhois(Module* Creator) : Command(Creator, "SWHOIS", 2, 2) , operblock("swhois_operblock", ExtensionItem::EXT_USER, Creator) , swhois("swhois", ExtensionItem::EXT_USER, Creator) { flags_needed = 'o'; syntax = "<nick> :<swhois>"; TRANSLATE2(TR_NICK, TR_TEXT); } CmdResult Handle(User* user, const Params& parameters) CXX11_OVERRIDE { User* dest = ServerInstance->FindNick(parameters[0]); if (!dest) // allow setting swhois using SWHOIS before reg { user->WriteNumeric(Numerics::NoSuchNick(parameters[0])); return CMD_FAILURE; } std::string* text = swhois.get(dest); if (text) { // We already had it set... if (!user->server->IsULine()) // Ulines set SWHOISes silently ServerInstance->SNO->WriteGlobalSno('a', "%s used SWHOIS to set %s's extra whois from '%s' to '%s'", user->nick.c_str(), dest->nick.c_str(), text->c_str(), parameters[1].c_str()); } else if (!user->server->IsULine()) { // Ulines set SWHOISes silently ServerInstance->SNO->WriteGlobalSno('a', "%s used SWHOIS to set %s's extra whois to '%s'", user->nick.c_str(), dest->nick.c_str(), parameters[1].c_str()); } operblock.set(user, 0); if (parameters[1].empty()) swhois.unset(dest); else swhois.set(dest, parameters[1]); /* Bug #376 - feature request - * To cut down on the amount of commands services etc have to recognise, this only sends METADATA across the network now * not an actual SWHOIS command. Any SWHOIS command sent from services will be automatically translated to METADATA by this. * Sorry w00t i know this was your fix, but i got bored and wanted to clear down the tracker :) * -- Brain */ ServerInstance->PI->SendMetaData(dest, "swhois", parameters[1]); return CMD_SUCCESS; } }; class ModuleSWhois : public Module, public Whois::LineEventListener { CommandSwhois cmd; public: ModuleSWhois() : Whois::LineEventListener(this) , cmd(this) { } // :kenny.chatspike.net 320 Brain Azhrarn :is getting paid to play games. ModResult OnWhoisLine(Whois::Context& whois, Numeric::Numeric& numeric) CXX11_OVERRIDE { /* We use this and not OnWhois because this triggers for remote, too */ if (numeric.GetNumeric() == 312) { /* Insert our numeric before 312 */ std::string* swhois = cmd.swhois.get(whois.GetTarget()); if (swhois) { whois.SendLine(RPL_WHOISSPECIAL, *swhois); } } /* Dont block anything */ return MOD_RES_PASSTHRU; } void OnPostOper(User* user, const std::string &opertype, const std::string &opername) CXX11_OVERRIDE { if (!IS_LOCAL(user)) return; std::string swhois = user->oper->getConfig("swhois"); if (!swhois.length()) return; cmd.operblock.set(user, 1); cmd.swhois.set(user, swhois); ServerInstance->PI->SendMetaData(user, "swhois", swhois); } void OnPostDeoper(User* user) CXX11_OVERRIDE { std::string* swhois = cmd.swhois.get(user); if (!swhois) return; if (!cmd.operblock.get(user)) return; cmd.operblock.set(user, 0); cmd.swhois.unset(user); ServerInstance->PI->SendMetaData(user, "swhois", ""); } void OnDecodeMetaData(Extensible* target, const std::string& extname, const std::string&) CXX11_OVERRIDE { User* dest = static_cast<User*>(target); if (dest && (extname == "swhois")) cmd.operblock.set(dest, 0); } Version GetVersion() CXX11_OVERRIDE { return Version("Provides the SWHOIS command which allows setting of arbitrary WHOIS lines", VF_OPTCOMMON | VF_VENDOR); } }; MODULE_INIT(ModuleSWhois) ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/src/modules/m_timedbans.cpp����������������������������������������������������������0000664�0000000�0000000�00000015241�13554550454�0020573�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * InspIRCd -- Internet Relay Chat Daemon * * Copyright (C) 2009-2010 Daniel De Graaf <danieldg@inspircd.org> * Copyright (C) 2005-2008 Craig Edwards <craigedwards@brainbox.cc> * Copyright (C) 2007 Dennis Friis <peavey@inspircd.org> * Copyright (C) 2006 Robin Burchell <robin+git@viroteck.net> * * 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 "inspircd.h" #include "listmode.h" // Holds a timed ban class TimedBan { public: std::string mask; std::string setter; time_t expire; Channel* chan; }; typedef std::vector<TimedBan> timedbans; timedbans TimedBanList; // Handle /TBAN class CommandTban : public Command { ChanModeReference banmode; bool IsBanSet(Channel* chan, const std::string& mask) { ListModeBase* banlm = static_cast<ListModeBase*>(*banmode); if (!banlm) return false; const ListModeBase::ModeList* bans = banlm->GetList(chan); if (bans) { for (ListModeBase::ModeList::const_iterator i = bans->begin(); i != bans->end(); ++i) { const ListModeBase::ListItem& ban = *i; if (!strcasecmp(ban.mask.c_str(), mask.c_str())) return true; } } return false; } public: CommandTban(Module* Creator) : Command(Creator,"TBAN", 3) , banmode(Creator, "ban") { syntax = "<channel> <duration> <banmask>"; } CmdResult Handle(User* user, const Params& parameters) CXX11_OVERRIDE { Channel* channel = ServerInstance->FindChan(parameters[0]); if (!channel) { user->WriteNumeric(Numerics::NoSuchChannel(parameters[0])); return CMD_FAILURE; } unsigned int cm = channel->GetPrefixValue(user); if (cm < HALFOP_VALUE) { user->WriteNumeric(ERR_CHANOPRIVSNEEDED, channel->name, "You do not have permission to set bans on this channel"); return CMD_FAILURE; } TimedBan T; unsigned long duration; if (!InspIRCd::Duration(parameters[1], duration)) { user->WriteNotice("Invalid ban time"); return CMD_FAILURE; } unsigned long expire = duration + ServerInstance->Time(); std::string mask = parameters[2]; bool isextban = ((mask.size() > 2) && (mask[1] == ':')); if (!isextban && !InspIRCd::IsValidMask(mask)) mask.append("!*@*"); if (IsBanSet(channel, mask)) { user->WriteNotice("Ban already set"); return CMD_FAILURE; } Modes::ChangeList setban; setban.push_add(ServerInstance->Modes->FindMode('b', MODETYPE_CHANNEL), mask); // Pass the user (instead of ServerInstance->FakeClient) to ModeHandler::Process() to // make it so that the user sets the mode themselves ServerInstance->Modes->Process(user, channel, NULL, setban); if (ServerInstance->Modes->GetLastChangeList().empty()) { user->WriteNotice("Invalid ban mask"); return CMD_FAILURE; } T.mask = mask; T.setter = user->nick; T.expire = expire + (IS_REMOTE(user) ? 5 : 0); T.chan = channel; TimedBanList.push_back(T); const std::string message = InspIRCd::Format("Timed ban %s added by %s on %s lasting for %s.", mask.c_str(), user->nick.c_str(), channel->name.c_str(), InspIRCd::DurationString(duration).c_str()); // If halfop is loaded, send notice to halfops and above, otherwise send to ops and above PrefixMode* mh = ServerInstance->Modes->FindPrefixMode('h'); char pfxchar = (mh && mh->name == "halfop") ? mh->GetPrefix() : '@'; ClientProtocol::Messages::Privmsg notice(ServerInstance->FakeClient, channel, message, MSG_NOTICE); channel->Write(ServerInstance->GetRFCEvents().privmsg, notice, pfxchar); ServerInstance->PI->SendChannelNotice(channel, pfxchar, message); return CMD_SUCCESS; } RouteDescriptor GetRouting(User* user, const Params& parameters) CXX11_OVERRIDE { return ROUTE_BROADCAST; } }; class BanWatcher : public ModeWatcher { public: BanWatcher(Module* parent) : ModeWatcher(parent, "ban", MODETYPE_CHANNEL) { } void AfterMode(User* source, User* dest, Channel* chan, const std::string& banmask, bool adding) CXX11_OVERRIDE { if (adding) return; for (timedbans::iterator i = TimedBanList.begin(); i != TimedBanList.end(); ++i) { if (i->chan != chan) continue; const std::string& target = i->mask; if (irc::equals(banmask, target)) { TimedBanList.erase(i); break; } } } }; class ChannelMatcher { Channel* const chan; public: ChannelMatcher(Channel* ch) : chan(ch) { } bool operator()(const TimedBan& tb) const { return (tb.chan == chan); } }; class ModuleTimedBans : public Module { CommandTban cmd; BanWatcher banwatcher; public: ModuleTimedBans() : cmd(this) , banwatcher(this) { } void OnBackgroundTimer(time_t curtime) CXX11_OVERRIDE { timedbans expired; for (timedbans::iterator i = TimedBanList.begin(); i != TimedBanList.end();) { if (curtime > i->expire) { expired.push_back(*i); i = TimedBanList.erase(i); } else ++i; } for (timedbans::iterator i = expired.begin(); i != expired.end(); i++) { const std::string mask = i->mask; Channel* cr = i->chan; const std::string message = InspIRCd::Format("Timed ban %s set by %s on %s has expired.", mask.c_str(), i->setter.c_str(), cr->name.c_str()); // If halfop is loaded, send notice to halfops and above, otherwise send to ops and above PrefixMode* mh = ServerInstance->Modes->FindPrefixMode('h'); char pfxchar = (mh && mh->name == "halfop") ? mh->GetPrefix() : '@'; ClientProtocol::Messages::Privmsg notice(ClientProtocol::Messages::Privmsg::nocopy, ServerInstance->FakeClient, cr, message, MSG_NOTICE); cr->Write(ServerInstance->GetRFCEvents().privmsg, notice, pfxchar); ServerInstance->PI->SendChannelNotice(cr, pfxchar, message); Modes::ChangeList setban; setban.push_remove(ServerInstance->Modes->FindMode('b', MODETYPE_CHANNEL), mask); ServerInstance->Modes->Process(ServerInstance->FakeClient, cr, NULL, setban); } } void OnChannelDelete(Channel* chan) CXX11_OVERRIDE { // Remove all timed bans affecting the channel from internal bookkeeping TimedBanList.erase(std::remove_if(TimedBanList.begin(), TimedBanList.end(), ChannelMatcher(chan)), TimedBanList.end()); } Version GetVersion() CXX11_OVERRIDE { return Version("Provides the TBAN command, timed channel bans", VF_COMMON | VF_VENDOR); } }; MODULE_INIT(ModuleTimedBans) ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/src/modules/m_tline.cpp��������������������������������������������������������������0000664�0000000�0000000�00000004621�13554550454�0017740�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * InspIRCd -- Internet Relay Chat Daemon * * Copyright (C) 2007 Dennis Friis <peavey@inspircd.org> * Copyright (C) 2006-2007 Craig Edwards <craigedwards@brainbox.cc> * * This file is part of InspIRCd. InspIRCd is free software: you can * redistribute it and/or modify it under the terms of the GNU General Public * License as published by the Free Software Foundation, version 2. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include "inspircd.h" /** Handle /TLINE */ class CommandTline : public Command { public: CommandTline(Module* Creator) : Command(Creator,"TLINE", 1) { flags_needed = 'o'; this->syntax = "<mask>"; } CmdResult Handle(User* user, const Params& parameters) CXX11_OVERRIDE { unsigned int n_matched = 0; unsigned int n_match_host = 0; unsigned int n_match_ip = 0; const user_hash& users = ServerInstance->Users->GetUsers(); for (user_hash::const_iterator u = users.begin(); u != users.end(); ++u) { if (InspIRCd::Match(u->second->GetFullRealHost(),parameters[0])) { n_matched++; n_match_host++; } else { std::string host = u->second->ident + "@" + u->second->GetIPString(); if (InspIRCd::MatchCIDR(host, parameters[0])) { n_matched++; n_match_ip++; } } } unsigned long n_counted = users.size(); if (n_matched) { float p = (n_matched / (float)n_counted) * 100; user->WriteNotice(InspIRCd::Format("*** TLINE: Counted %lu user(s). Matched '%s' against %u user(s) (%0.2f%% of the userbase). %u by hostname and %u by IP address.", n_counted, parameters[0].c_str(), n_matched, p, n_match_host, n_match_ip)); } else user->WriteNotice(InspIRCd::Format("*** TLINE: Counted %lu user(s). Matched '%s' against no user(s).", n_counted, parameters[0].c_str())); return CMD_SUCCESS; } }; class ModuleTLine : public Module { CommandTline cmd; public: ModuleTLine() : cmd(this) { } Version GetVersion() CXX11_OVERRIDE { return Version("Provides the TLINE command, used to test how many users a mask matches against", VF_VENDOR); } }; MODULE_INIT(ModuleTLine) ���������������������������������������������������������������������������������������������������������������inspircd-3.4.0/src/modules/m_topiclock.cpp����������������������������������������������������������0000664�0000000�0000000�00000007135�13554550454�0020617�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * InspIRCd -- Internet Relay Chat Daemon * * Copyright (C) 2012 Attila Molnar <attilamolnar@hush.com> * * This file is part of InspIRCd. InspIRCd is free software: you can * redistribute it and/or modify it under the terms of the GNU General Public * License as published by the Free Software Foundation, version 2. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include "inspircd.h" enum { // InspIRCd-specific. ERR_TOPICLOCK = 744 }; class CommandSVSTOPIC : public Command { public: CommandSVSTOPIC(Module* Creator) : Command(Creator, "SVSTOPIC", 1, 4) { flags_needed = FLAG_SERVERONLY; } CmdResult Handle(User* user, const Params& parameters) CXX11_OVERRIDE { if (!user->server->IsULine()) { // Ulines only return CMD_FAILURE; } Channel* chan = ServerInstance->FindChan(parameters[0]); if (!chan) return CMD_FAILURE; if (parameters.size() == 4) { // 4 parameter version, set all topic data on the channel to the ones given in the parameters time_t topicts = ConvToNum<time_t>(parameters[1]); if (!topicts) { ServerInstance->Logs->Log(MODNAME, LOG_DEFAULT, "Received SVSTOPIC with a 0 topicts, dropped."); return CMD_INVALID; } chan->SetTopic(user, parameters[3], topicts, &parameters[2]); } else { // 1 parameter version, nuke the topic chan->SetTopic(user, std::string(), 0); chan->setby.clear(); } return CMD_SUCCESS; } RouteDescriptor GetRouting(User* user, const Params& parameters) CXX11_OVERRIDE { return ROUTE_BROADCAST; } }; // TODO: add a BoolExtItem to replace this. class FlagExtItem : public ExtensionItem { public: FlagExtItem(const std::string& key, Module* owner) : ExtensionItem(key, ExtensionItem::EXT_CHANNEL, owner) { } bool get(const Extensible* container) const { return (get_raw(container) != NULL); } std::string ToHuman(const Extensible* container, void* item) const CXX11_OVERRIDE { // Make the human version more readable. return "true"; } std::string ToNetwork(const Extensible* container, void* item) const CXX11_OVERRIDE { return "1"; } void FromNetwork(Extensible* container, const std::string& value) CXX11_OVERRIDE { if (value == "1") set_raw(container, this); else unset_raw(container); } void set(Extensible* container, bool value) { if (value) set_raw(container, this); else unset_raw(container); } void unset(Extensible* container) { unset_raw(container); } void free(Extensible* container, void* item) CXX11_OVERRIDE { // nothing to free } }; class ModuleTopicLock : public Module { CommandSVSTOPIC cmd; FlagExtItem topiclock; public: ModuleTopicLock() : cmd(this), topiclock("topiclock", this) { } ModResult OnPreTopicChange(User* user, Channel* chan, const std::string &topic) CXX11_OVERRIDE { // Only fired for local users currently, but added a check anyway if ((IS_LOCAL(user)) && (topiclock.get(chan))) { user->WriteNumeric(ERR_TOPICLOCK, chan->name, "TOPIC cannot be changed due to topic lock being active on the channel"); return MOD_RES_DENY; } return MOD_RES_PASSTHRU; } Version GetVersion() CXX11_OVERRIDE { return Version("Implements server-side topic locks and the server-to-server command SVSTOPIC", VF_COMMON | VF_VENDOR); } }; MODULE_INIT(ModuleTopicLock) �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/src/modules/m_uhnames.cpp������������������������������������������������������������0000664�0000000�0000000�00000004513�13554550454�0020265�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * InspIRCd -- Internet Relay Chat Daemon * * Copyright (C) 2009 Daniel De Graaf <danieldg@inspircd.org> * Copyright (C) 2007-2008 Craig Edwards <craigedwards@brainbox.cc> * Copyright (C) 2007 Dennis Friis <peavey@inspircd.org> * * This file is part of InspIRCd. InspIRCd is free software: you can * redistribute it and/or modify it under the terms of the GNU General Public * License as published by the Free Software Foundation, version 2. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include "inspircd.h" #include "modules/cap.h" #include "modules/names.h" class ModuleUHNames : public Module , public Names::EventListener { private: Cap::Capability cap; public: ModuleUHNames() : Names::EventListener(this) , cap(this, "userhost-in-names") { } Version GetVersion() CXX11_OVERRIDE { return Version("Provides the UHNAMES (CAP userhost-in-names) capability", VF_VENDOR); } void On005Numeric(std::map<std::string, std::string>& tokens) CXX11_OVERRIDE { // The legacy PROTOCTL system is a wrapper around the cap. dynamic_reference_nocheck<Cap::Manager> capmanager(this, "capmanager"); if (capmanager) tokens["UHNAMES"]; } ModResult OnPreCommand(std::string& command, CommandBase::Params& parameters, LocalUser* user, bool validated) CXX11_OVERRIDE { /* We don't actually create a proper command handler class for PROTOCTL, * because other modules might want to have PROTOCTL hooks too. * Therefore, we just hook its as an unvalidated command therefore we * can capture it even if it doesnt exist! :-) */ if (command == "PROTOCTL") { if ((parameters.size()) && (!strcasecmp(parameters[0].c_str(),"UHNAMES"))) { cap.set(user, true); return MOD_RES_DENY; } } return MOD_RES_PASSTHRU; } ModResult OnNamesListItem(LocalUser* issuer, Membership* memb, std::string& prefixes, std::string& nick) CXX11_OVERRIDE { if (cap.get(issuer)) nick = memb->user->GetFullHost(); return MOD_RES_PASSTHRU; } }; MODULE_INIT(ModuleUHNames) �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/src/modules/m_uninvite.cpp�����������������������������������������������������������0000664�0000000�0000000�00000007047�13554550454�0020473�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * InspIRCd -- Internet Relay Chat Daemon * * Copyright (C) 2009 Daniel De Graaf <danieldg@inspircd.org> * Copyright (C) 2007 Dennis Friis <peavey@inspircd.org> * Copyright (C) 2006-2007 Craig Edwards <craigedwards@brainbox.cc> * Copyright (C) 2006 Robin Burchell <robin+git@viroteck.net> * * 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 "inspircd.h" #include "modules/invite.h" enum { // InspIRCd-specific. RPL_UNINVITED = 653 }; /** Handle /UNINVITE */ class CommandUninvite : public Command { Invite::API invapi; public: CommandUninvite(Module* Creator) : Command(Creator, "UNINVITE", 2) , invapi(Creator) { syntax = "<nick> <channel>"; TRANSLATE2(TR_NICK, TR_TEXT); } CmdResult Handle(User* user, const Params& parameters) CXX11_OVERRIDE { User* u; if (IS_LOCAL(user)) u = ServerInstance->FindNickOnly(parameters[0]); else u = ServerInstance->FindNick(parameters[0]); Channel* c = ServerInstance->FindChan(parameters[1]); if ((!c) || (!u) || (u->registered != REG_ALL)) { if (!c) { user->WriteNumeric(Numerics::NoSuchChannel(parameters[1])); } else { user->WriteNumeric(Numerics::NoSuchNick(parameters[0])); } return CMD_FAILURE; } if (IS_LOCAL(user)) { if (c->GetPrefixValue(user) < HALFOP_VALUE) { user->WriteNumeric(ERR_CHANOPRIVSNEEDED, c->name, InspIRCd::Format("You must be a channel %soperator", c->GetPrefixValue(u) == HALFOP_VALUE ? "" : "half-")); return CMD_FAILURE; } } /* Servers remember invites only for their local users, so act * only if the target is local. Otherwise the command will be * passed to the target users server. */ LocalUser* lu = IS_LOCAL(u); if (lu) { // XXX: The source of the numeric we send must be the server of the user doing the /UNINVITE, // so they don't see where the target user is connected to if (!invapi->Remove(lu, c)) { Numeric::Numeric n(505); n.SetServer(user->server); n.push(u->nick).push(c->name).push(InspIRCd::Format("Is not invited to channel %s", c->name.c_str())); user->WriteRemoteNumeric(n); return CMD_FAILURE; } Numeric::Numeric n(494); n.SetServer(user->server); n.push(c->name).push(u->nick).push("Uninvited"); user->WriteRemoteNumeric(n); lu->WriteNumeric(RPL_UNINVITED, InspIRCd::Format("You were uninvited from %s by %s", c->name.c_str(), user->nick.c_str())); std::string msg = "*** " + user->nick + " uninvited " + u->nick + "."; c->WriteNotice(msg); ServerInstance->PI->SendChannelNotice(c, 0, msg); } return CMD_SUCCESS; } RouteDescriptor GetRouting(User* user, const Params& parameters) CXX11_OVERRIDE { return ROUTE_OPT_UCAST(parameters[0]); } }; class ModuleUninvite : public Module { CommandUninvite cmd; public: ModuleUninvite() : cmd(this) { } Version GetVersion() CXX11_OVERRIDE { return Version("Provides the UNINVITE command which lets users un-invite other users from channels", VF_VENDOR | VF_OPTCOMMON); } }; MODULE_INIT(ModuleUninvite) �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/src/modules/m_userip.cpp�������������������������������������������������������������0000664�0000000�0000000�00000004653�13554550454�0020141�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * InspIRCd -- Internet Relay Chat Daemon * * Copyright (C) 2007 Dennis Friis <peavey@inspircd.org> * Copyright (C) 2005, 2007 Craig Edwards <craigedwards@brainbox.cc> * Copyright (C) 2006 Robin Burchell <robin+git@viroteck.net> * * 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 "inspircd.h" /** Handle /USERIP */ class CommandUserip : public Command { public: CommandUserip(Module* Creator) : Command(Creator,"USERIP", 1) { syntax = "<nick> [<nick>]+"; } CmdResult Handle(User* user, const Params& parameters) CXX11_OVERRIDE { std::string retbuf; int nicks = 0; bool checked_privs = false; bool has_privs = false; for (size_t i = 0; i < parameters.size(); i++) { User *u = ServerInstance->FindNickOnly(parameters[i]); if ((u) && (u->registered == REG_ALL)) { // Anyone may query their own IP if (u != user) { if (!checked_privs) { // Do not trigger the insufficient priviliges message more than once checked_privs = true; has_privs = user->HasPrivPermission("users/auspex"); if (!has_privs) user->WriteNumeric(ERR_NOPRIVILEGES, "Permission Denied - You do not have the required operator privileges"); } if (!has_privs) continue; } retbuf = retbuf + u->nick + (u->IsOper() ? "*" : "") + "="; if (u->IsAway()) retbuf += "-"; else retbuf += "+"; retbuf += u->ident + "@" + u->GetIPString() + " "; nicks++; } } if (nicks != 0) user->WriteNumeric(RPL_USERIP, retbuf); return CMD_SUCCESS; } }; class ModuleUserIP : public Module { CommandUserip cmd; public: ModuleUserIP() : cmd(this) { } void On005Numeric(std::map<std::string, std::string>& tokens) CXX11_OVERRIDE { tokens["USERIP"]; } Version GetVersion() CXX11_OVERRIDE { return Version("Provides the USERIP command", VF_VENDOR); } }; MODULE_INIT(ModuleUserIP) �������������������������������������������������������������������������������������inspircd-3.4.0/src/modules/m_vhost.cpp��������������������������������������������������������������0000664�0000000�0000000�00000006512�13554550454�0017771�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * InspIRCd -- Internet Relay Chat Daemon * * Copyright (C) 2009 Daniel De Graaf <danieldg@inspircd.org> * Copyright (C) 2007 Dennis Friis <peavey@inspircd.org> * Copyright (C) 2006-2007 Craig Edwards <craigedwards@brainbox.cc> * Copyright (C) 2006 Robin Burchell <robin+git@viroteck.net> * * 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 "inspircd.h" struct CustomVhost { const std::string name; const std::string password; const std::string hash; const std::string vhost; CustomVhost(const std::string& n, const std::string& p, const std::string& h, const std::string& v) : name(n) , password(p) , hash(h) , vhost(v) { } bool CheckPass(User* user, const std::string& pass) const { return ServerInstance->PassCompare(user, password, pass, hash); } }; typedef std::multimap<std::string, CustomVhost> CustomVhostMap; typedef std::pair<CustomVhostMap::iterator, CustomVhostMap::iterator> MatchingConfigs; /** Handle /VHOST */ class CommandVhost : public Command { public: CustomVhostMap vhosts; CommandVhost(Module* Creator) : Command(Creator, "VHOST", 2) { syntax = "<username> <password>"; } CmdResult Handle(User* user, const Params& parameters) CXX11_OVERRIDE { MatchingConfigs matching = vhosts.equal_range(parameters[0]); for (MatchingConfigs::first_type i = matching.first; i != matching.second; ++i) { CustomVhost config = i->second; if (config.CheckPass(user, parameters[1])) { user->WriteNotice("Setting your VHost: " + config.vhost); user->ChangeDisplayedHost(config.vhost); return CMD_SUCCESS; } } user->WriteNotice("Invalid username or password."); return CMD_FAILURE; } }; class ModuleVHost : public Module { CommandVhost cmd; public: ModuleVHost() : cmd(this) { } void ReadConfig(ConfigStatus& status) CXX11_OVERRIDE { CustomVhostMap newhosts; ConfigTagList tags = ServerInstance->Config->ConfTags("vhost"); for (ConfigIter i = tags.first; i != tags.second; ++i) { ConfigTag* tag = i->second; std::string mask = tag->getString("host"); if (mask.empty()) throw ModuleException("<vhost:host> is empty! at " + tag->getTagLocation()); std::string username = tag->getString("user"); if (username.empty()) throw ModuleException("<vhost:user> is empty! at " + tag->getTagLocation()); std::string pass = tag->getString("pass"); if (pass.empty()) throw ModuleException("<vhost:pass> is empty! at " + tag->getTagLocation()); std::string hash = tag->getString("hash"); CustomVhost vhost(username, pass, hash, mask); newhosts.insert(std::make_pair(username, vhost)); } cmd.vhosts.swap(newhosts); } Version GetVersion() CXX11_OVERRIDE { return Version("Provides masking of user hostnames via the VHOST command", VF_VENDOR); } }; MODULE_INIT(ModuleVHost) ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/src/modules/m_watch.cpp��������������������������������������������������������������0000664�0000000�0000000�00000016753�13554550454�0017744�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * InspIRCd -- Internet Relay Chat Daemon * * Copyright (C) 2016 Attila Molnar <attilamolnar@hush.com> * * This file is part of InspIRCd. InspIRCd is free software: you can * redistribute it and/or modify it under the terms of the GNU General Public * License as published by the Free Software Foundation, version 2. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include "inspircd.h" #include "modules/away.h" #define INSPIRCD_MONITOR_MANAGER_ONLY #include "m_monitor.cpp" enum { RPL_GONEAWAY = 598, RPL_NOTAWAY = 599, RPL_LOGON = 600, RPL_LOGOFF = 601, RPL_WATCHOFF = 602, RPL_WATCHSTAT = 603, RPL_NOWON = 604, RPL_NOWOFF = 605, RPL_WATCHLIST = 606, RPL_ENDOFWATCHLIST = 607, // RPL_CLEARWATCH = 608, // unused RPL_NOWISAWAY = 609, ERR_TOOMANYWATCH = 512, ERR_INVALIDWATCHNICK = 942 }; class CommandWatch : public SplitCommand { // Additional penalty for /WATCH commands that request a list from the server static const unsigned int ListPenalty = 4000; IRCv3::Monitor::Manager& manager; static void SendOnlineOffline(LocalUser* user, const std::string& nick, bool show_offline = true) { User* target = IRCv3::Monitor::Manager::FindNick(nick); if (target) { // The away state should only be sent if the client requests away notifications for a nick but 2.0 always sends them so we do that too if (target->IsAway()) user->WriteNumeric(RPL_NOWISAWAY, target->nick, target->ident, target->GetDisplayedHost(), (unsigned long)target->awaytime, "is away"); else user->WriteNumeric(RPL_NOWON, target->nick, target->ident, target->GetDisplayedHost(), (unsigned long)target->age, "is online"); } else if (show_offline) user->WriteNumeric(RPL_NOWOFF, nick, "*", "*", "0", "is offline"); } void HandlePlus(LocalUser* user, const std::string& nick) { IRCv3::Monitor::Manager::WatchResult result = manager.Watch(user, nick, maxwatch); if (result == IRCv3::Monitor::Manager::WR_TOOMANY) { // List is full, send error numeric user->WriteNumeric(ERR_TOOMANYWATCH, nick, "Too many WATCH entries"); return; } else if (result == IRCv3::Monitor::Manager::WR_INVALIDNICK) { user->WriteNumeric(ERR_INVALIDWATCHNICK, nick, "Invalid nickname"); return; } else if (result != IRCv3::Monitor::Manager::WR_OK) return; SendOnlineOffline(user, nick); } void HandleMinus(LocalUser* user, const std::string& nick) { if (!manager.Unwatch(user, nick)) return; User* target = IRCv3::Monitor::Manager::FindNick(nick); if (target) user->WriteNumeric(RPL_WATCHOFF, target->nick, target->ident, target->GetDisplayedHost(), (unsigned long)target->age, "stopped watching"); else user->WriteNumeric(RPL_WATCHOFF, nick, "*", "*", "0", "stopped watching"); } void HandleList(LocalUser* user, bool show_offline) { user->CommandFloodPenalty += ListPenalty; const IRCv3::Monitor::WatchedList& list = manager.GetWatched(user); for (IRCv3::Monitor::WatchedList::const_iterator i = list.begin(); i != list.end(); ++i) { const IRCv3::Monitor::Entry* entry = *i; SendOnlineOffline(user, entry->GetNick(), show_offline); } user->WriteNumeric(RPL_ENDOFWATCHLIST, "End of WATCH list"); } void HandleStats(LocalUser* user) { user->CommandFloodPenalty += ListPenalty; // Do not show how many clients are watching this nick, it's pointless const IRCv3::Monitor::WatchedList& list = manager.GetWatched(user); user->WriteNumeric(RPL_WATCHSTAT, InspIRCd::Format("You have %lu and are on 0 WATCH entries", (unsigned long)list.size())); Numeric::Builder<' '> out(user, RPL_WATCHLIST); for (IRCv3::Monitor::WatchedList::const_iterator i = list.begin(); i != list.end(); ++i) { const IRCv3::Monitor::Entry* entry = *i; out.Add(entry->GetNick()); } out.Flush(); user->WriteNumeric(RPL_ENDOFWATCHLIST, "End of WATCH S"); } public: unsigned int maxwatch; CommandWatch(Module* mod, IRCv3::Monitor::Manager& managerref) : SplitCommand(mod, "WATCH") , manager(managerref) { allow_empty_last_param = false; syntax = "C|L|l|S|(+|-)<nick> [(+|-)<nick>]+"; } CmdResult HandleLocal(LocalUser* user, const Params& parameters) CXX11_OVERRIDE { if (parameters.empty()) { HandleList(user, false); return CMD_SUCCESS; } bool watch_l_done = false; bool watch_s_done = false; for (std::vector<std::string>::const_iterator i = parameters.begin(); i != parameters.end(); ++i) { const std::string& token = *i; char subcmd = toupper(token[0]); if (subcmd == '+') { HandlePlus(user, token.substr(1)); } else if (subcmd == '-') { HandleMinus(user, token.substr(1)); } else if (subcmd == 'C') { manager.UnwatchAll(user); } else if ((subcmd == 'L') && (!watch_l_done)) { watch_l_done = true; // WATCH L requests a full list with online and offline nicks // WATCH l requests a list with only online nicks HandleList(user, (token[0] == 'L')); } else if ((subcmd == 'S') && (!watch_s_done)) { watch_s_done = true; HandleStats(user); } } return CMD_SUCCESS; } }; class ModuleWatch : public Module , public Away::EventListener { IRCv3::Monitor::Manager manager; CommandWatch cmd; void SendAlert(User* user, const std::string& nick, unsigned int numeric, const char* numerictext, time_t shownts) { const IRCv3::Monitor::WatcherList* list = manager.GetWatcherList(nick); if (!list) return; Numeric::Numeric num(numeric); num.push(nick).push(user->ident).push(user->GetDisplayedHost()).push(ConvToStr(shownts)).push(numerictext); for (IRCv3::Monitor::WatcherList::const_iterator i = list->begin(); i != list->end(); ++i) { LocalUser* curr = *i; curr->WriteNumeric(num); } } void Online(User* user) { SendAlert(user, user->nick, RPL_LOGON, "arrived online", user->age); } void Offline(User* user, const std::string& nick) { SendAlert(user, nick, RPL_LOGOFF, "went offline", user->age); } public: ModuleWatch() : Away::EventListener(this) , manager(this, "watch") , cmd(this, manager) { } void ReadConfig(ConfigStatus& status) CXX11_OVERRIDE { ConfigTag* tag = ServerInstance->Config->ConfValue("watch"); cmd.maxwatch = tag->getUInt("maxwatch", 30, 1); } void OnPostConnect(User* user) CXX11_OVERRIDE { Online(user); } void OnUserPostNick(User* user, const std::string& oldnick) CXX11_OVERRIDE { // Detect and ignore nickname case change if (ServerInstance->FindNickOnly(oldnick) == user) return; Offline(user, oldnick); Online(user); } void OnUserQuit(User* user, const std::string& message, const std::string& oper_message) CXX11_OVERRIDE { LocalUser* localuser = IS_LOCAL(user); if (localuser) manager.UnwatchAll(localuser); Offline(user, user->nick); } void OnUserAway(User* user) CXX11_OVERRIDE { SendAlert(user, user->nick, RPL_GONEAWAY, user->awaymsg.c_str(), user->awaytime); } void OnUserBack(User* user) CXX11_OVERRIDE { SendAlert(user, user->nick, RPL_NOTAWAY, "is no longer away", ServerInstance->Time()); } void On005Numeric(std::map<std::string, std::string>& tokens) CXX11_OVERRIDE { tokens["WATCH"] = ConvToStr(cmd.maxwatch); } Version GetVersion() CXX11_OVERRIDE { return Version("Provides WATCH support", VF_VENDOR); } }; MODULE_INIT(ModuleWatch) ���������������������inspircd-3.4.0/src/modules/m_websocket.cpp����������������������������������������������������������0000664�0000000�0000000�00000033135�13554550454�0020615�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * InspIRCd -- Internet Relay Chat Daemon * * Copyright (C) 2016 Attila Molnar <attilamolnar@hush.com> * * This file is part of InspIRCd. InspIRCd is free software: you can * redistribute it and/or modify it under the terms of the GNU General Public * License as published by the Free Software Foundation, version 2. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ /// $CompilerFlags: -Ivendor_directory("utfcpp") #include "inspircd.h" #include "iohook.h" #include "modules/hash.h" #include <utf8.h> typedef std::vector<std::string> OriginList; static const char MagicGUID[] = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11"; static const char whitespace[] = " \t\r\n"; static dynamic_reference_nocheck<HashProvider>* sha1; class WebSocketHookProvider : public IOHookProvider { public: OriginList allowedorigins; bool sendastext; WebSocketHookProvider(Module* mod) : IOHookProvider(mod, "websocket", IOHookProvider::IOH_UNKNOWN, true) { } void OnAccept(StreamSocket* sock, irc::sockets::sockaddrs* client, irc::sockets::sockaddrs* server) CXX11_OVERRIDE; void OnConnect(StreamSocket* sock) CXX11_OVERRIDE { } }; class WebSocketHook : public IOHookMiddle { class HTTPHeaderFinder { std::string::size_type bpos; std::string::size_type len; public: bool Find(const std::string& req, const char* header, std::string::size_type headerlen, std::string::size_type maxpos) { std::string::size_type keybegin = req.find(header); if ((keybegin == std::string::npos) || (keybegin > maxpos) || (keybegin == 0) || (req[keybegin-1] != '\n')) return false; keybegin += headerlen; bpos = req.find_first_not_of(whitespace, keybegin, sizeof(whitespace)-1); if ((bpos == std::string::npos) || (bpos > maxpos)) return false; const std::string::size_type epos = req.find_first_of(whitespace, bpos, sizeof(whitespace)-1); len = epos - bpos; return true; } std::string ExtractValue(const std::string& req) const { return std::string(req, bpos, len); } }; enum OpCode { OP_CONTINUATION = 0x00, OP_TEXT = 0x01, OP_BINARY = 0x02, OP_CLOSE = 0x08, OP_PING = 0x09, OP_PONG = 0x0a }; enum State { STATE_HTTPREQ, STATE_ESTABLISHED }; static const unsigned char WS_MASKBIT = (1 << 7); static const unsigned char WS_FINBIT = (1 << 7); static const unsigned char WS_PAYLOAD_LENGTH_MAGIC_LARGE = 126; static const unsigned char WS_PAYLOAD_LENGTH_MAGIC_HUGE = 127; static const size_t WS_MAX_PAYLOAD_LENGTH_SMALL = 125; static const size_t WS_MAX_PAYLOAD_LENGTH_LARGE = 65535; static const size_t MAXHEADERSIZE = sizeof(uint64_t) + 2; // Clients sending ping or pong frames faster than this are killed static const time_t MINPINGPONGDELAY = 10; State state; time_t lastpingpong; OriginList& allowedorigins; bool& sendastext; static size_t FillHeader(unsigned char* outbuf, size_t sendlength, OpCode opcode) { size_t pos = 0; outbuf[pos++] = WS_FINBIT | opcode; if (sendlength <= WS_MAX_PAYLOAD_LENGTH_SMALL) { outbuf[pos++] = sendlength; } else if (sendlength <= WS_MAX_PAYLOAD_LENGTH_LARGE) { outbuf[pos++] = WS_PAYLOAD_LENGTH_MAGIC_LARGE; outbuf[pos++] = (sendlength >> 8) & 0xff; outbuf[pos++] = sendlength & 0xff; } else { outbuf[pos++] = WS_PAYLOAD_LENGTH_MAGIC_HUGE; const uint64_t len = sendlength; for (int i = sizeof(uint64_t)-1; i >= 0; i--) outbuf[pos++] = ((len >> i*8) & 0xff); } return pos; } static StreamSocket::SendQueue::Element PrepareSendQElem(size_t size, OpCode opcode) { unsigned char header[MAXHEADERSIZE]; const size_t n = FillHeader(header, size, opcode); return StreamSocket::SendQueue::Element(reinterpret_cast<const char*>(header), n); } int HandleAppData(StreamSocket* sock, std::string& appdataout, bool allowlarge) { std::string& myrecvq = GetRecvQ(); // Need 1 byte opcode, minimum 1 byte len, 4 bytes masking key if (myrecvq.length() < 6) return 0; const std::string& cmyrecvq = myrecvq; unsigned char len1 = (unsigned char)cmyrecvq[1]; if (!(len1 & WS_MASKBIT)) { sock->SetError("WebSocket protocol violation: unmasked client frame"); return -1; } len1 &= ~WS_MASKBIT; // Assume the length is a single byte, if not, update values later unsigned int len = len1; unsigned int payloadstartoffset = 6; const unsigned char* maskkey = reinterpret_cast<const unsigned char*>(&cmyrecvq[2]); if (len1 == WS_PAYLOAD_LENGTH_MAGIC_LARGE) { // allowlarge is false for control frames according to the RFC meaning large pings, etc. are not allowed if (!allowlarge) { sock->SetError("WebSocket protocol violation: large control frame"); return -1; } // Large frame, has 2 bytes len after the magic byte indicating the length // Need 1 byte opcode, 3 bytes len, 4 bytes masking key if (myrecvq.length() < 8) return 0; unsigned char len2 = (unsigned char)cmyrecvq[2]; unsigned char len3 = (unsigned char)cmyrecvq[3]; len = (len2 << 8) | len3; if (len <= WS_MAX_PAYLOAD_LENGTH_SMALL) { sock->SetError("WebSocket protocol violation: non-minimal length encoding used"); return -1; } maskkey += 2; payloadstartoffset += 2; } else if (len1 == WS_PAYLOAD_LENGTH_MAGIC_HUGE) { sock->SetError("WebSocket: Huge frames are not supported"); return -1; } if (myrecvq.length() < payloadstartoffset + len) return 0; unsigned int maskkeypos = 0; const std::string::iterator endit = myrecvq.begin() + payloadstartoffset + len; for (std::string::const_iterator i = myrecvq.begin() + payloadstartoffset; i != endit; ++i) { const unsigned char c = (unsigned char)*i; appdataout.push_back(c ^ maskkey[maskkeypos++]); maskkeypos %= 4; } myrecvq.erase(myrecvq.begin(), endit); return 1; } int HandlePingPongFrame(StreamSocket* sock, bool isping) { if (lastpingpong + MINPINGPONGDELAY >= ServerInstance->Time()) { sock->SetError("WebSocket: Ping/pong flood"); return -1; } lastpingpong = ServerInstance->Time(); std::string appdata; const int result = HandleAppData(sock, appdata, false); // If it's a pong stop here regardless of the result so we won't generate a reply if ((result <= 0) || (!isping)) return result; StreamSocket::SendQueue::Element elem = PrepareSendQElem(appdata.length(), OP_PONG); elem.append(appdata); GetSendQ().push_back(elem); SocketEngine::ChangeEventMask(sock, FD_ADD_TRIAL_WRITE); return 1; } int HandleWS(StreamSocket* sock, std::string& destrecvq) { if (GetRecvQ().empty()) return 0; unsigned char opcode = (unsigned char)GetRecvQ().c_str()[0]; switch (opcode & ~WS_FINBIT) { case OP_CONTINUATION: case OP_TEXT: case OP_BINARY: { std::string appdata; const int result = HandleAppData(sock, appdata, true); if (result != 1) return result; // Strip out any CR+LF which may have been erroneously sent. for (std::string::const_iterator iter = appdata.begin(); iter != appdata.end(); ++iter) { if (*iter != '\r' && *iter != '\n') destrecvq.push_back(*iter); } // If we are on the final message of this block append a line terminator. if (opcode & WS_FINBIT) destrecvq.append("\r\n"); return 1; } case OP_PING: { return HandlePingPongFrame(sock, true); } case OP_PONG: { // A pong frame may be sent unsolicited, so we have to handle it. // It may carry application data which we need to remove from the recvq as well. return HandlePingPongFrame(sock, false); } case OP_CLOSE: { sock->SetError("Connection closed"); return -1; } default: { sock->SetError("WebSocket: Invalid opcode"); return -1; } } } void FailHandshake(StreamSocket* sock, const char* httpreply, const char* sockerror) { GetSendQ().push_back(StreamSocket::SendQueue::Element(httpreply)); sock->DoWrite(); sock->SetError(sockerror); } int HandleHTTPReq(StreamSocket* sock) { std::string& recvq = GetRecvQ(); const std::string::size_type reqend = recvq.find("\r\n\r\n"); if (reqend == std::string::npos) return 0; bool allowedorigin = false; HTTPHeaderFinder originheader; if (originheader.Find(recvq, "Origin:", 7, reqend)) { const std::string origin = originheader.ExtractValue(recvq); for (OriginList::const_iterator iter = allowedorigins.begin(); iter != allowedorigins.end(); ++iter) { if (InspIRCd::Match(origin, *iter, ascii_case_insensitive_map)) { allowedorigin = true; break; } } } if (!allowedorigin) { FailHandshake(sock, "HTTP/1.1 403 Forbidden\r\nConnection: close\r\n\r\n", "WebSocket: Received HTTP request from a non-whitelisted origin"); return -1; } HTTPHeaderFinder keyheader; if (!keyheader.Find(recvq, "Sec-WebSocket-Key:", 18, reqend)) { FailHandshake(sock, "HTTP/1.1 501 Not Implemented\r\nConnection: close\r\n\r\n", "WebSocket: Received HTTP request which is not a websocket upgrade"); return -1; } if (!*sha1) { FailHandshake(sock, "HTTP/1.1 503 Service Unavailable\r\nConnection: close\r\n\r\n", "WebSocket: SHA-1 provider missing"); return -1; } state = STATE_ESTABLISHED; std::string key = keyheader.ExtractValue(recvq); key.append(MagicGUID); std::string reply = "HTTP/1.1 101 Switching Protocols\r\nUpgrade: websocket\r\nConnection: Upgrade\r\nSec-WebSocket-Accept: "; reply.append(BinToBase64((*sha1)->GenerateRaw(key), NULL, '=')).append("\r\n\r\n"); GetSendQ().push_back(StreamSocket::SendQueue::Element(reply)); SocketEngine::ChangeEventMask(sock, FD_ADD_TRIAL_WRITE); recvq.erase(0, reqend + 4); return 1; } public: WebSocketHook(IOHookProvider* Prov, StreamSocket* sock, OriginList& AllowedOrigins, bool& SendAsText) : IOHookMiddle(Prov) , state(STATE_HTTPREQ) , lastpingpong(0) , allowedorigins(AllowedOrigins) , sendastext(SendAsText) { sock->AddIOHook(this); } int OnStreamSocketWrite(StreamSocket* sock, StreamSocket::SendQueue& uppersendq) CXX11_OVERRIDE { StreamSocket::SendQueue& mysendq = GetSendQ(); // Return 1 to allow sending back an error HTTP response if (state != STATE_ESTABLISHED) return (mysendq.empty() ? 0 : 1); std::string message; for (StreamSocket::SendQueue::const_iterator elem = uppersendq.begin(); elem != uppersendq.end(); ++elem) { for (StreamSocket::SendQueue::Element::const_iterator chr = elem->begin(); chr != elem->end(); ++chr) { if (*chr == '\n') { // We have found an entire message. Send it in its own frame. if (sendastext) { // If we send messages as text then we need to ensure they are valid UTF-8. std::string encoded; utf8::replace_invalid(message.begin(), message.end(), std::back_inserter(encoded)); mysendq.push_back(PrepareSendQElem(encoded.length(), OP_TEXT)); mysendq.push_back(encoded); } else { // Otherwise, send the raw message as a binary frame. mysendq.push_back(PrepareSendQElem(message.length(), OP_BINARY)); mysendq.push_back(message); } message.clear(); } else if (*chr != '\r') { message.push_back(*chr); } } } // Empty the upper send queue and push whatever is left back onto it. uppersendq.clear(); if (!message.empty()) { uppersendq.push_back(message); return 0; } return 1; } int OnStreamSocketRead(StreamSocket* sock, std::string& destrecvq) CXX11_OVERRIDE { if (state == STATE_HTTPREQ) { int httpret = HandleHTTPReq(sock); if (httpret <= 0) return httpret; } int wsret; do { wsret = HandleWS(sock, destrecvq); } while ((!GetRecvQ().empty()) && (wsret > 0)); return wsret; } void OnStreamSocketClose(StreamSocket* sock) CXX11_OVERRIDE { } }; void WebSocketHookProvider::OnAccept(StreamSocket* sock, irc::sockets::sockaddrs* client, irc::sockets::sockaddrs* server) { new WebSocketHook(this, sock, allowedorigins, sendastext); } class ModuleWebSocket : public Module { dynamic_reference_nocheck<HashProvider> hash; reference<WebSocketHookProvider> hookprov; public: ModuleWebSocket() : hash(this, "hash/sha1") , hookprov(new WebSocketHookProvider(this)) { sha1 = &hash; } void ReadConfig(ConfigStatus& status) CXX11_OVERRIDE { ConfigTagList tags = ServerInstance->Config->ConfTags("wsorigin"); if (tags.first == tags.second) throw ModuleException("You have loaded the websocket module but not configured any allowed origins!"); OriginList allowedorigins; for (ConfigIter i = tags.first; i != tags.second; ++i) { ConfigTag* tag = i->second; // Ensure that we have the <wsorigin:allow> parameter. const std::string allow = tag->getString("allow"); if (allow.empty()) throw ModuleException("<wsorigin:allow> is a mandatory field, at " + tag->getTagLocation()); allowedorigins.push_back(allow); } ConfigTag* tag = ServerInstance->Config->ConfValue("websocket"); hookprov->sendastext = tag->getBool("sendastext", true); hookprov->allowedorigins.swap(allowedorigins); } void OnCleanup(ExtensionItem::ExtensibleType type, Extensible* item) CXX11_OVERRIDE { if (type != ExtensionItem::EXT_USER) return; LocalUser* user = IS_LOCAL(static_cast<User*>(item)); if ((user) && (user->eh.GetModHook(this))) ServerInstance->Users.QuitUser(user, "WebSocket module unloading"); } Version GetVersion() CXX11_OVERRIDE { return Version("Provides RFC 6455 WebSocket support", VF_VENDOR); } }; MODULE_INIT(ModuleWebSocket) �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/src/modules/m_xline_db.cpp�����������������������������������������������������������0000664�0000000�0000000�00000017024�13554550454�0020412�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * InspIRCd -- Internet Relay Chat Daemon * * Copyright (C) 2008 Thomas Stagner <aquanight@inspircd.org> * Copyright (C) 2008 Robin Burchell <robin+git@viroteck.net> * * 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 "inspircd.h" #include "xline.h" #include <fstream> class ModuleXLineDB : public Module , public Timer { private: bool dirty; std::string xlinedbpath; public: ModuleXLineDB() : Timer(0, true) { } void init() CXX11_OVERRIDE { /* Load the configuration * Note: * This is on purpose not changed on a rehash. It would be non-trivial to change the database on-the-fly. * Imagine a scenario where the new file already exists. Merging the current XLines with the existing database is likely a bad idea * ...and so is discarding all current in-memory XLines for the ones in the database. */ ConfigTag* Conf = ServerInstance->Config->ConfValue("xlinedb"); xlinedbpath = ServerInstance->Config->Paths.PrependData(Conf->getString("filename", "xline.db")); SetInterval(Conf->getDuration("saveperiod", 5)); // Read xlines before attaching to events ReadDatabase(); dirty = false; } /** Called whenever an xline is added by a local user. * This method is triggered after the line is added. * @param source The sender of the line or NULL for local server * @param line The xline being added */ void OnAddLine(User* source, XLine* line) CXX11_OVERRIDE { if (!line->from_config) dirty = true; } /** Called whenever an xline is deleted. * This method is triggered after the line is deleted. * @param source The user removing the line or NULL for local server * @param line the line being deleted */ void OnDelLine(User* source, XLine* line) CXX11_OVERRIDE { if (!line->from_config) dirty = true; } bool Tick(time_t) CXX11_OVERRIDE { if (dirty) { if (WriteDatabase()) dirty = false; } return true; } bool WriteDatabase() { /* * We need to perform an atomic write so as not to fuck things up. * So, let's write to a temporary file, flush it, then rename the file.. * Technically, that means that this can block, but I have *never* seen that. * -- w00t */ ServerInstance->Logs->Log(MODNAME, LOG_DEBUG, "Opening temporary database"); std::string xlinenewdbpath = xlinedbpath + ".new"; std::ofstream stream(xlinenewdbpath.c_str()); if (!stream.is_open()) { ServerInstance->Logs->Log(MODNAME, LOG_DEBUG, "Cannot create database \"%s\"! %s (%d)", xlinenewdbpath.c_str(), strerror(errno), errno); ServerInstance->SNO->WriteToSnoMask('x', "database: cannot create new xline db \"%s\": %s (%d)", xlinenewdbpath.c_str(), strerror(errno), errno); return false; } ServerInstance->Logs->Log(MODNAME, LOG_DEBUG, "Opened. Writing.."); /* * Now, much as I hate writing semi-unportable formats, additional * xline types may not have a conf tag, so let's just write them. * In addition, let's use a file version, so we can maintain some * semblance of backwards compatibility for reading on startup.. * -- w00t */ stream << "VERSION 1" << std::endl; // Now, let's write. std::vector<std::string> types = ServerInstance->XLines->GetAllTypes(); for (std::vector<std::string>::const_iterator it = types.begin(); it != types.end(); ++it) { XLineLookup* lookup = ServerInstance->XLines->GetAll(*it); if (!lookup) continue; // Not possible as we just obtained the list from XLineManager for (LookupIter i = lookup->begin(); i != lookup->end(); ++i) { XLine* line = i->second; if (line->from_config) continue; stream << "LINE " << line->type << " " << line->Displayable() << " " << line->source << " " << line->set_time << " " << line->duration << " :" << line->reason << std::endl; } } ServerInstance->Logs->Log(MODNAME, LOG_DEBUG, "Finished writing XLines. Checking for error.."); if (stream.fail()) { ServerInstance->Logs->Log(MODNAME, LOG_DEBUG, "Cannot write to new database \"%s\"! %s (%d)", xlinenewdbpath.c_str(), strerror(errno), errno); ServerInstance->SNO->WriteToSnoMask('x', "database: cannot write to new xline db \"%s\": %s (%d)", xlinenewdbpath.c_str(), strerror(errno), errno); return false; } stream.close(); #ifdef _WIN32 remove(xlinedbpath.c_str()); #endif // Use rename to move temporary to new db - this is guarenteed not to fuck up, even in case of a crash. if (rename(xlinenewdbpath.c_str(), xlinedbpath.c_str()) < 0) { ServerInstance->Logs->Log(MODNAME, LOG_DEBUG, "Cannot replace old database \"%s\" with new database \"%s\"! %s (%d)", xlinedbpath.c_str(), xlinenewdbpath.c_str(), strerror(errno), errno); ServerInstance->SNO->WriteToSnoMask('x', "database: cannot replace old xline db \"%s\" with new db \"%s\": %s (%d)", xlinedbpath.c_str(), xlinenewdbpath.c_str(), strerror(errno), errno); return false; } return true; } bool ReadDatabase() { // If the xline database doesn't exist then we don't need to load it. if (!FileSystem::FileExists(xlinedbpath)) return true; std::ifstream stream(xlinedbpath.c_str()); if (!stream.is_open()) { ServerInstance->Logs->Log(MODNAME, LOG_DEBUG, "Cannot read database \"%s\"! %s (%d)", xlinedbpath.c_str(), strerror(errno), errno); ServerInstance->SNO->WriteToSnoMask('x', "database: cannot read xline db \"%s\": %s (%d)", xlinedbpath.c_str(), strerror(errno), errno); return false; } std::string line; while (std::getline(stream, line)) { // Inspired by the command parser. :) irc::tokenstream tokens(line); int items = 0; std::string command_p[7]; std::string tmp; while (tokens.GetTrailing(tmp) && (items < 7)) { command_p[items] = tmp; items++; } ServerInstance->Logs->Log(MODNAME, LOG_DEBUG, "Processing %s", line.c_str()); if (command_p[0] == "VERSION") { if (command_p[1] != "1") { stream.close(); ServerInstance->Logs->Log(MODNAME, LOG_DEBUG, "I got database version %s - I don't understand it", command_p[1].c_str()); ServerInstance->SNO->WriteToSnoMask('x', "database: I got a database version (%s) I don't understand", command_p[1].c_str()); return false; } } else if (command_p[0] == "LINE") { // Mercilessly stolen from spanningtree XLineFactory* xlf = ServerInstance->XLines->GetFactory(command_p[1]); if (!xlf) { ServerInstance->SNO->WriteToSnoMask('x', "database: Unknown line type (%s).", command_p[1].c_str()); continue; } XLine* xl = xlf->Generate(ServerInstance->Time(), ConvToNum<unsigned long>(command_p[5]), command_p[3], command_p[6], command_p[2]); xl->SetCreateTime(ConvToNum<time_t>(command_p[4])); if (ServerInstance->XLines->AddLine(xl, NULL)) { ServerInstance->SNO->WriteToSnoMask('x', "database: Added a line of type %s", command_p[1].c_str()); } else delete xl; } } stream.close(); return true; } Version GetVersion() CXX11_OVERRIDE { return Version("Provides the ability to store X-lines in a database file", VF_VENDOR); } }; MODULE_INIT(ModuleXLineDB) ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/src/serializable.cpp�����������������������������������������������������������������0000664�0000000�0000000�00000020717�13554550454�0017313�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * InspIRCd -- Internet Relay Chat Daemon * * Copyright (C) 2019 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 "inspircd.h" Serializable::Data& Serializable::Data::Load(const std::string& key, std::string& out) { EntryMap::iterator iter = this->entries.find(key); if (iter == this->entries.end()) { ServerInstance->Logs->Log("SERIALIZE", LOG_DEBUG, "Unable to load missing kv %s!", key.c_str()); } else { out = iter->second; ServerInstance->Logs->Log("SERIALIZE", LOG_DEBUG, "Loaded kv %s: %s", key.c_str(), out.c_str()); } return *this; } Serializable::Data& Serializable::Data::Load(const std::string& key, Serializable::Data& out) { ChildMap::iterator iter = this->children.find(key); if (iter == this->children.end()) { ServerInstance->Logs->Log("SERIALIZE", LOG_DEBUG, "Unable to load missing data %s!", key.c_str()); } else { out = iter->second; ServerInstance->Logs->Log("SERIALIZE", LOG_DEBUG, "Loaded data: %s", key.c_str()); } return *this; } Serializable::Data& Serializable::Data::Store(const std::string& key, const std::string& value) { ServerInstance->Logs->Log("SERIALIZE", LOG_DEBUG, "Stored kv %s: %s", key.c_str(), value.c_str()); this->entries[key] = value; return *this; } Serializable::Data& Serializable::Data::Store(const std::string& key, const Serializable::Data& value) { ServerInstance->Logs->Log("SERIALIZE", LOG_DEBUG, "Stored data: %s", key.c_str()); this->children[key] = value; return *this; } bool Extensible::Deserialize(Serializable::Data& data) { // If the extensible has been culled then it shouldn't be deserialized. if (culled) return false; const Serializable::Data::EntryMap& entries = data.GetEntries(); for (Serializable::Data::EntryMap::const_iterator iter = entries.begin(); iter != entries.end(); ++iter) { const std::string& name = iter->first; ExtensionItem* item = ServerInstance->Extensions.GetItem(name); if (item) { item->FromInternal(this, iter->second); continue; } ServerInstance->Logs->Log("SERIALIZE", LOG_DEBUG, "Tried to deserialize the %s extension item but it doesn't exist", name.c_str()); } return true; } bool Extensible::Serialize(Serializable::Data& data) { // If the extensible has been culled then it shouldn't be serialized. if (culled) { ServerInstance->Logs->Log("SERIALIZE", LOG_DEBUG, "Tried to serialize an extensible which has been culled"); return false; } for (Extensible::ExtensibleStore::const_iterator iter = extensions.begin(); iter != extensions.end(); ++iter) { ExtensionItem* item = iter->first; const std::string value = item->ToInternal(this, iter->second); if (!value.empty()) data.Store(item->name, value); } return true; } bool User::Deserialize(Serializable::Data& data) { // If the user is quitting they shouldn't be deserialized. if (quitting) { ServerInstance->Logs->Log("SERIALIZE", LOG_DEBUG, "Tried to deserialize %s who is in the process of quitting", uuid.c_str()); return false; } // Check we're actually deserialising data for this user. std::string client_uuid; data.Load("uuid", client_uuid); if (!client_uuid.empty() && client_uuid != uuid) { ServerInstance->Logs->Log("SERIALIZE", LOG_DEBUG, "Tried to deserialize %s into %s", client_uuid.c_str(), uuid.c_str()); return false; } // Deserialize the extensions first. Serializable::Data exts; data.Load("extensions", exts); if (!Extensible::Deserialize(exts)) return false; long client_port; std::string client_addr; std::string user_modes; std::string user_oper; std::string user_snomasks; // Apply the members which can be applied directly. data.Load("age", age) .Load("awaymsg", awaymsg) .Load("awaytime", awaytime) .Load("client_sa.addr", client_addr) .Load("client_sa.port", client_port) .Load("displayhost", displayhost) .Load("ident", ident) .Load("modes", user_modes) .Load("nick", nick) .Load("oper", user_oper) .Load("realhost", realhost) .Load("realname", realname) .Load("signon", signon) .Load("snomasks", user_snomasks); // Apply the rest of the members. modes = std::bitset<ModeParser::MODEID_MAX>(user_modes); snomasks = std::bitset<64>(user_snomasks); ServerConfig::OperIndex::const_iterator iter = ServerInstance->Config->OperTypes.find(user_oper); if (iter != ServerInstance->Config->OperTypes.end()) oper = iter->second; else oper = new OperInfo(user_oper); irc::sockets::sockaddrs sa; if (irc::sockets::aptosa(client_addr, client_port, sa) || irc::sockets::untosa(client_addr, sa)) client_sa = sa; InvalidateCache(); return true; } bool User::Serialize(Serializable::Data& data) { // If the user is quitting they shouldn't be serialized. if (quitting) { ServerInstance->Logs->Log("SERIALIZE", LOG_DEBUG, "Tried to serialize %s who is in the process of quitting", uuid.c_str()); return false; } // If the user is unregistered they shouldn't be serialised. if (registered != REG_ALL) return false; // Serialize the extensions first. Serializable::Data exts; if (!Extensible::Serialize(exts)) return false; data.Store("extensions", exts); // The following member variables not checked above are not serialised: // * cached_fullhost (serialising cache variables is unnecessary) // * cached_fullrealhost (serialising cache variables is unnecessary) // * cached_hostip (serialising cache variables is unnecessary) // * cached_makehost (serialising cache variables is unnecessary) // * cachedip (serialising cache variables is unnecessary) // * server (specific to the origin server) // * usertype (can't be networked reliably) data.Store("age", age) .Store("awaymsg", awaymsg) .Store("awaytime", awaytime) .Store("client_sa.addr", client_sa.addr()) .Store("client_sa.port", client_sa.port()) .Store("displayhost", displayhost) .Store("ident", ident) .Store("modes", modes.to_string()) .Store("nick", nick) .Store("oper", oper ? oper->name : "") .Store("realhost", realhost) .Store("realname", realname) .Store("signon", signon) .Store("snomasks", snomasks.to_string()) .Store("uuid", uuid); return true; } bool LocalUser::Deserialize(Serializable::Data& data) { // Deserialize the base class first. if (!User::Deserialize(data)) return false; bool user_exempt; bool user_lastping; long server_port; std::string server_addr; // Apply the members which can be applied directly. data.Load("bytes_in", bytes_in) .Load("bytes_out", bytes_out) .Load("cmds_in", cmds_in) .Load("cmds_out", cmds_out) .Load("CommandFloodPenalty", CommandFloodPenalty) .Load("exempt", user_exempt) .Load("idle_lastmsg", idle_lastmsg) .Load("lastping", user_lastping) .Load("nextping", nextping) .Load("password", password) .Load("server_sa.addr", server_addr) .Load("server_sa.port", server_port); // Apply the rest of the members. irc::sockets::sockaddrs sa; if (irc::sockets::aptosa(server_addr, server_port, sa) || irc::sockets::untosa(server_addr, sa)) server_sa = sa; // These are bitfields so we need to ensure they only get the appropriate bits. exempt = user_exempt ? 1 : 0; lastping = user_lastping ? 1 : 0; return true; } bool LocalUser::Serialize(Serializable::Data& data) { // Serialize the base class first. if (!User::Serialize(data)) return false; // The following member variables not checked above are not serialised: // * already_sent (can't be networked reliably) // * eh (shouldn't be networked) // * MyClass (might not be the same on a different server) // * serializer (might not be the same on a different connection) data.Store("bytes_in", bytes_in) .Store("bytes_out", bytes_out) .Store("cmds_in", cmds_in) .Store("cmds_out", cmds_out) .Store("CommandFloodPenalty", CommandFloodPenalty) .Store("exempt", exempt) .Store("idle_lastmsg", idle_lastmsg) .Store("lastping", lastping) .Store("nextping", nextping) .Store("password", password) .Store("server_sa.addr", server_sa.addr()) .Store("server_sa.port", server_sa.port()); return true; } �������������������������������������������������inspircd-3.4.0/src/server.cpp�����������������������������������������������������������������������0000664�0000000�0000000�00000016673�13554550454�0016161�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * InspIRCd -- Internet Relay Chat Daemon * * Copyright (C) 2009 Daniel De Graaf <danieldg@inspircd.org> * Copyright (C) 2008 Craig Edwards <craigedwards@brainbox.cc> * Copyright (C) 2007-2008 Robin Burchell <robin+git@viroteck.net> * Copyright (C) 2007 Dennis Friis <peavey@inspircd.org> * * This file is part of InspIRCd. InspIRCd is free software: you can * redistribute it and/or modify it under the terms of the GNU General Public * License as published by the Free Software Foundation, version 2. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include "inspircd.h" #include "exitcodes.h" #include <signal.h> void InspIRCd::SignalHandler(int signal) { #ifdef _WIN32 if (signal == SIGTERM) #else if (signal == SIGHUP) { ServerInstance->SNO->WriteGlobalSno('a', "Rehashing due to SIGHUP"); Rehash(); } else if (signal == SIGTERM) #endif { Exit(EXIT_STATUS_SIGTERM); } } void InspIRCd::Exit(int status) { #ifdef _WIN32 SetServiceStopped(status); #endif this->Cleanup(); ServerInstance = NULL; delete this; exit (status); } void InspIRCd::Rehash(const std::string& uuid) { if (!ServerInstance->ConfigThread) { ServerInstance->ConfigThread = new ConfigReaderThread(uuid); ServerInstance->Threads.Start(ServerInstance->ConfigThread); } } std::string InspIRCd::GetVersionString(bool getFullVersion) { if (getFullVersion) return INSPIRCD_VERSION ". " + Config->ServerName + " :[" + Config->sid + "] " + Config->CustomVersion; return INSPIRCD_BRANCH ". " + Config->ServerName + " :" + Config->CustomVersion; } std::string UIDGenerator::GenerateSID(const std::string& servername, const std::string& serverdesc) { unsigned int sid = 0; for (std::string::const_iterator i = servername.begin(); i != servername.end(); ++i) sid = 5 * sid + *i; for (std::string::const_iterator i = serverdesc.begin(); i != serverdesc.end(); ++i) sid = 5 * sid + *i; std::string sidstr = ConvToStr(sid % 1000); sidstr.insert(0, 3 - sidstr.length(), '0'); return sidstr; } void UIDGenerator::IncrementUID(unsigned int pos) { /* * Okay. The rules for generating a UID go like this... * -- > ABCDEFGHIJKLMNOPQRSTUVWXYZ --> 012345679 --> WRAP * That is, we start at A. When we reach Z, we go to 0. At 9, we go to * A again, in an iterative fashion.. so.. * AAA9 -> AABA, and so on. -- w00t */ // If we hit Z, wrap around to 0. if (current_uid[pos] == 'Z') { current_uid[pos] = '0'; } else if (current_uid[pos] == '9') { /* * Or, if we hit 9, wrap around to pos = 'A' and (pos - 1)++, * e.g. A9 -> BA -> BB .. */ current_uid[pos] = 'A'; if (pos == 3) { // At pos 3, if we hit '9', we've run out of available UIDs, and reset to AAA..AAA. return; } this->IncrementUID(pos - 1); } else { // Anything else, nobody gives a shit. Just increment. current_uid[pos]++; } } void UIDGenerator::init(const std::string& sid) { /* * Copy SID into the first three digits, 9's to the rest, null term at the end * Why 9? Well, we increment before we find, otherwise we have an unnecessary copy, and I want UID to start at AAA..AA * and not AA..AB. So by initialising to 99999, we force it to rollover to AAAAA on the first IncrementUID call. * Kind of silly, but I like how it looks. * -- w */ current_uid.resize(UUID_LENGTH, '9'); current_uid[0] = sid[0]; current_uid[1] = sid[1]; current_uid[2] = sid[2]; } /* * Retrieve the next valid UUID that is free for this server. */ std::string UIDGenerator::GetUID() { while (1) { // Add one to the last UID this->IncrementUID(UUID_LENGTH - 1); if (!ServerInstance->FindUUID(current_uid)) break; /* * It's in use. We need to try the loop again. */ } return current_uid; } void ISupportManager::AppendValue(std::string& buffer, const std::string& value) { // If this token has no value then we have nothing to do. if (value.empty()) return; // This function implements value escaping according to the rules of the ISUPPORT draft: // https://tools.ietf.org/html/draft-brocklesby-irc-isupport-03 buffer.push_back('='); for (std::string::const_iterator iter = value.begin(); iter != value.end(); ++iter) { // The value must be escaped if: // (1) It is a banned character in an IRC <middle> parameter (NUL, LF, CR, SPACE). // (2) It has special meaning within an ISUPPORT token (EQUALS, BACKSLASH). if (*iter == '\0' || *iter == '\n' || *iter == '\r' || *iter == ' ' || *iter == '=' || *iter == '\\') buffer.append(InspIRCd::Format("\\x%X", *iter)); else buffer.push_back(*iter); } } void ISupportManager::Build() { /** * This is currently the neatest way we can build the initial ISUPPORT map. In * the future we can use an initializer list here. */ std::map<std::string, std::string> tokens; tokens["AWAYLEN"] = ConvToStr(ServerInstance->Config->Limits.MaxAway); tokens["CASEMAPPING"] = ServerInstance->Config->CaseMapping; tokens["CHANLIMIT"] = InspIRCd::Format("#:%u", ServerInstance->Config->MaxChans); tokens["CHANMODES"] = ServerInstance->Modes->GiveModeList(MODETYPE_CHANNEL); tokens["CHANNELLEN"] = ConvToStr(ServerInstance->Config->Limits.ChanMax); tokens["CHANTYPES"] = "#"; tokens["HOSTLEN"] = ConvToStr(ServerInstance->Config->Limits.MaxHost); tokens["KICKLEN"] = ConvToStr(ServerInstance->Config->Limits.MaxKick); tokens["LINELEN"] = ConvToStr(ServerInstance->Config->Limits.MaxLine); tokens["MAXTARGETS"] = ConvToStr(ServerInstance->Config->MaxTargets); tokens["MODES"] = ConvToStr(ServerInstance->Config->Limits.MaxModes); tokens["NETWORK"] = ServerInstance->Config->Network; tokens["NICKLEN"] = ConvToStr(ServerInstance->Config->Limits.NickMax); tokens["PREFIX"] = ServerInstance->Modes->BuildPrefixes(); tokens["STATUSMSG"] = ServerInstance->Modes->BuildPrefixes(false); tokens["TOPICLEN"] = ConvToStr(ServerInstance->Config->Limits.MaxTopic); tokens["USERLEN"] = ConvToStr(ServerInstance->Config->Limits.IdentMax); // Modules can add new tokens and also edit or remove existing tokens FOREACH_MOD(On005Numeric, (tokens)); // EXTBAN is a special case as we need to sort it and prepend a comma. std::map<std::string, std::string>::iterator extban = tokens.find("EXTBAN"); if (extban != tokens.end()) { std::sort(extban->second.begin(), extban->second.end()); extban->second.insert(0, ","); } // Transform the map into a list of lines, ready to be sent to clients Numeric::Numeric numeric(RPL_ISUPPORT); unsigned int token_count = 0; cachedlines.clear(); for (std::map<std::string, std::string>::const_iterator it = tokens.begin(); it != tokens.end(); ++it) { numeric.push(it->first); std::string& token = numeric.GetParams().back(); AppendValue(token, it->second); token_count++; if (token_count % 13 == 12 || it == --tokens.end()) { // Reached maximum number of tokens for this line or the current token // is the last one; finalize the line and store it for later use numeric.push("are supported by this server"); cachedlines.push_back(numeric); numeric.GetParams().clear(); } } } void ISupportManager::SendTo(LocalUser* user) { for (std::vector<Numeric::Numeric>::const_iterator i = cachedlines.begin(); i != cachedlines.end(); ++i) user->WriteNumeric(*i); } ���������������������������������������������������������������������inspircd-3.4.0/src/snomasks.cpp���������������������������������������������������������������������0000664�0000000�0000000�00000010415�13554550454�0016475�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * InspIRCd -- Internet Relay Chat Daemon * * Copyright (C) 2009-2010 Daniel De Graaf <danieldg@inspircd.org> * Copyright (C) 2008 Robin Burchell <robin+git@viroteck.net> * Copyright (C) 2007 Dennis Friis <peavey@inspircd.org> * Copyright (C) 2006 Craig Edwards <craigedwards@brainbox.cc> * * This file is part of InspIRCd. InspIRCd is free software: you can * redistribute it and/or modify it under the terms of the GNU General Public * License as published by the Free Software Foundation, version 2. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include "inspircd.h" void SnomaskManager::FlushSnotices() { for (int i=0; i < 26; i++) masks[i].Flush(); } void SnomaskManager::EnableSnomask(char letter, const std::string &type) { if (letter >= 'a' && letter <= 'z') masks[letter - 'a'].Description = type; } void SnomaskManager::WriteToSnoMask(char letter, const std::string &text) { if (letter >= 'a' && letter <= 'z') masks[letter - 'a'].SendMessage(text, letter); if (letter >= 'A' && letter <= 'Z') masks[letter - 'A'].SendMessage(text, letter); } void SnomaskManager::WriteGlobalSno(char letter, const std::string& text) { WriteToSnoMask(letter, text); letter = toupper(letter); ServerInstance->PI->SendSNONotice(letter, text); } void SnomaskManager::WriteToSnoMask(char letter, const char* text, ...) { std::string textbuffer; VAFORMAT(textbuffer, text, text); this->WriteToSnoMask(letter, textbuffer); } void SnomaskManager::WriteGlobalSno(char letter, const char* text, ...) { std::string textbuffer; VAFORMAT(textbuffer, text, text); this->WriteGlobalSno(letter, textbuffer); } SnomaskManager::SnomaskManager() { EnableSnomask('c',"CONNECT"); /* Local connect notices */ EnableSnomask('q',"QUIT"); /* Local quit notices */ EnableSnomask('k',"KILL"); /* Kill notices */ EnableSnomask('o',"OPER"); /* Oper up/down notices */ EnableSnomask('a',"ANNOUNCEMENT"); /* formerly WriteOpers() - generic notices to all opers */ EnableSnomask('x',"XLINE"); /* X-line notices (G/Z/Q/K/E/R/SHUN/CBan) */ EnableSnomask('t',"STATS"); /* Local or remote stats request */ } bool SnomaskManager::IsSnomaskUsable(char ch) const { return ((isalpha(ch)) && (!masks[tolower(ch) - 'a'].Description.empty())); } Snomask::Snomask() : Count(0) { } void Snomask::SendMessage(const std::string& message, char letter) { if ((!ServerInstance->Config->NoSnoticeStack) && (message == LastMessage) && (letter == LastLetter)) { Count++; return; } this->Flush(); std::string desc = GetDescription(letter); ModResult MOD_RESULT; FIRST_MOD_RESULT(OnSendSnotice, MOD_RESULT, (letter, desc, message)); if (MOD_RESULT == MOD_RES_DENY) return; Snomask::Send(letter, desc, message); LastMessage = message; LastLetter = letter; Count++; } void Snomask::Flush() { if (Count > 1) { std::string desc = GetDescription(LastLetter); std::string msg = "(last message repeated " + ConvToStr(Count) + " times)"; FOREACH_MOD(OnSendSnotice, (LastLetter, desc, msg)); Snomask::Send(LastLetter, desc, msg); } LastMessage.clear(); Count = 0; } void Snomask::Send(char letter, const std::string& desc, const std::string& msg) { ServerInstance->Logs->Log(desc, LOG_DEFAULT, msg); const std::string finalmsg = InspIRCd::Format("*** %s: %s", desc.c_str(), msg.c_str()); /* Only opers can receive snotices, so we iterate the oper list */ const UserManager::OperList& opers = ServerInstance->Users->all_opers; for (UserManager::OperList::const_iterator i = opers.begin(); i != opers.end(); ++i) { User* user = *i; // IsNoticeMaskSet() returns false for opers who aren't +s, no need to check for it seperately if (IS_LOCAL(user) && user->IsNoticeMaskSet(letter)) user->WriteNotice(finalmsg); } } std::string Snomask::GetDescription(char letter) const { std::string ret; if (isupper(letter)) ret = "REMOTE"; if (!Description.empty()) ret += Description; else ret += std::string("SNO-") + (char)tolower(letter); return ret; } ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/src/socket.cpp�����������������������������������������������������������������������0000664�0000000�0000000�00000030540�13554550454�0016130�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * InspIRCd -- Internet Relay Chat Daemon * * Copyright (C) 2009-2010 Daniel De Graaf <danieldg@inspircd.org> * Copyright (C) 2007-2008 Robin Burchell <robin+git@viroteck.net> * Copyright (C) 2005-2008 Craig Edwards <craigedwards@brainbox.cc> * Copyright (C) 2007 Dennis Friis <peavey@inspircd.org> * Copyright (C) 2006 Oliver Lupton <oliverlupton@gmail.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 "inspircd.h" bool InspIRCd::BindPort(ConfigTag* tag, const irc::sockets::sockaddrs& sa, std::vector<ListenSocket*>& old_ports) { for (std::vector<ListenSocket*>::iterator n = old_ports.begin(); n != old_ports.end(); ++n) { if ((**n).bind_sa == sa) { // Replace tag, we know addr and port match, but other info (type, ssl) may not. ServerInstance->Logs->Log("SOCKET", LOG_DEFAULT, "Replacing listener on %s from old tag at %s with new tag from %s", sa.str().c_str(), (*n)->bind_tag->getTagLocation().c_str(), tag->getTagLocation().c_str()); (*n)->bind_tag = tag; (*n)->ResetIOHookProvider(); old_ports.erase(n); return true; } } ListenSocket* ll = new ListenSocket(tag, sa); if (ll->GetFd() < 0) { ServerInstance->Logs->Log("SOCKET", LOG_DEFAULT, "Failed to listen on %s from tag at %s: %s", sa.str().c_str(), tag->getTagLocation().c_str(), strerror(errno)); delete ll; return false; } ServerInstance->Logs->Log("SOCKET", LOG_DEFAULT, "Added a listener on %s from tag at %s", sa.str().c_str(), tag->getTagLocation().c_str()); ports.push_back(ll); return true; } int InspIRCd::BindPorts(FailedPortList& failed_ports) { int bound = 0; std::vector<ListenSocket*> old_ports(ports.begin(), ports.end()); ConfigTagList tags = ServerInstance->Config->ConfTags("bind"); for (ConfigIter i = tags.first; i != tags.second; ++i) { ConfigTag* tag = i->second; // Are we creating a TCP/IP listener? const std::string address = tag->getString("address"); const std::string portlist = tag->getString("port"); if (!address.empty() || !portlist.empty()) { // InspIRCd supports IPv4 and IPv6 natively; no 4in6 required. if (strncasecmp(address.c_str(), "::ffff:", 7) == 0) this->Logs->Log("SOCKET", LOG_DEFAULT, "Using 4in6 (::ffff:) isn't recommended. You should bind IPv4 addresses directly instead."); // A TCP listener with no ports is not very useful. if (portlist.empty()) this->Logs->Log("SOCKET", LOG_DEFAULT, "TCP listener on %s at %s has no ports specified!", address.empty() ? "*" : address.c_str(), tag->getTagLocation().c_str()); irc::portparser portrange(portlist, false); for (int port; (port = portrange.GetToken()); ) { irc::sockets::sockaddrs bindspec; if (!irc::sockets::aptosa(address, port, bindspec)) continue; if (!BindPort(tag, bindspec, old_ports)) failed_ports.push_back(std::make_pair(bindspec, errno)); else bound++; } continue; } #ifndef _WIN32 // Are we creating a UNIX listener? const std::string path = tag->getString("path"); if (!path.empty()) { // Expand the path relative to the config directory. const std::string fullpath = ServerInstance->Config->Paths.PrependData(path); // UNIX socket paths are length limited to less than PATH_MAX. irc::sockets::sockaddrs bindspec; if (fullpath.length() > std::min(ServerInstance->Config->Limits.MaxHost, sizeof(bindspec.un.sun_path) - 1)) { this->Logs->Log("SOCKET", LOG_DEFAULT, "UNIX listener on %s at %s specified a path that is too long!", fullpath.c_str(), tag->getTagLocation().c_str()); continue; } // Check for characters which are problematic in the IRC message format. if (fullpath.find_first_of("\n\r\t!@: ") != std::string::npos) { this->Logs->Log("SOCKET", LOG_DEFAULT, "UNIX listener on %s at %s specified a path containing invalid characters!", fullpath.c_str(), tag->getTagLocation().c_str()); continue; } irc::sockets::untosa(fullpath, bindspec); if (!BindPort(tag, bindspec, old_ports)) failed_ports.push_back(std::make_pair(bindspec, errno)); else bound++; } #endif } std::vector<ListenSocket*>::iterator n = ports.begin(); for (std::vector<ListenSocket*>::iterator o = old_ports.begin(); o != old_ports.end(); ++o) { while (n != ports.end() && *n != *o) n++; if (n == ports.end()) { this->Logs->Log("SOCKET", LOG_DEFAULT, "Port bindings slipped out of vector, aborting close!"); break; } this->Logs->Log("SOCKET", LOG_DEFAULT, "Port binding %s was removed from the config file, closing.", (**n).bind_sa.str().c_str()); delete *n; // this keeps the iterator valid, pointing to the next element n = ports.erase(n); } return bound; } bool irc::sockets::aptosa(const std::string& addr, int port, irc::sockets::sockaddrs& sa) { memset(&sa, 0, sizeof(sa)); if (addr.empty() || addr.c_str()[0] == '*') { if (ServerInstance->Config->WildcardIPv6) { sa.in6.sin6_family = AF_INET6; sa.in6.sin6_port = htons(port); } else { sa.in4.sin_family = AF_INET; sa.in4.sin_port = htons(port); } return true; } else if (inet_pton(AF_INET, addr.c_str(), &sa.in4.sin_addr) > 0) { sa.in4.sin_family = AF_INET; sa.in4.sin_port = htons(port); return true; } else if (inet_pton(AF_INET6, addr.c_str(), &sa.in6.sin6_addr) > 0) { sa.in6.sin6_family = AF_INET6; sa.in6.sin6_port = htons(port); return true; } return false; } bool irc::sockets::untosa(const std::string& path, irc::sockets::sockaddrs& sa) { memset(&sa, 0, sizeof(sa)); if (path.length() >= sizeof(sa.un.sun_path)) return false; sa.un.sun_family = AF_UNIX; memcpy(&sa.un.sun_path, path.c_str(), path.length() + 1); return true; } bool irc::sockets::isunix(const std::string& file) { #ifndef _WIN32 struct stat sb; if (stat(file.c_str(), &sb) == 0 && S_ISSOCK(sb.st_mode)) return true; #endif return false; } int irc::sockets::sockaddrs::family() const { return sa.sa_family; } int irc::sockets::sockaddrs::port() const { switch (family()) { case AF_INET: return ntohs(in4.sin_port); case AF_INET6: return ntohs(in6.sin6_port); case AF_UNIX: return 0; } // If we have reached this point then we have encountered a bug. ServerInstance->Logs->Log("SOCKET", LOG_DEBUG, "BUG: irc::sockets::sockaddrs::port(): socket type %d is unknown!", family()); return 0; } std::string irc::sockets::sockaddrs::addr() const { switch (family()) { case AF_INET: char ip4addr[INET_ADDRSTRLEN]; if (!inet_ntop(AF_INET, (void*)&in4.sin_addr, ip4addr, sizeof(ip4addr))) return "0.0.0.0"; return ip4addr; case AF_INET6: char ip6addr[INET6_ADDRSTRLEN]; if (!inet_ntop(AF_INET6, (void*)&in6.sin6_addr, ip6addr, sizeof(ip6addr))) return "0:0:0:0:0:0:0:0"; return ip6addr; case AF_UNIX: return un.sun_path; } // If we have reached this point then we have encountered a bug. ServerInstance->Logs->Log("SOCKET", LOG_DEBUG, "BUG: irc::sockets::sockaddrs::addr(): socket type %d is unknown!", family()); return "<unknown>"; } std::string irc::sockets::sockaddrs::str() const { switch (family()) { case AF_INET: char ip4addr[INET_ADDRSTRLEN]; if (!inet_ntop(AF_INET, (void*)&in4.sin_addr, ip4addr, sizeof(ip4addr))) strcpy(ip4addr, "0.0.0.0"); return InspIRCd::Format("%s:%u", ip4addr, ntohs(in4.sin_port)); case AF_INET6: char ip6addr[INET6_ADDRSTRLEN]; if (!inet_ntop(AF_INET6, (void*)&in6.sin6_addr, ip6addr, sizeof(ip6addr))) strcpy(ip6addr, "0:0:0:0:0:0:0:0"); return InspIRCd::Format("[%s]:%u", ip6addr, ntohs(in6.sin6_port)); case AF_UNIX: return un.sun_path; } // If we have reached this point then we have encountered a bug. ServerInstance->Logs->Log("SOCKET", LOG_DEBUG, "BUG: irc::sockets::sockaddrs::str(): socket type %d is unknown!", family()); return "<unknown>"; } socklen_t irc::sockets::sockaddrs::sa_size() const { switch (family()) { case AF_INET: return sizeof(in4); case AF_INET6: return sizeof(in6); case AF_UNIX: return sizeof(un); } // If we have reached this point then we have encountered a bug. ServerInstance->Logs->Log("SOCKET", LOG_DEBUG, "BUG: irc::sockets::sockaddrs::sa_size(): socket type %d is unknown!", family()); return 0; } bool irc::sockets::sockaddrs::operator==(const irc::sockets::sockaddrs& other) const { if (family() != other.family()) return false; switch (family()) { case AF_INET: return (in4.sin_port == other.in4.sin_port) && (in4.sin_addr.s_addr == other.in4.sin_addr.s_addr); case AF_INET6: return (in6.sin6_port == other.in6.sin6_port) && !memcmp(in6.sin6_addr.s6_addr, other.in6.sin6_addr.s6_addr, 16); case AF_UNIX: return !strcmp(un.sun_path, other.un.sun_path); } // If we have reached this point then we have encountered a bug. ServerInstance->Logs->Log("SOCKET", LOG_DEBUG, "BUG: irc::sockets::sockaddrs::operator==(): socket type %d is unknown!", family()); return !memcmp(this, &other, sizeof(*this)); } static void sa2cidr(irc::sockets::cidr_mask& cidr, const irc::sockets::sockaddrs& sa, unsigned char range) { const unsigned char* base; unsigned char target_byte; memset(cidr.bits, 0, sizeof(cidr.bits)); cidr.type = sa.family(); switch (cidr.type) { case AF_UNIX: // XXX: UNIX sockets don't support CIDR. This fix is non-ideal but I can't // really think of another way to handle it. cidr.length = 0; return; case AF_INET: cidr.length = range > 32 ? 32 : range; target_byte = sizeof(sa.in4.sin_addr); base = (unsigned char*)&sa.in4.sin_addr; break; case AF_INET6: cidr.length = range > 128 ? 128 : range; target_byte = sizeof(sa.in6.sin6_addr); base = (unsigned char*)&sa.in6.sin6_addr; break; default: // If we have reached this point then we have encountered a bug. ServerInstance->Logs->Log("SOCKET", LOG_DEBUG, "BUG: sa2cidr(): socket type %d is unknown!", cidr.type); cidr.length = 0; return; } unsigned int border = cidr.length / 8; unsigned int bitmask = (0xFF00 >> (range & 7)) & 0xFF; for(unsigned int i=0; i < target_byte; i++) { if (i < border) cidr.bits[i] = base[i]; else if (i == border) cidr.bits[i] = base[i] & bitmask; else return; } } irc::sockets::cidr_mask::cidr_mask(const irc::sockets::sockaddrs& sa, unsigned char range) { sa2cidr(*this, sa, range); } irc::sockets::cidr_mask::cidr_mask(const std::string& mask) { std::string::size_type bits_chars = mask.rfind('/'); irc::sockets::sockaddrs sa; if (bits_chars == std::string::npos) { irc::sockets::aptosa(mask, 0, sa); sa2cidr(*this, sa, 128); } else { unsigned char range = ConvToNum<unsigned char>(mask.substr(bits_chars + 1)); irc::sockets::aptosa(mask.substr(0, bits_chars), 0, sa); sa2cidr(*this, sa, range); } } std::string irc::sockets::cidr_mask::str() const { irc::sockets::sockaddrs sa; sa.sa.sa_family = type; unsigned char* base; size_t len; switch (type) { case AF_INET: base = (unsigned char*)&sa.in4.sin_addr; len = 4; break; case AF_INET6: base = (unsigned char*)&sa.in6.sin6_addr; len = 16; break; case AF_UNIX: return sa.un.sun_path; default: // If we have reached this point then we have encountered a bug. ServerInstance->Logs->Log("SOCKET", LOG_DEBUG, "BUG: irc::sockets::cidr_mask::str(): socket type %d is unknown!", type); return "<unknown>"; } memcpy(base, bits, len); return sa.addr() + "/" + ConvToStr((int)length); } bool irc::sockets::cidr_mask::operator==(const cidr_mask& other) const { return type == other.type && length == other.length && 0 == memcmp(bits, other.bits, 16); } bool irc::sockets::cidr_mask::operator<(const cidr_mask& other) const { if (type != other.type) return type < other.type; if (length != other.length) return length < other.length; return memcmp(bits, other.bits, 16) < 0; } bool irc::sockets::cidr_mask::match(const irc::sockets::sockaddrs& addr) const { if (addr.family() != type) return false; irc::sockets::cidr_mask tmp(addr, length); return tmp == *this; } ����������������������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/src/socketengine.cpp�����������������������������������������������������������������0000664�0000000�0000000�00000022254�13554550454�0017321�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * InspIRCd -- Internet Relay Chat Daemon * * Copyright (C) 2009 Daniel De Graaf <danieldg@inspircd.org> * Copyright (C) 2008 Robin Burchell <robin+git@viroteck.net> * Copyright (C) 2005-2008 Craig Edwards <craigedwards@brainbox.cc> * Copyright (C) 2007 Burlex <???@???> * Copyright (C) 2007 Dennis Friis <peavey@inspircd.org> * * This file is part of InspIRCd. InspIRCd is free software: you can * redistribute it and/or modify it under the terms of the GNU General Public * License as published by the Free Software Foundation, version 2. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include "exitcodes.h" #include "inspircd.h" #include <iostream> /** Reference table, contains all current handlers **/ std::vector<EventHandler*> SocketEngine::ref; /** Current number of descriptors in the engine */ size_t SocketEngine::CurrentSetSize = 0; /** List of handlers that want a trial read/write */ std::set<int> SocketEngine::trials; size_t SocketEngine::MaxSetSize = 0; /** Socket engine statistics: count of various events, bandwidth usage */ SocketEngine::Statistics SocketEngine::stats; EventHandler::EventHandler() { fd = -1; event_mask = 0; } void EventHandler::SwapInternals(EventHandler& other) { std::swap(fd, other.fd); std::swap(event_mask, other.event_mask); } void EventHandler::SetFd(int FD) { this->fd = FD; } void EventHandler::OnEventHandlerWrite() { } void EventHandler::OnEventHandlerError(int errornum) { } void SocketEngine::InitError() { std::cerr << con_red << "FATAL ERROR!" << con_reset << " Socket engine initialization failed. " << strerror(errno) << '.' << std::endl; exit(EXIT_STATUS_SOCKETENGINE); } void SocketEngine::LookupMaxFds() { #if defined _WIN32 MaxSetSize = FD_SETSIZE; #else struct rlimit limits; if (!getrlimit(RLIMIT_NOFILE, &limits)) MaxSetSize = limits.rlim_cur; #if defined __APPLE__ limits.rlim_cur = limits.rlim_max == RLIM_INFINITY ? OPEN_MAX : limits.rlim_max; #else limits.rlim_cur = limits.rlim_max; #endif if (!setrlimit(RLIMIT_NOFILE, &limits)) MaxSetSize = limits.rlim_cur; #endif } void SocketEngine::ChangeEventMask(EventHandler* eh, int change) { int old_m = eh->event_mask; int new_m = old_m; // if we are changing read/write type, remove the previously set bit if (change & FD_WANT_READ_MASK) new_m &= ~FD_WANT_READ_MASK; if (change & FD_WANT_WRITE_MASK) new_m &= ~FD_WANT_WRITE_MASK; // if adding a trial read/write, insert it into the set if (change & FD_TRIAL_NOTE_MASK && !(old_m & FD_TRIAL_NOTE_MASK)) trials.insert(eh->GetFd()); new_m |= change; if (new_m == old_m) return; eh->event_mask = new_m; OnSetEvent(eh, old_m, new_m); } void SocketEngine::DispatchTrialWrites() { std::vector<int> working_list; working_list.reserve(trials.size()); working_list.assign(trials.begin(), trials.end()); trials.clear(); for(unsigned int i=0; i < working_list.size(); i++) { int fd = working_list[i]; EventHandler* eh = GetRef(fd); if (!eh) continue; int mask = eh->event_mask; eh->event_mask &= ~(FD_ADD_TRIAL_READ | FD_ADD_TRIAL_WRITE); if ((mask & (FD_ADD_TRIAL_READ | FD_READ_WILL_BLOCK)) == FD_ADD_TRIAL_READ) eh->OnEventHandlerRead(); if ((mask & (FD_ADD_TRIAL_WRITE | FD_WRITE_WILL_BLOCK)) == FD_ADD_TRIAL_WRITE) eh->OnEventHandlerWrite(); } } bool SocketEngine::AddFdRef(EventHandler* eh) { int fd = eh->GetFd(); if (HasFd(fd)) return false; while (static_cast<unsigned int>(fd) >= ref.size()) ref.resize(ref.empty() ? 1 : (ref.size() * 2)); ref[fd] = eh; CurrentSetSize++; return true; } void SocketEngine::DelFdRef(EventHandler *eh) { int fd = eh->GetFd(); if (GetRef(fd) == eh) { ref[fd] = NULL; CurrentSetSize--; } } bool SocketEngine::HasFd(int fd) { return GetRef(fd) != NULL; } EventHandler* SocketEngine::GetRef(int fd) { if (fd < 0 || static_cast<unsigned int>(fd) >= ref.size()) return NULL; return ref[fd]; } bool SocketEngine::BoundsCheckFd(EventHandler* eh) { if (!eh) return false; if (eh->GetFd() < 0) return false; return true; } int SocketEngine::Accept(EventHandler* fd, sockaddr *addr, socklen_t *addrlen) { return accept(fd->GetFd(), addr, addrlen); } int SocketEngine::Close(EventHandler* eh) { DelFd(eh); int ret = Close(eh->GetFd()); eh->SetFd(-1); return ret; } int SocketEngine::Close(int fd) { #ifdef _WIN32 return closesocket(fd); #else return close(fd); #endif } int SocketEngine::Blocking(int fd) { #ifdef _WIN32 unsigned long opt = 0; return ioctlsocket(fd, FIONBIO, &opt); #else int flags = fcntl(fd, F_GETFL, 0); return fcntl(fd, F_SETFL, flags & ~O_NONBLOCK); #endif } int SocketEngine::NonBlocking(int fd) { #ifdef _WIN32 unsigned long opt = 1; return ioctlsocket(fd, FIONBIO, &opt); #else int flags = fcntl(fd, F_GETFL, 0); return fcntl(fd, F_SETFL, flags | O_NONBLOCK); #endif } void SocketEngine::SetReuse(int fd) { int on = 1; setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char*)&on, sizeof(on)); } int SocketEngine::RecvFrom(EventHandler* fd, void *buf, size_t len, int flags, sockaddr *from, socklen_t *fromlen) { int nbRecvd = recvfrom(fd->GetFd(), (char*)buf, len, flags, from, fromlen); stats.UpdateReadCounters(nbRecvd); return nbRecvd; } int SocketEngine::Send(EventHandler* fd, const void *buf, size_t len, int flags) { int nbSent = send(fd->GetFd(), (const char*)buf, len, flags); stats.UpdateWriteCounters(nbSent); return nbSent; } int SocketEngine::Recv(EventHandler* fd, void *buf, size_t len, int flags) { int nbRecvd = recv(fd->GetFd(), (char*)buf, len, flags); stats.UpdateReadCounters(nbRecvd); return nbRecvd; } int SocketEngine::SendTo(EventHandler* fd, const void* buf, size_t len, int flags, const irc::sockets::sockaddrs& address) { int nbSent = sendto(fd->GetFd(), (const char*)buf, len, flags, &address.sa, address.sa_size()); stats.UpdateWriteCounters(nbSent); return nbSent; } int SocketEngine::WriteV(EventHandler* fd, const IOVector* iovec, int count) { int sent = writev(fd->GetFd(), iovec, count); stats.UpdateWriteCounters(sent); return sent; } #ifdef _WIN32 int SocketEngine::WriteV(EventHandler* fd, const iovec* iovec, int count) { // On Windows the fields in iovec are not in the order required by the Winsock API; IOVector has // the fields in the correct order. // Create temporary IOVectors from the iovecs and pass them to the WriteV() method that accepts the // platform's native struct. IOVector wiovec[128]; count = std::min(count, static_cast<int>(sizeof(wiovec) / sizeof(IOVector))); for (int i = 0; i < count; i++) { wiovec[i].iov_len = iovec[i].iov_len; wiovec[i].iov_base = reinterpret_cast<char*>(iovec[i].iov_base); } return WriteV(fd, wiovec, count); } #endif int SocketEngine::Connect(EventHandler* fd, const irc::sockets::sockaddrs& address) { int ret = connect(fd->GetFd(), &address.sa, address.sa_size()); #ifdef _WIN32 if ((ret == SOCKET_ERROR) && (WSAGetLastError() == WSAEWOULDBLOCK)) errno = EINPROGRESS; #endif return ret; } int SocketEngine::Shutdown(EventHandler* fd, int how) { return shutdown(fd->GetFd(), how); } int SocketEngine::Bind(int fd, const irc::sockets::sockaddrs& addr) { return bind(fd, &addr.sa, addr.sa_size()); } int SocketEngine::Listen(int sockfd, int backlog) { return listen(sockfd, backlog); } int SocketEngine::Shutdown(int fd, int how) { return shutdown(fd, how); } void SocketEngine::Statistics::UpdateReadCounters(int len_in) { CheckFlush(); ReadEvents++; if (len_in > 0) indata += len_in; else if (len_in < 0) ErrorEvents++; } void SocketEngine::Statistics::UpdateWriteCounters(int len_out) { CheckFlush(); WriteEvents++; if (len_out > 0) outdata += len_out; else if (len_out < 0) ErrorEvents++; } void SocketEngine::Statistics::CheckFlush() const { // Reset the in/out byte counters if it has been more than a second time_t now = ServerInstance->Time(); if (lastempty != now) { lastempty = now; indata = outdata = 0; } } void SocketEngine::Statistics::GetBandwidth(float& kbitpersec_in, float& kbitpersec_out, float& kbitpersec_total) const { CheckFlush(); float in_kbit = indata * 8; float out_kbit = outdata * 8; kbitpersec_total = ((in_kbit + out_kbit) / 1024); kbitpersec_in = in_kbit / 1024; kbitpersec_out = out_kbit / 1024; } std::string SocketEngine::LastError() { #ifndef _WIN32 return strerror(errno); #else char szErrorString[500]; DWORD dwErrorCode = WSAGetLastError(); if (FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, dwErrorCode, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPSTR)szErrorString, _countof(szErrorString), NULL) == 0) sprintf_s(szErrorString, _countof(szErrorString), "Error code: %u", dwErrorCode); std::string::size_type p; std::string ret = szErrorString; while ((p = ret.find_last_of("\r\n")) != std::string::npos) ret.erase(p, 1); return ret; #endif } std::string SocketEngine::GetError(int errnum) { #ifndef _WIN32 return strerror(errnum); #else WSASetLastError(errnum); return LastError(); #endif } ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/src/socketengines/�������������������������������������������������������������������0000775�0000000�0000000�00000000000�13554550454�0016773�5����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/src/socketengines/socketengine_epoll.cpp���������������������������������������������0000664�0000000�0000000�00000013041�13554550454�0023347�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * InspIRCd -- Internet Relay Chat Daemon * * Copyright (C) 2009 Daniel De Graaf <danieldg@inspircd.org> * Copyright (C) 2007-2008 Craig Edwards <craigedwards@brainbox.cc> * * This file is part of InspIRCd. InspIRCd is free software: you can * redistribute it and/or modify it under the terms of the GNU General Public * License as published by the Free Software Foundation, version 2. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include "inspircd.h" #include <sys/epoll.h> #include <sys/resource.h> /** A specialisation of the SocketEngine class, designed to use linux 2.6 epoll(). */ namespace { int EngineHandle; /** These are used by epoll() to hold socket events */ std::vector<struct epoll_event> events(16); } void SocketEngine::Init() { LookupMaxFds(); // 128 is not a maximum, just a hint at the eventual number of sockets that may be polled, // and it is completely ignored by 2.6.8 and later kernels, except it must be larger than zero. EngineHandle = epoll_create(128); if (EngineHandle == -1) InitError(); } void SocketEngine::RecoverFromFork() { } void SocketEngine::Deinit() { Close(EngineHandle); } static unsigned mask_to_epoll(int event_mask) { unsigned rv = 0; if (event_mask & (FD_WANT_POLL_READ | FD_WANT_POLL_WRITE | FD_WANT_SINGLE_WRITE)) { // we need to use standard polling on this FD if (event_mask & (FD_WANT_POLL_READ | FD_WANT_FAST_READ)) rv |= EPOLLIN; if (event_mask & (FD_WANT_POLL_WRITE | FD_WANT_FAST_WRITE | FD_WANT_SINGLE_WRITE)) rv |= EPOLLOUT; } else { // we can use edge-triggered polling on this FD rv = EPOLLET; if (event_mask & (FD_WANT_FAST_READ | FD_WANT_EDGE_READ)) rv |= EPOLLIN; if (event_mask & (FD_WANT_FAST_WRITE | FD_WANT_EDGE_WRITE)) rv |= EPOLLOUT; } return rv; } bool SocketEngine::AddFd(EventHandler* eh, int event_mask) { int fd = eh->GetFd(); if (fd < 0) { ServerInstance->Logs->Log("SOCKET", LOG_DEBUG, "AddFd out of range: (fd: %d)", fd); return false; } if (!SocketEngine::AddFdRef(eh)) { ServerInstance->Logs->Log("SOCKET", LOG_DEBUG, "Attempt to add duplicate fd: %d", fd); return false; } struct epoll_event ev; memset(&ev, 0, sizeof(ev)); ev.events = mask_to_epoll(event_mask); ev.data.ptr = static_cast<void*>(eh); int i = epoll_ctl(EngineHandle, EPOLL_CTL_ADD, fd, &ev); if (i < 0) { ServerInstance->Logs->Log("SOCKET", LOG_DEBUG, "Error adding fd: %d to socketengine: %s", fd, strerror(errno)); return false; } ServerInstance->Logs->Log("SOCKET", LOG_DEBUG, "New file descriptor: %d", fd); eh->SetEventMask(event_mask); ResizeDouble(events); return true; } void SocketEngine::OnSetEvent(EventHandler* eh, int old_mask, int new_mask) { unsigned old_events = mask_to_epoll(old_mask); unsigned new_events = mask_to_epoll(new_mask); if (old_events != new_events) { // ok, we actually have something to tell the kernel about struct epoll_event ev; memset(&ev, 0, sizeof(ev)); ev.events = new_events; ev.data.ptr = static_cast<void*>(eh); epoll_ctl(EngineHandle, EPOLL_CTL_MOD, eh->GetFd(), &ev); } } void SocketEngine::DelFd(EventHandler* eh) { int fd = eh->GetFd(); if (fd < 0) { ServerInstance->Logs->Log("SOCKET", LOG_DEBUG, "DelFd out of range: (fd: %d)", fd); return; } // Do not initialize epoll_event because for EPOLL_CTL_DEL operations the event is ignored and can be NULL. // In kernel versions before 2.6.9, the EPOLL_CTL_DEL operation required a non-NULL pointer in event, // even though this argument is ignored. Since Linux 2.6.9, event can be specified as NULL when using EPOLL_CTL_DEL. struct epoll_event ev; int i = epoll_ctl(EngineHandle, EPOLL_CTL_DEL, fd, &ev); if (i < 0) { ServerInstance->Logs->Log("SOCKET", LOG_DEBUG, "epoll_ctl can't remove socket: %s", strerror(errno)); } SocketEngine::DelFdRef(eh); ServerInstance->Logs->Log("SOCKET", LOG_DEBUG, "Remove file descriptor: %d", fd); } int SocketEngine::DispatchEvents() { int i = epoll_wait(EngineHandle, &events[0], events.size(), 1000); ServerInstance->UpdateTime(); stats.TotalEvents += i; for (int j = 0; j < i; j++) { // Copy these in case the vector gets resized and ev invalidated const epoll_event ev = events[j]; EventHandler* const eh = static_cast<EventHandler*>(ev.data.ptr); const int fd = eh->GetFd(); if (fd < 0) continue; if (ev.events & EPOLLHUP) { stats.ErrorEvents++; eh->OnEventHandlerError(0); continue; } if (ev.events & EPOLLERR) { stats.ErrorEvents++; /* Get error number */ socklen_t codesize = sizeof(int); int errcode; if (getsockopt(fd, SOL_SOCKET, SO_ERROR, &errcode, &codesize) < 0) errcode = errno; eh->OnEventHandlerError(errcode); continue; } int mask = eh->GetEventMask(); if (ev.events & EPOLLIN) mask &= ~FD_READ_WILL_BLOCK; if (ev.events & EPOLLOUT) { mask &= ~FD_WRITE_WILL_BLOCK; if (mask & FD_WANT_SINGLE_WRITE) { int nm = mask & ~FD_WANT_SINGLE_WRITE; OnSetEvent(eh, mask, nm); mask = nm; } } eh->SetEventMask(mask); if (ev.events & EPOLLIN) { eh->OnEventHandlerRead(); if (eh != GetRef(fd)) // whoa! we got deleted, better not give out the write event continue; } if (ev.events & EPOLLOUT) { eh->OnEventHandlerWrite(); } } return i; } �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/src/socketengines/socketengine_kqueue.cpp��������������������������������������������0000664�0000000�0000000�00000012540�13554550454�0023536�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * InspIRCd -- Internet Relay Chat Daemon * * Copyright (C) 2009-2010 Daniel De Graaf <danieldg@inspircd.org> * Copyright (C) 2009 Uli Schlachter <psychon@znc.in> * Copyright (C) 2007-2008 Craig Edwards <craigedwards@brainbox.cc> * * This file is part of InspIRCd. InspIRCd is free software: you can * redistribute it and/or modify it under the terms of the GNU General Public * License as published by the Free Software Foundation, version 2. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include "inspircd.h" #include <sys/types.h> #include <sys/event.h> #include <sys/time.h> #include <sys/sysctl.h> /** A specialisation of the SocketEngine class, designed to use BSD kqueue(). */ namespace { int EngineHandle; unsigned int ChangePos = 0; /** These are used by kqueue() to hold socket events */ std::vector<struct kevent> ke_list(16); /** Pending changes */ std::vector<struct kevent> changelist(8); #if defined __NetBSD__ && __NetBSD_Version__ <= 999001400 inline intptr_t udata_cast(EventHandler* eh) { // On NetBSD <10 the last parameter of EV_SET is intptr_t. return reinterpret_cast<intptr_t>(eh); } #else inline void* udata_cast(EventHandler* eh) { // On other platforms the last parameter of EV_SET is void*. return static_cast<void*>(eh); } #endif } /** Initialize the kqueue engine */ void SocketEngine::Init() { LookupMaxFds(); RecoverFromFork(); } void SocketEngine::RecoverFromFork() { /* * The only bad thing about kqueue is that its fd cant survive a fork and is not inherited. * BUM HATS. * */ EngineHandle = kqueue(); if (EngineHandle == -1) InitError(); } /** Shutdown the kqueue engine */ void SocketEngine::Deinit() { Close(EngineHandle); } static struct kevent* GetChangeKE() { if (ChangePos >= changelist.size()) changelist.resize(changelist.size() * 2); return &changelist[ChangePos++]; } bool SocketEngine::AddFd(EventHandler* eh, int event_mask) { int fd = eh->GetFd(); if (fd < 0) return false; if (!SocketEngine::AddFdRef(eh)) return false; // We always want to read from the socket... struct kevent* ke = GetChangeKE(); EV_SET(ke, fd, EVFILT_READ, EV_ADD, 0, 0, udata_cast(eh)); ServerInstance->Logs->Log("SOCKET", LOG_DEBUG, "New file descriptor: %d", fd); eh->SetEventMask(event_mask); OnSetEvent(eh, 0, event_mask); ResizeDouble(ke_list); return true; } void SocketEngine::DelFd(EventHandler* eh) { int fd = eh->GetFd(); if (fd < 0) { ServerInstance->Logs->Log("SOCKET", LOG_DEFAULT, "DelFd() on invalid fd: %d", fd); return; } // First remove the write filter ignoring errors, since we can't be // sure if there are actually any write filters registered. struct kevent* ke = GetChangeKE(); EV_SET(ke, eh->GetFd(), EVFILT_WRITE, EV_DELETE, 0, 0, NULL); // Then remove the read filter. ke = GetChangeKE(); EV_SET(ke, eh->GetFd(), EVFILT_READ, EV_DELETE, 0, 0, NULL); SocketEngine::DelFdRef(eh); ServerInstance->Logs->Log("SOCKET", LOG_DEBUG, "Remove file descriptor: %d", fd); } void SocketEngine::OnSetEvent(EventHandler* eh, int old_mask, int new_mask) { if ((new_mask & FD_WANT_POLL_WRITE) && !(old_mask & FD_WANT_POLL_WRITE)) { // new poll-style write struct kevent* ke = GetChangeKE(); EV_SET(ke, eh->GetFd(), EVFILT_WRITE, EV_ADD, 0, 0, udata_cast(eh)); } else if ((old_mask & FD_WANT_POLL_WRITE) && !(new_mask & FD_WANT_POLL_WRITE)) { // removing poll-style write struct kevent* ke = GetChangeKE(); EV_SET(ke, eh->GetFd(), EVFILT_WRITE, EV_DELETE, 0, 0, NULL); } if ((new_mask & (FD_WANT_FAST_WRITE | FD_WANT_SINGLE_WRITE)) && !(old_mask & (FD_WANT_FAST_WRITE | FD_WANT_SINGLE_WRITE))) { struct kevent* ke = GetChangeKE(); EV_SET(ke, eh->GetFd(), EVFILT_WRITE, EV_ADD | EV_ONESHOT, 0, 0, udata_cast(eh)); } } int SocketEngine::DispatchEvents() { struct timespec ts; ts.tv_nsec = 0; ts.tv_sec = 1; int i = kevent(EngineHandle, &changelist.front(), ChangePos, &ke_list.front(), ke_list.size(), &ts); ChangePos = 0; ServerInstance->UpdateTime(); if (i < 0) return i; stats.TotalEvents += i; for (int j = 0; j < i; j++) { // This can't be a static_cast because udata is intptr_t on NetBSD. struct kevent& kev = ke_list[j]; EventHandler* eh = reinterpret_cast<EventHandler*>(kev.udata); if (!eh) continue; // Copy these in case the vector gets resized and kev invalidated const int fd = eh->GetFd(); const short filter = kev.filter; if (fd < 0) continue; if (kev.flags & EV_EOF) { stats.ErrorEvents++; eh->OnEventHandlerError(kev.fflags); continue; } if (filter == EVFILT_WRITE) { /* When mask is FD_WANT_FAST_WRITE or FD_WANT_SINGLE_WRITE, * we set a one-shot write, so we need to clear that bit * to detect when it set again. */ const int bits_to_clr = FD_WANT_SINGLE_WRITE | FD_WANT_FAST_WRITE | FD_WRITE_WILL_BLOCK; eh->SetEventMask(eh->GetEventMask() & ~bits_to_clr); eh->OnEventHandlerWrite(); } else if (filter == EVFILT_READ) { eh->SetEventMask(eh->GetEventMask() & ~FD_READ_WILL_BLOCK); eh->OnEventHandlerRead(); } } return i; } ����������������������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/src/socketengines/socketengine_poll.cpp����������������������������������������������0000664�0000000�0000000�00000012744�13554550454�0023213�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * InspIRCd -- Internet Relay Chat Daemon * * Copyright (C) 2014 Adam <Adam@anope.org> * Copyright (C) 2009 Daniel De Graaf <danieldg@inspircd.org> * Copyright (C) 2009 Uli Schlachter <psychon@znc.in> * Copyright (C) 2009 Craig Edwards <craigedwards@brainbox.cc> * Copyright (C) 2008 Robin Burchell <robin+git@viroteck.net> * * 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 "inspircd.h" #include <sys/poll.h> #include <sys/resource.h> /** A specialisation of the SocketEngine class, designed to use poll(). */ namespace { /** These are used by poll() to hold socket events */ std::vector<struct pollfd> events(16); /** This vector maps fds to an index in the events array. */ std::vector<int> fd_mappings(16, -1); } void SocketEngine::Init() { LookupMaxFds(); } void SocketEngine::Deinit() { } void SocketEngine::RecoverFromFork() { } static int mask_to_poll(int event_mask) { int rv = 0; if (event_mask & (FD_WANT_POLL_READ | FD_WANT_FAST_READ)) rv |= POLLIN; if (event_mask & (FD_WANT_POLL_WRITE | FD_WANT_FAST_WRITE | FD_WANT_SINGLE_WRITE)) rv |= POLLOUT; return rv; } bool SocketEngine::AddFd(EventHandler* eh, int event_mask) { int fd = eh->GetFd(); if (fd < 0) { ServerInstance->Logs->Log("SOCKET", LOG_DEBUG, "AddFd out of range: (fd: %d)", fd); return false; } if (static_cast<unsigned int>(fd) < fd_mappings.size() && fd_mappings[fd] != -1) { ServerInstance->Logs->Log("SOCKET", LOG_DEBUG, "Attempt to add duplicate fd: %d", fd); return false; } unsigned int index = CurrentSetSize; if (!SocketEngine::AddFdRef(eh)) { ServerInstance->Logs->Log("SOCKET", LOG_DEBUG, "Attempt to add duplicate fd: %d", fd); return false; } while (static_cast<unsigned int>(fd) >= fd_mappings.size()) fd_mappings.resize(fd_mappings.size() * 2, -1); fd_mappings[fd] = index; ResizeDouble(events); events[index].fd = fd; events[index].events = mask_to_poll(event_mask); ServerInstance->Logs->Log("SOCKET", LOG_DEBUG, "New file descriptor: %d (%d; index %d)", fd, events[index].events, index); eh->SetEventMask(event_mask); return true; } void SocketEngine::OnSetEvent(EventHandler* eh, int old_mask, int new_mask) { int fd = eh->GetFd(); if (fd < 0 || static_cast<unsigned int>(fd) >= fd_mappings.size() || fd_mappings[fd] == -1) { ServerInstance->Logs->Log("SOCKET", LOG_DEBUG, "SetEvents() on unknown fd: %d", eh->GetFd()); return; } events[fd_mappings[fd]].events = mask_to_poll(new_mask); } void SocketEngine::DelFd(EventHandler* eh) { int fd = eh->GetFd(); if (fd < 0) { ServerInstance->Logs->Log("SOCKET", LOG_DEBUG, "DelFd out of range: (fd: %d)", fd); return; } if (static_cast<unsigned int>(fd) >= fd_mappings.size() || fd_mappings[fd] == -1) { ServerInstance->Logs->Log("SOCKET", LOG_DEBUG, "DelFd() on unknown fd: %d", fd); return; } unsigned int index = fd_mappings[fd]; unsigned int last_index = CurrentSetSize - 1; int last_fd = events[last_index].fd; if (index != last_index) { // We need to move the last fd we got into this gap (gaps are evil!) // So update the mapping for the last fd to its new position fd_mappings[last_fd] = index; // move last_fd from last_index into index events[index].fd = last_fd; events[index].events = events[last_index].events; } // Now remove all data for the last fd we got into out list. // Above code made sure this always is right fd_mappings[fd] = -1; events[last_index].fd = 0; events[last_index].events = 0; SocketEngine::DelFdRef(eh); ServerInstance->Logs->Log("SOCKET", LOG_DEBUG, "Remove file descriptor: %d (index: %d) " "(Filled gap with: %d (index: %d))", fd, index, last_fd, last_index); } int SocketEngine::DispatchEvents() { int i = poll(&events[0], CurrentSetSize, 1000); int processed = 0; ServerInstance->UpdateTime(); for (size_t index = 0; index < CurrentSetSize && processed < i; index++) { struct pollfd& pfd = events[index]; // Copy these in case the vector gets resized and pfd invalidated const int fd = pfd.fd; const short revents = pfd.revents; if (revents) processed++; EventHandler* eh = GetRef(fd); if (!eh) continue; if (revents & POLLHUP) { eh->OnEventHandlerError(0); continue; } if (revents & POLLERR) { // Get error number socklen_t codesize = sizeof(int); int errcode; if (getsockopt(fd, SOL_SOCKET, SO_ERROR, &errcode, &codesize) < 0) errcode = errno; eh->OnEventHandlerError(errcode); continue; } if (revents & POLLIN) { eh->SetEventMask(eh->GetEventMask() & ~FD_READ_WILL_BLOCK); eh->OnEventHandlerRead(); if (eh != GetRef(fd)) // whoops, deleted out from under us continue; } if (revents & POLLOUT) { int mask = eh->GetEventMask(); mask &= ~(FD_WRITE_WILL_BLOCK | FD_WANT_SINGLE_WRITE); eh->SetEventMask(mask); // The vector could've been resized, reference can be invalid by now; don't use it events[index].events = mask_to_poll(mask); eh->OnEventHandlerWrite(); } } return i; } ����������������������������inspircd-3.4.0/src/socketengines/socketengine_select.cpp��������������������������������������������0000664�0000000�0000000�00000007376�13554550454�0023531�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * InspIRCd -- Internet Relay Chat Daemon * * Copyright (C) 2014 Adam <Adam@anope.org> * Copyright (C) 2009 Daniel De Graaf <danieldg@inspircd.org> * Copyright (C) 2007-2008 Craig Edwards <craigedwards@brainbox.cc> * * This file is part of InspIRCd. InspIRCd is free software: you can * redistribute it and/or modify it under the terms of the GNU General Public * License as published by the Free Software Foundation, version 2. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include "inspircd.h" #ifndef _WIN32 #include <sys/select.h> #endif // _WIN32 /** A specialisation of the SocketEngine class, designed to use traditional select(). */ namespace { fd_set ReadSet, WriteSet, ErrSet; int MaxFD = 0; } void SocketEngine::Init() { MaxSetSize = FD_SETSIZE; FD_ZERO(&ReadSet); FD_ZERO(&WriteSet); FD_ZERO(&ErrSet); } void SocketEngine::Deinit() { } void SocketEngine::RecoverFromFork() { } bool SocketEngine::AddFd(EventHandler* eh, int event_mask) { int fd = eh->GetFd(); if (fd < 0) return false; if (static_cast<size_t>(fd) >= GetMaxFds()) return false; if (!SocketEngine::AddFdRef(eh)) return false; eh->SetEventMask(event_mask); OnSetEvent(eh, 0, event_mask); FD_SET(fd, &ErrSet); if (fd > MaxFD) MaxFD = fd; ServerInstance->Logs->Log("SOCKET", LOG_DEBUG, "New file descriptor: %d", fd); return true; } void SocketEngine::DelFd(EventHandler* eh) { int fd = eh->GetFd(); if (fd < 0) return; if (static_cast<size_t>(fd) >= GetMaxFds()) return; SocketEngine::DelFdRef(eh); FD_CLR(fd, &ReadSet); FD_CLR(fd, &WriteSet); FD_CLR(fd, &ErrSet); if (fd == MaxFD) --MaxFD; ServerInstance->Logs->Log("SOCKET", LOG_DEBUG, "Remove file descriptor: %d", fd); } void SocketEngine::OnSetEvent(EventHandler* eh, int old_mask, int new_mask) { int fd = eh->GetFd(); int diff = old_mask ^ new_mask; if (diff & (FD_WANT_POLL_READ | FD_WANT_FAST_READ)) { if (new_mask & (FD_WANT_POLL_READ | FD_WANT_FAST_READ)) FD_SET(fd, &ReadSet); else FD_CLR(fd, &ReadSet); } if (diff & (FD_WANT_POLL_WRITE | FD_WANT_FAST_WRITE | FD_WANT_SINGLE_WRITE)) { if (new_mask & (FD_WANT_POLL_WRITE | FD_WANT_FAST_WRITE | FD_WANT_SINGLE_WRITE)) FD_SET(fd, &WriteSet); else FD_CLR(fd, &WriteSet); } } int SocketEngine::DispatchEvents() { timeval tval; tval.tv_sec = 1; tval.tv_usec = 0; fd_set rfdset = ReadSet, wfdset = WriteSet, errfdset = ErrSet; int sresult = select(MaxFD + 1, &rfdset, &wfdset, &errfdset, &tval); ServerInstance->UpdateTime(); for (int i = 0, j = sresult; i <= MaxFD && j > 0; i++) { int has_read = FD_ISSET(i, &rfdset), has_write = FD_ISSET(i, &wfdset), has_error = FD_ISSET(i, &errfdset); if (!(has_read || has_write || has_error)) continue; --j; EventHandler* ev = GetRef(i); if (!ev) continue; if (has_error) { stats.ErrorEvents++; socklen_t codesize = sizeof(int); int errcode = 0; if (getsockopt(i, SOL_SOCKET, SO_ERROR, (char*)&errcode, &codesize) < 0) errcode = errno; ev->OnEventHandlerError(errcode); continue; } if (has_read) { ev->SetEventMask(ev->GetEventMask() & ~FD_READ_WILL_BLOCK); ev->OnEventHandlerRead(); if (ev != GetRef(i)) continue; } if (has_write) { int newmask = (ev->GetEventMask() & ~(FD_WRITE_WILL_BLOCK | FD_WANT_SINGLE_WRITE)); SocketEngine::OnSetEvent(ev, ev->GetEventMask(), newmask); ev->SetEventMask(newmask); ev->OnEventHandlerWrite(); } } return sresult; } ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/src/threadengine.cpp�����������������������������������������������������������������0000664�0000000�0000000�00000001542�13554550454�0017275�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * InspIRCd -- Internet Relay Chat Daemon * * Copyright (C) 2008 Craig Edwards <craigedwards@brainbox.cc> * * This file is part of InspIRCd. InspIRCd is free software: you can * redistribute it and/or modify it under the terms of the GNU General Public * License as published by the Free Software Foundation, version 2. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include "inspircd.h" void Thread::SetExitFlag() { ExitFlag = true; } void Thread::join() { ServerInstance->Threads.Stop(this); } ��������������������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/src/threadengines/�������������������������������������������������������������������0000775�0000000�0000000�00000000000�13554550454�0016752�5����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/src/threadengines/threadengine_pthread.cpp�������������������������������������������0000664�0000000�0000000�00000007124�13554550454�0023626�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * InspIRCd -- Internet Relay Chat Daemon * * Copyright (C) 2009-2010 Daniel De Graaf <danieldg@inspircd.org> * Copyright (C) 2008 Craig Edwards <craigedwards@brainbox.cc> * * This file is part of InspIRCd. InspIRCd is free software: you can * redistribute it and/or modify it under the terms of the GNU General Public * License as published by the Free Software Foundation, version 2. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include "inspircd.h" #include "threadengines/threadengine_pthread.h" #include <pthread.h> #include <fcntl.h> static void* entry_point(void* parameter) { /* Recommended by nenolod, signal safety on a per-thread basis */ sigset_t set; sigemptyset(&set); sigaddset(&set, SIGPIPE); pthread_sigmask(SIG_BLOCK, &set, NULL); Thread* pt = static_cast<Thread*>(parameter); pt->Run(); return parameter; } void ThreadEngine::Start(Thread* thread) { if (pthread_create(&thread->state.pthread_id, NULL, entry_point, thread) != 0) throw CoreException("Unable to create new thread: " + std::string(strerror(errno))); } void ThreadEngine::Stop(Thread* thread) { thread->SetExitFlag(); pthread_join(thread->state.pthread_id, NULL); } #ifdef HAS_EVENTFD #include <sys/eventfd.h> class ThreadSignalSocket : public EventHandler { SocketThread* parent; public: ThreadSignalSocket(SocketThread* p, int newfd) : parent(p) { SetFd(newfd); SocketEngine::AddFd(this, FD_WANT_FAST_READ | FD_WANT_NO_WRITE); } ~ThreadSignalSocket() { SocketEngine::Close(this); } void Notify() { eventfd_write(fd, 1); } void OnEventHandlerRead() CXX11_OVERRIDE { eventfd_t dummy; eventfd_read(fd, &dummy); parent->OnNotify(); } void OnEventHandlerWrite() CXX11_OVERRIDE { ServerInstance->GlobalCulls.AddItem(this); } void OnEventHandlerError(int errcode) CXX11_OVERRIDE { ThreadSignalSocket::OnEventHandlerWrite(); } }; SocketThread::SocketThread() { signal.sock = NULL; int fd = eventfd(0, EFD_NONBLOCK); if (fd < 0) throw CoreException("Could not create pipe " + std::string(strerror(errno))); signal.sock = new ThreadSignalSocket(this, fd); } #else class ThreadSignalSocket : public EventHandler { SocketThread* parent; int send_fd; public: ThreadSignalSocket(SocketThread* p, int recvfd, int sendfd) : parent(p), send_fd(sendfd) { SetFd(recvfd); SocketEngine::NonBlocking(fd); SocketEngine::AddFd(this, FD_WANT_FAST_READ | FD_WANT_NO_WRITE); } ~ThreadSignalSocket() { close(send_fd); SocketEngine::Close(this); } void Notify() { static const char dummy = '*'; write(send_fd, &dummy, 1); } void OnEventHandlerRead() CXX11_OVERRIDE { char dummy[128]; read(fd, dummy, 128); parent->OnNotify(); } void OnEventHandlerWrite() CXX11_OVERRIDE { ServerInstance->GlobalCulls.AddItem(this); } void OnEventHandlerError(int errcode) CXX11_OVERRIDE { ThreadSignalSocket::OnEventHandlerWrite(); } }; SocketThread::SocketThread() { signal.sock = NULL; int fds[2]; if (pipe(fds)) throw CoreException("Could not create pipe " + std::string(strerror(errno))); signal.sock = new ThreadSignalSocket(this, fds[0], fds[1]); } #endif void SocketThread::NotifyParent() { signal.sock->Notify(); } SocketThread::~SocketThread() { if (signal.sock) { signal.sock->cull(); delete signal.sock; } } ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/src/threadengines/threadengine_win32.cpp���������������������������������������������0000664�0000000�0000000�00000006506�13554550454�0023144�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * InspIRCd -- Internet Relay Chat Daemon * * Copyright (C) 2009 Daniel De Graaf <danieldg@inspircd.org> * Copyright (C) 2008 Craig Edwards <craigedwards@brainbox.cc> * * This file is part of InspIRCd. InspIRCd is free software: you can * redistribute it and/or modify it under the terms of the GNU General Public * License as published by the Free Software Foundation, version 2. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include "inspircd.h" #include "threadengines/threadengine_win32.h" void ThreadEngine::Start(Thread* thread) { thread->state.handle = CreateThread(NULL, 0, ThreadEngine::Entry, thread, 0, NULL); if (thread->state.handle == NULL) { DWORD lasterr = GetLastError(); std::string err = "Unable to create new thread: " + ConvToStr(lasterr); SetLastError(ERROR_SUCCESS); throw CoreException(err); } } DWORD WINAPI ThreadEngine::Entry(void* parameter) { Thread* pt = static_cast<Thread*>(parameter); pt->Run(); return 0; } void ThreadEngine::Stop(Thread* thread) { thread->SetExitFlag(); HANDLE handle = thread->state.handle; WaitForSingleObject(handle,INFINITE); CloseHandle(handle); } class ThreadSignalSocket : public BufferedSocket { SocketThread* parent; public: ThreadSignalSocket(SocketThread* t, int newfd) : BufferedSocket(newfd), parent(t) { } void OnDataReady() { recvq.clear(); parent->OnNotify(); } void OnError(BufferedSocketError) { ServerInstance->GlobalCulls.AddItem(this); } }; static bool BindAndListen(int sockfd, int port, const char* addr) { irc::sockets::sockaddrs servaddr; if (!irc::sockets::aptosa(addr, port, servaddr)) return false; if (SocketEngine::Bind(sockfd, servaddr) != 0) return false; if (SocketEngine::Listen(sockfd, ServerInstance->Config->MaxConn) != 0) { ServerInstance->Logs->Log("SOCKET", LOG_DEFAULT, "ERROR in listen(): %s", strerror(errno)); return false; } return true; } SocketThread::SocketThread() { int listenFD = socket(AF_INET, SOCK_STREAM, 0); if (listenFD == -1) throw CoreException("Could not create ITC pipe"); int connFD = socket(AF_INET, SOCK_STREAM, 0); if (connFD == -1) throw CoreException("Could not create ITC pipe"); if (!BindAndListen(listenFD, 0, "127.0.0.1")) throw CoreException("Could not create ITC pipe"); SocketEngine::NonBlocking(connFD); struct sockaddr_in addr; socklen_t sz = sizeof(addr); getsockname(listenFD, reinterpret_cast<struct sockaddr*>(&addr), &sz); connect(connFD, reinterpret_cast<struct sockaddr*>(&addr), sz); SocketEngine::Blocking(listenFD); int nfd = accept(listenFD, reinterpret_cast<struct sockaddr*>(&addr), &sz); if (nfd < 0) throw CoreException("Could not create ITC pipe"); new ThreadSignalSocket(this, nfd); closesocket(listenFD); SocketEngine::Blocking(connFD); this->signal.connFD = connFD; } void SocketThread::NotifyParent() { char dummy = '*'; send(signal.connFD, &dummy, 1, 0); } SocketThread::~SocketThread() { if (signal.connFD >= 0) { shutdown(signal.connFD, 2); closesocket(signal.connFD); } } ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/src/timer.cpp������������������������������������������������������������������������0000664�0000000�0000000�00000004030�13554550454�0015753�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * InspIRCd -- Internet Relay Chat Daemon * * Copyright (C) 2008 Robin Burchell <robin+git@viroteck.net> * Copyright (C) 2007 Dennis Friis <peavey@inspircd.org> * Copyright (C) 2006-2007 Craig Edwards <craigedwards@brainbox.cc> * Copyright (C) 2006 Oliver Lupton <oliverlupton@gmail.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 "inspircd.h" void Timer::SetInterval(unsigned int newinterval) { ServerInstance->Timers.DelTimer(this); secs = newinterval; SetTrigger(ServerInstance->Time() + newinterval); ServerInstance->Timers.AddTimer(this); } Timer::Timer(unsigned int secs_from_now, bool repeating) : trigger(ServerInstance->Time() + secs_from_now) , secs(secs_from_now) , repeat(repeating) { } Timer::~Timer() { ServerInstance->Timers.DelTimer(this); } void TimerManager::TickTimers(time_t TIME) { for (TimerMap::iterator i = Timers.begin(); i != Timers.end(); ) { Timer* t = i->second; if (t->GetTrigger() > TIME) break; Timers.erase(i++); if (!t->Tick(TIME)) continue; if (t->GetRepeat()) { t->SetTrigger(TIME + t->GetInterval()); AddTimer(t); } } } void TimerManager::DelTimer(Timer* t) { std::pair<TimerMap::iterator, TimerMap::iterator> itpair = Timers.equal_range(t->GetTrigger()); for (TimerMap::iterator i = itpair.first; i != itpair.second; ++i) { if (i->second == t) { Timers.erase(i); break; } } } void TimerManager::AddTimer(Timer* t) { Timers.insert(std::make_pair(t->GetTrigger(), t)); } ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/src/usermanager.cpp������������������������������������������������������������������0000664�0000000�0000000�00000027327�13554550454�0017162�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * InspIRCd -- Internet Relay Chat Daemon * * Copyright (C) 2009-2010 Daniel De Graaf <danieldg@inspircd.org> * Copyright (C) 2008 Dennis Friis <peavey@inspircd.org> * Copyright (C) 2008 Robin Burchell <robin+git@viroteck.net> * Copyright (C) 2008 Craig Edwards <craigedwards@brainbox.cc> * * This file is part of InspIRCd. InspIRCd is free software: you can * redistribute it and/or modify it under the terms of the GNU General Public * License as published by the Free Software Foundation, version 2. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include "inspircd.h" #include "xline.h" #include "iohook.h" namespace { class WriteCommonQuit : public User::ForEachNeighborHandler { ClientProtocol::Messages::Quit quitmsg; ClientProtocol::Event quitevent; ClientProtocol::Messages::Quit operquitmsg; ClientProtocol::Event operquitevent; void Execute(LocalUser* user) CXX11_OVERRIDE { user->Send(user->IsOper() ? operquitevent : quitevent); } public: WriteCommonQuit(User* user, const std::string& msg, const std::string& opermsg) : quitmsg(user, msg) , quitevent(ServerInstance->GetRFCEvents().quit, quitmsg) , operquitmsg(user, opermsg) , operquitevent(ServerInstance->GetRFCEvents().quit, operquitmsg) { user->ForEachNeighbor(*this, false); } }; void CheckPingTimeout(LocalUser* user) { // Check if it is time to ping the user yet. if (ServerInstance->Time() < user->nextping) return; // This user didn't answer the last ping, remove them. if (!user->lastping) { ModResult res; FIRST_MOD_RESULT(OnConnectionFail, res, (user, I_ERR_TIMEOUT)); if (res == MOD_RES_ALLOW) { // A module is preventing this user from being timed out. user->lastping = 1; user->nextping = ServerInstance->Time() + user->MyClass->GetPingTime(); return; } time_t secs = ServerInstance->Time() - (user->nextping - user->MyClass->GetPingTime()); const std::string message = "Ping timeout: " + ConvToStr(secs) + (secs != 1 ? " seconds" : " second"); ServerInstance->Users.QuitUser(user, message); return; } // Send a ping to the client. ClientProtocol::Messages::Ping ping; user->Send(ServerInstance->GetRFCEvents().ping, ping); user->lastping = 0; user->nextping = ServerInstance->Time() + user->MyClass->GetPingTime(); } void CheckRegistrationTimeout(LocalUser* user) { if (user->GetClass() && (ServerInstance->Time() > (user->signon + user->GetClass()->GetRegTimeout()))) { // Either the user did not send NICK/USER or a module blocked registration in // OnCheckReady until the client timed out. ServerInstance->Users.QuitUser(user, "Registration timeout"); } } void CheckModulesReady(LocalUser* user) { ModResult res; FIRST_MOD_RESULT(OnCheckReady, res, (user)); if (res == MOD_RES_PASSTHRU) { // User has sent NICK/USER and modules are ready. user->FullConnect(); return; } // If the user has been quit in OnCheckReady then we shouldn't quit // them again for having a registration timeout. if (!user->quitting) CheckRegistrationTimeout(user); } } UserManager::UserManager() : already_sent_id(0) , unregistered_count(0) { } UserManager::~UserManager() { for (user_hash::iterator i = clientlist.begin(); i != clientlist.end(); ++i) { delete i->second; } } void UserManager::AddUser(int socket, ListenSocket* via, irc::sockets::sockaddrs* client, irc::sockets::sockaddrs* server) { // User constructor allocates a new UUID for the user and inserts it into the uuidlist LocalUser* const New = new LocalUser(socket, client, server); UserIOHandler* eh = &New->eh; ServerInstance->Logs->Log("USERS", LOG_DEBUG, "New user fd: %d", socket); this->unregistered_count++; this->clientlist[New->nick] = New; this->AddClone(New); this->local_users.push_front(New); FOREACH_MOD(OnUserInit, (New)); if (!SocketEngine::AddFd(eh, FD_WANT_FAST_READ | FD_WANT_EDGE_WRITE)) { ServerInstance->Logs->Log("USERS", LOG_DEBUG, "Internal error on new connection"); this->QuitUser(New, "Internal error handling connection"); return; } // If this listener has an IO hook provider set then tell it about the connection for (ListenSocket::IOHookProvList::iterator i = via->iohookprovs.begin(); i != via->iohookprovs.end(); ++i) { ListenSocket::IOHookProvRef& iohookprovref = *i; if (!iohookprovref) continue; iohookprovref->OnAccept(eh, client, server); // IOHook could have encountered a fatal error, e.g. if the TLS ClientHello was already in the queue and there was no common TLS version if (!eh->getError().empty()) { QuitUser(New, eh->getError()); return; } } if (this->local_users.size() > ServerInstance->Config->SoftLimit) { ServerInstance->SNO->WriteToSnoMask('a', "Warning: softlimit value has been reached: %d clients", ServerInstance->Config->SoftLimit); this->QuitUser(New,"No more connections allowed"); return; } // First class check. We do this again in LocalUser::FullConnect() after DNS is done, and NICK/USER is received. New->SetClass(); // If the user doesn't have an acceptable connect class CheckClass() quits them New->CheckClass(ServerInstance->Config->CCOnConnect); if (New->quitting) return; /* * even with bancache, we still have to keep User::exempt current. * besides that, if we get a positive bancache hit, we still won't fuck * them over if they are exempt. -- w00t */ New->exempt = (ServerInstance->XLines->MatchesLine("E",New) != NULL); BanCacheHit* const b = ServerInstance->BanCache.GetHit(New->GetIPString()); if (b) { if (!b->Type.empty() && !New->exempt) { /* user banned */ ServerInstance->Logs->Log("BANCACHE", LOG_DEBUG, "BanCache: Positive hit for " + New->GetIPString()); if (!ServerInstance->Config->XLineMessage.empty()) New->WriteNumeric(ERR_YOUREBANNEDCREEP, ServerInstance->Config->XLineMessage); if (ServerInstance->Config->HideBans) this->QuitUser(New, b->Type + "-lined", &b->Reason); else this->QuitUser(New, b->Reason); return; } else { ServerInstance->Logs->Log("BANCACHE", LOG_DEBUG, "BanCache: Negative hit for " + New->GetIPString()); } } else { if (!New->exempt) { XLine* r = ServerInstance->XLines->MatchesLine("Z",New); if (r) { r->Apply(New); return; } } } if (ServerInstance->Config->RawLog) New->WriteNotice("*** Raw I/O logging is enabled on this server. All messages, passwords, and commands are being recorded."); FOREACH_MOD(OnSetUserIP, (New)); if (!New->quitting) FOREACH_MOD(OnUserPostInit, (New)); } void UserManager::QuitUser(User* user, const std::string& quitmessage, const std::string* operquitmessage) { if (user->quitting) { ServerInstance->Logs->Log("USERS", LOG_DEFAULT, "ERROR: Tried to quit quitting user: " + user->nick); return; } if (IS_SERVER(user)) { ServerInstance->Logs->Log("USERS", LOG_DEFAULT, "ERROR: Tried to quit server user: " + user->nick); return; } std::string quitmsg(quitmessage); std::string operquitmsg; if (operquitmessage) operquitmsg.assign(*operquitmessage); LocalUser* const localuser = IS_LOCAL(user); if (localuser) { ModResult MOD_RESULT; FIRST_MOD_RESULT(OnUserPreQuit, MOD_RESULT, (localuser, quitmsg, operquitmsg)); if (MOD_RESULT == MOD_RES_DENY) return; } if (quitmsg.length() > ServerInstance->Config->Limits.MaxQuit) quitmsg.erase(ServerInstance->Config->Limits.MaxQuit + 1); if (operquitmsg.empty()) operquitmsg.assign(quitmsg); else if (operquitmsg.length() > ServerInstance->Config->Limits.MaxQuit) operquitmsg.erase(ServerInstance->Config->Limits.MaxQuit + 1); user->quitting = true; ServerInstance->Logs->Log("USERS", LOG_DEBUG, "QuitUser: %s=%s '%s'", user->uuid.c_str(), user->nick.c_str(), quitmessage.c_str()); if (localuser) { ClientProtocol::Messages::Error errormsg(InspIRCd::Format("Closing link: (%s@%s) [%s]", user->ident.c_str(), user->GetRealHost().c_str(), operquitmsg.c_str())); localuser->Send(ServerInstance->GetRFCEvents().error, errormsg); } ServerInstance->GlobalCulls.AddItem(user); if (user->registered == REG_ALL) { FOREACH_MOD(OnUserQuit, (user, quitmsg, operquitmsg)); WriteCommonQuit(user, quitmsg, operquitmsg); } else unregistered_count--; if (IS_LOCAL(user)) { LocalUser* lu = IS_LOCAL(user); FOREACH_MOD(OnUserDisconnect, (lu)); lu->eh.Close(); if (lu->registered == REG_ALL) ServerInstance->SNO->WriteToSnoMask('q',"Client exiting: %s (%s) [%s]", user->GetFullRealHost().c_str(), user->GetIPString().c_str(), operquitmsg.c_str()); local_users.erase(lu); } if (!clientlist.erase(user->nick)) ServerInstance->Logs->Log("USERS", LOG_DEFAULT, "ERROR: Nick not found in clientlist, cannot remove: " + user->nick); uuidlist.erase(user->uuid); user->PurgeEmptyChannels(); user->UnOper(); } void UserManager::AddClone(User* user) { CloneCounts& counts = clonemap[user->GetCIDRMask()]; counts.global++; if (IS_LOCAL(user)) counts.local++; } void UserManager::RemoveCloneCounts(User *user) { CloneMap::iterator it = clonemap.find(user->GetCIDRMask()); if (it != clonemap.end()) { CloneCounts& counts = it->second; counts.global--; if (counts.global == 0) { // No more users from this IP, remove entry from the map clonemap.erase(it); return; } if (IS_LOCAL(user)) counts.local--; } } void UserManager::RehashCloneCounts() { clonemap.clear(); const user_hash& hash = ServerInstance->Users.GetUsers(); for (user_hash::const_iterator i = hash.begin(); i != hash.end(); ++i) { User* u = i->second; AddClone(u); } } const UserManager::CloneCounts& UserManager::GetCloneCounts(User* user) const { CloneMap::const_iterator it = clonemap.find(user->GetCIDRMask()); if (it != clonemap.end()) return it->second; else return zeroclonecounts; } void UserManager::ServerNoticeAll(const char* text, ...) { std::string message; VAFORMAT(message, text, text); ClientProtocol::Messages::Privmsg msg(ClientProtocol::Messages::Privmsg::nocopy, ServerInstance->FakeClient, ServerInstance->Config->ServerName, message, MSG_NOTICE); ClientProtocol::Event msgevent(ServerInstance->GetRFCEvents().privmsg, msg); for (LocalList::const_iterator i = local_users.begin(); i != local_users.end(); ++i) { LocalUser* user = *i; user->Send(msgevent); } } /** * This function is called once a second from the mainloop. * It is intended to do background checking on all the users, e.g. do * ping checks, registration timeouts, etc. */ void UserManager::DoBackgroundUserStuff() { for (LocalList::iterator i = local_users.begin(); i != local_users.end(); ) { // It's possible that we quit the user below due to ping timeout etc. and QuitUser() removes it from the list LocalUser* curr = *i; ++i; if (curr->CommandFloodPenalty || curr->eh.getSendQSize()) { unsigned int rate = curr->MyClass->GetCommandRate(); if (curr->CommandFloodPenalty > rate) curr->CommandFloodPenalty -= rate; else curr->CommandFloodPenalty = 0; curr->eh.OnDataReady(); } switch (curr->registered) { case REG_ALL: CheckPingTimeout(curr); break; case REG_NICKUSER: CheckModulesReady(curr); break; default: CheckRegistrationTimeout(curr); break; } } } already_sent_t UserManager::NextAlreadySentId() { if (++already_sent_id == 0) { // Wrapped around, reset the already_sent ids of all users already_sent_id = 1; for (LocalList::iterator i = local_users.begin(); i != local_users.end(); ++i) { LocalUser* user = *i; user->already_sent = 0; } } return already_sent_id; } ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/src/users.cpp������������������������������������������������������������������������0000664�0000000�0000000�00000105433�13554550454�0016005�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * InspIRCd -- Internet Relay Chat Daemon * * Copyright (C) 2009-2010 Daniel De Graaf <danieldg@inspircd.org> * Copyright (C) 2006-2009 Robin Burchell <robin+git@viroteck.net> * Copyright (C) 2006-2007, 2009 Dennis Friis <peavey@inspircd.org> * Copyright (C) 2008 John Brooks <john.brooks@dereferenced.net> * Copyright (C) 2008 Thomas Stagner <aquanight@inspircd.org> * Copyright (C) 2008 Oliver Lupton <oliverlupton@gmail.com> * Copyright (C) 2003-2008 Craig Edwards <craigedwards@brainbox.cc> * * This file is part of InspIRCd. InspIRCd is free software: you can * redistribute it and/or modify it under the terms of the GNU General Public * License as published by the Free Software Foundation, version 2. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include "inspircd.h" #include "xline.h" ClientProtocol::MessageList LocalUser::sendmsglist; bool User::IsNoticeMaskSet(unsigned char sm) { if (!isalpha(sm)) return false; return (snomasks[sm-65]); } bool User::IsModeSet(unsigned char m) const { ModeHandler* mh = ServerInstance->Modes->FindMode(m, MODETYPE_USER); return (mh && modes[mh->GetId()]); } std::string User::GetModeLetters(bool includeparams) const { std::string ret(1, '+'); std::string params; for (unsigned char i = 'A'; i <= 'z'; i++) { const ModeHandler* const mh = ServerInstance->Modes.FindMode(i, MODETYPE_USER); if ((!mh) || (!IsModeSet(mh))) continue; ret.push_back(mh->GetModeChar()); if ((includeparams) && (mh->NeedsParam(true))) { const std::string val = mh->GetUserParameter(this); if (!val.empty()) params.append(1, ' ').append(val); } } ret += params; return ret; } User::User(const std::string& uid, Server* srv, UserType type) : age(ServerInstance->Time()) , signon(0) , uuid(uid) , server(srv) , registered(REG_NONE) , quitting(false) , usertype(type) { client_sa.sa.sa_family = AF_UNSPEC; ServerInstance->Logs->Log("USERS", LOG_DEBUG, "New UUID for user: %s", uuid.c_str()); // Do not insert FakeUsers into the uuidlist so FindUUID() won't return them which is the desired behavior if (type != USERTYPE_SERVER) { if (!ServerInstance->Users.uuidlist.insert(std::make_pair(uuid, this)).second) throw CoreException("Duplicate UUID in User constructor: " + uuid); } } LocalUser::LocalUser(int myfd, irc::sockets::sockaddrs* client, irc::sockets::sockaddrs* servaddr) : User(ServerInstance->UIDGen.GetUID(), ServerInstance->FakeClient->server, USERTYPE_LOCAL) , eh(this) , serializer(NULL) , bytes_in(0) , bytes_out(0) , cmds_in(0) , cmds_out(0) , quitting_sendq(false) , lastping(true) , exempt(false) , nextping(0) , idle_lastmsg(0) , CommandFloodPenalty(0) , already_sent(0) { signon = ServerInstance->Time(); // The user's default nick is their UUID nick = uuid; ident = uuid; eh.SetFd(myfd); memcpy(&client_sa, client, sizeof(irc::sockets::sockaddrs)); memcpy(&server_sa, servaddr, sizeof(irc::sockets::sockaddrs)); ChangeRealHost(GetIPString(), true); } LocalUser::LocalUser(int myfd, const std::string& uid, Serializable::Data& data) : User(uid, ServerInstance->FakeClient->server, USERTYPE_LOCAL) , eh(this) , already_sent(0) { eh.SetFd(myfd); Deserialize(data); } User::~User() { } const std::string& User::MakeHost() { if (!this->cached_makehost.empty()) return this->cached_makehost; this->cached_makehost = ident + "@" + GetRealHost(); return this->cached_makehost; } const std::string& User::MakeHostIP() { if (!this->cached_hostip.empty()) return this->cached_hostip; this->cached_hostip = ident + "@" + this->GetIPString(); return this->cached_hostip; } const std::string& User::GetFullHost() { if (!this->cached_fullhost.empty()) return this->cached_fullhost; this->cached_fullhost = nick + "!" + ident + "@" + GetDisplayedHost(); return this->cached_fullhost; } const std::string& User::GetFullRealHost() { if (!this->cached_fullrealhost.empty()) return this->cached_fullrealhost; this->cached_fullrealhost = nick + "!" + ident + "@" + GetRealHost(); return this->cached_fullrealhost; } bool User::HasModePermission(const ModeHandler* mh) const { return true; } bool LocalUser::HasModePermission(const ModeHandler* mh) const { if (!this->IsOper()) return false; const unsigned char mode = mh->GetModeChar(); if (!ModeParser::IsModeChar(mode)) return false; return ((mh->GetModeType() == MODETYPE_USER ? oper->AllowedUserModes : oper->AllowedChanModes))[(mode - 'A')]; } /* * users on remote servers can completely bypass all permissions based checks. * This prevents desyncs when one server has different type/class tags to another. * That having been said, this does open things up to the possibility of source changes * allowing remote kills, etc - but if they have access to the src, they most likely have * access to the conf - so it's an end to a means either way. */ bool User::HasCommandPermission(const std::string&) { return true; } bool LocalUser::HasCommandPermission(const std::string& command) { // are they even an oper at all? if (!this->IsOper()) { return false; } return oper->AllowedOperCommands.Contains(command); } bool User::HasPrivPermission(const std::string& privstr) { return true; } bool LocalUser::HasPrivPermission(const std::string& privstr) { if (!this->IsOper()) return false; return oper->AllowedPrivs.Contains(privstr); } void UserIOHandler::OnDataReady() { if (user->quitting) return; if (recvq.length() > user->MyClass->GetRecvqMax() && !user->HasPrivPermission("users/flood/increased-buffers")) { ServerInstance->Users->QuitUser(user, "RecvQ exceeded"); ServerInstance->SNO->WriteToSnoMask('a', "User %s RecvQ of %lu exceeds connect class maximum of %lu", user->nick.c_str(), (unsigned long)recvq.length(), user->MyClass->GetRecvqMax()); return; } unsigned long sendqmax = ULONG_MAX; if (!user->HasPrivPermission("users/flood/increased-buffers")) sendqmax = user->MyClass->GetSendqSoftMax(); unsigned long penaltymax = ULONG_MAX; if (!user->HasPrivPermission("users/flood/no-fakelag")) penaltymax = user->MyClass->GetPenaltyThreshold() * 1000; // The cleaned message sent by the user or empty if not found yet. std::string line; // The position of the most \n character or npos if not found yet. std::string::size_type eolpos; // The position within the recvq of the current character. std::string::size_type qpos; while (user->CommandFloodPenalty < penaltymax && getSendQSize() < sendqmax) { // Check the newly received data for an EOL. eolpos = recvq.find('\n', checked_until); if (eolpos == std::string::npos) { checked_until = recvq.length(); return; } // We've found a line! Clean it up and move it to the line buffer. line.reserve(eolpos); for (qpos = 0; qpos < eolpos; ++qpos) { char c = recvq[qpos]; switch (c) { case '\0': c = ' '; break; case '\r': continue; } line.push_back(c); } // just found a newline. Terminate the string, and pull it out of recvq recvq.erase(0, eolpos + 1); checked_until = 0; // TODO should this be moved to when it was inserted in recvq? ServerInstance->stats.Recv += qpos; user->bytes_in += qpos; user->cmds_in++; ServerInstance->Parser.ProcessBuffer(user, line); if (user->quitting) return; // clear() does not reclaim memory associated with the string, so our .reserve() call is safe line.clear(); } if (user->CommandFloodPenalty >= penaltymax && !user->MyClass->fakelag) ServerInstance->Users->QuitUser(user, "Excess Flood"); } void UserIOHandler::AddWriteBuf(const std::string &data) { if (user->quitting_sendq) return; if (!user->quitting && getSendQSize() + data.length() > user->MyClass->GetSendqHardMax() && !user->HasPrivPermission("users/flood/increased-buffers")) { user->quitting_sendq = true; ServerInstance->GlobalCulls.AddSQItem(user); return; } // We still want to append data to the sendq of a quitting user, // e.g. their ERROR message that says 'closing link' WriteData(data); } void UserIOHandler::SwapInternals(UserIOHandler& other) { StreamSocket::SwapInternals(other); std::swap(checked_until, other.checked_until); } bool UserIOHandler::OnSetEndPoint(const irc::sockets::sockaddrs& server, const irc::sockets::sockaddrs& client) { memcpy(&user->server_sa, &server, sizeof(irc::sockets::sockaddrs)); user->SetClientIP(client); return !user->quitting; } void UserIOHandler::OnError(BufferedSocketError sockerr) { ModResult res; FIRST_MOD_RESULT(OnConnectionFail, res, (user, sockerr)); if (res != MOD_RES_ALLOW) ServerInstance->Users->QuitUser(user, getError()); } CullResult User::cull() { if (!quitting) ServerInstance->Users->QuitUser(this, "Culled without QuitUser"); if (client_sa.family() != AF_UNSPEC) ServerInstance->Users->RemoveCloneCounts(this); return Extensible::cull(); } CullResult LocalUser::cull() { eh.cull(); return User::cull(); } CullResult FakeUser::cull() { // Fake users don't quit, they just get culled. quitting = true; // Fake users are not inserted into UserManager::clientlist or uuidlist, so we don't need to modify those here return User::cull(); } void User::Oper(OperInfo* info) { ModeHandler* opermh = ServerInstance->Modes->FindMode('o', MODETYPE_USER); if (opermh) { if (this->IsModeSet(opermh)) this->UnOper(); this->SetMode(opermh, true); } this->oper = info; LocalUser* localuser = IS_LOCAL(this); if (localuser) { Modes::ChangeList changelist; changelist.push_add(opermh); ClientProtocol::Events::Mode modemsg(ServerInstance->FakeClient, NULL, localuser, changelist); localuser->Send(modemsg); } FOREACH_MOD(OnOper, (this, info->name)); std::string opername; if (info->oper_block) opername = info->oper_block->getString("name"); ServerInstance->SNO->WriteToSnoMask('o', "%s (%s@%s) is now a server operator of type %s (using oper '%s')", nick.c_str(), ident.c_str(), GetRealHost().c_str(), oper->name.c_str(), opername.c_str()); this->WriteNumeric(RPL_YOUAREOPER, InspIRCd::Format("You are now %s %s", strchr("aeiouAEIOU", oper->name[0]) ? "an" : "a", oper->name.c_str())); ServerInstance->Users->all_opers.push_back(this); // Expand permissions from config for faster lookup if (localuser) oper->init(); FOREACH_MOD(OnPostOper, (this, oper->name, opername)); } void OperInfo::init() { AllowedOperCommands.Clear(); AllowedPrivs.Clear(); AllowedUserModes.reset(); AllowedChanModes.reset(); AllowedUserModes['o' - 'A'] = true; // Call me paranoid if you want. for(std::vector<reference<ConfigTag> >::iterator iter = class_blocks.begin(); iter != class_blocks.end(); ++iter) { ConfigTag* tag = *iter; AllowedOperCommands.AddList(tag->getString("commands")); AllowedPrivs.AddList(tag->getString("privs")); std::string modes = tag->getString("usermodes"); for (std::string::const_iterator c = modes.begin(); c != modes.end(); ++c) { if (*c == '*') { this->AllowedUserModes.set(); } else if (*c >= 'A' && *c <= 'z') { this->AllowedUserModes[*c - 'A'] = true; } } modes = tag->getString("chanmodes"); for (std::string::const_iterator c = modes.begin(); c != modes.end(); ++c) { if (*c == '*') { this->AllowedChanModes.set(); } else if (*c >= 'A' && *c <= 'z') { this->AllowedChanModes[*c - 'A'] = true; } } } } void User::UnOper() { if (!this->IsOper()) return; /* * unset their oper type (what IS_OPER checks). * note, order is important - this must come before modes as -o attempts * to call UnOper. -- w00t */ oper = NULL; // Remove the user from the oper list stdalgo::vector::swaperase(ServerInstance->Users->all_opers, this); // If the user is quitting we shouldn't remove any modes as it results in // mode messages being broadcast across the network. if (quitting) return; /* Remove all oper only modes from the user when the deoper - Bug #466*/ Modes::ChangeList changelist; const ModeParser::ModeHandlerMap& usermodes = ServerInstance->Modes->GetModes(MODETYPE_USER); for (ModeParser::ModeHandlerMap::const_iterator i = usermodes.begin(); i != usermodes.end(); ++i) { ModeHandler* mh = i->second; if (mh->NeedsOper()) changelist.push_remove(mh); } ServerInstance->Modes->Process(this, NULL, this, changelist); ModeHandler* opermh = ServerInstance->Modes->FindMode('o', MODETYPE_USER); if (opermh) this->SetMode(opermh, false); FOREACH_MOD(OnPostDeoper, (this)); } /* * Check class restrictions */ void LocalUser::CheckClass(bool clone_count) { ConnectClass* a = this->MyClass; if (!a) { ServerInstance->Users->QuitUser(this, "Access denied by configuration"); return; } else if (a->type == CC_DENY) { ServerInstance->Users->QuitUser(this, a->config->getString("reason", "Unauthorised connection")); return; } else if (clone_count) { const UserManager::CloneCounts& clonecounts = ServerInstance->Users->GetCloneCounts(this); if ((a->GetMaxLocal()) && (clonecounts.local > a->GetMaxLocal())) { ServerInstance->Users->QuitUser(this, "No more connections allowed from your host via this connect class (local)"); if (a->maxconnwarn) { ServerInstance->SNO->WriteToSnoMask('a', "WARNING: maximum local connections for the %s class (%ld) exceeded by %s", a->name.c_str(), a->GetMaxLocal(), this->GetIPString().c_str()); } return; } else if ((a->GetMaxGlobal()) && (clonecounts.global > a->GetMaxGlobal())) { ServerInstance->Users->QuitUser(this, "No more connections allowed from your host via this connect class (global)"); if (a->maxconnwarn) { ServerInstance->SNO->WriteToSnoMask('a', "WARNING: maximum global connections for the %s class (%ld) exceeded by %s", a->name.c_str(), a->GetMaxGlobal(), this->GetIPString().c_str()); } return; } } this->nextping = ServerInstance->Time() + a->GetPingTime(); } bool LocalUser::CheckLines(bool doZline) { const char* check[] = { "G" , "K", (doZline) ? "Z" : NULL, NULL }; if (!this->exempt) { for (int n = 0; check[n]; ++n) { XLine *r = ServerInstance->XLines->MatchesLine(check[n], this); if (r) { r->Apply(this); return true; } } } return false; } void LocalUser::FullConnect() { ServerInstance->stats.Connects++; this->idle_lastmsg = ServerInstance->Time(); /* * You may be thinking "wtf, we checked this in User::AddClient!" - and yes, we did, BUT. * At the time AddClient is called, we don't have a resolved host, by here we probably do - which * may put the user into a totally seperate class with different restrictions! so we *must* check again. * Don't remove this! -- w00t */ MyClass = NULL; SetClass(); CheckClass(); CheckLines(); if (quitting) return; /* * We don't set REG_ALL until triggering OnUserConnect, so some module events don't spew out stuff * for a user that doesn't exist yet. */ FOREACH_MOD(OnUserConnect, (this)); /* Now registered */ if (ServerInstance->Users->unregistered_count) ServerInstance->Users->unregistered_count--; this->registered = REG_ALL; FOREACH_MOD(OnPostConnect, (this)); ServerInstance->SNO->WriteToSnoMask('c',"Client connecting on port %d (class %s): %s (%s) [%s]", this->server_sa.port(), this->MyClass->name.c_str(), GetFullRealHost().c_str(), this->GetIPString().c_str(), this->GetRealName().c_str()); ServerInstance->Logs->Log("BANCACHE", LOG_DEBUG, "BanCache: Adding NEGATIVE hit for " + this->GetIPString()); ServerInstance->BanCache.AddHit(this->GetIPString(), "", ""); // reset the flood penalty (which could have been raised due to things like auto +x) CommandFloodPenalty = 0; } void User::InvalidateCache() { /* Invalidate cache */ cachedip.clear(); cached_fullhost.clear(); cached_hostip.clear(); cached_makehost.clear(); cached_fullrealhost.clear(); } bool User::ChangeNick(const std::string& newnick, time_t newts) { if (quitting) { ServerInstance->Logs->Log("USERS", LOG_DEFAULT, "ERROR: Attempted to change nick of a quitting user: " + this->nick); return false; } User* const InUse = ServerInstance->FindNickOnly(newnick); if (InUse == this) { // case change, don't need to check campers // and, if it's identical including case, we can leave right now // We also don't update the nick TS if it's a case change, either if (newnick == nick) return true; } else { /* * Uh oh.. if the nickname is in use, and it's not in use by the person using it (doh) -- * then we have a potential collide. Check whether someone else is camping on the nick * (i.e. connect -> send NICK, don't send USER.) If they are camping, force-change the * camper to their UID, and allow the incoming nick change. * * If the guy using the nick is already using it, tell the incoming nick change to gtfo, * because the nick is already (rightfully) in use. -- w00t */ if (InUse) { if (InUse->registered != REG_ALL) { /* force the camper to their UUID, and ask them to re-send a NICK. */ LocalUser* const localuser = static_cast<LocalUser*>(InUse); localuser->OverruleNick(); } else { /* No camping, tell the incoming user to stop trying to change nick ;p */ this->WriteNumeric(ERR_NICKNAMEINUSE, newnick, "Nickname is already in use."); return false; } } age = newts ? newts : ServerInstance->Time(); } if (this->registered == REG_ALL) { ClientProtocol::Messages::Nick nickmsg(this, newnick); ClientProtocol::Event nickevent(ServerInstance->GetRFCEvents().nick, nickmsg); this->WriteCommonRaw(nickevent, true); } const std::string oldnick = nick; nick = newnick; InvalidateCache(); ServerInstance->Users->clientlist.erase(oldnick); ServerInstance->Users->clientlist[newnick] = this; if (registered == REG_ALL) FOREACH_MOD(OnUserPostNick, (this,oldnick)); return true; } void LocalUser::OverruleNick() { { ClientProtocol::Messages::Nick nickmsg(this, this->uuid); this->Send(ServerInstance->GetRFCEvents().nick, nickmsg); } this->WriteNumeric(ERR_NICKNAMEINUSE, this->nick, "Nickname overruled."); // Clear the bit before calling ChangeNick() to make it NOT run the OnUserPostNick() hook this->registered &= ~REG_NICK; this->ChangeNick(this->uuid); } const std::string& User::GetIPString() { if (cachedip.empty()) { cachedip = client_sa.addr(); /* IP addresses starting with a : on irc are a Bad Thing (tm) */ if (cachedip[0] == ':') cachedip.insert(cachedip.begin(),1,'0'); } return cachedip; } const std::string& User::GetHost(bool uncloak) const { return uncloak ? GetRealHost() : GetDisplayedHost(); } const std::string& User::GetDisplayedHost() const { return displayhost.empty() ? realhost : displayhost; } const std::string& User::GetRealHost() const { return realhost; } const std::string& User::GetRealName() const { return realname; } irc::sockets::cidr_mask User::GetCIDRMask() { unsigned char range = 0; switch (client_sa.family()) { case AF_INET6: range = ServerInstance->Config->c_ipv6_range; break; case AF_INET: range = ServerInstance->Config->c_ipv4_range; break; } return irc::sockets::cidr_mask(client_sa, range); } bool User::SetClientIP(const std::string& address) { irc::sockets::sockaddrs sa; if (!irc::sockets::aptosa(address, client_sa.port(), sa)) return false; User::SetClientIP(sa); return true; } void User::SetClientIP(const irc::sockets::sockaddrs& sa) { const std::string oldip(GetIPString()); memcpy(&client_sa, &sa, sizeof(irc::sockets::sockaddrs)); this->InvalidateCache(); // If the users hostname was their IP then update it. if (GetRealHost() == oldip) ChangeRealHost(GetIPString(), false); if (GetDisplayedHost() == oldip) ChangeDisplayedHost(GetIPString()); } bool LocalUser::SetClientIP(const std::string& address) { irc::sockets::sockaddrs sa; if (!irc::sockets::aptosa(address, client_sa.port(), sa)) return false; LocalUser::SetClientIP(sa); return true; } void LocalUser::SetClientIP(const irc::sockets::sockaddrs& sa) { if (sa == client_sa) return; ServerInstance->Users->RemoveCloneCounts(this); User::SetClientIP(sa); ServerInstance->Users->AddClone(this); // Recheck the connect class. this->MyClass = NULL; this->SetClass(); this->CheckClass(); if (!quitting) FOREACH_MOD(OnSetUserIP, (this)); } void LocalUser::Write(const ClientProtocol::SerializedMessage& text) { if (!SocketEngine::BoundsCheckFd(&eh)) return; if (ServerInstance->Config->RawLog) { if (text.empty()) return; std::string::size_type nlpos = text.find_first_of("\r\n", 0, 2); if (nlpos == std::string::npos) nlpos = text.length(); // TODO is this ok, test it ServerInstance->Logs->Log("USEROUTPUT", LOG_RAWIO, "C[%s] O %.*s", uuid.c_str(), (int) nlpos, text.c_str()); } eh.AddWriteBuf(text); const size_t bytessent = text.length() + 2; ServerInstance->stats.Sent += bytessent; this->bytes_out += bytessent; this->cmds_out++; } void LocalUser::Send(ClientProtocol::Event& protoev) { if (!serializer) { ServerInstance->Logs->Log("USERS", LOG_DEBUG, "BUG: LocalUser::Send() called on %s who does not have a serializer!", GetFullRealHost().c_str()); return; } // In the most common case a static LocalUser field, sendmsglist, is passed to the event to be // populated. The list is cleared before returning. // To handle re-enters, if sendmsglist is non-empty upon entering the method then a temporary // list is used instead of the static one. if (sendmsglist.empty()) { Send(protoev, sendmsglist); sendmsglist.clear(); } else { ClientProtocol::MessageList msglist; Send(protoev, msglist); } } void LocalUser::Send(ClientProtocol::Event& protoev, ClientProtocol::MessageList& msglist) { // Modules can personalize the messages sent per user for the event protoev.GetMessagesForUser(this, msglist); for (ClientProtocol::MessageList::const_iterator i = msglist.begin(); i != msglist.end(); ++i) { ClientProtocol::Message& curr = **i; ModResult res; FIRST_MOD_RESULT(OnUserWrite, res, (this, curr)); if (res != MOD_RES_DENY) Write(serializer->SerializeForUser(this, curr)); } } void User::WriteNumeric(const Numeric::Numeric& numeric) { LocalUser* const localuser = IS_LOCAL(this); if (!localuser) return; ModResult MOD_RESULT; FIRST_MOD_RESULT(OnNumeric, MOD_RESULT, (this, numeric)); if (MOD_RESULT == MOD_RES_DENY) return; ClientProtocol::Messages::Numeric numericmsg(numeric, localuser); localuser->Send(ServerInstance->GetRFCEvents().numeric, numericmsg); } void User::WriteRemoteNotice(const std::string& text) { ServerInstance->PI->SendUserNotice(this, text); } void LocalUser::WriteRemoteNotice(const std::string& text) { WriteNotice(text); } namespace { class WriteCommonRawHandler : public User::ForEachNeighborHandler { ClientProtocol::Event& ev; void Execute(LocalUser* user) CXX11_OVERRIDE { user->Send(ev); } public: WriteCommonRawHandler(ClientProtocol::Event& protoev) : ev(protoev) { } }; } void User::WriteCommonRaw(ClientProtocol::Event& protoev, bool include_self) { WriteCommonRawHandler handler(protoev); ForEachNeighbor(handler, include_self); } void User::ForEachNeighbor(ForEachNeighborHandler& handler, bool include_self) { // The basic logic for visiting the neighbors of a user is to iterate the channel list of the user // and visit all users on those channels. Because two users may share more than one common channel, // we must skip users that we have already visited. // To do this, we make use of a global counter and an integral 'already_sent' field in LocalUser. // The global counter is incremented every time we do something for each neighbor of a user. Then, // before visiting a member we examine user->already_sent. If it's equal to the current counter, we // skip the member. Otherwise, we set it to the current counter and visit the member. // Ask modules to build a list of exceptions. // Mods may also exclude entire channels by erasing them from include_chans. IncludeChanList include_chans(chans.begin(), chans.end()); std::map<User*, bool> exceptions; exceptions[this] = include_self; FOREACH_MOD(OnBuildNeighborList, (this, include_chans, exceptions)); // Get next id, guaranteed to differ from the already_sent field of all users const already_sent_t newid = ServerInstance->Users.NextAlreadySentId(); // Handle exceptions first for (std::map<User*, bool>::const_iterator i = exceptions.begin(); i != exceptions.end(); ++i) { LocalUser* curr = IS_LOCAL(i->first); if (curr) { // Mark as visited to ensure we won't visit again if there is a common channel curr->already_sent = newid; // Always treat quitting users as excluded if ((i->second) && (!curr->quitting)) handler.Execute(curr); } } // Now consider the real neighbors for (IncludeChanList::const_iterator i = include_chans.begin(); i != include_chans.end(); ++i) { Channel* chan = (*i)->chan; const Channel::MemberMap& userlist = chan->GetUsers(); for (Channel::MemberMap::const_iterator j = userlist.begin(); j != userlist.end(); ++j) { LocalUser* curr = IS_LOCAL(j->first); // User not yet visited? if ((curr) && (curr->already_sent != newid)) { // Mark as visited and execute function curr->already_sent = newid; handler.Execute(curr); } } } } void User::WriteRemoteNumeric(const Numeric::Numeric& numeric) { WriteNumeric(numeric); } /* return 0 or 1 depending if users u and u2 share one or more common channels * (used by QUIT, NICK etc which arent channel specific notices) * * The old algorithm in 1.0 for this was relatively inefficient, iterating over * the first users channels then the second users channels within the outer loop, * therefore it was a maximum of x*y iterations (upon returning 0 and checking * all possible iterations). However this new function instead checks against the * channel's userlist in the inner loop which is a std::map<User*,User*> * and saves us time as we already know what pointer value we are after. * Don't quote me on the maths as i am not a mathematician or computer scientist, * but i believe this algorithm is now x+(log y) maximum iterations instead. */ bool User::SharesChannelWith(User *other) { /* Outer loop */ for (User::ChanList::iterator i = this->chans.begin(); i != this->chans.end(); ++i) { /* Eliminate the inner loop (which used to be ~equal in size to the outer loop) * by replacing it with a map::find which *should* be more efficient */ if ((*i)->chan->HasUser(other)) return true; } return false; } bool User::ChangeRealName(const std::string& real) { if (!this->realname.compare(real)) return true; if (IS_LOCAL(this)) { ModResult MOD_RESULT; FIRST_MOD_RESULT(OnPreChangeRealName, MOD_RESULT, (IS_LOCAL(this), real)); if (MOD_RESULT == MOD_RES_DENY) return false; FOREACH_MOD(OnChangeRealName, (this, real)); } this->realname.assign(real, 0, ServerInstance->Config->Limits.MaxReal); return true; } bool User::ChangeDisplayedHost(const std::string& shost) { if (GetDisplayedHost() == shost) return true; LocalUser* luser = IS_LOCAL(this); if (luser) { ModResult MOD_RESULT; FIRST_MOD_RESULT(OnPreChangeHost, MOD_RESULT, (luser, shost)); if (MOD_RESULT == MOD_RES_DENY) return false; } FOREACH_MOD(OnChangeHost, (this,shost)); if (realhost == shost) this->displayhost.clear(); else this->displayhost.assign(shost, 0, ServerInstance->Config->Limits.MaxHost); this->InvalidateCache(); if (IS_LOCAL(this) && this->registered != REG_NONE) this->WriteNumeric(RPL_YOURDISPLAYEDHOST, this->GetDisplayedHost(), "is now your displayed host"); return true; } void User::ChangeRealHost(const std::string& host, bool resetdisplay) { // If the real host is the new host and we are not resetting the // display host then we have nothing to do. const bool changehost = (realhost != host); if (!changehost && !resetdisplay) return; // If the displayhost is not set and we are not resetting it then // we need to copy it to the displayhost field. if (displayhost.empty() && !resetdisplay) displayhost = realhost; // If the displayhost is the new host or we are resetting it then // we clear its contents to save memory. else if (displayhost == host || resetdisplay) displayhost.clear(); // If we are just resetting the display host then we don't need to // do anything else. if (!changehost) return; realhost = host; this->InvalidateCache(); } bool User::ChangeIdent(const std::string& newident) { if (this->ident == newident) return true; FOREACH_MOD(OnChangeIdent, (this,newident)); this->ident.assign(newident, 0, ServerInstance->Config->Limits.IdentMax); this->InvalidateCache(); return true; } /* * Sets a user's connection class. * If the class name is provided, it will be used. Otherwise, the class will be guessed using host/ip/ident/etc. * NOTE: If the <ALLOW> or <DENY> tag specifies an ip, and this user resolves, * then their ip will be taken as 'priority' anyway, so for example, * <connect allow="127.0.0.1"> will match joe!bloggs@localhost */ void LocalUser::SetClass(const std::string &explicit_name) { ConnectClass *found = NULL; ServerInstance->Logs->Log("CONNECTCLASS", LOG_DEBUG, "Setting connect class for UID %s", this->uuid.c_str()); if (!explicit_name.empty()) { for (ServerConfig::ClassVector::const_iterator i = ServerInstance->Config->Classes.begin(); i != ServerInstance->Config->Classes.end(); ++i) { ConnectClass* c = *i; if (explicit_name == c->name) { ServerInstance->Logs->Log("CONNECTCLASS", LOG_DEBUG, "Explicitly set to %s", explicit_name.c_str()); found = c; } } } else { for (ServerConfig::ClassVector::const_iterator i = ServerInstance->Config->Classes.begin(); i != ServerInstance->Config->Classes.end(); ++i) { ConnectClass* c = *i; ServerInstance->Logs->Log("CONNECTCLASS", LOG_DEBUG, "Checking %s", c->GetName().c_str()); ModResult MOD_RESULT; FIRST_MOD_RESULT(OnSetConnectClass, MOD_RESULT, (this,c)); if (MOD_RESULT == MOD_RES_DENY) continue; if (MOD_RESULT == MOD_RES_ALLOW) { ServerInstance->Logs->Log("CONNECTCLASS", LOG_DEBUG, "Class forced by module to %s", c->GetName().c_str()); found = c; break; } if (c->type == CC_NAMED) continue; bool regdone = (registered != REG_NONE); if (c->config->getBool("registered", regdone) != regdone) continue; /* check if host matches.. */ if (!InspIRCd::MatchCIDR(this->GetIPString(), c->GetHost(), NULL) && !InspIRCd::MatchCIDR(this->GetRealHost(), c->GetHost(), NULL)) { ServerInstance->Logs->Log("CONNECTCLASS", LOG_DEBUG, "No host match (for %s)", c->GetHost().c_str()); continue; } /* * deny change if change will take class over the limit check it HERE, not after we found a matching class, * because we should attempt to find another class if this one doesn't match us. -- w00t */ if (c->limit && (c->GetReferenceCount() >= c->limit)) { ServerInstance->Logs->Log("CONNECTCLASS", LOG_DEBUG, "OOPS: Connect class limit (%lu) hit, denying", c->limit); continue; } /* if it requires a port ... */ if (!c->ports.empty()) { /* and our port doesn't match, fail. */ if (!c->ports.count(this->server_sa.port())) { ServerInstance->Logs->Log("CONNECTCLASS", LOG_DEBUG, "Requires a different port, skipping"); continue; } } if (regdone && !c->config->getString("password").empty()) { if (!ServerInstance->PassCompare(this, c->config->getString("password"), password, c->config->getString("hash"))) { ServerInstance->Logs->Log("CONNECTCLASS", LOG_DEBUG, "Bad password, skipping"); continue; } } /* we stop at the first class that meets ALL critera. */ found = c; break; } } /* * Okay, assuming we found a class that matches.. switch us into that class, keeping refcounts up to date. */ if (found) { MyClass = found; } } void User::PurgeEmptyChannels() { // firstly decrement the count on each channel for (User::ChanList::iterator i = this->chans.begin(); i != this->chans.end(); ) { Channel* c = (*i)->chan; ++i; c->DelUser(this); } } void User::WriteNotice(const std::string& text) { LocalUser* const localuser = IS_LOCAL(this); if (!localuser) return; ClientProtocol::Messages::Privmsg msg(ClientProtocol::Messages::Privmsg::nocopy, ServerInstance->FakeClient, localuser, text, MSG_NOTICE); localuser->Send(ServerInstance->GetRFCEvents().privmsg, msg); } const std::string& FakeUser::GetFullHost() { if (!ServerInstance->Config->HideServer.empty()) return ServerInstance->Config->HideServer; return server->GetName(); } const std::string& FakeUser::GetFullRealHost() { if (!ServerInstance->Config->HideServer.empty()) return ServerInstance->Config->HideServer; return server->GetName(); } ConnectClass::ConnectClass(ConfigTag* tag, char t, const std::string& mask) : config(tag) , type(t) , fakelag(true) , name("unnamed") , registration_timeout(0) , host(mask) , pingtime(0) , softsendqmax(0) , hardsendqmax(0) , recvqmax(0) , penaltythreshold(0) , commandrate(0) , maxlocal(0) , maxglobal(0) , maxconnwarn(true) , maxchans(0) , limit(0) , resolvehostnames(true) { } ConnectClass::ConnectClass(ConfigTag* tag, char t, const std::string& mask, const ConnectClass& parent) { Update(&parent); name = "unnamed"; type = t; host = mask; // Connect classes can inherit from each other but this is problematic for modules which can't use // ConnectClass::Update so we build a hybrid tag containing all of the values set on this class as // well as the parent class. ConfigItems* items = NULL; config = ConfigTag::create(tag->tag, tag->src_name, tag->src_line, items); const ConfigItems& parentkeys = parent.config->getItems(); for (ConfigItems::const_iterator piter = parentkeys.begin(); piter != parentkeys.end(); ++piter) { // The class name and parent name are not inherited if (stdalgo::string::equalsci(piter->first, "name") || stdalgo::string::equalsci(piter->first, "parent")) continue; // Store the item in the config tag. If this item also // exists in the child it will be overwritten. (*items)[piter->first] = piter->second; } const ConfigItems& childkeys = tag->getItems(); for (ConfigItems::const_iterator citer = childkeys.begin(); citer != childkeys.end(); ++citer) { // This will overwrite the parent value if present. (*items)[citer->first] = citer->second; } } void ConnectClass::Update(const ConnectClass* src) { config = src->config; type = src->type; fakelag = src->fakelag; name = src->name; registration_timeout = src->registration_timeout; host = src->host; pingtime = src->pingtime; softsendqmax = src->softsendqmax; hardsendqmax = src->hardsendqmax; recvqmax = src->recvqmax; penaltythreshold = src->penaltythreshold; commandrate = src->commandrate; maxlocal = src->maxlocal; maxglobal = src->maxglobal; maxconnwarn = src->maxconnwarn; maxchans = src->maxchans; limit = src->limit; resolvehostnames = src->resolvehostnames; ports = src->ports; } �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/src/version.sh�����������������������������������������������������������������������0000775�0000000�0000000�00000000040�13554550454�0016150�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������#!/bin/sh echo "InspIRCd-3.4.0" ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/src/wildcard.cpp���������������������������������������������������������������������0000664�0000000�0000000�00000005661�13554550454�0016437�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * InspIRCd -- Internet Relay Chat Daemon * * Copyright (C) 2008 Robin Burchell <robin+git@viroteck.net> * Copyright (C) 2003, 2006-2008 Craig Edwards <craigedwards@brainbox.cc> * Copyright (C) 2007-2008 Dennis Friis <peavey@inspircd.org> * * This file is part of InspIRCd. InspIRCd is free software: you can * redistribute it and/or modify it under the terms of the GNU General Public * License as published by the Free Software Foundation, version 2. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include "inspircd.h" static bool MatchInternal(const unsigned char* str, const unsigned char* mask, unsigned const char* map) { unsigned char* cp = NULL; unsigned char* mp = NULL; unsigned char* string = (unsigned char*)str; unsigned char* wild = (unsigned char*)mask; while ((*string) && (*wild != '*')) { if ((map[*wild] != map[*string]) && (*wild != '?')) { return 0; } wild++; string++; } while (*string) { if (*wild == '*') { if (!*++wild) { return 1; } mp = wild; cp = string+1; } else if ((map[*wild] == map[*string]) || (*wild == '?')) { wild++; string++; } else { wild = mp; string = cp++; } } while (*wild == '*') { wild++; } return !*wild; } // Below here is all wrappers around MatchInternal bool InspIRCd::Match(const std::string& str, const std::string& mask, unsigned const char* map) { if (!map) map = national_case_insensitive_map; return MatchInternal((const unsigned char*)str.c_str(), (const unsigned char*)mask.c_str(), map); } bool InspIRCd::Match(const char* str, const char* mask, unsigned const char* map) { if (!map) map = national_case_insensitive_map; return MatchInternal((const unsigned char*)str, (const unsigned char*)mask, map); } bool InspIRCd::MatchCIDR(const std::string& str, const std::string& mask, unsigned const char* map) { if (irc::sockets::MatchCIDR(str, mask, true)) return true; // Fall back to regular match return InspIRCd::Match(str, mask, map); } bool InspIRCd::MatchCIDR(const char* str, const char* mask, unsigned const char* map) { if (irc::sockets::MatchCIDR(str, mask, true)) return true; // Fall back to regular match return InspIRCd::Match(str, mask, map); } bool InspIRCd::MatchMask(const std::string& masks, const std::string& hostname, const std::string& ipaddr) { irc::spacesepstream masklist(masks); std::string mask; while (masklist.GetToken(mask)) { if (InspIRCd::Match(hostname, mask, ascii_case_insensitive_map) || InspIRCd::MatchCIDR(ipaddr, mask, ascii_case_insensitive_map)) { return true; } } return false; } �������������������������������������������������������������������������������inspircd-3.4.0/src/xline.cpp������������������������������������������������������������������������0000664�0000000�0000000�00000046233�13554550454�0015765�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * InspIRCd -- Internet Relay Chat Daemon * * Copyright (C) 2009 Daniel De Graaf <danieldg@inspircd.org> * Copyright (C) 2005-2009 Robin Burchell <robin+git@viroteck.net> * Copyright (C) 2004-2008 Craig Edwards <craigedwards@brainbox.cc> * Copyright (C) 2007 Dennis Friis <peavey@inspircd.org> * Copyright (C) 2007 John Brooks <john.brooks@dereferenced.net> * * 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 "inspircd.h" #include "xline.h" #include "modules/stats.h" /** An XLineFactory specialized to generate GLine* pointers */ class GLineFactory : public XLineFactory { public: GLineFactory() : XLineFactory("G") { } /** Generate a GLine */ XLine* Generate(time_t set_time, unsigned long duration, const std::string& source, const std::string& reason, const std::string& xline_specific_mask) CXX11_OVERRIDE { IdentHostPair ih = ServerInstance->XLines->IdentSplit(xline_specific_mask); return new GLine(set_time, duration, source, reason, ih.first, ih.second); } }; /** An XLineFactory specialized to generate ELine* pointers */ class ELineFactory : public XLineFactory { public: ELineFactory() : XLineFactory("E") { } /** Generate an ELine */ XLine* Generate(time_t set_time, unsigned long duration, const std::string& source, const std::string& reason, const std::string& xline_specific_mask) CXX11_OVERRIDE { IdentHostPair ih = ServerInstance->XLines->IdentSplit(xline_specific_mask); return new ELine(set_time, duration, source, reason, ih.first, ih.second); } }; /** An XLineFactory specialized to generate KLine* pointers */ class KLineFactory : public XLineFactory { public: KLineFactory() : XLineFactory("K") { } /** Generate a KLine */ XLine* Generate(time_t set_time, unsigned long duration, const std::string& source, const std::string& reason, const std::string& xline_specific_mask) CXX11_OVERRIDE { IdentHostPair ih = ServerInstance->XLines->IdentSplit(xline_specific_mask); return new KLine(set_time, duration, source, reason, ih.first, ih.second); } }; /** An XLineFactory specialized to generate QLine* pointers */ class QLineFactory : public XLineFactory { public: QLineFactory() : XLineFactory("Q") { } /** Generate a QLine */ XLine* Generate(time_t set_time, unsigned long duration, const std::string& source, const std::string& reason, const std::string& xline_specific_mask) CXX11_OVERRIDE { return new QLine(set_time, duration, source, reason, xline_specific_mask); } }; /** An XLineFactory specialized to generate ZLine* pointers */ class ZLineFactory : public XLineFactory { public: ZLineFactory() : XLineFactory("Z") { } /** Generate a ZLine */ XLine* Generate(time_t set_time, unsigned long duration, const std::string& source, const std::string& reason, const std::string& xline_specific_mask) CXX11_OVERRIDE { return new ZLine(set_time, duration, source, reason, xline_specific_mask); } }; /* * This is now version 3 of the XLine subsystem, let's see if we can get it as nice and * efficient as we can this time so we can close this file and never ever touch it again .. * * Background: * Version 1 stored all line types in one list (one for g, one for z, etc). This was fine, * but both version 1 and 2 suck at applying lines efficiently. That is, every time a new line * was added, it iterated every existing line for every existing user. Ow. Expiry was also * expensive, as the lists were NOT sorted. * * Version 2 moved permanent lines into a seperate list from non-permanent to help optimize * matching speed, but matched in the same way. * Expiry was also sped up by sorting the list by expiry (meaning just remove the items at the * head of the list that are outdated.) * * This was fine and good, but it looked less than ideal in code, and matching was still slower * than it could have been, something which we address here. * * VERSION 3: * All lines are (as in v1) stored together -- no seperation of perm and non-perm. They are stored in * a map of maps (first map is line type, second map is for quick lookup on add/delete/etc). * * Expiry is *no longer* performed on a timer, and no longer uses a sorted list of any variety. This * is now done by only checking for expiry when a line is accessed, meaning that expiry is no longer * a resource intensive problem. * * Application no longer tries to apply every single line on every single user - instead, now only lines * added since the previous application are applied. This keeps S2S ADDLINE during burst nice and fast, * while at the same time not slowing things the fuck down when we try adding a ban with lots of preexisting * bans. :) */ bool XLine::Matches(User *u) { return false; } /* * Checks what users match a given vector of ELines and sets their ban exempt flag accordingly. */ void XLineManager::CheckELines() { ContainerIter n = lookup_lines.find("E"); if (n == lookup_lines.end()) return; XLineLookup& ELines = n->second; if (ELines.empty()) return; const UserManager::LocalList& list = ServerInstance->Users.GetLocalUsers(); for (UserManager::LocalList::const_iterator u2 = list.begin(); u2 != list.end(); u2++) { LocalUser* u = *u2; u->exempt = false; /* This uses safe iteration to ensure that if a line expires here, it doenst trash the iterator */ LookupIter safei; for (LookupIter i = ELines.begin(); i != ELines.end(); ) { safei = i; safei++; XLine *e = i->second; if ((!e->duration || ServerInstance->Time() < e->expiry) && e->Matches(u)) u->exempt = true; i = safei; } } } XLineLookup* XLineManager::GetAll(const std::string &type) { ContainerIter n = lookup_lines.find(type); if (n == lookup_lines.end()) return NULL; LookupIter safei; const time_t current = ServerInstance->Time(); /* Expire any dead ones, before sending */ for (LookupIter x = n->second.begin(); x != n->second.end(); ) { safei = x; safei++; if (x->second->duration && current > x->second->expiry) { ExpireLine(n, x); } x = safei; } return &(n->second); } void XLineManager::DelAll(const std::string &type) { ContainerIter n = lookup_lines.find(type); if (n == lookup_lines.end()) return; LookupIter x; /* Delete all of a given type (this should probably use DelLine, but oh well) */ while ((x = n->second.begin()) != n->second.end()) { ExpireLine(n, x); } } std::vector<std::string> XLineManager::GetAllTypes() { std::vector<std::string> items; for (ContainerIter x = lookup_lines.begin(); x != lookup_lines.end(); ++x) items.push_back(x->first); return items; } IdentHostPair XLineManager::IdentSplit(const std::string &ident_and_host) { IdentHostPair n = std::make_pair<std::string,std::string>("*","*"); std::string::size_type x = ident_and_host.find('@'); if (x != std::string::npos) { n.second = ident_and_host.substr(x + 1,ident_and_host.length()); n.first = ident_and_host.substr(0, x); if (!n.first.length()) n.first.assign("*"); if (!n.second.length()) n.second.assign("*"); } else { n.first.clear(); n.second = ident_and_host; } return n; } // adds a line bool XLineManager::AddLine(XLine* line, User* user) { if (line->duration && ServerInstance->Time() > line->expiry) return false; // Don't apply expired XLines. /* Don't apply duplicate xlines */ ContainerIter x = lookup_lines.find(line->type); if (x != lookup_lines.end()) { LookupIter i = x->second.find(line->Displayable()); if (i != x->second.end()) { bool silent = false; // Allow replacing a config line for an updated config line. if (i->second->from_config && line->from_config) { // Nothing changed, skip adding this one. if (i->second->reason == line->reason) return false; silent = true; } // Allow replacing a non-config line for a new config line. else if (!line->from_config) { // X-line propagation bug was here, if the line to be added already exists and // it's expired then expire it and add the new one instead of returning false if ((!i->second->duration) || (ServerInstance->Time() < i->second->expiry)) return false; } else { silent = true; } ExpireLine(x, i, silent); } } /*ELine* item = new ELine(ServerInstance->Time(), duration, source, reason, ih.first.c_str(), ih.second.c_str());*/ XLineFactory* xlf = GetFactory(line->type); if (!xlf) return false; ServerInstance->BanCache.RemoveEntries(line->type, false); // XXX perhaps remove ELines here? if (xlf->AutoApplyToUserList(line)) pending_lines.push_back(line); lookup_lines[line->type][line->Displayable()] = line; line->OnAdd(); FOREACH_MOD(OnAddLine, (user, line)); return true; } // deletes a line, returns true if the line existed and was removed bool XLineManager::DelLine(const char* hostmask, const std::string& type, std::string& reason, User* user, bool simulate) { ContainerIter x = lookup_lines.find(type); if (x == lookup_lines.end()) return false; LookupIter y = x->second.find(hostmask); if (y == x->second.end()) return false; reason.assign(y->second->reason); if (simulate) return true; ServerInstance->BanCache.RemoveEntries(y->second->type, true); FOREACH_MOD(OnDelLine, (user, y->second)); y->second->Unset(); stdalgo::erase(pending_lines, y->second); delete y->second; x->second.erase(y); return true; } void ELine::Unset() { ServerInstance->XLines->CheckELines(); } // returns a pointer to the reason if a nickname matches a Q-line, NULL if it didn't match XLine* XLineManager::MatchesLine(const std::string &type, User* user) { ContainerIter x = lookup_lines.find(type); if (x == lookup_lines.end()) return NULL; const time_t current = ServerInstance->Time(); LookupIter safei; for (LookupIter i = x->second.begin(); i != x->second.end(); ) { safei = i; safei++; if (i->second->duration && current > i->second->expiry) { /* Expire the line, proceed to next one */ ExpireLine(x, i); i = safei; continue; } if (i->second->Matches(user)) { return i->second; } i = safei; } return NULL; } XLine* XLineManager::MatchesLine(const std::string &type, const std::string &pattern) { ContainerIter x = lookup_lines.find(type); if (x == lookup_lines.end()) return NULL; const time_t current = ServerInstance->Time(); LookupIter safei; for (LookupIter i = x->second.begin(); i != x->second.end(); ) { safei = i; safei++; if (i->second->Matches(pattern)) { if (i->second->duration && current > i->second->expiry) { /* Expire the line, return nothing */ ExpireLine(x, i); /* See above */ i = safei; continue; } else return i->second; } i = safei; } return NULL; } // removes lines that have expired void XLineManager::ExpireLine(ContainerIter container, LookupIter item, bool silent) { FOREACH_MOD(OnExpireLine, (item->second)); if (!silent) item->second->DisplayExpiry(); item->second->Unset(); /* TODO: Can we skip this loop by having a 'pending' field in the XLine class, which is set when a line * is pending, cleared when it is no longer pending, so we skip over this loop if its not pending? * -- Brain */ stdalgo::erase(pending_lines, item->second); delete item->second; container->second.erase(item); } // applies lines, removing clients and changing nicks etc as applicable void XLineManager::ApplyLines() { const UserManager::LocalList& list = ServerInstance->Users.GetLocalUsers(); for (UserManager::LocalList::const_iterator j = list.begin(); j != list.end(); ) { LocalUser* u = *j++; // Don't ban people who are exempt. if (u->exempt) continue; for (std::vector<XLine *>::iterator i = pending_lines.begin(); i != pending_lines.end(); i++) { XLine *x = *i; if (x->Matches(u)) { x->Apply(u); // If applying the X-line has killed the user then don't // apply any more lines to them. if (u->quitting) break; } } } pending_lines.clear(); } void XLineManager::InvokeStats(const std::string& type, unsigned int numeric, Stats::Context& stats) { ContainerIter n = lookup_lines.find(type); time_t current = ServerInstance->Time(); LookupIter safei; if (n != lookup_lines.end()) { XLineLookup& list = n->second; for (LookupIter i = list.begin(); i != list.end(); ) { safei = i; safei++; if (i->second->duration && current > i->second->expiry) { ExpireLine(n, i); } else stats.AddRow(numeric, i->second->Displayable()+" "+ ConvToStr(i->second->set_time)+" "+ConvToStr(i->second->duration)+" "+i->second->source+" :"+i->second->reason); i = safei; } } } XLineManager::XLineManager() { GLineFactory* GFact; ELineFactory* EFact; KLineFactory* KFact; QLineFactory* QFact; ZLineFactory* ZFact; GFact = new GLineFactory; EFact = new ELineFactory; KFact = new KLineFactory; QFact = new QLineFactory; ZFact = new ZLineFactory; RegisterFactory(GFact); RegisterFactory(EFact); RegisterFactory(KFact); RegisterFactory(QFact); RegisterFactory(ZFact); } XLineManager::~XLineManager() { const char gekqz[] = "GEKQZ"; for(unsigned int i=0; i < sizeof(gekqz); i++) { XLineFactory* xlf = GetFactory(std::string(1, gekqz[i])); delete xlf; } // Delete all existing XLines for (XLineContainer::iterator i = lookup_lines.begin(); i != lookup_lines.end(); i++) { for (XLineLookup::iterator j = i->second.begin(); j != i->second.end(); j++) { delete j->second; } } } void XLine::Apply(User* u) { } bool XLine::IsBurstable() { return !from_config; } void XLine::DefaultApply(User* u, const std::string &line, bool bancache) { const std::string banReason = line + "-lined: " + reason; if (!ServerInstance->Config->XLineMessage.empty()) u->WriteNumeric(ERR_YOUREBANNEDCREEP, ServerInstance->Config->XLineMessage); if (ServerInstance->Config->HideBans) ServerInstance->Users->QuitUser(u, line + "-lined", &banReason); else ServerInstance->Users->QuitUser(u, banReason); if (bancache) { ServerInstance->Logs->Log("BANCACHE", LOG_DEBUG, "BanCache: Adding positive hit (" + line + ") for " + u->GetIPString()); ServerInstance->BanCache.AddHit(u->GetIPString(), this->type, banReason, (this->duration > 0 ? (this->expiry - ServerInstance->Time()) : 0)); } } bool KLine::Matches(User *u) { LocalUser* lu = IS_LOCAL(u); if (lu && lu->exempt) return false; if (InspIRCd::Match(u->ident, this->identmask, ascii_case_insensitive_map)) { if (InspIRCd::MatchCIDR(u->GetRealHost(), this->hostmask, ascii_case_insensitive_map) || InspIRCd::MatchCIDR(u->GetIPString(), this->hostmask, ascii_case_insensitive_map)) { return true; } } return false; } void KLine::Apply(User* u) { DefaultApply(u, "K", (this->identmask == "*") ? true : false); } bool GLine::Matches(User *u) { LocalUser* lu = IS_LOCAL(u); if (lu && lu->exempt) return false; if (InspIRCd::Match(u->ident, this->identmask, ascii_case_insensitive_map)) { if (InspIRCd::MatchCIDR(u->GetRealHost(), this->hostmask, ascii_case_insensitive_map) || InspIRCd::MatchCIDR(u->GetIPString(), this->hostmask, ascii_case_insensitive_map)) { return true; } } return false; } void GLine::Apply(User* u) { DefaultApply(u, "G", (this->identmask == "*") ? true : false); } bool ELine::Matches(User *u) { if (InspIRCd::Match(u->ident, this->identmask, ascii_case_insensitive_map)) { if (InspIRCd::MatchCIDR(u->GetRealHost(), this->hostmask, ascii_case_insensitive_map) || InspIRCd::MatchCIDR(u->GetIPString(), this->hostmask, ascii_case_insensitive_map)) { return true; } } return false; } bool ZLine::Matches(User *u) { LocalUser* lu = IS_LOCAL(u); if (lu && lu->exempt) return false; if (InspIRCd::MatchCIDR(u->GetIPString(), this->ipaddr)) return true; else return false; } void ZLine::Apply(User* u) { DefaultApply(u, "Z", true); } bool QLine::Matches(User *u) { if (InspIRCd::Match(u->nick, this->nick)) return true; return false; } void QLine::Apply(User* u) { /* Force to uuid on apply of Q-line, no need to disconnect anymore :) */ u->ChangeNick(u->uuid); } bool ZLine::Matches(const std::string &str) { if (InspIRCd::MatchCIDR(str, this->ipaddr)) return true; else return false; } bool QLine::Matches(const std::string &str) { if (InspIRCd::Match(str, this->nick)) return true; return false; } bool ELine::Matches(const std::string &str) { return (InspIRCd::MatchCIDR(str, matchtext)); } bool KLine::Matches(const std::string &str) { return (InspIRCd::MatchCIDR(str.c_str(), matchtext)); } bool GLine::Matches(const std::string &str) { return (InspIRCd::MatchCIDR(str, matchtext)); } void ELine::OnAdd() { /* When adding one E-line, only check the one E-line */ const UserManager::LocalList& list = ServerInstance->Users.GetLocalUsers(); for (UserManager::LocalList::const_iterator u2 = list.begin(); u2 != list.end(); u2++) { LocalUser* u = *u2; if (this->Matches(u)) u->exempt = true; } } void XLine::DisplayExpiry() { bool onechar = (type.length() == 1); ServerInstance->SNO->WriteToSnoMask('x', "Removing expired %s%s %s (set by %s %s ago): %s", type.c_str(), (onechar ? "-line" : ""), Displayable().c_str(), source.c_str(), InspIRCd::DurationString(ServerInstance->Time() - set_time).c_str(), reason.c_str()); } const std::string& ELine::Displayable() { return matchtext; } const std::string& KLine::Displayable() { return matchtext; } const std::string& GLine::Displayable() { return matchtext; } const std::string& ZLine::Displayable() { return ipaddr; } const std::string& QLine::Displayable() { return nick; } bool KLine::IsBurstable() { return false; } bool XLineManager::RegisterFactory(XLineFactory* xlf) { XLineFactMap::iterator n = line_factory.find(xlf->GetType()); if (n != line_factory.end()) return false; line_factory[xlf->GetType()] = xlf; return true; } bool XLineManager::UnregisterFactory(XLineFactory* xlf) { XLineFactMap::iterator n = line_factory.find(xlf->GetType()); if (n == line_factory.end()) return false; line_factory.erase(n); return true; } XLineFactory* XLineManager::GetFactory(const std::string &type) { XLineFactMap::iterator n = line_factory.find(type); if (n == line_factory.end()) return NULL; return n->second; } void XLineManager::ExpireRemovedConfigLines(const std::string& type, const insp::flat_set<std::string>& configlines) { // Nothing to do. if (lookup_lines.empty()) return; ContainerIter xlines = lookup_lines.find(type); if (xlines == lookup_lines.end()) return; for (LookupIter xline = xlines->second.begin(); xline != xlines->second.end(); ) { LookupIter cachedxline = xline++; if (!cachedxline->second->from_config) continue; if (!configlines.count(cachedxline->second->Displayable())) ExpireLine(xlines, cachedxline); } } ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/tools/�������������������������������������������������������������������������������0000775�0000000�0000000�00000000000�13554550454�0014503�5����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/tools/genssl�������������������������������������������������������������������������0000775�0000000�0000000�00000012424�13554550454�0015727�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������#!/usr/bin/env perl # # InspIRCd -- Internet Relay Chat Daemon # # Copyright (C) 2007 Dennis Friis <peavey@inspircd.org> # Copyright (C) 2007 Craig Edwards <craigedwards@brainbox.cc> # Copyright (C) 2013 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/>. # BEGIN { require 5.10.0; } use feature ':5.10'; use strict; use warnings FATAL => qw(all); use File::Temp(); # IMPORTANT: This script has to be able to run by itself so that it can be used # by binary distributions where the make/console.pm module will not # be available! sub prompt($$) { my ($question, $default) = @_; return prompt_string(1, $question, $default) if eval 'use FindBin;use lib $FindBin::RealDir;use make::console; 1'; say $question; print "[$default] => "; chomp(my $answer = <STDIN>); say ''; return $answer ? $answer : $default; } if ($#ARGV != 0 || $ARGV[0] !~ /^(?:auto|gnutls|openssl)$/i) { say STDERR "Usage: $0 <auto|gnutls|openssl>"; exit 1; } # On OS X the GnuTLS certtool is prefixed to avoid collision with the system certtool. my $certtool = $^O eq 'darwin' ? 'gnutls-certtool' : 'certtool'; # Check whether the user has the required tools installed. my $has_gnutls = `$certtool --version v 2>/dev/null`; my $has_openssl = !system 'openssl version >/dev/null 2>&1'; # The framework the user has specified. my $tool = lc $ARGV[0]; # If the user has not explicitly specified a framework then detect one. if ($tool eq 'auto') { if ($has_gnutls) { $tool = 'gnutls'; } elsif ($has_openssl) { $tool = 'openssl'; } else { say STDERR "SSL generation failed: could not find $certtool or openssl in the PATH!"; exit 1; } } elsif ($tool eq 'gnutls' && !$has_gnutls) { say STDERR "SSL generation failed: could not find '$certtool' in the PATH!"; exit 1; } elsif ($tool eq 'openssl' && !$has_openssl) { say STDERR 'SSL generation failed: could not find \'openssl\' in the PATH!'; exit 1; } # Harvest information needed to generate the certificate. my $common_name = prompt('What is the hostname of your server?', 'irc.example.com'); my $email = prompt('What email address can you be contacted at?', 'example@example.com'); my $unit = prompt('What is the name of your unit?', 'Server Admins'); my $organization = prompt('What is the name of your organization?', 'Example IRC Network'); my $city = prompt('What city are you located in?', 'Example City'); my $state = prompt('What state are you located in?', 'Example State'); my $country = prompt('What is the ISO 3166-1 code for the country you are located in?', 'XZ'); my $days = prompt('How many days do you want your certificate to be valid for?', '365'); # Contains the SSL certificate in DER form. my $dercert; # Contains the exit code of openssl/gnutls-certtool. my $status = 0; if ($tool eq 'gnutls') { $has_gnutls =~ /certtool.+?(\d+\.\d+)/; my $sec_param = $1 lt '2.10' ? '--bits 2048' : '--sec-param normal'; my $tmp = new File::Temp(); print $tmp <<__GNUTLS_END__; cn = "$common_name" email = "$email" unit = "$unit" organization = "$organization" locality = "$city" state = "$state" country = "$country" expiration_days = $days tls_www_client tls_www_server signing_key encryption_key cert_signing_key crl_signing_key code_signing_key ocsp_signing_key time_stamping_key __GNUTLS_END__ close($tmp); $status ||= system "$certtool --generate-privkey $sec_param --outfile key.pem"; $status ||= system "$certtool --generate-self-signed --load-privkey key.pem --outfile cert.pem --template $tmp"; $status ||= system "$certtool --generate-request --load-privkey key.pem --outfile csr.pem --template $tmp"; $status ||= system "$certtool --generate-dh-params $sec_param --outfile dhparams.pem"; $dercert = `$certtool --certificate-info --infile cert.pem --outder` unless $status; } elsif ($tool eq 'openssl') { my $tmp = new File::Temp(); print $tmp <<__OPENSSL_END__; $country $state $city $organization $unit $common_name $email . $organization __OPENSSL_END__ close($tmp); $status ||= system "cat $tmp | openssl req -x509 -nodes -newkey rsa:2048 -keyout key.pem -out cert.pem -days $days 2>/dev/null"; $status ||= system "cat $tmp | openssl req -new -nodes -key key.pem -out csr.pem 2>/dev/null"; $status ||= system 'openssl dhparam -out dhparams.pem 2048'; $dercert = `openssl x509 -in cert.pem -outform DER` unless $status; } if ($status) { say STDERR "SSL generation failed: $tool exited with a non-zero status!"; exit 1; } if (defined $dercert && eval 'use Digest::SHA; 1') { my $hash = Digest::SHA->new(256); $hash->add($dercert); say ''; say 'If you are using the self-signed certificate then add this TLSA record to your domain for DANE support:'; say "_6697._tcp." . $common_name . " TLSA 3 0 1 " . $hash->hexdigest; } ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/tools/test-build���������������������������������������������������������������������0000775�0000000�0000000�00000004425�13554550454�0016512�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������#!/usr/bin/env perl # # InspIRCd -- Internet Relay Chat Daemon # # Copyright (C) 2013-2014 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/>. # BEGIN { require 5.10.0; unless (-f 'configure') { print "Error: $0 must be run from the main source directory!\n"; exit 1; } } use feature ':5.10'; use strict; use warnings FATAL => qw(all); use FindBin qw($RealDir); use lib $RealDir; use make::common; use make::configure; $ENV{INSPIRCD_DEBUG} = 3; $ENV{INSPIRCD_VERBOSE} = 1; system 'git', 'clean', '-dfx'; my @compilers = $#ARGV >= 0 ? @ARGV : qw(g++ clang++ icpc); foreach my $compiler (@compilers) { if (system "$compiler -v > /dev/null 2>&1") { say "Skipping $compiler as it is not installed on this system!"; next; } $ENV{CXX} = $compiler; my @socketengines = qw(select); push @socketengines, 'epoll' if test_header $compiler, 'sys/epoll.h'; push @socketengines, 'kqueue' if test_file $compiler, 'kqueue.cpp'; push @socketengines, 'poll' if test_header $compiler, 'poll.h'; foreach my $socketengine (@socketengines) { say "Attempting to build using the $compiler compiler and the $socketengine socket engine..."; system './configure', '--enable-extras', $ENV{TEST_BUILD_MODULES} if defined $ENV{TEST_BUILD_MODULES}; if (system './configure', '--development', '--socketengine', $socketengine) { say "Failed to configure using the $compiler compiler and the $socketengine socket engine!"; exit 1; } if (system 'make', '--jobs', get_cpu_count, 'install') { say "Failed to compile using the $compiler compiler and the $socketengine socket engine!"; exit 1; } say "Building using the $compiler compiler and the $socketengine socket engine succeeded!"; } system 'git', 'clean', '-dfx'; } �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/tools/travis-ci.sh�������������������������������������������������������������������0000775�0000000�0000000�00000001201�13554550454�0016735�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������#!/bin/bash set -ev if [ "$TRAVIS_OS_NAME" = "linux" ] then sudo apt-get update --assume-yes sudo apt-get install --assume-yes libgnutls-dev libldap2-dev libmaxminddb-dev libmbedtls-dev libmysqlclient-dev libpcre3-dev libpq-dev libre2-dev libsqlite3-dev libssl-dev libtre-dev else >&2 echo "'$TRAVIS_OS_NAME' is an unknown Travis CI environment!" exit 1 fi export TEST_BUILD_MODULES="m_geo_maxmind.cpp,m_ldap.cpp,m_mysql.cpp,m_pgsql.cpp,m_regex_pcre.cpp,m_regex_posix.cpp,m_regex_re2.cpp,m_regex_stdlib.cpp,m_regex_tre.cpp,m_sqlite3.cpp,m_ssl_gnutls.cpp,m_ssl_mbedtls.cpp,m_ssl_openssl.cpp,m_sslrehashsignal.cpp" ./tools/test-build $CXX �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/vendor/������������������������������������������������������������������������������0000775�0000000�0000000�00000000000�13554550454�0014640�5����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/vendor/README.md���������������������������������������������������������������������0000664�0000000�0000000�00000002146�13554550454�0016122�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������# Vendored Libraries This directory contains vendored dependencies that are shipped with InspIRCd to avoid users needing to install them manually. ## bcrypt **Author** &mdash; Solar Designer &lt;solar@openwall.com&gt; **Last Updated** &mdash; 2018-08-14 (v1.3) **License** &mdash; Public Domain **Website** &mdash; [https://www.openwall.com/crypt/](https://www.openwall.com/crypt/) ## http_parser **Author** &mdash; Joyent, Inc. and other Node contributors **Last Updated** &mdash; 2019-04-25 (v2.9.2) **License** &mdash; MIT License **Website** &mdash; [https://github.com/nodejs/http-parser](https://github.com/nodejs/http-parser) ## sha256 **Author** &mdash; Olivier Gay &lt;olivier.gay@a3.epfl.ch&gt; **Last Updated** &mdash; 2018-09-06 (2007-02-02) **License** &mdash; 3-clause BSD License **Website** &mdash; [http://www.ouah.org/ogay/sha2/](http://www.ouah.org/ogay/sha2/) ## utfcpp **Author** &mdash; Nemanja Trifunovic **Last Updated** &mdash; 2019-08-02 (v3.1) **License** &mdash; Boost Software License **Website** &mdash; [https://github.com/nemtrif/utfcpp](https://github.com/nemtrif/utfcpp) ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/vendor/bcrypt/�����������������������������������������������������������������������0000775�0000000�0000000�00000000000�13554550454�0016143�5����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/vendor/bcrypt/crypt_blowfish.c�������������������������������������������������������0000664�0000000�0000000�00000077051�13554550454�0021357�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * The crypt_blowfish homepage is: * * http://www.openwall.com/crypt/ * * This code comes from John the Ripper password cracker, with reentrant * and crypt(3) interfaces added, but optimizations specific to password * cracking removed. * * Written by Solar Designer <solar at openwall.com> in 1998-2014. * No copyright is claimed, and the software is hereby placed in the public * domain. In case this attempt to disclaim copyright and place the software * in the public domain is deemed null and void, then the software is * Copyright (c) 1998-2014 Solar Designer and it is hereby released to the * general public under the following terms: * * Redistribution and use in source and binary forms, with or without * modification, are permitted. * * There's ABSOLUTELY NO WARRANTY, express or implied. * * It is my intent that you should be able to use this on your system, * as part of a software package, or anywhere else to improve security, * ensure compatibility, or for any other purpose. I would appreciate * it if you give credit where it is due and keep your modifications in * the public domain as well, but I don't require that in order to let * you place this code and any modifications you make under a license * of your choice. * * This implementation is fully compatible with OpenBSD's bcrypt.c for prefix * "$2b$", originally by Niels Provos <provos at citi.umich.edu>, and it uses * some of his ideas. The password hashing algorithm was designed by David * Mazieres <dm at lcs.mit.edu>. For information on the level of * compatibility for bcrypt hash prefixes other than "$2b$", please refer to * the comments in BF_set_key() below and to the included crypt(3) man page. * * There's a paper on the algorithm that explains its design decisions: * * http://www.usenix.org/events/usenix99/provos.html * * Some of the tricks in BF_ROUND might be inspired by Eric Young's * Blowfish library (I can't be sure if I would think of something if I * hadn't seen his code). */ #include <string.h> #include <errno.h> #ifndef __set_errno #define __set_errno(val) errno = (val) #endif /* Just to make sure the prototypes match the actual definitions */ #include "crypt_blowfish.h" #ifdef __i386__ #define BF_ASM 1 #define BF_SCALE 1 #elif defined(__x86_64__) || defined(__alpha__) || defined(__hppa__) #define BF_ASM 0 #define BF_SCALE 1 #else #define BF_ASM 0 #define BF_SCALE 0 #endif typedef unsigned int BF_word; typedef signed int BF_word_signed; /* Number of Blowfish rounds, this is also hardcoded into a few places */ #define BF_N 16 typedef BF_word BF_key[BF_N + 2]; typedef struct { BF_word S[4][0x100]; BF_key P; } BF_ctx; /* * Magic IV for 64 Blowfish encryptions that we do at the end. * The string is "OrpheanBeholderScryDoubt" on big-endian. */ static BF_word BF_magic_w[6] = { 0x4F727068, 0x65616E42, 0x65686F6C, 0x64657253, 0x63727944, 0x6F756274 }; /* * P-box and S-box tables initialized with digits of Pi. */ static BF_ctx BF_init_state = { { { 0xd1310ba6, 0x98dfb5ac, 0x2ffd72db, 0xd01adfb7, 0xb8e1afed, 0x6a267e96, 0xba7c9045, 0xf12c7f99, 0x24a19947, 0xb3916cf7, 0x0801f2e2, 0x858efc16, 0x636920d8, 0x71574e69, 0xa458fea3, 0xf4933d7e, 0x0d95748f, 0x728eb658, 0x718bcd58, 0x82154aee, 0x7b54a41d, 0xc25a59b5, 0x9c30d539, 0x2af26013, 0xc5d1b023, 0x286085f0, 0xca417918, 0xb8db38ef, 0x8e79dcb0, 0x603a180e, 0x6c9e0e8b, 0xb01e8a3e, 0xd71577c1, 0xbd314b27, 0x78af2fda, 0x55605c60, 0xe65525f3, 0xaa55ab94, 0x57489862, 0x63e81440, 0x55ca396a, 0x2aab10b6, 0xb4cc5c34, 0x1141e8ce, 0xa15486af, 0x7c72e993, 0xb3ee1411, 0x636fbc2a, 0x2ba9c55d, 0x741831f6, 0xce5c3e16, 0x9b87931e, 0xafd6ba33, 0x6c24cf5c, 0x7a325381, 0x28958677, 0x3b8f4898, 0x6b4bb9af, 0xc4bfe81b, 0x66282193, 0x61d809cc, 0xfb21a991, 0x487cac60, 0x5dec8032, 0xef845d5d, 0xe98575b1, 0xdc262302, 0xeb651b88, 0x23893e81, 0xd396acc5, 0x0f6d6ff3, 0x83f44239, 0x2e0b4482, 0xa4842004, 0x69c8f04a, 0x9e1f9b5e, 0x21c66842, 0xf6e96c9a, 0x670c9c61, 0xabd388f0, 0x6a51a0d2, 0xd8542f68, 0x960fa728, 0xab5133a3, 0x6eef0b6c, 0x137a3be4, 0xba3bf050, 0x7efb2a98, 0xa1f1651d, 0x39af0176, 0x66ca593e, 0x82430e88, 0x8cee8619, 0x456f9fb4, 0x7d84a5c3, 0x3b8b5ebe, 0xe06f75d8, 0x85c12073, 0x401a449f, 0x56c16aa6, 0x4ed3aa62, 0x363f7706, 0x1bfedf72, 0x429b023d, 0x37d0d724, 0xd00a1248, 0xdb0fead3, 0x49f1c09b, 0x075372c9, 0x80991b7b, 0x25d479d8, 0xf6e8def7, 0xe3fe501a, 0xb6794c3b, 0x976ce0bd, 0x04c006ba, 0xc1a94fb6, 0x409f60c4, 0x5e5c9ec2, 0x196a2463, 0x68fb6faf, 0x3e6c53b5, 0x1339b2eb, 0x3b52ec6f, 0x6dfc511f, 0x9b30952c, 0xcc814544, 0xaf5ebd09, 0xbee3d004, 0xde334afd, 0x660f2807, 0x192e4bb3, 0xc0cba857, 0x45c8740f, 0xd20b5f39, 0xb9d3fbdb, 0x5579c0bd, 0x1a60320a, 0xd6a100c6, 0x402c7279, 0x679f25fe, 0xfb1fa3cc, 0x8ea5e9f8, 0xdb3222f8, 0x3c7516df, 0xfd616b15, 0x2f501ec8, 0xad0552ab, 0x323db5fa, 0xfd238760, 0x53317b48, 0x3e00df82, 0x9e5c57bb, 0xca6f8ca0, 0x1a87562e, 0xdf1769db, 0xd542a8f6, 0x287effc3, 0xac6732c6, 0x8c4f5573, 0x695b27b0, 0xbbca58c8, 0xe1ffa35d, 0xb8f011a0, 0x10fa3d98, 0xfd2183b8, 0x4afcb56c, 0x2dd1d35b, 0x9a53e479, 0xb6f84565, 0xd28e49bc, 0x4bfb9790, 0xe1ddf2da, 0xa4cb7e33, 0x62fb1341, 0xcee4c6e8, 0xef20cada, 0x36774c01, 0xd07e9efe, 0x2bf11fb4, 0x95dbda4d, 0xae909198, 0xeaad8e71, 0x6b93d5a0, 0xd08ed1d0, 0xafc725e0, 0x8e3c5b2f, 0x8e7594b7, 0x8ff6e2fb, 0xf2122b64, 0x8888b812, 0x900df01c, 0x4fad5ea0, 0x688fc31c, 0xd1cff191, 0xb3a8c1ad, 0x2f2f2218, 0xbe0e1777, 0xea752dfe, 0x8b021fa1, 0xe5a0cc0f, 0xb56f74e8, 0x18acf3d6, 0xce89e299, 0xb4a84fe0, 0xfd13e0b7, 0x7cc43b81, 0xd2ada8d9, 0x165fa266, 0x80957705, 0x93cc7314, 0x211a1477, 0xe6ad2065, 0x77b5fa86, 0xc75442f5, 0xfb9d35cf, 0xebcdaf0c, 0x7b3e89a0, 0xd6411bd3, 0xae1e7e49, 0x00250e2d, 0x2071b35e, 0x226800bb, 0x57b8e0af, 0x2464369b, 0xf009b91e, 0x5563911d, 0x59dfa6aa, 0x78c14389, 0xd95a537f, 0x207d5ba2, 0x02e5b9c5, 0x83260376, 0x6295cfa9, 0x11c81968, 0x4e734a41, 0xb3472dca, 0x7b14a94a, 0x1b510052, 0x9a532915, 0xd60f573f, 0xbc9bc6e4, 0x2b60a476, 0x81e67400, 0x08ba6fb5, 0x571be91f, 0xf296ec6b, 0x2a0dd915, 0xb6636521, 0xe7b9f9b6, 0xff34052e, 0xc5855664, 0x53b02d5d, 0xa99f8fa1, 0x08ba4799, 0x6e85076a }, { 0x4b7a70e9, 0xb5b32944, 0xdb75092e, 0xc4192623, 0xad6ea6b0, 0x49a7df7d, 0x9cee60b8, 0x8fedb266, 0xecaa8c71, 0x699a17ff, 0x5664526c, 0xc2b19ee1, 0x193602a5, 0x75094c29, 0xa0591340, 0xe4183a3e, 0x3f54989a, 0x5b429d65, 0x6b8fe4d6, 0x99f73fd6, 0xa1d29c07, 0xefe830f5, 0x4d2d38e6, 0xf0255dc1, 0x4cdd2086, 0x8470eb26, 0x6382e9c6, 0x021ecc5e, 0x09686b3f, 0x3ebaefc9, 0x3c971814, 0x6b6a70a1, 0x687f3584, 0x52a0e286, 0xb79c5305, 0xaa500737, 0x3e07841c, 0x7fdeae5c, 0x8e7d44ec, 0x5716f2b8, 0xb03ada37, 0xf0500c0d, 0xf01c1f04, 0x0200b3ff, 0xae0cf51a, 0x3cb574b2, 0x25837a58, 0xdc0921bd, 0xd19113f9, 0x7ca92ff6, 0x94324773, 0x22f54701, 0x3ae5e581, 0x37c2dadc, 0xc8b57634, 0x9af3dda7, 0xa9446146, 0x0fd0030e, 0xecc8c73e, 0xa4751e41, 0xe238cd99, 0x3bea0e2f, 0x3280bba1, 0x183eb331, 0x4e548b38, 0x4f6db908, 0x6f420d03, 0xf60a04bf, 0x2cb81290, 0x24977c79, 0x5679b072, 0xbcaf89af, 0xde9a771f, 0xd9930810, 0xb38bae12, 0xdccf3f2e, 0x5512721f, 0x2e6b7124, 0x501adde6, 0x9f84cd87, 0x7a584718, 0x7408da17, 0xbc9f9abc, 0xe94b7d8c, 0xec7aec3a, 0xdb851dfa, 0x63094366, 0xc464c3d2, 0xef1c1847, 0x3215d908, 0xdd433b37, 0x24c2ba16, 0x12a14d43, 0x2a65c451, 0x50940002, 0x133ae4dd, 0x71dff89e, 0x10314e55, 0x81ac77d6, 0x5f11199b, 0x043556f1, 0xd7a3c76b, 0x3c11183b, 0x5924a509, 0xf28fe6ed, 0x97f1fbfa, 0x9ebabf2c, 0x1e153c6e, 0x86e34570, 0xeae96fb1, 0x860e5e0a, 0x5a3e2ab3, 0x771fe71c, 0x4e3d06fa, 0x2965dcb9, 0x99e71d0f, 0x803e89d6, 0x5266c825, 0x2e4cc978, 0x9c10b36a, 0xc6150eba, 0x94e2ea78, 0xa5fc3c53, 0x1e0a2df4, 0xf2f74ea7, 0x361d2b3d, 0x1939260f, 0x19c27960, 0x5223a708, 0xf71312b6, 0xebadfe6e, 0xeac31f66, 0xe3bc4595, 0xa67bc883, 0xb17f37d1, 0x018cff28, 0xc332ddef, 0xbe6c5aa5, 0x65582185, 0x68ab9802, 0xeecea50f, 0xdb2f953b, 0x2aef7dad, 0x5b6e2f84, 0x1521b628, 0x29076170, 0xecdd4775, 0x619f1510, 0x13cca830, 0xeb61bd96, 0x0334fe1e, 0xaa0363cf, 0xb5735c90, 0x4c70a239, 0xd59e9e0b, 0xcbaade14, 0xeecc86bc, 0x60622ca7, 0x9cab5cab, 0xb2f3846e, 0x648b1eaf, 0x19bdf0ca, 0xa02369b9, 0x655abb50, 0x40685a32, 0x3c2ab4b3, 0x319ee9d5, 0xc021b8f7, 0x9b540b19, 0x875fa099, 0x95f7997e, 0x623d7da8, 0xf837889a, 0x97e32d77, 0x11ed935f, 0x16681281, 0x0e358829, 0xc7e61fd6, 0x96dedfa1, 0x7858ba99, 0x57f584a5, 0x1b227263, 0x9b83c3ff, 0x1ac24696, 0xcdb30aeb, 0x532e3054, 0x8fd948e4, 0x6dbc3128, 0x58ebf2ef, 0x34c6ffea, 0xfe28ed61, 0xee7c3c73, 0x5d4a14d9, 0xe864b7e3, 0x42105d14, 0x203e13e0, 0x45eee2b6, 0xa3aaabea, 0xdb6c4f15, 0xfacb4fd0, 0xc742f442, 0xef6abbb5, 0x654f3b1d, 0x41cd2105, 0xd81e799e, 0x86854dc7, 0xe44b476a, 0x3d816250, 0xcf62a1f2, 0x5b8d2646, 0xfc8883a0, 0xc1c7b6a3, 0x7f1524c3, 0x69cb7492, 0x47848a0b, 0x5692b285, 0x095bbf00, 0xad19489d, 0x1462b174, 0x23820e00, 0x58428d2a, 0x0c55f5ea, 0x1dadf43e, 0x233f7061, 0x3372f092, 0x8d937e41, 0xd65fecf1, 0x6c223bdb, 0x7cde3759, 0xcbee7460, 0x4085f2a7, 0xce77326e, 0xa6078084, 0x19f8509e, 0xe8efd855, 0x61d99735, 0xa969a7aa, 0xc50c06c2, 0x5a04abfc, 0x800bcadc, 0x9e447a2e, 0xc3453484, 0xfdd56705, 0x0e1e9ec9, 0xdb73dbd3, 0x105588cd, 0x675fda79, 0xe3674340, 0xc5c43465, 0x713e38d8, 0x3d28f89e, 0xf16dff20, 0x153e21e7, 0x8fb03d4a, 0xe6e39f2b, 0xdb83adf7 }, { 0xe93d5a68, 0x948140f7, 0xf64c261c, 0x94692934, 0x411520f7, 0x7602d4f7, 0xbcf46b2e, 0xd4a20068, 0xd4082471, 0x3320f46a, 0x43b7d4b7, 0x500061af, 0x1e39f62e, 0x97244546, 0x14214f74, 0xbf8b8840, 0x4d95fc1d, 0x96b591af, 0x70f4ddd3, 0x66a02f45, 0xbfbc09ec, 0x03bd9785, 0x7fac6dd0, 0x31cb8504, 0x96eb27b3, 0x55fd3941, 0xda2547e6, 0xabca0a9a, 0x28507825, 0x530429f4, 0x0a2c86da, 0xe9b66dfb, 0x68dc1462, 0xd7486900, 0x680ec0a4, 0x27a18dee, 0x4f3ffea2, 0xe887ad8c, 0xb58ce006, 0x7af4d6b6, 0xaace1e7c, 0xd3375fec, 0xce78a399, 0x406b2a42, 0x20fe9e35, 0xd9f385b9, 0xee39d7ab, 0x3b124e8b, 0x1dc9faf7, 0x4b6d1856, 0x26a36631, 0xeae397b2, 0x3a6efa74, 0xdd5b4332, 0x6841e7f7, 0xca7820fb, 0xfb0af54e, 0xd8feb397, 0x454056ac, 0xba489527, 0x55533a3a, 0x20838d87, 0xfe6ba9b7, 0xd096954b, 0x55a867bc, 0xa1159a58, 0xcca92963, 0x99e1db33, 0xa62a4a56, 0x3f3125f9, 0x5ef47e1c, 0x9029317c, 0xfdf8e802, 0x04272f70, 0x80bb155c, 0x05282ce3, 0x95c11548, 0xe4c66d22, 0x48c1133f, 0xc70f86dc, 0x07f9c9ee, 0x41041f0f, 0x404779a4, 0x5d886e17, 0x325f51eb, 0xd59bc0d1, 0xf2bcc18f, 0x41113564, 0x257b7834, 0x602a9c60, 0xdff8e8a3, 0x1f636c1b, 0x0e12b4c2, 0x02e1329e, 0xaf664fd1, 0xcad18115, 0x6b2395e0, 0x333e92e1, 0x3b240b62, 0xeebeb922, 0x85b2a20e, 0xe6ba0d99, 0xde720c8c, 0x2da2f728, 0xd0127845, 0x95b794fd, 0x647d0862, 0xe7ccf5f0, 0x5449a36f, 0x877d48fa, 0xc39dfd27, 0xf33e8d1e, 0x0a476341, 0x992eff74, 0x3a6f6eab, 0xf4f8fd37, 0xa812dc60, 0xa1ebddf8, 0x991be14c, 0xdb6e6b0d, 0xc67b5510, 0x6d672c37, 0x2765d43b, 0xdcd0e804, 0xf1290dc7, 0xcc00ffa3, 0xb5390f92, 0x690fed0b, 0x667b9ffb, 0xcedb7d9c, 0xa091cf0b, 0xd9155ea3, 0xbb132f88, 0x515bad24, 0x7b9479bf, 0x763bd6eb, 0x37392eb3, 0xcc115979, 0x8026e297, 0xf42e312d, 0x6842ada7, 0xc66a2b3b, 0x12754ccc, 0x782ef11c, 0x6a124237, 0xb79251e7, 0x06a1bbe6, 0x4bfb6350, 0x1a6b1018, 0x11caedfa, 0x3d25bdd8, 0xe2e1c3c9, 0x44421659, 0x0a121386, 0xd90cec6e, 0xd5abea2a, 0x64af674e, 0xda86a85f, 0xbebfe988, 0x64e4c3fe, 0x9dbc8057, 0xf0f7c086, 0x60787bf8, 0x6003604d, 0xd1fd8346, 0xf6381fb0, 0x7745ae04, 0xd736fccc, 0x83426b33, 0xf01eab71, 0xb0804187, 0x3c005e5f, 0x77a057be, 0xbde8ae24, 0x55464299, 0xbf582e61, 0x4e58f48f, 0xf2ddfda2, 0xf474ef38, 0x8789bdc2, 0x5366f9c3, 0xc8b38e74, 0xb475f255, 0x46fcd9b9, 0x7aeb2661, 0x8b1ddf84, 0x846a0e79, 0x915f95e2, 0x466e598e, 0x20b45770, 0x8cd55591, 0xc902de4c, 0xb90bace1, 0xbb8205d0, 0x11a86248, 0x7574a99e, 0xb77f19b6, 0xe0a9dc09, 0x662d09a1, 0xc4324633, 0xe85a1f02, 0x09f0be8c, 0x4a99a025, 0x1d6efe10, 0x1ab93d1d, 0x0ba5a4df, 0xa186f20f, 0x2868f169, 0xdcb7da83, 0x573906fe, 0xa1e2ce9b, 0x4fcd7f52, 0x50115e01, 0xa70683fa, 0xa002b5c4, 0x0de6d027, 0x9af88c27, 0x773f8641, 0xc3604c06, 0x61a806b5, 0xf0177a28, 0xc0f586e0, 0x006058aa, 0x30dc7d62, 0x11e69ed7, 0x2338ea63, 0x53c2dd94, 0xc2c21634, 0xbbcbee56, 0x90bcb6de, 0xebfc7da1, 0xce591d76, 0x6f05e409, 0x4b7c0188, 0x39720a3d, 0x7c927c24, 0x86e3725f, 0x724d9db9, 0x1ac15bb4, 0xd39eb8fc, 0xed545578, 0x08fca5b5, 0xd83d7cd3, 0x4dad0fc4, 0x1e50ef5e, 0xb161e6f8, 0xa28514d9, 0x6c51133c, 0x6fd5c7e7, 0x56e14ec4, 0x362abfce, 0xddc6c837, 0xd79a3234, 0x92638212, 0x670efa8e, 0x406000e0 }, { 0x3a39ce37, 0xd3faf5cf, 0xabc27737, 0x5ac52d1b, 0x5cb0679e, 0x4fa33742, 0xd3822740, 0x99bc9bbe, 0xd5118e9d, 0xbf0f7315, 0xd62d1c7e, 0xc700c47b, 0xb78c1b6b, 0x21a19045, 0xb26eb1be, 0x6a366eb4, 0x5748ab2f, 0xbc946e79, 0xc6a376d2, 0x6549c2c8, 0x530ff8ee, 0x468dde7d, 0xd5730a1d, 0x4cd04dc6, 0x2939bbdb, 0xa9ba4650, 0xac9526e8, 0xbe5ee304, 0xa1fad5f0, 0x6a2d519a, 0x63ef8ce2, 0x9a86ee22, 0xc089c2b8, 0x43242ef6, 0xa51e03aa, 0x9cf2d0a4, 0x83c061ba, 0x9be96a4d, 0x8fe51550, 0xba645bd6, 0x2826a2f9, 0xa73a3ae1, 0x4ba99586, 0xef5562e9, 0xc72fefd3, 0xf752f7da, 0x3f046f69, 0x77fa0a59, 0x80e4a915, 0x87b08601, 0x9b09e6ad, 0x3b3ee593, 0xe990fd5a, 0x9e34d797, 0x2cf0b7d9, 0x022b8b51, 0x96d5ac3a, 0x017da67d, 0xd1cf3ed6, 0x7c7d2d28, 0x1f9f25cf, 0xadf2b89b, 0x5ad6b472, 0x5a88f54c, 0xe029ac71, 0xe019a5e6, 0x47b0acfd, 0xed93fa9b, 0xe8d3c48d, 0x283b57cc, 0xf8d56629, 0x79132e28, 0x785f0191, 0xed756055, 0xf7960e44, 0xe3d35e8c, 0x15056dd4, 0x88f46dba, 0x03a16125, 0x0564f0bd, 0xc3eb9e15, 0x3c9057a2, 0x97271aec, 0xa93a072a, 0x1b3f6d9b, 0x1e6321f5, 0xf59c66fb, 0x26dcf319, 0x7533d928, 0xb155fdf5, 0x03563482, 0x8aba3cbb, 0x28517711, 0xc20ad9f8, 0xabcc5167, 0xccad925f, 0x4de81751, 0x3830dc8e, 0x379d5862, 0x9320f991, 0xea7a90c2, 0xfb3e7bce, 0x5121ce64, 0x774fbe32, 0xa8b6e37e, 0xc3293d46, 0x48de5369, 0x6413e680, 0xa2ae0810, 0xdd6db224, 0x69852dfd, 0x09072166, 0xb39a460a, 0x6445c0dd, 0x586cdecf, 0x1c20c8ae, 0x5bbef7dd, 0x1b588d40, 0xccd2017f, 0x6bb4e3bb, 0xdda26a7e, 0x3a59ff45, 0x3e350a44, 0xbcb4cdd5, 0x72eacea8, 0xfa6484bb, 0x8d6612ae, 0xbf3c6f47, 0xd29be463, 0x542f5d9e, 0xaec2771b, 0xf64e6370, 0x740e0d8d, 0xe75b1357, 0xf8721671, 0xaf537d5d, 0x4040cb08, 0x4eb4e2cc, 0x34d2466a, 0x0115af84, 0xe1b00428, 0x95983a1d, 0x06b89fb4, 0xce6ea048, 0x6f3f3b82, 0x3520ab82, 0x011a1d4b, 0x277227f8, 0x611560b1, 0xe7933fdc, 0xbb3a792b, 0x344525bd, 0xa08839e1, 0x51ce794b, 0x2f32c9b7, 0xa01fbac9, 0xe01cc87e, 0xbcc7d1f6, 0xcf0111c3, 0xa1e8aac7, 0x1a908749, 0xd44fbd9a, 0xd0dadecb, 0xd50ada38, 0x0339c32a, 0xc6913667, 0x8df9317c, 0xe0b12b4f, 0xf79e59b7, 0x43f5bb3a, 0xf2d519ff, 0x27d9459c, 0xbf97222c, 0x15e6fc2a, 0x0f91fc71, 0x9b941525, 0xfae59361, 0xceb69ceb, 0xc2a86459, 0x12baa8d1, 0xb6c1075e, 0xe3056a0c, 0x10d25065, 0xcb03a442, 0xe0ec6e0e, 0x1698db3b, 0x4c98a0be, 0x3278e964, 0x9f1f9532, 0xe0d392df, 0xd3a0342b, 0x8971f21e, 0x1b0a7441, 0x4ba3348c, 0xc5be7120, 0xc37632d8, 0xdf359f8d, 0x9b992f2e, 0xe60b6f47, 0x0fe3f11d, 0xe54cda54, 0x1edad891, 0xce6279cf, 0xcd3e7e6f, 0x1618b166, 0xfd2c1d05, 0x848fd2c5, 0xf6fb2299, 0xf523f357, 0xa6327623, 0x93a83531, 0x56cccd02, 0xacf08162, 0x5a75ebb5, 0x6e163697, 0x88d273cc, 0xde966292, 0x81b949d0, 0x4c50901b, 0x71c65614, 0xe6c6c7bd, 0x327a140a, 0x45e1d006, 0xc3f27b9a, 0xc9aa53fd, 0x62a80f00, 0xbb25bfe2, 0x35bdd2f6, 0x71126905, 0xb2040222, 0xb6cbcf7c, 0xcd769c2b, 0x53113ec0, 0x1640e3d3, 0x38abbd60, 0x2547adf0, 0xba38209c, 0xf746ce76, 0x77afa1c5, 0x20756060, 0x85cbfe4e, 0x8ae88dd8, 0x7aaaf9b0, 0x4cf9aa7e, 0x1948c25c, 0x02fb8a8c, 0x01c36ae4, 0xd6ebe1f9, 0x90d4f869, 0xa65cdea0, 0x3f09252d, 0xc208e69f, 0xb74e6132, 0xce77e25b, 0x578fdfe3, 0x3ac372e6 } }, { 0x243f6a88, 0x85a308d3, 0x13198a2e, 0x03707344, 0xa4093822, 0x299f31d0, 0x082efa98, 0xec4e6c89, 0x452821e6, 0x38d01377, 0xbe5466cf, 0x34e90c6c, 0xc0ac29b7, 0xc97c50dd, 0x3f84d5b5, 0xb5470917, 0x9216d5d9, 0x8979fb1b } }; static unsigned char BF_itoa64[64 + 1] = "./ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"; static unsigned char BF_atoi64[0x60] = { 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 0, 1, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 64, 64, 64, 64, 64, 64, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 64, 64, 64, 64, 64, 64, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 64, 64, 64, 64, 64 }; #define BF_safe_atoi64(dst, src) \ { \ tmp = (unsigned char)(src); \ if ((unsigned int)(tmp -= 0x20) >= 0x60) return -1; \ tmp = BF_atoi64[tmp]; \ if (tmp > 63) return -1; \ (dst) = tmp; \ } static int BF_decode(BF_word *dst, const char *src, int size) { unsigned char *dptr = (unsigned char *)dst; unsigned char *end = dptr + size; const unsigned char *sptr = (const unsigned char *)src; unsigned int tmp, c1, c2, c3, c4; do { BF_safe_atoi64(c1, *sptr++); BF_safe_atoi64(c2, *sptr++); *dptr++ = (c1 << 2) | ((c2 & 0x30) >> 4); if (dptr >= end) break; BF_safe_atoi64(c3, *sptr++); *dptr++ = ((c2 & 0x0F) << 4) | ((c3 & 0x3C) >> 2); if (dptr >= end) break; BF_safe_atoi64(c4, *sptr++); *dptr++ = ((c3 & 0x03) << 6) | c4; } while (dptr < end); return 0; } static void BF_encode(char *dst, const BF_word *src, int size) { const unsigned char *sptr = (const unsigned char *)src; const unsigned char *end = sptr + size; unsigned char *dptr = (unsigned char *)dst; unsigned int c1, c2; do { c1 = *sptr++; *dptr++ = BF_itoa64[c1 >> 2]; c1 = (c1 & 0x03) << 4; if (sptr >= end) { *dptr++ = BF_itoa64[c1]; break; } c2 = *sptr++; c1 |= c2 >> 4; *dptr++ = BF_itoa64[c1]; c1 = (c2 & 0x0f) << 2; if (sptr >= end) { *dptr++ = BF_itoa64[c1]; break; } c2 = *sptr++; c1 |= c2 >> 6; *dptr++ = BF_itoa64[c1]; *dptr++ = BF_itoa64[c2 & 0x3f]; } while (sptr < end); } static void BF_swap(BF_word *x, int count) { static int endianness_check = 1; char *is_little_endian = (char *)&endianness_check; BF_word tmp; if (*is_little_endian) do { tmp = *x; tmp = (tmp << 16) | (tmp >> 16); *x++ = ((tmp & 0x00FF00FF) << 8) | ((tmp >> 8) & 0x00FF00FF); } while (--count); } #if BF_SCALE /* Architectures which can shift addresses left by 2 bits with no extra cost */ #define BF_ROUND(L, R, N) \ tmp1 = L & 0xFF; \ tmp2 = L >> 8; \ tmp2 &= 0xFF; \ tmp3 = L >> 16; \ tmp3 &= 0xFF; \ tmp4 = L >> 24; \ tmp1 = data.ctx.S[3][tmp1]; \ tmp2 = data.ctx.S[2][tmp2]; \ tmp3 = data.ctx.S[1][tmp3]; \ tmp3 += data.ctx.S[0][tmp4]; \ tmp3 ^= tmp2; \ R ^= data.ctx.P[N + 1]; \ tmp3 += tmp1; \ R ^= tmp3; #else /* Architectures with no complicated addressing modes supported */ #define BF_INDEX(S, i) \ (*((BF_word *)(((unsigned char *)S) + (i)))) #define BF_ROUND(L, R, N) \ tmp1 = L & 0xFF; \ tmp1 <<= 2; \ tmp2 = L >> 6; \ tmp2 &= 0x3FC; \ tmp3 = L >> 14; \ tmp3 &= 0x3FC; \ tmp4 = L >> 22; \ tmp4 &= 0x3FC; \ tmp1 = BF_INDEX(data.ctx.S[3], tmp1); \ tmp2 = BF_INDEX(data.ctx.S[2], tmp2); \ tmp3 = BF_INDEX(data.ctx.S[1], tmp3); \ tmp3 += BF_INDEX(data.ctx.S[0], tmp4); \ tmp3 ^= tmp2; \ R ^= data.ctx.P[N + 1]; \ tmp3 += tmp1; \ R ^= tmp3; #endif /* * Encrypt one block, BF_N is hardcoded here. */ #define BF_ENCRYPT \ L ^= data.ctx.P[0]; \ BF_ROUND(L, R, 0); \ BF_ROUND(R, L, 1); \ BF_ROUND(L, R, 2); \ BF_ROUND(R, L, 3); \ BF_ROUND(L, R, 4); \ BF_ROUND(R, L, 5); \ BF_ROUND(L, R, 6); \ BF_ROUND(R, L, 7); \ BF_ROUND(L, R, 8); \ BF_ROUND(R, L, 9); \ BF_ROUND(L, R, 10); \ BF_ROUND(R, L, 11); \ BF_ROUND(L, R, 12); \ BF_ROUND(R, L, 13); \ BF_ROUND(L, R, 14); \ BF_ROUND(R, L, 15); \ tmp4 = R; \ R = L; \ L = tmp4 ^ data.ctx.P[BF_N + 1]; #if BF_ASM #define BF_body() \ _BF_body_r(&data.ctx); #else #define BF_body() \ L = R = 0; \ ptr = data.ctx.P; \ do { \ ptr += 2; \ BF_ENCRYPT; \ *(ptr - 2) = L; \ *(ptr - 1) = R; \ } while (ptr < &data.ctx.P[BF_N + 2]); \ \ ptr = data.ctx.S[0]; \ do { \ ptr += 2; \ BF_ENCRYPT; \ *(ptr - 2) = L; \ *(ptr - 1) = R; \ } while (ptr < &data.ctx.S[3][0xFF]); #endif static void BF_set_key(const char *key, BF_key expanded, BF_key initial, unsigned char flags) { const char *ptr = key; unsigned int bug, i, j; BF_word safety, sign, diff, tmp[2]; /* * There was a sign extension bug in older revisions of this function. While * we would have liked to simply fix the bug and move on, we have to provide * a backwards compatibility feature (essentially the bug) for some systems and * a safety measure for some others. The latter is needed because for certain * multiple inputs to the buggy algorithm there exist easily found inputs to * the correct algorithm that produce the same hash. Thus, we optionally * deviate from the correct algorithm just enough to avoid such collisions. * While the bug itself affected the majority of passwords containing * characters with the 8th bit set (although only a percentage of those in a * collision-producing way), the anti-collision safety measure affects * only a subset of passwords containing the '\xff' character (not even all of * those passwords, just some of them). This character is not found in valid * UTF-8 sequences and is rarely used in popular 8-bit character encodings. * Thus, the safety measure is unlikely to cause much annoyance, and is a * reasonable tradeoff to use when authenticating against existing hashes that * are not reliably known to have been computed with the correct algorithm. * * We use an approach that tries to minimize side-channel leaks of password * information - that is, we mostly use fixed-cost bitwise operations instead * of branches or table lookups. (One conditional branch based on password * length remains. It is not part of the bug aftermath, though, and is * difficult and possibly unreasonable to avoid given the use of C strings by * the caller, which results in similar timing leaks anyway.) * * For actual implementation, we set an array index in the variable "bug" * (0 means no bug, 1 means sign extension bug emulation) and a flag in the * variable "safety" (bit 16 is set when the safety measure is requested). * Valid combinations of settings are: * * Prefix "$2a$": bug = 0, safety = 0x10000 * Prefix "$2b$": bug = 0, safety = 0 * Prefix "$2x$": bug = 1, safety = 0 * Prefix "$2y$": bug = 0, safety = 0 */ bug = (unsigned int)flags & 1; safety = ((BF_word)flags & 2) << 15; sign = diff = 0; for (i = 0; i < BF_N + 2; i++) { tmp[0] = tmp[1] = 0; for (j = 0; j < 4; j++) { tmp[0] <<= 8; tmp[0] |= (unsigned char)*ptr; /* correct */ tmp[1] <<= 8; tmp[1] |= (BF_word_signed)(signed char)*ptr; /* bug */ /* * Sign extension in the first char has no effect - nothing to overwrite yet, * and those extra 24 bits will be fully shifted out of the 32-bit word. For * chars 2, 3, 4 in each four-char block, we set bit 7 of "sign" if sign * extension in tmp[1] occurs. Once this flag is set, it remains set. */ if (j) sign |= tmp[1] & 0x80; if (!*ptr) ptr = key; else ptr++; } diff |= tmp[0] ^ tmp[1]; /* Non-zero on any differences */ expanded[i] = tmp[bug]; initial[i] = BF_init_state.P[i] ^ tmp[bug]; } /* * At this point, "diff" is zero iff the correct and buggy algorithms produced * exactly the same result. If so and if "sign" is non-zero, which indicates * that there was a non-benign sign extension, this means that we have a * collision between the correctly computed hash for this password and a set of * passwords that could be supplied to the buggy algorithm. Our safety measure * is meant to protect from such many-buggy to one-correct collisions, by * deviating from the correct algorithm in such cases. Let's check for this. */ diff |= diff >> 16; /* still zero iff exact match */ diff &= 0xffff; /* ditto */ diff += 0xffff; /* bit 16 set iff "diff" was non-zero (on non-match) */ sign <<= 9; /* move the non-benign sign extension flag to bit 16 */ sign &= ~diff & safety; /* action needed? */ /* * If we have determined that we need to deviate from the correct algorithm, * flip bit 16 in initial expanded key. (The choice of 16 is arbitrary, but * let's stick to it now. It came out of the approach we used above, and it's * not any worse than any other choice we could make.) * * It is crucial that we don't do the same to the expanded key used in the main * Eksblowfish loop. By doing it to only one of these two, we deviate from a * state that could be directly specified by a password to the buggy algorithm * (and to the fully correct one as well, but that's a side-effect). */ initial[0] ^= sign; } static const unsigned char flags_by_subtype[26] = {2, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 4, 0}; static char *BF_crypt(const char *key, const char *setting, char *output, int size, BF_word min) { #if BF_ASM extern void _BF_body_r(BF_ctx *ctx); #endif struct { BF_ctx ctx; BF_key expanded_key; union { BF_word salt[4]; BF_word output[6]; } binary; } data; BF_word L, R; BF_word tmp1, tmp2, tmp3, tmp4; BF_word *ptr; BF_word count; int i; if (size < 7 + 22 + 31 + 1) { __set_errno(ERANGE); return NULL; } if (setting[0] != '$' || setting[1] != '2' || setting[2] < 'a' || setting[2] > 'z' || !flags_by_subtype[(unsigned int)(unsigned char)setting[2] - 'a'] || setting[3] != '$' || setting[4] < '0' || setting[4] > '3' || setting[5] < '0' || setting[5] > '9' || (setting[4] == '3' && setting[5] > '1') || setting[6] != '$') { __set_errno(EINVAL); return NULL; } count = (BF_word)1 << ((setting[4] - '0') * 10 + (setting[5] - '0')); if (count < min || BF_decode(data.binary.salt, &setting[7], 16)) { __set_errno(EINVAL); return NULL; } BF_swap(data.binary.salt, 4); BF_set_key(key, data.expanded_key, data.ctx.P, flags_by_subtype[(unsigned int)(unsigned char)setting[2] - 'a']); memcpy(data.ctx.S, BF_init_state.S, sizeof(data.ctx.S)); L = R = 0; for (i = 0; i < BF_N + 2; i += 2) { L ^= data.binary.salt[i & 2]; R ^= data.binary.salt[(i & 2) + 1]; BF_ENCRYPT; data.ctx.P[i] = L; data.ctx.P[i + 1] = R; } ptr = data.ctx.S[0]; do { ptr += 4; L ^= data.binary.salt[(BF_N + 2) & 3]; R ^= data.binary.salt[(BF_N + 3) & 3]; BF_ENCRYPT; *(ptr - 4) = L; *(ptr - 3) = R; L ^= data.binary.salt[(BF_N + 4) & 3]; R ^= data.binary.salt[(BF_N + 5) & 3]; BF_ENCRYPT; *(ptr - 2) = L; *(ptr - 1) = R; } while (ptr < &data.ctx.S[3][0xFF]); do { int done; for (i = 0; i < BF_N + 2; i += 2) { data.ctx.P[i] ^= data.expanded_key[i]; data.ctx.P[i + 1] ^= data.expanded_key[i + 1]; } done = 0; do { BF_body(); if (done) break; done = 1; tmp1 = data.binary.salt[0]; tmp2 = data.binary.salt[1]; tmp3 = data.binary.salt[2]; tmp4 = data.binary.salt[3]; for (i = 0; i < BF_N; i += 4) { data.ctx.P[i] ^= tmp1; data.ctx.P[i + 1] ^= tmp2; data.ctx.P[i + 2] ^= tmp3; data.ctx.P[i + 3] ^= tmp4; } data.ctx.P[16] ^= tmp1; data.ctx.P[17] ^= tmp2; } while (1); } while (--count); for (i = 0; i < 6; i += 2) { L = BF_magic_w[i]; R = BF_magic_w[i + 1]; count = 64; do { BF_ENCRYPT; } while (--count); data.binary.output[i] = L; data.binary.output[i + 1] = R; } memcpy(output, setting, 7 + 22 - 1); output[7 + 22 - 1] = BF_itoa64[(int) BF_atoi64[(int)setting[7 + 22 - 1] - 0x20] & 0x30]; /* This has to be bug-compatible with the original implementation, so * only encode 23 of the 24 bytes. :-) */ BF_swap(data.binary.output, 6); BF_encode(&output[7 + 22], data.binary.output, 23); output[7 + 22 + 31] = '\0'; return output; } int _crypt_output_magic(const char *setting, char *output, int size) { if (size < 3) return -1; output[0] = '*'; output[1] = '0'; output[2] = '\0'; if (setting[0] == '*' && setting[1] == '0') output[1] = '1'; return 0; } /* * Please preserve the runtime self-test. It serves two purposes at once: * * 1. We really can't afford the risk of producing incompatible hashes e.g. * when there's something like gcc bug 26587 again, whereas an application or * library integrating this code might not also integrate our external tests or * it might not run them after every build. Even if it does, the miscompile * might only occur on the production build, but not on a testing build (such * as because of different optimization settings). It is painful to recover * from incorrectly-computed hashes - merely fixing whatever broke is not * enough. Thus, a proactive measure like this self-test is needed. * * 2. We don't want to leave sensitive data from our actual password hash * computation on the stack or in registers. Previous revisions of the code * would do explicit cleanups, but simply running the self-test after hash * computation is more reliable. * * The performance cost of this quick self-test is around 0.6% at the "$2a$08" * setting. */ char *_crypt_blowfish_rn(const char *key, const char *setting, char *output, int size) { const char *test_key = "8b \xd0\xc1\xd2\xcf\xcc\xd8"; const char *test_setting = "$2a$00$abcdefghijklmnopqrstuu"; static const char * const test_hashes[2] = {"i1D709vfamulimlGcq0qq3UvuUasvEa\0\x55", /* 'a', 'b', 'y' */ "VUrPmXD6q/nVSSp7pNDhCR9071IfIRe\0\x55"}; /* 'x' */ const char *test_hash = test_hashes[0]; char *retval; const char *p; int save_errno, ok; struct { char s[7 + 22 + 1]; char o[7 + 22 + 31 + 1 + 1 + 1]; } buf; /* Hash the supplied password */ _crypt_output_magic(setting, output, size); retval = BF_crypt(key, setting, output, size, 16); save_errno = errno; /* * Do a quick self-test. It is important that we make both calls to BF_crypt() * from the same scope such that they likely use the same stack locations, * which makes the second call overwrite the first call's sensitive data on the * stack and makes it more likely that any alignment related issues would be * detected by the self-test. */ memcpy(buf.s, test_setting, sizeof(buf.s)); if (retval) { unsigned int flags = flags_by_subtype[ (unsigned int)(unsigned char)setting[2] - 'a']; test_hash = test_hashes[flags & 1]; buf.s[2] = setting[2]; } memset(buf.o, 0x55, sizeof(buf.o)); buf.o[sizeof(buf.o) - 1] = 0; p = BF_crypt(test_key, buf.s, buf.o, sizeof(buf.o) - (1 + 1), 1); ok = (p == buf.o && !memcmp(p, buf.s, 7 + 22) && !memcmp(p + (7 + 22), test_hash, 31 + 1 + 1 + 1)); { const char *k = "\xff\xa3" "34" "\xff\xff\xff\xa3" "345"; BF_key ae, ai, ye, yi; BF_set_key(k, ae, ai, 2); /* $2a$ */ BF_set_key(k, ye, yi, 4); /* $2y$ */ ai[0] ^= 0x10000; /* undo the safety (for comparison) */ ok = ok && ai[0] == 0xdb9c59bc && ye[17] == 0x33343500 && !memcmp(ae, ye, sizeof(ae)) && !memcmp(ai, yi, sizeof(ai)); } __set_errno(save_errno); if (ok) return retval; /* Should not happen */ _crypt_output_magic(setting, output, size); __set_errno(EINVAL); /* pretend we don't support this hash type */ return NULL; } char *_crypt_gensalt_blowfish_rn(const char *prefix, unsigned long count, const char *input, int size, char *output, int output_size) { if (size < 16 || output_size < 7 + 22 + 1 || (count && (count < 4 || count > 31)) || prefix[0] != '$' || prefix[1] != '2' || (prefix[2] != 'a' && prefix[2] != 'b' && prefix[2] != 'y')) { if (output_size > 0) output[0] = '\0'; __set_errno((output_size < 7 + 22 + 1) ? ERANGE : EINVAL); return NULL; } if (!count) count = 5; output[0] = '$'; output[1] = '2'; output[2] = prefix[2]; output[3] = '$'; output[4] = '0' + count / 10; output[5] = '0' + count % 10; output[6] = '$'; BF_encode(&output[7], (const BF_word *)input, 16); output[7 + 22] = '\0'; return output; } ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/vendor/bcrypt/crypt_blowfish.h�������������������������������������������������������0000664�0000000�0000000�00000001761�13554550454�0021357�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * Written by Solar Designer <solar at openwall.com> in 2000-2011. * No copyright is claimed, and the software is hereby placed in the public * domain. In case this attempt to disclaim copyright and place the software * in the public domain is deemed null and void, then the software is * Copyright (c) 2000-2011 Solar Designer and it is hereby released to the * general public under the following terms: * * Redistribution and use in source and binary forms, with or without * modification, are permitted. * * There's ABSOLUTELY NO WARRANTY, express or implied. * * See crypt_blowfish.c for more information. */ #ifndef _CRYPT_BLOWFISH_H #define _CRYPT_BLOWFISH_H extern int _crypt_output_magic(const char *setting, char *output, int size); extern char *_crypt_blowfish_rn(const char *key, const char *setting, char *output, int size); extern char *_crypt_gensalt_blowfish_rn(const char *prefix, unsigned long count, const char *input, int size, char *output, int output_size); #endif ���������������inspircd-3.4.0/vendor/http_parser/������������������������������������������������������������������0000775�0000000�0000000�00000000000�13554550454�0017173�5����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/vendor/http_parser/http_parser.c�����������������������������������������������������0000664�0000000�0000000�00000215413�13554550454�0021700�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* Copyright Joyent, Inc. and other Node contributors. * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to * deal in the Software without restriction, including without limitation the * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or * sell copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS * IN THE SOFTWARE. */ #include "http_parser.h" #include <assert.h> #include <stddef.h> #include <ctype.h> #include <string.h> #include <limits.h> static uint32_t max_header_size = HTTP_MAX_HEADER_SIZE; #ifndef ULLONG_MAX # define ULLONG_MAX ((uint64_t) -1) /* 2^64-1 */ #endif #ifndef MIN # define MIN(a,b) ((a) < (b) ? (a) : (b)) #endif #ifndef ARRAY_SIZE # define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0])) #endif #ifndef BIT_AT # define BIT_AT(a, i) \ (!!((unsigned int) (a)[(unsigned int) (i) >> 3] & \ (1 << ((unsigned int) (i) & 7)))) #endif #ifndef ELEM_AT # define ELEM_AT(a, i, v) ((unsigned int) (i) < ARRAY_SIZE(a) ? (a)[(i)] : (v)) #endif #define SET_ERRNO(e) \ do { \ parser->nread = nread; \ parser->http_errno = (e); \ } while(0) #define CURRENT_STATE() p_state #define UPDATE_STATE(V) p_state = (enum state) (V); #define RETURN(V) \ do { \ parser->nread = nread; \ parser->state = CURRENT_STATE(); \ return (V); \ } while (0); #define REEXECUTE() \ goto reexecute; \ #ifdef __GNUC__ # define LIKELY(X) __builtin_expect(!!(X), 1) # define UNLIKELY(X) __builtin_expect(!!(X), 0) #else # define LIKELY(X) (X) # define UNLIKELY(X) (X) #endif /* Run the notify callback FOR, returning ER if it fails */ #define CALLBACK_NOTIFY_(FOR, ER) \ do { \ assert(HTTP_PARSER_ERRNO(parser) == HPE_OK); \ \ if (LIKELY(settings->on_##FOR)) { \ parser->state = CURRENT_STATE(); \ if (UNLIKELY(0 != settings->on_##FOR(parser))) { \ SET_ERRNO(HPE_CB_##FOR); \ } \ UPDATE_STATE(parser->state); \ \ /* We either errored above or got paused; get out */ \ if (UNLIKELY(HTTP_PARSER_ERRNO(parser) != HPE_OK)) { \ return (ER); \ } \ } \ } while (0) /* Run the notify callback FOR and consume the current byte */ #define CALLBACK_NOTIFY(FOR) CALLBACK_NOTIFY_(FOR, p - data + 1) /* Run the notify callback FOR and don't consume the current byte */ #define CALLBACK_NOTIFY_NOADVANCE(FOR) CALLBACK_NOTIFY_(FOR, p - data) /* Run data callback FOR with LEN bytes, returning ER if it fails */ #define CALLBACK_DATA_(FOR, LEN, ER) \ do { \ assert(HTTP_PARSER_ERRNO(parser) == HPE_OK); \ \ if (FOR##_mark) { \ if (LIKELY(settings->on_##FOR)) { \ parser->state = CURRENT_STATE(); \ if (UNLIKELY(0 != \ settings->on_##FOR(parser, FOR##_mark, (LEN)))) { \ SET_ERRNO(HPE_CB_##FOR); \ } \ UPDATE_STATE(parser->state); \ \ /* We either errored above or got paused; get out */ \ if (UNLIKELY(HTTP_PARSER_ERRNO(parser) != HPE_OK)) { \ return (ER); \ } \ } \ FOR##_mark = NULL; \ } \ } while (0) /* Run the data callback FOR and consume the current byte */ #define CALLBACK_DATA(FOR) \ CALLBACK_DATA_(FOR, p - FOR##_mark, p - data + 1) /* Run the data callback FOR and don't consume the current byte */ #define CALLBACK_DATA_NOADVANCE(FOR) \ CALLBACK_DATA_(FOR, p - FOR##_mark, p - data) /* Set the mark FOR; non-destructive if mark is already set */ #define MARK(FOR) \ do { \ if (!FOR##_mark) { \ FOR##_mark = p; \ } \ } while (0) /* Don't allow the total size of the HTTP headers (including the status * line) to exceed max_header_size. This check is here to protect * embedders against denial-of-service attacks where the attacker feeds * us a never-ending header that the embedder keeps buffering. * * This check is arguably the responsibility of embedders but we're doing * it on the embedder's behalf because most won't bother and this way we * make the web a little safer. max_header_size is still far bigger * than any reasonable request or response so this should never affect * day-to-day operation. */ #define COUNT_HEADER_SIZE(V) \ do { \ nread += (uint32_t)(V); \ if (UNLIKELY(nread > max_header_size)) { \ SET_ERRNO(HPE_HEADER_OVERFLOW); \ goto error; \ } \ } while (0) #define PROXY_CONNECTION "proxy-connection" #define CONNECTION "connection" #define CONTENT_LENGTH "content-length" #define TRANSFER_ENCODING "transfer-encoding" #define UPGRADE "upgrade" #define CHUNKED "chunked" #define KEEP_ALIVE "keep-alive" #define CLOSE "close" static const char *method_strings[] = { #define XX(num, name, string) #string, HTTP_METHOD_MAP(XX) #undef XX }; /* Tokens as defined by rfc 2616. Also lowercases them. * token = 1*<any CHAR except CTLs or separators> * separators = "(" | ")" | "<" | ">" | "@" * | "," | ";" | ":" | "\" | <"> * | "/" | "[" | "]" | "?" | "=" * | "{" | "}" | SP | HT */ static const char tokens[256] = { /* 0 nul 1 soh 2 stx 3 etx 4 eot 5 enq 6 ack 7 bel */ 0, 0, 0, 0, 0, 0, 0, 0, /* 8 bs 9 ht 10 nl 11 vt 12 np 13 cr 14 so 15 si */ 0, 0, 0, 0, 0, 0, 0, 0, /* 16 dle 17 dc1 18 dc2 19 dc3 20 dc4 21 nak 22 syn 23 etb */ 0, 0, 0, 0, 0, 0, 0, 0, /* 24 can 25 em 26 sub 27 esc 28 fs 29 gs 30 rs 31 us */ 0, 0, 0, 0, 0, 0, 0, 0, /* 32 sp 33 ! 34 " 35 # 36 $ 37 % 38 & 39 ' */ ' ', '!', 0, '#', '$', '%', '&', '\'', /* 40 ( 41 ) 42 * 43 + 44 , 45 - 46 . 47 / */ 0, 0, '*', '+', 0, '-', '.', 0, /* 48 0 49 1 50 2 51 3 52 4 53 5 54 6 55 7 */ '0', '1', '2', '3', '4', '5', '6', '7', /* 56 8 57 9 58 : 59 ; 60 < 61 = 62 > 63 ? */ '8', '9', 0, 0, 0, 0, 0, 0, /* 64 @ 65 A 66 B 67 C 68 D 69 E 70 F 71 G */ 0, 'a', 'b', 'c', 'd', 'e', 'f', 'g', /* 72 H 73 I 74 J 75 K 76 L 77 M 78 N 79 O */ 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', /* 80 P 81 Q 82 R 83 S 84 T 85 U 86 V 87 W */ 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', /* 88 X 89 Y 90 Z 91 [ 92 \ 93 ] 94 ^ 95 _ */ 'x', 'y', 'z', 0, 0, 0, '^', '_', /* 96 ` 97 a 98 b 99 c 100 d 101 e 102 f 103 g */ '`', 'a', 'b', 'c', 'd', 'e', 'f', 'g', /* 104 h 105 i 106 j 107 k 108 l 109 m 110 n 111 o */ 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', /* 112 p 113 q 114 r 115 s 116 t 117 u 118 v 119 w */ 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', /* 120 x 121 y 122 z 123 { 124 | 125 } 126 ~ 127 del */ 'x', 'y', 'z', 0, '|', 0, '~', 0 }; static const int8_t unhex[256] = {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1 ,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1 ,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1 , 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,-1,-1,-1,-1,-1,-1 ,-1,10,11,12,13,14,15,-1,-1,-1,-1,-1,-1,-1,-1,-1 ,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1 ,-1,10,11,12,13,14,15,-1,-1,-1,-1,-1,-1,-1,-1,-1 ,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1 }; #if HTTP_PARSER_STRICT # define T(v) 0 #else # define T(v) v #endif static const uint8_t normal_url_char[32] = { /* 0 nul 1 soh 2 stx 3 etx 4 eot 5 enq 6 ack 7 bel */ 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0, /* 8 bs 9 ht 10 nl 11 vt 12 np 13 cr 14 so 15 si */ 0 | T(2) | 0 | 0 | T(16) | 0 | 0 | 0, /* 16 dle 17 dc1 18 dc2 19 dc3 20 dc4 21 nak 22 syn 23 etb */ 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0, /* 24 can 25 em 26 sub 27 esc 28 fs 29 gs 30 rs 31 us */ 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0, /* 32 sp 33 ! 34 " 35 # 36 $ 37 % 38 & 39 ' */ 0 | 2 | 4 | 0 | 16 | 32 | 64 | 128, /* 40 ( 41 ) 42 * 43 + 44 , 45 - 46 . 47 / */ 1 | 2 | 4 | 8 | 16 | 32 | 64 | 128, /* 48 0 49 1 50 2 51 3 52 4 53 5 54 6 55 7 */ 1 | 2 | 4 | 8 | 16 | 32 | 64 | 128, /* 56 8 57 9 58 : 59 ; 60 < 61 = 62 > 63 ? */ 1 | 2 | 4 | 8 | 16 | 32 | 64 | 0, /* 64 @ 65 A 66 B 67 C 68 D 69 E 70 F 71 G */ 1 | 2 | 4 | 8 | 16 | 32 | 64 | 128, /* 72 H 73 I 74 J 75 K 76 L 77 M 78 N 79 O */ 1 | 2 | 4 | 8 | 16 | 32 | 64 | 128, /* 80 P 81 Q 82 R 83 S 84 T 85 U 86 V 87 W */ 1 | 2 | 4 | 8 | 16 | 32 | 64 | 128, /* 88 X 89 Y 90 Z 91 [ 92 \ 93 ] 94 ^ 95 _ */ 1 | 2 | 4 | 8 | 16 | 32 | 64 | 128, /* 96 ` 97 a 98 b 99 c 100 d 101 e 102 f 103 g */ 1 | 2 | 4 | 8 | 16 | 32 | 64 | 128, /* 104 h 105 i 106 j 107 k 108 l 109 m 110 n 111 o */ 1 | 2 | 4 | 8 | 16 | 32 | 64 | 128, /* 112 p 113 q 114 r 115 s 116 t 117 u 118 v 119 w */ 1 | 2 | 4 | 8 | 16 | 32 | 64 | 128, /* 120 x 121 y 122 z 123 { 124 | 125 } 126 ~ 127 del */ 1 | 2 | 4 | 8 | 16 | 32 | 64 | 0, }; #undef T enum state { s_dead = 1 /* important that this is > 0 */ , s_start_req_or_res , s_res_or_resp_H , s_start_res , s_res_H , s_res_HT , s_res_HTT , s_res_HTTP , s_res_http_major , s_res_http_dot , s_res_http_minor , s_res_http_end , s_res_first_status_code , s_res_status_code , s_res_status_start , s_res_status , s_res_line_almost_done , s_start_req , s_req_method , s_req_spaces_before_url , s_req_schema , s_req_schema_slash , s_req_schema_slash_slash , s_req_server_start , s_req_server , s_req_server_with_at , s_req_path , s_req_query_string_start , s_req_query_string , s_req_fragment_start , s_req_fragment , s_req_http_start , s_req_http_H , s_req_http_HT , s_req_http_HTT , s_req_http_HTTP , s_req_http_I , s_req_http_IC , s_req_http_major , s_req_http_dot , s_req_http_minor , s_req_http_end , s_req_line_almost_done , s_header_field_start , s_header_field , s_header_value_discard_ws , s_header_value_discard_ws_almost_done , s_header_value_discard_lws , s_header_value_start , s_header_value , s_header_value_lws , s_header_almost_done , s_chunk_size_start , s_chunk_size , s_chunk_parameters , s_chunk_size_almost_done , s_headers_almost_done , s_headers_done /* Important: 's_headers_done' must be the last 'header' state. All * states beyond this must be 'body' states. It is used for overflow * checking. See the PARSING_HEADER() macro. */ , s_chunk_data , s_chunk_data_almost_done , s_chunk_data_done , s_body_identity , s_body_identity_eof , s_message_done }; #define PARSING_HEADER(state) (state <= s_headers_done) enum header_states { h_general = 0 , h_C , h_CO , h_CON , h_matching_connection , h_matching_proxy_connection , h_matching_content_length , h_matching_transfer_encoding , h_matching_upgrade , h_connection , h_content_length , h_content_length_num , h_content_length_ws , h_transfer_encoding , h_upgrade , h_matching_transfer_encoding_chunked , h_matching_connection_token_start , h_matching_connection_keep_alive , h_matching_connection_close , h_matching_connection_upgrade , h_matching_connection_token , h_transfer_encoding_chunked , h_connection_keep_alive , h_connection_close , h_connection_upgrade }; enum http_host_state { s_http_host_dead = 1 , s_http_userinfo_start , s_http_userinfo , s_http_host_start , s_http_host_v6_start , s_http_host , s_http_host_v6 , s_http_host_v6_end , s_http_host_v6_zone_start , s_http_host_v6_zone , s_http_host_port_start , s_http_host_port }; /* Macros for character classes; depends on strict-mode */ #define CR '\r' #define LF '\n' #define LOWER(c) (unsigned char)(c | 0x20) #define IS_ALPHA(c) (LOWER(c) >= 'a' && LOWER(c) <= 'z') #define IS_NUM(c) ((c) >= '0' && (c) <= '9') #define IS_ALPHANUM(c) (IS_ALPHA(c) || IS_NUM(c)) #define IS_HEX(c) (IS_NUM(c) || (LOWER(c) >= 'a' && LOWER(c) <= 'f')) #define IS_MARK(c) ((c) == '-' || (c) == '_' || (c) == '.' || \ (c) == '!' || (c) == '~' || (c) == '*' || (c) == '\'' || (c) == '(' || \ (c) == ')') #define IS_USERINFO_CHAR(c) (IS_ALPHANUM(c) || IS_MARK(c) || (c) == '%' || \ (c) == ';' || (c) == ':' || (c) == '&' || (c) == '=' || (c) == '+' || \ (c) == '$' || (c) == ',') #define STRICT_TOKEN(c) ((c == ' ') ? 0 : tokens[(unsigned char)c]) #if HTTP_PARSER_STRICT #define TOKEN(c) STRICT_TOKEN(c) #define IS_URL_CHAR(c) (BIT_AT(normal_url_char, (unsigned char)c)) #define IS_HOST_CHAR(c) (IS_ALPHANUM(c) || (c) == '.' || (c) == '-') #else #define TOKEN(c) tokens[(unsigned char)c] #define IS_URL_CHAR(c) \ (BIT_AT(normal_url_char, (unsigned char)c) || ((c) & 0x80)) #define IS_HOST_CHAR(c) \ (IS_ALPHANUM(c) || (c) == '.' || (c) == '-' || (c) == '_') #endif /** * Verify that a char is a valid visible (printable) US-ASCII * character or %x80-FF **/ #define IS_HEADER_CHAR(ch) \ (ch == CR || ch == LF || ch == 9 || ((unsigned char)ch > 31 && ch != 127)) #define start_state (parser->type == HTTP_REQUEST ? s_start_req : s_start_res) #if HTTP_PARSER_STRICT # define STRICT_CHECK(cond) \ do { \ if (cond) { \ SET_ERRNO(HPE_STRICT); \ goto error; \ } \ } while (0) # define NEW_MESSAGE() (http_should_keep_alive(parser) ? start_state : s_dead) #else # define STRICT_CHECK(cond) # define NEW_MESSAGE() start_state #endif /* Map errno values to strings for human-readable output */ #define HTTP_STRERROR_GEN(n, s) { "HPE_" #n, s }, static struct { const char *name; const char *description; } http_strerror_tab[] = { HTTP_ERRNO_MAP(HTTP_STRERROR_GEN) }; #undef HTTP_STRERROR_GEN int http_message_needs_eof(const http_parser *parser); /* Our URL parser. * * This is designed to be shared by http_parser_execute() for URL validation, * hence it has a state transition + byte-for-byte interface. In addition, it * is meant to be embedded in http_parser_parse_url(), which does the dirty * work of turning state transitions URL components for its API. * * This function should only be invoked with non-space characters. It is * assumed that the caller cares about (and can detect) the transition between * URL and non-URL states by looking for these. */ static enum state parse_url_char(enum state s, const char ch) { if (ch == ' ' || ch == '\r' || ch == '\n') { return s_dead; } #if HTTP_PARSER_STRICT if (ch == '\t' || ch == '\f') { return s_dead; } #endif switch (s) { case s_req_spaces_before_url: /* Proxied requests are followed by scheme of an absolute URI (alpha). * All methods except CONNECT are followed by '/' or '*'. */ if (ch == '/' || ch == '*') { return s_req_path; } if (IS_ALPHA(ch)) { return s_req_schema; } break; case s_req_schema: if (IS_ALPHA(ch)) { return s; } if (ch == ':') { return s_req_schema_slash; } break; case s_req_schema_slash: if (ch == '/') { return s_req_schema_slash_slash; } break; case s_req_schema_slash_slash: if (ch == '/') { return s_req_server_start; } break; case s_req_server_with_at: if (ch == '@') { return s_dead; } /* fall through */ case s_req_server_start: case s_req_server: if (ch == '/') { return s_req_path; } if (ch == '?') { return s_req_query_string_start; } if (ch == '@') { return s_req_server_with_at; } if (IS_USERINFO_CHAR(ch) || ch == '[' || ch == ']') { return s_req_server; } break; case s_req_path: if (IS_URL_CHAR(ch)) { return s; } switch (ch) { case '?': return s_req_query_string_start; case '#': return s_req_fragment_start; } break; case s_req_query_string_start: case s_req_query_string: if (IS_URL_CHAR(ch)) { return s_req_query_string; } switch (ch) { case '?': /* allow extra '?' in query string */ return s_req_query_string; case '#': return s_req_fragment_start; } break; case s_req_fragment_start: if (IS_URL_CHAR(ch)) { return s_req_fragment; } switch (ch) { case '?': return s_req_fragment; case '#': return s; } break; case s_req_fragment: if (IS_URL_CHAR(ch)) { return s; } switch (ch) { case '?': case '#': return s; } break; default: break; } /* We should never fall out of the switch above unless there's an error */ return s_dead; } size_t http_parser_execute (http_parser *parser, const http_parser_settings *settings, const char *data, size_t len) { char c, ch; int8_t unhex_val; const char *p = data; const char *header_field_mark = 0; const char *header_value_mark = 0; const char *url_mark = 0; const char *body_mark = 0; const char *status_mark = 0; enum state p_state = (enum state) parser->state; const unsigned int lenient = parser->lenient_http_headers; uint32_t nread = parser->nread; /* We're in an error state. Don't bother doing anything. */ if (HTTP_PARSER_ERRNO(parser) != HPE_OK) { return 0; } if (len == 0) { switch (CURRENT_STATE()) { case s_body_identity_eof: /* Use of CALLBACK_NOTIFY() here would erroneously return 1 byte read if * we got paused. */ CALLBACK_NOTIFY_NOADVANCE(message_complete); return 0; case s_dead: case s_start_req_or_res: case s_start_res: case s_start_req: return 0; default: SET_ERRNO(HPE_INVALID_EOF_STATE); return 1; } } if (CURRENT_STATE() == s_header_field) header_field_mark = data; if (CURRENT_STATE() == s_header_value) header_value_mark = data; switch (CURRENT_STATE()) { case s_req_path: case s_req_schema: case s_req_schema_slash: case s_req_schema_slash_slash: case s_req_server_start: case s_req_server: case s_req_server_with_at: case s_req_query_string_start: case s_req_query_string: case s_req_fragment_start: case s_req_fragment: url_mark = data; break; case s_res_status: status_mark = data; break; default: break; } for (p=data; p != data + len; p++) { ch = *p; if (PARSING_HEADER(CURRENT_STATE())) COUNT_HEADER_SIZE(1); reexecute: switch (CURRENT_STATE()) { case s_dead: /* this state is used after a 'Connection: close' message * the parser will error out if it reads another message */ if (LIKELY(ch == CR || ch == LF)) break; SET_ERRNO(HPE_CLOSED_CONNECTION); goto error; case s_start_req_or_res: { if (ch == CR || ch == LF) break; parser->flags = 0; parser->content_length = ULLONG_MAX; if (ch == 'H') { UPDATE_STATE(s_res_or_resp_H); CALLBACK_NOTIFY(message_begin); } else { parser->type = HTTP_REQUEST; UPDATE_STATE(s_start_req); REEXECUTE(); } break; } case s_res_or_resp_H: if (ch == 'T') { parser->type = HTTP_RESPONSE; UPDATE_STATE(s_res_HT); } else { if (UNLIKELY(ch != 'E')) { SET_ERRNO(HPE_INVALID_CONSTANT); goto error; } parser->type = HTTP_REQUEST; parser->method = HTTP_HEAD; parser->index = 2; UPDATE_STATE(s_req_method); } break; case s_start_res: { if (ch == CR || ch == LF) break; parser->flags = 0; parser->content_length = ULLONG_MAX; if (ch == 'H') { UPDATE_STATE(s_res_H); } else { SET_ERRNO(HPE_INVALID_CONSTANT); goto error; } CALLBACK_NOTIFY(message_begin); break; } case s_res_H: STRICT_CHECK(ch != 'T'); UPDATE_STATE(s_res_HT); break; case s_res_HT: STRICT_CHECK(ch != 'T'); UPDATE_STATE(s_res_HTT); break; case s_res_HTT: STRICT_CHECK(ch != 'P'); UPDATE_STATE(s_res_HTTP); break; case s_res_HTTP: STRICT_CHECK(ch != '/'); UPDATE_STATE(s_res_http_major); break; case s_res_http_major: if (UNLIKELY(!IS_NUM(ch))) { SET_ERRNO(HPE_INVALID_VERSION); goto error; } parser->http_major = ch - '0'; UPDATE_STATE(s_res_http_dot); break; case s_res_http_dot: { if (UNLIKELY(ch != '.')) { SET_ERRNO(HPE_INVALID_VERSION); goto error; } UPDATE_STATE(s_res_http_minor); break; } case s_res_http_minor: if (UNLIKELY(!IS_NUM(ch))) { SET_ERRNO(HPE_INVALID_VERSION); goto error; } parser->http_minor = ch - '0'; UPDATE_STATE(s_res_http_end); break; case s_res_http_end: { if (UNLIKELY(ch != ' ')) { SET_ERRNO(HPE_INVALID_VERSION); goto error; } UPDATE_STATE(s_res_first_status_code); break; } case s_res_first_status_code: { if (!IS_NUM(ch)) { if (ch == ' ') { break; } SET_ERRNO(HPE_INVALID_STATUS); goto error; } parser->status_code = ch - '0'; UPDATE_STATE(s_res_status_code); break; } case s_res_status_code: { if (!IS_NUM(ch)) { switch (ch) { case ' ': UPDATE_STATE(s_res_status_start); break; case CR: case LF: UPDATE_STATE(s_res_status_start); REEXECUTE(); break; default: SET_ERRNO(HPE_INVALID_STATUS); goto error; } break; } parser->status_code *= 10; parser->status_code += ch - '0'; if (UNLIKELY(parser->status_code > 999)) { SET_ERRNO(HPE_INVALID_STATUS); goto error; } break; } case s_res_status_start: { MARK(status); UPDATE_STATE(s_res_status); parser->index = 0; if (ch == CR || ch == LF) REEXECUTE(); break; } case s_res_status: if (ch == CR) { UPDATE_STATE(s_res_line_almost_done); CALLBACK_DATA(status); break; } if (ch == LF) { UPDATE_STATE(s_header_field_start); CALLBACK_DATA(status); break; } break; case s_res_line_almost_done: STRICT_CHECK(ch != LF); UPDATE_STATE(s_header_field_start); break; case s_start_req: { if (ch == CR || ch == LF) break; parser->flags = 0; parser->content_length = ULLONG_MAX; if (UNLIKELY(!IS_ALPHA(ch))) { SET_ERRNO(HPE_INVALID_METHOD); goto error; } parser->method = (enum http_method) 0; parser->index = 1; switch (ch) { case 'A': parser->method = HTTP_ACL; break; case 'B': parser->method = HTTP_BIND; break; case 'C': parser->method = HTTP_CONNECT; /* or COPY, CHECKOUT */ break; case 'D': parser->method = HTTP_DELETE; break; case 'G': parser->method = HTTP_GET; break; case 'H': parser->method = HTTP_HEAD; break; case 'L': parser->method = HTTP_LOCK; /* or LINK */ break; case 'M': parser->method = HTTP_MKCOL; /* or MOVE, MKACTIVITY, MERGE, M-SEARCH, MKCALENDAR */ break; case 'N': parser->method = HTTP_NOTIFY; break; case 'O': parser->method = HTTP_OPTIONS; break; case 'P': parser->method = HTTP_POST; /* or PROPFIND|PROPPATCH|PUT|PATCH|PURGE */ break; case 'R': parser->method = HTTP_REPORT; /* or REBIND */ break; case 'S': parser->method = HTTP_SUBSCRIBE; /* or SEARCH, SOURCE */ break; case 'T': parser->method = HTTP_TRACE; break; case 'U': parser->method = HTTP_UNLOCK; /* or UNSUBSCRIBE, UNBIND, UNLINK */ break; default: SET_ERRNO(HPE_INVALID_METHOD); goto error; } UPDATE_STATE(s_req_method); CALLBACK_NOTIFY(message_begin); break; } case s_req_method: { const char *matcher; if (UNLIKELY(ch == '\0')) { SET_ERRNO(HPE_INVALID_METHOD); goto error; } matcher = method_strings[parser->method]; if (ch == ' ' && matcher[parser->index] == '\0') { UPDATE_STATE(s_req_spaces_before_url); } else if (ch == matcher[parser->index]) { ; /* nada */ } else if ((ch >= 'A' && ch <= 'Z') || ch == '-') { switch (parser->method << 16 | parser->index << 8 | ch) { #define XX(meth, pos, ch, new_meth) \ case (HTTP_##meth << 16 | pos << 8 | ch): \ parser->method = HTTP_##new_meth; break; XX(POST, 1, 'U', PUT) XX(POST, 1, 'A', PATCH) XX(POST, 1, 'R', PROPFIND) XX(PUT, 2, 'R', PURGE) XX(CONNECT, 1, 'H', CHECKOUT) XX(CONNECT, 2, 'P', COPY) XX(MKCOL, 1, 'O', MOVE) XX(MKCOL, 1, 'E', MERGE) XX(MKCOL, 1, '-', MSEARCH) XX(MKCOL, 2, 'A', MKACTIVITY) XX(MKCOL, 3, 'A', MKCALENDAR) XX(SUBSCRIBE, 1, 'E', SEARCH) XX(SUBSCRIBE, 1, 'O', SOURCE) XX(REPORT, 2, 'B', REBIND) XX(PROPFIND, 4, 'P', PROPPATCH) XX(LOCK, 1, 'I', LINK) XX(UNLOCK, 2, 'S', UNSUBSCRIBE) XX(UNLOCK, 2, 'B', UNBIND) XX(UNLOCK, 3, 'I', UNLINK) #undef XX default: SET_ERRNO(HPE_INVALID_METHOD); goto error; } } else { SET_ERRNO(HPE_INVALID_METHOD); goto error; } ++parser->index; break; } case s_req_spaces_before_url: { if (ch == ' ') break; MARK(url); if (parser->method == HTTP_CONNECT) { UPDATE_STATE(s_req_server_start); } UPDATE_STATE(parse_url_char(CURRENT_STATE(), ch)); if (UNLIKELY(CURRENT_STATE() == s_dead)) { SET_ERRNO(HPE_INVALID_URL); goto error; } break; } case s_req_schema: case s_req_schema_slash: case s_req_schema_slash_slash: case s_req_server_start: { switch (ch) { /* No whitespace allowed here */ case ' ': case CR: case LF: SET_ERRNO(HPE_INVALID_URL); goto error; default: UPDATE_STATE(parse_url_char(CURRENT_STATE(), ch)); if (UNLIKELY(CURRENT_STATE() == s_dead)) { SET_ERRNO(HPE_INVALID_URL); goto error; } } break; } case s_req_server: case s_req_server_with_at: case s_req_path: case s_req_query_string_start: case s_req_query_string: case s_req_fragment_start: case s_req_fragment: { switch (ch) { case ' ': UPDATE_STATE(s_req_http_start); CALLBACK_DATA(url); break; case CR: case LF: parser->http_major = 0; parser->http_minor = 9; UPDATE_STATE((ch == CR) ? s_req_line_almost_done : s_header_field_start); CALLBACK_DATA(url); break; default: UPDATE_STATE(parse_url_char(CURRENT_STATE(), ch)); if (UNLIKELY(CURRENT_STATE() == s_dead)) { SET_ERRNO(HPE_INVALID_URL); goto error; } } break; } case s_req_http_start: switch (ch) { case ' ': break; case 'H': UPDATE_STATE(s_req_http_H); break; case 'I': if (parser->method == HTTP_SOURCE) { UPDATE_STATE(s_req_http_I); break; } /* fall through */ default: SET_ERRNO(HPE_INVALID_CONSTANT); goto error; } break; case s_req_http_H: STRICT_CHECK(ch != 'T'); UPDATE_STATE(s_req_http_HT); break; case s_req_http_HT: STRICT_CHECK(ch != 'T'); UPDATE_STATE(s_req_http_HTT); break; case s_req_http_HTT: STRICT_CHECK(ch != 'P'); UPDATE_STATE(s_req_http_HTTP); break; case s_req_http_I: STRICT_CHECK(ch != 'C'); UPDATE_STATE(s_req_http_IC); break; case s_req_http_IC: STRICT_CHECK(ch != 'E'); UPDATE_STATE(s_req_http_HTTP); /* Treat "ICE" as "HTTP". */ break; case s_req_http_HTTP: STRICT_CHECK(ch != '/'); UPDATE_STATE(s_req_http_major); break; case s_req_http_major: if (UNLIKELY(!IS_NUM(ch))) { SET_ERRNO(HPE_INVALID_VERSION); goto error; } parser->http_major = ch - '0'; UPDATE_STATE(s_req_http_dot); break; case s_req_http_dot: { if (UNLIKELY(ch != '.')) { SET_ERRNO(HPE_INVALID_VERSION); goto error; } UPDATE_STATE(s_req_http_minor); break; } case s_req_http_minor: if (UNLIKELY(!IS_NUM(ch))) { SET_ERRNO(HPE_INVALID_VERSION); goto error; } parser->http_minor = ch - '0'; UPDATE_STATE(s_req_http_end); break; case s_req_http_end: { if (ch == CR) { UPDATE_STATE(s_req_line_almost_done); break; } if (ch == LF) { UPDATE_STATE(s_header_field_start); break; } SET_ERRNO(HPE_INVALID_VERSION); goto error; break; } /* end of request line */ case s_req_line_almost_done: { if (UNLIKELY(ch != LF)) { SET_ERRNO(HPE_LF_EXPECTED); goto error; } UPDATE_STATE(s_header_field_start); break; } case s_header_field_start: { if (ch == CR) { UPDATE_STATE(s_headers_almost_done); break; } if (ch == LF) { /* they might be just sending \n instead of \r\n so this would be * the second \n to denote the end of headers*/ UPDATE_STATE(s_headers_almost_done); REEXECUTE(); } c = TOKEN(ch); if (UNLIKELY(!c)) { SET_ERRNO(HPE_INVALID_HEADER_TOKEN); goto error; } MARK(header_field); parser->index = 0; UPDATE_STATE(s_header_field); switch (c) { case 'c': parser->header_state = h_C; break; case 'p': parser->header_state = h_matching_proxy_connection; break; case 't': parser->header_state = h_matching_transfer_encoding; break; case 'u': parser->header_state = h_matching_upgrade; break; default: parser->header_state = h_general; break; } break; } case s_header_field: { const char* start = p; for (; p != data + len; p++) { ch = *p; c = TOKEN(ch); if (!c) break; switch (parser->header_state) { case h_general: { size_t left = data + len - p; const char* pe = p + MIN(left, max_header_size); while (p+1 < pe && TOKEN(p[1])) { p++; } break; } case h_C: parser->index++; parser->header_state = (c == 'o' ? h_CO : h_general); break; case h_CO: parser->index++; parser->header_state = (c == 'n' ? h_CON : h_general); break; case h_CON: parser->index++; switch (c) { case 'n': parser->header_state = h_matching_connection; break; case 't': parser->header_state = h_matching_content_length; break; default: parser->header_state = h_general; break; } break; /* connection */ case h_matching_connection: parser->index++; if (parser->index > sizeof(CONNECTION)-1 || c != CONNECTION[parser->index]) { parser->header_state = h_general; } else if (parser->index == sizeof(CONNECTION)-2) { parser->header_state = h_connection; } break; /* proxy-connection */ case h_matching_proxy_connection: parser->index++; if (parser->index > sizeof(PROXY_CONNECTION)-1 || c != PROXY_CONNECTION[parser->index]) { parser->header_state = h_general; } else if (parser->index == sizeof(PROXY_CONNECTION)-2) { parser->header_state = h_connection; } break; /* content-length */ case h_matching_content_length: parser->index++; if (parser->index > sizeof(CONTENT_LENGTH)-1 || c != CONTENT_LENGTH[parser->index]) { parser->header_state = h_general; } else if (parser->index == sizeof(CONTENT_LENGTH)-2) { parser->header_state = h_content_length; } break; /* transfer-encoding */ case h_matching_transfer_encoding: parser->index++; if (parser->index > sizeof(TRANSFER_ENCODING)-1 || c != TRANSFER_ENCODING[parser->index]) { parser->header_state = h_general; } else if (parser->index == sizeof(TRANSFER_ENCODING)-2) { parser->header_state = h_transfer_encoding; } break; /* upgrade */ case h_matching_upgrade: parser->index++; if (parser->index > sizeof(UPGRADE)-1 || c != UPGRADE[parser->index]) { parser->header_state = h_general; } else if (parser->index == sizeof(UPGRADE)-2) { parser->header_state = h_upgrade; } break; case h_connection: case h_content_length: case h_transfer_encoding: case h_upgrade: if (ch != ' ') parser->header_state = h_general; break; default: assert(0 && "Unknown header_state"); break; } } if (p == data + len) { --p; COUNT_HEADER_SIZE(p - start); break; } COUNT_HEADER_SIZE(p - start); if (ch == ':') { UPDATE_STATE(s_header_value_discard_ws); CALLBACK_DATA(header_field); break; } SET_ERRNO(HPE_INVALID_HEADER_TOKEN); goto error; } case s_header_value_discard_ws: if (ch == ' ' || ch == '\t') break; if (ch == CR) { UPDATE_STATE(s_header_value_discard_ws_almost_done); break; } if (ch == LF) { UPDATE_STATE(s_header_value_discard_lws); break; } /* fall through */ case s_header_value_start: { MARK(header_value); UPDATE_STATE(s_header_value); parser->index = 0; c = LOWER(ch); switch (parser->header_state) { case h_upgrade: parser->flags |= F_UPGRADE; parser->header_state = h_general; break; case h_transfer_encoding: /* looking for 'Transfer-Encoding: chunked' */ if ('c' == c) { parser->header_state = h_matching_transfer_encoding_chunked; } else { parser->header_state = h_general; } break; case h_content_length: if (UNLIKELY(!IS_NUM(ch))) { SET_ERRNO(HPE_INVALID_CONTENT_LENGTH); goto error; } if (parser->flags & F_CONTENTLENGTH) { SET_ERRNO(HPE_UNEXPECTED_CONTENT_LENGTH); goto error; } parser->flags |= F_CONTENTLENGTH; parser->content_length = ch - '0'; parser->header_state = h_content_length_num; break; /* when obsolete line folding is encountered for content length * continue to the s_header_value state */ case h_content_length_ws: break; case h_connection: /* looking for 'Connection: keep-alive' */ if (c == 'k') { parser->header_state = h_matching_connection_keep_alive; /* looking for 'Connection: close' */ } else if (c == 'c') { parser->header_state = h_matching_connection_close; } else if (c == 'u') { parser->header_state = h_matching_connection_upgrade; } else { parser->header_state = h_matching_connection_token; } break; /* Multi-value `Connection` header */ case h_matching_connection_token_start: break; default: parser->header_state = h_general; break; } break; } case s_header_value: { const char* start = p; enum header_states h_state = (enum header_states) parser->header_state; for (; p != data + len; p++) { ch = *p; if (ch == CR) { UPDATE_STATE(s_header_almost_done); parser->header_state = h_state; CALLBACK_DATA(header_value); break; } if (ch == LF) { UPDATE_STATE(s_header_almost_done); COUNT_HEADER_SIZE(p - start); parser->header_state = h_state; CALLBACK_DATA_NOADVANCE(header_value); REEXECUTE(); } if (!lenient && !IS_HEADER_CHAR(ch)) { SET_ERRNO(HPE_INVALID_HEADER_TOKEN); goto error; } c = LOWER(ch); switch (h_state) { case h_general: { size_t left = data + len - p; const char* pe = p + MIN(left, max_header_size); for (; p != pe; p++) { ch = *p; if (ch == CR || ch == LF) { --p; break; } if (!lenient && !IS_HEADER_CHAR(ch)) { SET_ERRNO(HPE_INVALID_HEADER_TOKEN); goto error; } } if (p == data + len) --p; break; } case h_connection: case h_transfer_encoding: assert(0 && "Shouldn't get here."); break; case h_content_length: if (ch == ' ') break; h_state = h_content_length_num; /* fall through */ case h_content_length_num: { uint64_t t; if (ch == ' ') { h_state = h_content_length_ws; break; } if (UNLIKELY(!IS_NUM(ch))) { SET_ERRNO(HPE_INVALID_CONTENT_LENGTH); parser->header_state = h_state; goto error; } t = parser->content_length; t *= 10; t += ch - '0'; /* Overflow? Test against a conservative limit for simplicity. */ if (UNLIKELY((ULLONG_MAX - 10) / 10 < parser->content_length)) { SET_ERRNO(HPE_INVALID_CONTENT_LENGTH); parser->header_state = h_state; goto error; } parser->content_length = t; break; } case h_content_length_ws: if (ch == ' ') break; SET_ERRNO(HPE_INVALID_CONTENT_LENGTH); parser->header_state = h_state; goto error; /* Transfer-Encoding: chunked */ case h_matching_transfer_encoding_chunked: parser->index++; if (parser->index > sizeof(CHUNKED)-1 || c != CHUNKED[parser->index]) { h_state = h_general; } else if (parser->index == sizeof(CHUNKED)-2) { h_state = h_transfer_encoding_chunked; } break; case h_matching_connection_token_start: /* looking for 'Connection: keep-alive' */ if (c == 'k') { h_state = h_matching_connection_keep_alive; /* looking for 'Connection: close' */ } else if (c == 'c') { h_state = h_matching_connection_close; } else if (c == 'u') { h_state = h_matching_connection_upgrade; } else if (STRICT_TOKEN(c)) { h_state = h_matching_connection_token; } else if (c == ' ' || c == '\t') { /* Skip lws */ } else { h_state = h_general; } break; /* looking for 'Connection: keep-alive' */ case h_matching_connection_keep_alive: parser->index++; if (parser->index > sizeof(KEEP_ALIVE)-1 || c != KEEP_ALIVE[parser->index]) { h_state = h_matching_connection_token; } else if (parser->index == sizeof(KEEP_ALIVE)-2) { h_state = h_connection_keep_alive; } break; /* looking for 'Connection: close' */ case h_matching_connection_close: parser->index++; if (parser->index > sizeof(CLOSE)-1 || c != CLOSE[parser->index]) { h_state = h_matching_connection_token; } else if (parser->index == sizeof(CLOSE)-2) { h_state = h_connection_close; } break; /* looking for 'Connection: upgrade' */ case h_matching_connection_upgrade: parser->index++; if (parser->index > sizeof(UPGRADE) - 1 || c != UPGRADE[parser->index]) { h_state = h_matching_connection_token; } else if (parser->index == sizeof(UPGRADE)-2) { h_state = h_connection_upgrade; } break; case h_matching_connection_token: if (ch == ',') { h_state = h_matching_connection_token_start; parser->index = 0; } break; case h_transfer_encoding_chunked: if (ch != ' ') h_state = h_general; break; case h_connection_keep_alive: case h_connection_close: case h_connection_upgrade: if (ch == ',') { if (h_state == h_connection_keep_alive) { parser->flags |= F_CONNECTION_KEEP_ALIVE; } else if (h_state == h_connection_close) { parser->flags |= F_CONNECTION_CLOSE; } else if (h_state == h_connection_upgrade) { parser->flags |= F_CONNECTION_UPGRADE; } h_state = h_matching_connection_token_start; parser->index = 0; } else if (ch != ' ') { h_state = h_matching_connection_token; } break; default: UPDATE_STATE(s_header_value); h_state = h_general; break; } } parser->header_state = h_state; if (p == data + len) --p; COUNT_HEADER_SIZE(p - start); break; } case s_header_almost_done: { if (UNLIKELY(ch != LF)) { SET_ERRNO(HPE_LF_EXPECTED); goto error; } UPDATE_STATE(s_header_value_lws); break; } case s_header_value_lws: { if (ch == ' ' || ch == '\t') { if (parser->header_state == h_content_length_num) { /* treat obsolete line folding as space */ parser->header_state = h_content_length_ws; } UPDATE_STATE(s_header_value_start); REEXECUTE(); } /* finished the header */ switch (parser->header_state) { case h_connection_keep_alive: parser->flags |= F_CONNECTION_KEEP_ALIVE; break; case h_connection_close: parser->flags |= F_CONNECTION_CLOSE; break; case h_transfer_encoding_chunked: parser->flags |= F_CHUNKED; break; case h_connection_upgrade: parser->flags |= F_CONNECTION_UPGRADE; break; default: break; } UPDATE_STATE(s_header_field_start); REEXECUTE(); } case s_header_value_discard_ws_almost_done: { STRICT_CHECK(ch != LF); UPDATE_STATE(s_header_value_discard_lws); break; } case s_header_value_discard_lws: { if (ch == ' ' || ch == '\t') { UPDATE_STATE(s_header_value_discard_ws); break; } else { switch (parser->header_state) { case h_connection_keep_alive: parser->flags |= F_CONNECTION_KEEP_ALIVE; break; case h_connection_close: parser->flags |= F_CONNECTION_CLOSE; break; case h_connection_upgrade: parser->flags |= F_CONNECTION_UPGRADE; break; case h_transfer_encoding_chunked: parser->flags |= F_CHUNKED; break; case h_content_length: /* do not allow empty content length */ SET_ERRNO(HPE_INVALID_CONTENT_LENGTH); goto error; break; default: break; } /* header value was empty */ MARK(header_value); UPDATE_STATE(s_header_field_start); CALLBACK_DATA_NOADVANCE(header_value); REEXECUTE(); } } case s_headers_almost_done: { STRICT_CHECK(ch != LF); if (parser->flags & F_TRAILING) { /* End of a chunked request */ UPDATE_STATE(s_message_done); CALLBACK_NOTIFY_NOADVANCE(chunk_complete); REEXECUTE(); } /* Cannot use chunked encoding and a content-length header together per the HTTP specification. */ if ((parser->flags & F_CHUNKED) && (parser->flags & F_CONTENTLENGTH)) { SET_ERRNO(HPE_UNEXPECTED_CONTENT_LENGTH); goto error; } UPDATE_STATE(s_headers_done); /* Set this here so that on_headers_complete() callbacks can see it */ if ((parser->flags & F_UPGRADE) && (parser->flags & F_CONNECTION_UPGRADE)) { /* For responses, "Upgrade: foo" and "Connection: upgrade" are * mandatory only when it is a 101 Switching Protocols response, * otherwise it is purely informational, to announce support. */ parser->upgrade = (parser->type == HTTP_REQUEST || parser->status_code == 101); } else { parser->upgrade = (parser->method == HTTP_CONNECT); } /* Here we call the headers_complete callback. This is somewhat * different than other callbacks because if the user returns 1, we * will interpret that as saying that this message has no body. This * is needed for the annoying case of recieving a response to a HEAD * request. * * We'd like to use CALLBACK_NOTIFY_NOADVANCE() here but we cannot, so * we have to simulate it by handling a change in errno below. */ if (settings->on_headers_complete) { switch (settings->on_headers_complete(parser)) { case 0: break; case 2: parser->upgrade = 1; /* fall through */ case 1: parser->flags |= F_SKIPBODY; break; default: SET_ERRNO(HPE_CB_headers_complete); RETURN(p - data); /* Error */ } } if (HTTP_PARSER_ERRNO(parser) != HPE_OK) { RETURN(p - data); } REEXECUTE(); } case s_headers_done: { int hasBody; STRICT_CHECK(ch != LF); parser->nread = 0; nread = 0; hasBody = parser->flags & F_CHUNKED || (parser->content_length > 0 && parser->content_length != ULLONG_MAX); if (parser->upgrade && (parser->method == HTTP_CONNECT || (parser->flags & F_SKIPBODY) || !hasBody)) { /* Exit, the rest of the message is in a different protocol. */ UPDATE_STATE(NEW_MESSAGE()); CALLBACK_NOTIFY(message_complete); RETURN((p - data) + 1); } if (parser->flags & F_SKIPBODY) { UPDATE_STATE(NEW_MESSAGE()); CALLBACK_NOTIFY(message_complete); } else if (parser->flags & F_CHUNKED) { /* chunked encoding - ignore Content-Length header */ UPDATE_STATE(s_chunk_size_start); } else { if (parser->content_length == 0) { /* Content-Length header given but zero: Content-Length: 0\r\n */ UPDATE_STATE(NEW_MESSAGE()); CALLBACK_NOTIFY(message_complete); } else if (parser->content_length != ULLONG_MAX) { /* Content-Length header given and non-zero */ UPDATE_STATE(s_body_identity); } else { if (!http_message_needs_eof(parser)) { /* Assume content-length 0 - read the next */ UPDATE_STATE(NEW_MESSAGE()); CALLBACK_NOTIFY(message_complete); } else { /* Read body until EOF */ UPDATE_STATE(s_body_identity_eof); } } } break; } case s_body_identity: { uint64_t to_read = MIN(parser->content_length, (uint64_t) ((data + len) - p)); assert(parser->content_length != 0 && parser->content_length != ULLONG_MAX); /* The difference between advancing content_length and p is because * the latter will automaticaly advance on the next loop iteration. * Further, if content_length ends up at 0, we want to see the last * byte again for our message complete callback. */ MARK(body); parser->content_length -= to_read; p += to_read - 1; if (parser->content_length == 0) { UPDATE_STATE(s_message_done); /* Mimic CALLBACK_DATA_NOADVANCE() but with one extra byte. * * The alternative to doing this is to wait for the next byte to * trigger the data callback, just as in every other case. The * problem with this is that this makes it difficult for the test * harness to distinguish between complete-on-EOF and * complete-on-length. It's not clear that this distinction is * important for applications, but let's keep it for now. */ CALLBACK_DATA_(body, p - body_mark + 1, p - data); REEXECUTE(); } break; } /* read until EOF */ case s_body_identity_eof: MARK(body); p = data + len - 1; break; case s_message_done: UPDATE_STATE(NEW_MESSAGE()); CALLBACK_NOTIFY(message_complete); if (parser->upgrade) { /* Exit, the rest of the message is in a different protocol. */ RETURN((p - data) + 1); } break; case s_chunk_size_start: { assert(nread == 1); assert(parser->flags & F_CHUNKED); unhex_val = unhex[(unsigned char)ch]; if (UNLIKELY(unhex_val == -1)) { SET_ERRNO(HPE_INVALID_CHUNK_SIZE); goto error; } parser->content_length = unhex_val; UPDATE_STATE(s_chunk_size); break; } case s_chunk_size: { uint64_t t; assert(parser->flags & F_CHUNKED); if (ch == CR) { UPDATE_STATE(s_chunk_size_almost_done); break; } unhex_val = unhex[(unsigned char)ch]; if (unhex_val == -1) { if (ch == ';' || ch == ' ') { UPDATE_STATE(s_chunk_parameters); break; } SET_ERRNO(HPE_INVALID_CHUNK_SIZE); goto error; } t = parser->content_length; t *= 16; t += unhex_val; /* Overflow? Test against a conservative limit for simplicity. */ if (UNLIKELY((ULLONG_MAX - 16) / 16 < parser->content_length)) { SET_ERRNO(HPE_INVALID_CONTENT_LENGTH); goto error; } parser->content_length = t; break; } case s_chunk_parameters: { assert(parser->flags & F_CHUNKED); /* just ignore this shit. TODO check for overflow */ if (ch == CR) { UPDATE_STATE(s_chunk_size_almost_done); break; } break; } case s_chunk_size_almost_done: { assert(parser->flags & F_CHUNKED); STRICT_CHECK(ch != LF); parser->nread = 0; nread = 0; if (parser->content_length == 0) { parser->flags |= F_TRAILING; UPDATE_STATE(s_header_field_start); } else { UPDATE_STATE(s_chunk_data); } CALLBACK_NOTIFY(chunk_header); break; } case s_chunk_data: { uint64_t to_read = MIN(parser->content_length, (uint64_t) ((data + len) - p)); assert(parser->flags & F_CHUNKED); assert(parser->content_length != 0 && parser->content_length != ULLONG_MAX); /* See the explanation in s_body_identity for why the content * length and data pointers are managed this way. */ MARK(body); parser->content_length -= to_read; p += to_read - 1; if (parser->content_length == 0) { UPDATE_STATE(s_chunk_data_almost_done); } break; } case s_chunk_data_almost_done: assert(parser->flags & F_CHUNKED); assert(parser->content_length == 0); STRICT_CHECK(ch != CR); UPDATE_STATE(s_chunk_data_done); CALLBACK_DATA(body); break; case s_chunk_data_done: assert(parser->flags & F_CHUNKED); STRICT_CHECK(ch != LF); parser->nread = 0; nread = 0; UPDATE_STATE(s_chunk_size_start); CALLBACK_NOTIFY(chunk_complete); break; default: assert(0 && "unhandled state"); SET_ERRNO(HPE_INVALID_INTERNAL_STATE); goto error; } } /* Run callbacks for any marks that we have leftover after we ran out of * bytes. There should be at most one of these set, so it's OK to invoke * them in series (unset marks will not result in callbacks). * * We use the NOADVANCE() variety of callbacks here because 'p' has already * overflowed 'data' and this allows us to correct for the off-by-one that * we'd otherwise have (since CALLBACK_DATA() is meant to be run with a 'p' * value that's in-bounds). */ assert(((header_field_mark ? 1 : 0) + (header_value_mark ? 1 : 0) + (url_mark ? 1 : 0) + (body_mark ? 1 : 0) + (status_mark ? 1 : 0)) <= 1); CALLBACK_DATA_NOADVANCE(header_field); CALLBACK_DATA_NOADVANCE(header_value); CALLBACK_DATA_NOADVANCE(url); CALLBACK_DATA_NOADVANCE(body); CALLBACK_DATA_NOADVANCE(status); RETURN(len); error: if (HTTP_PARSER_ERRNO(parser) == HPE_OK) { SET_ERRNO(HPE_UNKNOWN); } RETURN(p - data); } /* Does the parser need to see an EOF to find the end of the message? */ int http_message_needs_eof (const http_parser *parser) { if (parser->type == HTTP_REQUEST) { return 0; } /* See RFC 2616 section 4.4 */ if (parser->status_code / 100 == 1 || /* 1xx e.g. Continue */ parser->status_code == 204 || /* No Content */ parser->status_code == 304 || /* Not Modified */ parser->flags & F_SKIPBODY) { /* response to a HEAD request */ return 0; } if ((parser->flags & F_CHUNKED) || parser->content_length != ULLONG_MAX) { return 0; } return 1; } int http_should_keep_alive (const http_parser *parser) { if (parser->http_major > 0 && parser->http_minor > 0) { /* HTTP/1.1 */ if (parser->flags & F_CONNECTION_CLOSE) { return 0; } } else { /* HTTP/1.0 or earlier */ if (!(parser->flags & F_CONNECTION_KEEP_ALIVE)) { return 0; } } return !http_message_needs_eof(parser); } const char * http_method_str (enum http_method m) { return ELEM_AT(method_strings, m, "<unknown>"); } const char * http_status_str (enum http_status s) { switch (s) { #define XX(num, name, string) case HTTP_STATUS_##name: return #string; HTTP_STATUS_MAP(XX) #undef XX default: return "<unknown>"; } } void http_parser_init (http_parser *parser, enum http_parser_type t) { void *data = parser->data; /* preserve application data */ memset(parser, 0, sizeof(*parser)); parser->data = data; parser->type = t; parser->state = (t == HTTP_REQUEST ? s_start_req : (t == HTTP_RESPONSE ? s_start_res : s_start_req_or_res)); parser->http_errno = HPE_OK; } void http_parser_settings_init(http_parser_settings *settings) { memset(settings, 0, sizeof(*settings)); } const char * http_errno_name(enum http_errno err) { assert(((size_t) err) < ARRAY_SIZE(http_strerror_tab)); return http_strerror_tab[err].name; } const char * http_errno_description(enum http_errno err) { assert(((size_t) err) < ARRAY_SIZE(http_strerror_tab)); return http_strerror_tab[err].description; } static enum http_host_state http_parse_host_char(enum http_host_state s, const char ch) { switch(s) { case s_http_userinfo: case s_http_userinfo_start: if (ch == '@') { return s_http_host_start; } if (IS_USERINFO_CHAR(ch)) { return s_http_userinfo; } break; case s_http_host_start: if (ch == '[') { return s_http_host_v6_start; } if (IS_HOST_CHAR(ch)) { return s_http_host; } break; case s_http_host: if (IS_HOST_CHAR(ch)) { return s_http_host; } /* fall through */ case s_http_host_v6_end: if (ch == ':') { return s_http_host_port_start; } break; case s_http_host_v6: if (ch == ']') { return s_http_host_v6_end; } /* fall through */ case s_http_host_v6_start: if (IS_HEX(ch) || ch == ':' || ch == '.') { return s_http_host_v6; } if (s == s_http_host_v6 && ch == '%') { return s_http_host_v6_zone_start; } break; case s_http_host_v6_zone: if (ch == ']') { return s_http_host_v6_end; } /* fall through */ case s_http_host_v6_zone_start: /* RFC 6874 Zone ID consists of 1*( unreserved / pct-encoded) */ if (IS_ALPHANUM(ch) || ch == '%' || ch == '.' || ch == '-' || ch == '_' || ch == '~') { return s_http_host_v6_zone; } break; case s_http_host_port: case s_http_host_port_start: if (IS_NUM(ch)) { return s_http_host_port; } break; default: break; } return s_http_host_dead; } static int http_parse_host(const char * buf, struct http_parser_url *u, int found_at) { enum http_host_state s; const char *p; size_t buflen = u->field_data[UF_HOST].off + u->field_data[UF_HOST].len; assert(u->field_set & (1 << UF_HOST)); u->field_data[UF_HOST].len = 0; s = found_at ? s_http_userinfo_start : s_http_host_start; for (p = buf + u->field_data[UF_HOST].off; p < buf + buflen; p++) { enum http_host_state new_s = http_parse_host_char(s, *p); if (new_s == s_http_host_dead) { return 1; } switch(new_s) { case s_http_host: if (s != s_http_host) { u->field_data[UF_HOST].off = (uint16_t)(p - buf); } u->field_data[UF_HOST].len++; break; case s_http_host_v6: if (s != s_http_host_v6) { u->field_data[UF_HOST].off = (uint16_t)(p - buf); } u->field_data[UF_HOST].len++; break; case s_http_host_v6_zone_start: case s_http_host_v6_zone: u->field_data[UF_HOST].len++; break; case s_http_host_port: if (s != s_http_host_port) { u->field_data[UF_PORT].off = (uint16_t)(p - buf); u->field_data[UF_PORT].len = 0; u->field_set |= (1 << UF_PORT); } u->field_data[UF_PORT].len++; break; case s_http_userinfo: if (s != s_http_userinfo) { u->field_data[UF_USERINFO].off = (uint16_t)(p - buf); u->field_data[UF_USERINFO].len = 0; u->field_set |= (1 << UF_USERINFO); } u->field_data[UF_USERINFO].len++; break; default: break; } s = new_s; } /* Make sure we don't end somewhere unexpected */ switch (s) { case s_http_host_start: case s_http_host_v6_start: case s_http_host_v6: case s_http_host_v6_zone_start: case s_http_host_v6_zone: case s_http_host_port_start: case s_http_userinfo: case s_http_userinfo_start: return 1; default: break; } return 0; } void http_parser_url_init(struct http_parser_url *u) { memset(u, 0, sizeof(*u)); } int http_parser_parse_url(const char *buf, size_t buflen, int is_connect, struct http_parser_url *u) { enum state s; const char *p; enum http_parser_url_fields uf, old_uf; int found_at = 0; if (buflen == 0) { return 1; } u->port = u->field_set = 0; s = is_connect ? s_req_server_start : s_req_spaces_before_url; old_uf = UF_MAX; for (p = buf; p < buf + buflen; p++) { s = parse_url_char(s, *p); /* Figure out the next field that we're operating on */ switch (s) { case s_dead: return 1; /* Skip delimeters */ case s_req_schema_slash: case s_req_schema_slash_slash: case s_req_server_start: case s_req_query_string_start: case s_req_fragment_start: continue; case s_req_schema: uf = UF_SCHEMA; break; case s_req_server_with_at: found_at = 1; /* fall through */ case s_req_server: uf = UF_HOST; break; case s_req_path: uf = UF_PATH; break; case s_req_query_string: uf = UF_QUERY; break; case s_req_fragment: uf = UF_FRAGMENT; break; default: assert(!"Unexpected state"); return 1; } /* Nothing's changed; soldier on */ if (uf == old_uf) { u->field_data[uf].len++; continue; } u->field_data[uf].off = (uint16_t)(p - buf); u->field_data[uf].len = 1; u->field_set |= (1 << uf); old_uf = uf; } /* host must be present if there is a schema */ /* parsing http:///toto will fail */ if ((u->field_set & (1 << UF_SCHEMA)) && (u->field_set & (1 << UF_HOST)) == 0) { return 1; } if (u->field_set & (1 << UF_HOST)) { if (http_parse_host(buf, u, found_at) != 0) { return 1; } } /* CONNECT requests can only contain "hostname:port" */ if (is_connect && u->field_set != ((1 << UF_HOST)|(1 << UF_PORT))) { return 1; } if (u->field_set & (1 << UF_PORT)) { uint16_t off; uint16_t len; const char* p; const char* end; unsigned long v; off = u->field_data[UF_PORT].off; len = u->field_data[UF_PORT].len; end = buf + off + len; /* NOTE: The characters are already validated and are in the [0-9] range */ assert(off + len <= buflen && "Port number overflow"); v = 0; for (p = buf + off; p < end; p++) { v *= 10; v += *p - '0'; /* Ports have a max value of 2^16 */ if (v > 0xffff) { return 1; } } u->port = (uint16_t) v; } return 0; } void http_parser_pause(http_parser *parser, int paused) { /* Users should only be pausing/unpausing a parser that is not in an error * state. In non-debug builds, there's not much that we can do about this * other than ignore it. */ if (HTTP_PARSER_ERRNO(parser) == HPE_OK || HTTP_PARSER_ERRNO(parser) == HPE_PAUSED) { uint32_t nread = parser->nread; /* used by the SET_ERRNO macro */ SET_ERRNO((paused) ? HPE_PAUSED : HPE_OK); } else { assert(0 && "Attempting to pause parser in error state"); } } int http_body_is_final(const struct http_parser *parser) { return parser->state == s_message_done; } unsigned long http_parser_version(void) { return HTTP_PARSER_VERSION_MAJOR * 0x10000 | HTTP_PARSER_VERSION_MINOR * 0x00100 | HTTP_PARSER_VERSION_PATCH * 0x00001; } void http_parser_set_max_header_size(uint32_t size) { max_header_size = size; } �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/vendor/http_parser/http_parser.h�����������������������������������������������������0000664�0000000�0000000�00000045045�13554550454�0021707�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* Copyright Joyent, Inc. and other Node contributors. All rights reserved. * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to * deal in the Software without restriction, including without limitation the * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or * sell copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS * IN THE SOFTWARE. */ #ifndef http_parser_h #define http_parser_h #ifdef __cplusplus extern "C" { #endif /* Also update SONAME in the Makefile whenever you change these. */ #define HTTP_PARSER_VERSION_MAJOR 2 #define HTTP_PARSER_VERSION_MINOR 9 #define HTTP_PARSER_VERSION_PATCH 2 #include <stddef.h> #if defined(_WIN32) && !defined(__MINGW32__) && \ (!defined(_MSC_VER) || _MSC_VER<1600) && !defined(__WINE__) #include <BaseTsd.h> typedef __int8 int8_t; typedef unsigned __int8 uint8_t; typedef __int16 int16_t; typedef unsigned __int16 uint16_t; typedef __int32 int32_t; typedef unsigned __int32 uint32_t; typedef __int64 int64_t; typedef unsigned __int64 uint64_t; #else #include <stdint.h> #endif /* Compile with -DHTTP_PARSER_STRICT=0 to make less checks, but run * faster */ #ifndef HTTP_PARSER_STRICT # define HTTP_PARSER_STRICT 1 #endif /* Maximium header size allowed. If the macro is not defined * before including this header then the default is used. To * change the maximum header size, define the macro in the build * environment (e.g. -DHTTP_MAX_HEADER_SIZE=<value>). To remove * the effective limit on the size of the header, define the macro * to a very large number (e.g. -DHTTP_MAX_HEADER_SIZE=0x7fffffff) */ #ifndef HTTP_MAX_HEADER_SIZE # define HTTP_MAX_HEADER_SIZE (80*1024) #endif typedef struct http_parser http_parser; typedef struct http_parser_settings http_parser_settings; /* Callbacks should return non-zero to indicate an error. The parser will * then halt execution. * * The one exception is on_headers_complete. In a HTTP_RESPONSE parser * returning '1' from on_headers_complete will tell the parser that it * should not expect a body. This is used when receiving a response to a * HEAD request which may contain 'Content-Length' or 'Transfer-Encoding: * chunked' headers that indicate the presence of a body. * * Returning `2` from on_headers_complete will tell parser that it should not * expect neither a body nor any futher responses on this connection. This is * useful for handling responses to a CONNECT request which may not contain * `Upgrade` or `Connection: upgrade` headers. * * http_data_cb does not return data chunks. It will be called arbitrarily * many times for each string. E.G. you might get 10 callbacks for "on_url" * each providing just a few characters more data. */ typedef int (*http_data_cb) (http_parser*, const char *at, size_t length); typedef int (*http_cb) (http_parser*); /* Status Codes */ #define HTTP_STATUS_MAP(XX) \ XX(100, CONTINUE, Continue) \ XX(101, SWITCHING_PROTOCOLS, Switching Protocols) \ XX(102, PROCESSING, Processing) \ XX(200, OK, OK) \ XX(201, CREATED, Created) \ XX(202, ACCEPTED, Accepted) \ XX(203, NON_AUTHORITATIVE_INFORMATION, Non-Authoritative Information) \ XX(204, NO_CONTENT, No Content) \ XX(205, RESET_CONTENT, Reset Content) \ XX(206, PARTIAL_CONTENT, Partial Content) \ XX(207, MULTI_STATUS, Multi-Status) \ XX(208, ALREADY_REPORTED, Already Reported) \ XX(226, IM_USED, IM Used) \ XX(300, MULTIPLE_CHOICES, Multiple Choices) \ XX(301, MOVED_PERMANENTLY, Moved Permanently) \ XX(302, FOUND, Found) \ XX(303, SEE_OTHER, See Other) \ XX(304, NOT_MODIFIED, Not Modified) \ XX(305, USE_PROXY, Use Proxy) \ XX(307, TEMPORARY_REDIRECT, Temporary Redirect) \ XX(308, PERMANENT_REDIRECT, Permanent Redirect) \ XX(400, BAD_REQUEST, Bad Request) \ XX(401, UNAUTHORIZED, Unauthorized) \ XX(402, PAYMENT_REQUIRED, Payment Required) \ XX(403, FORBIDDEN, Forbidden) \ XX(404, NOT_FOUND, Not Found) \ XX(405, METHOD_NOT_ALLOWED, Method Not Allowed) \ XX(406, NOT_ACCEPTABLE, Not Acceptable) \ XX(407, PROXY_AUTHENTICATION_REQUIRED, Proxy Authentication Required) \ XX(408, REQUEST_TIMEOUT, Request Timeout) \ XX(409, CONFLICT, Conflict) \ XX(410, GONE, Gone) \ XX(411, LENGTH_REQUIRED, Length Required) \ XX(412, PRECONDITION_FAILED, Precondition Failed) \ XX(413, PAYLOAD_TOO_LARGE, Payload Too Large) \ XX(414, URI_TOO_LONG, URI Too Long) \ XX(415, UNSUPPORTED_MEDIA_TYPE, Unsupported Media Type) \ XX(416, RANGE_NOT_SATISFIABLE, Range Not Satisfiable) \ XX(417, EXPECTATION_FAILED, Expectation Failed) \ XX(421, MISDIRECTED_REQUEST, Misdirected Request) \ XX(422, UNPROCESSABLE_ENTITY, Unprocessable Entity) \ XX(423, LOCKED, Locked) \ XX(424, FAILED_DEPENDENCY, Failed Dependency) \ XX(426, UPGRADE_REQUIRED, Upgrade Required) \ XX(428, PRECONDITION_REQUIRED, Precondition Required) \ XX(429, TOO_MANY_REQUESTS, Too Many Requests) \ XX(431, REQUEST_HEADER_FIELDS_TOO_LARGE, Request Header Fields Too Large) \ XX(451, UNAVAILABLE_FOR_LEGAL_REASONS, Unavailable For Legal Reasons) \ XX(500, INTERNAL_SERVER_ERROR, Internal Server Error) \ XX(501, NOT_IMPLEMENTED, Not Implemented) \ XX(502, BAD_GATEWAY, Bad Gateway) \ XX(503, SERVICE_UNAVAILABLE, Service Unavailable) \ XX(504, GATEWAY_TIMEOUT, Gateway Timeout) \ XX(505, HTTP_VERSION_NOT_SUPPORTED, HTTP Version Not Supported) \ XX(506, VARIANT_ALSO_NEGOTIATES, Variant Also Negotiates) \ XX(507, INSUFFICIENT_STORAGE, Insufficient Storage) \ XX(508, LOOP_DETECTED, Loop Detected) \ XX(510, NOT_EXTENDED, Not Extended) \ XX(511, NETWORK_AUTHENTICATION_REQUIRED, Network Authentication Required) \ enum http_status { #define XX(num, name, string) HTTP_STATUS_##name = num, HTTP_STATUS_MAP(XX) #undef XX }; /* Request Methods */ #define HTTP_METHOD_MAP(XX) \ XX(0, DELETE, DELETE) \ XX(1, GET, GET) \ XX(2, HEAD, HEAD) \ XX(3, POST, POST) \ XX(4, PUT, PUT) \ /* pathological */ \ XX(5, CONNECT, CONNECT) \ XX(6, OPTIONS, OPTIONS) \ XX(7, TRACE, TRACE) \ /* WebDAV */ \ XX(8, COPY, COPY) \ XX(9, LOCK, LOCK) \ XX(10, MKCOL, MKCOL) \ XX(11, MOVE, MOVE) \ XX(12, PROPFIND, PROPFIND) \ XX(13, PROPPATCH, PROPPATCH) \ XX(14, SEARCH, SEARCH) \ XX(15, UNLOCK, UNLOCK) \ XX(16, BIND, BIND) \ XX(17, REBIND, REBIND) \ XX(18, UNBIND, UNBIND) \ XX(19, ACL, ACL) \ /* subversion */ \ XX(20, REPORT, REPORT) \ XX(21, MKACTIVITY, MKACTIVITY) \ XX(22, CHECKOUT, CHECKOUT) \ XX(23, MERGE, MERGE) \ /* upnp */ \ XX(24, MSEARCH, M-SEARCH) \ XX(25, NOTIFY, NOTIFY) \ XX(26, SUBSCRIBE, SUBSCRIBE) \ XX(27, UNSUBSCRIBE, UNSUBSCRIBE) \ /* RFC-5789 */ \ XX(28, PATCH, PATCH) \ XX(29, PURGE, PURGE) \ /* CalDAV */ \ XX(30, MKCALENDAR, MKCALENDAR) \ /* RFC-2068, section 19.6.1.2 */ \ XX(31, LINK, LINK) \ XX(32, UNLINK, UNLINK) \ /* icecast */ \ XX(33, SOURCE, SOURCE) \ enum http_method { #define XX(num, name, string) HTTP_##name = num, HTTP_METHOD_MAP(XX) #undef XX }; enum http_parser_type { HTTP_REQUEST, HTTP_RESPONSE, HTTP_BOTH }; /* Flag values for http_parser.flags field */ enum flags { F_CHUNKED = 1 << 0 , F_CONNECTION_KEEP_ALIVE = 1 << 1 , F_CONNECTION_CLOSE = 1 << 2 , F_CONNECTION_UPGRADE = 1 << 3 , F_TRAILING = 1 << 4 , F_UPGRADE = 1 << 5 , F_SKIPBODY = 1 << 6 , F_CONTENTLENGTH = 1 << 7 }; /* Map for errno-related constants * * The provided argument should be a macro that takes 2 arguments. */ #define HTTP_ERRNO_MAP(XX) \ /* No error */ \ XX(OK, "success") \ \ /* Callback-related errors */ \ XX(CB_message_begin, "the on_message_begin callback failed") \ XX(CB_url, "the on_url callback failed") \ XX(CB_header_field, "the on_header_field callback failed") \ XX(CB_header_value, "the on_header_value callback failed") \ XX(CB_headers_complete, "the on_headers_complete callback failed") \ XX(CB_body, "the on_body callback failed") \ XX(CB_message_complete, "the on_message_complete callback failed") \ XX(CB_status, "the on_status callback failed") \ XX(CB_chunk_header, "the on_chunk_header callback failed") \ XX(CB_chunk_complete, "the on_chunk_complete callback failed") \ \ /* Parsing-related errors */ \ XX(INVALID_EOF_STATE, "stream ended at an unexpected time") \ XX(HEADER_OVERFLOW, \ "too many header bytes seen; overflow detected") \ XX(CLOSED_CONNECTION, \ "data received after completed connection: close message") \ XX(INVALID_VERSION, "invalid HTTP version") \ XX(INVALID_STATUS, "invalid HTTP status code") \ XX(INVALID_METHOD, "invalid HTTP method") \ XX(INVALID_URL, "invalid URL") \ XX(INVALID_HOST, "invalid host") \ XX(INVALID_PORT, "invalid port") \ XX(INVALID_PATH, "invalid path") \ XX(INVALID_QUERY_STRING, "invalid query string") \ XX(INVALID_FRAGMENT, "invalid fragment") \ XX(LF_EXPECTED, "LF character expected") \ XX(INVALID_HEADER_TOKEN, "invalid character in header") \ XX(INVALID_CONTENT_LENGTH, \ "invalid character in content-length header") \ XX(UNEXPECTED_CONTENT_LENGTH, \ "unexpected content-length header") \ XX(INVALID_CHUNK_SIZE, \ "invalid character in chunk size header") \ XX(INVALID_CONSTANT, "invalid constant string") \ XX(INVALID_INTERNAL_STATE, "encountered unexpected internal state")\ XX(STRICT, "strict mode assertion failed") \ XX(PAUSED, "parser is paused") \ XX(UNKNOWN, "an unknown error occurred") /* Define HPE_* values for each errno value above */ #define HTTP_ERRNO_GEN(n, s) HPE_##n, enum http_errno { HTTP_ERRNO_MAP(HTTP_ERRNO_GEN) }; #undef HTTP_ERRNO_GEN /* Get an http_errno value from an http_parser */ #define HTTP_PARSER_ERRNO(p) ((enum http_errno) (p)->http_errno) struct http_parser { /** PRIVATE **/ unsigned int type : 2; /* enum http_parser_type */ unsigned int flags : 8; /* F_* values from 'flags' enum; semi-public */ unsigned int state : 7; /* enum state from http_parser.c */ unsigned int header_state : 7; /* enum header_state from http_parser.c */ unsigned int index : 7; /* index into current matcher */ unsigned int lenient_http_headers : 1; uint32_t nread; /* # bytes read in various scenarios */ uint64_t content_length; /* # bytes in body (0 if no Content-Length header) */ /** READ-ONLY **/ unsigned short http_major; unsigned short http_minor; unsigned int status_code : 16; /* responses only */ unsigned int method : 8; /* requests only */ unsigned int http_errno : 7; /* 1 = Upgrade header was present and the parser has exited because of that. * 0 = No upgrade header present. * Should be checked when http_parser_execute() returns in addition to * error checking. */ unsigned int upgrade : 1; /** PUBLIC **/ void *data; /* A pointer to get hook to the "connection" or "socket" object */ }; struct http_parser_settings { http_cb on_message_begin; http_data_cb on_url; http_data_cb on_status; http_data_cb on_header_field; http_data_cb on_header_value; http_cb on_headers_complete; http_data_cb on_body; http_cb on_message_complete; /* When on_chunk_header is called, the current chunk length is stored * in parser->content_length. */ http_cb on_chunk_header; http_cb on_chunk_complete; }; enum http_parser_url_fields { UF_SCHEMA = 0 , UF_HOST = 1 , UF_PORT = 2 , UF_PATH = 3 , UF_QUERY = 4 , UF_FRAGMENT = 5 , UF_USERINFO = 6 , UF_MAX = 7 }; /* Result structure for http_parser_parse_url(). * * Callers should index into field_data[] with UF_* values iff field_set * has the relevant (1 << UF_*) bit set. As a courtesy to clients (and * because we probably have padding left over), we convert any port to * a uint16_t. */ struct http_parser_url { uint16_t field_set; /* Bitmask of (1 << UF_*) values */ uint16_t port; /* Converted UF_PORT string */ struct { uint16_t off; /* Offset into buffer in which field starts */ uint16_t len; /* Length of run in buffer */ } field_data[UF_MAX]; }; /* Returns the library version. Bits 16-23 contain the major version number, * bits 8-15 the minor version number and bits 0-7 the patch level. * Usage example: * * unsigned long version = http_parser_version(); * unsigned major = (version >> 16) & 255; * unsigned minor = (version >> 8) & 255; * unsigned patch = version & 255; * printf("http_parser v%u.%u.%u\n", major, minor, patch); */ unsigned long http_parser_version(void); void http_parser_init(http_parser *parser, enum http_parser_type type); /* Initialize http_parser_settings members to 0 */ void http_parser_settings_init(http_parser_settings *settings); /* Executes the parser. Returns number of parsed bytes. Sets * `parser->http_errno` on error. */ size_t http_parser_execute(http_parser *parser, const http_parser_settings *settings, const char *data, size_t len); /* If http_should_keep_alive() in the on_headers_complete or * on_message_complete callback returns 0, then this should be * the last message on the connection. * If you are the server, respond with the "Connection: close" header. * If you are the client, close the connection. */ int http_should_keep_alive(const http_parser *parser); /* Returns a string version of the HTTP method. */ const char *http_method_str(enum http_method m); /* Returns a string version of the HTTP status code. */ const char *http_status_str(enum http_status s); /* Return a string name of the given error */ const char *http_errno_name(enum http_errno err); /* Return a string description of the given error */ const char *http_errno_description(enum http_errno err); /* Initialize all http_parser_url members to 0 */ void http_parser_url_init(struct http_parser_url *u); /* Parse a URL; return nonzero on failure */ int http_parser_parse_url(const char *buf, size_t buflen, int is_connect, struct http_parser_url *u); /* Pause or un-pause the parser; a nonzero value pauses */ void http_parser_pause(http_parser *parser, int paused); /* Checks if this is the final chunk of the body. */ int http_body_is_final(const http_parser *parser); /* Change the maximum header size provided at compile time. */ void http_parser_set_max_header_size(uint32_t size); #ifdef __cplusplus } #endif #endif �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/vendor/sha2/�������������������������������������������������������������������������0000775�0000000�0000000�00000000000�13554550454�0015475�5����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/vendor/sha2/sha2.c�������������������������������������������������������������������0000664�0000000�0000000�00000100267�13554550454�0016504�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * FIPS 180-2 SHA-224/256/384/512 implementation * Last update: 02/02/2007 * Issue date: 04/30/2005 * * Copyright (C) 2005, 2007 Olivier Gay <olivier.gay@a3.epfl.ch> * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the project nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #if 0 #define UNROLL_LOOPS /* Enable loops unrolling */ #endif #include <string.h> #include "sha2.h" #define SHFR(x, n) (x >> n) #define ROTR(x, n) ((x >> n) | (x << ((sizeof(x) << 3) - n))) #define ROTL(x, n) ((x << n) | (x >> ((sizeof(x) << 3) - n))) #define CH(x, y, z) ((x & y) ^ (~x & z)) #define MAJ(x, y, z) ((x & y) ^ (x & z) ^ (y & z)) #define SHA256_F1(x) (ROTR(x, 2) ^ ROTR(x, 13) ^ ROTR(x, 22)) #define SHA256_F2(x) (ROTR(x, 6) ^ ROTR(x, 11) ^ ROTR(x, 25)) #define SHA256_F3(x) (ROTR(x, 7) ^ ROTR(x, 18) ^ SHFR(x, 3)) #define SHA256_F4(x) (ROTR(x, 17) ^ ROTR(x, 19) ^ SHFR(x, 10)) #define SHA512_F1(x) (ROTR(x, 28) ^ ROTR(x, 34) ^ ROTR(x, 39)) #define SHA512_F2(x) (ROTR(x, 14) ^ ROTR(x, 18) ^ ROTR(x, 41)) #define SHA512_F3(x) (ROTR(x, 1) ^ ROTR(x, 8) ^ SHFR(x, 7)) #define SHA512_F4(x) (ROTR(x, 19) ^ ROTR(x, 61) ^ SHFR(x, 6)) #define UNPACK32(x, str) \ { \ *((str) + 3) = (uint8) ((x) ); \ *((str) + 2) = (uint8) ((x) >> 8); \ *((str) + 1) = (uint8) ((x) >> 16); \ *((str) + 0) = (uint8) ((x) >> 24); \ } #define PACK32(str, x) \ { \ *(x) = ((uint32) *((str) + 3) ) \ | ((uint32) *((str) + 2) << 8) \ | ((uint32) *((str) + 1) << 16) \ | ((uint32) *((str) + 0) << 24); \ } #define UNPACK64(x, str) \ { \ *((str) + 7) = (uint8) ((x) ); \ *((str) + 6) = (uint8) ((x) >> 8); \ *((str) + 5) = (uint8) ((x) >> 16); \ *((str) + 4) = (uint8) ((x) >> 24); \ *((str) + 3) = (uint8) ((x) >> 32); \ *((str) + 2) = (uint8) ((x) >> 40); \ *((str) + 1) = (uint8) ((x) >> 48); \ *((str) + 0) = (uint8) ((x) >> 56); \ } #define PACK64(str, x) \ { \ *(x) = ((uint64) *((str) + 7) ) \ | ((uint64) *((str) + 6) << 8) \ | ((uint64) *((str) + 5) << 16) \ | ((uint64) *((str) + 4) << 24) \ | ((uint64) *((str) + 3) << 32) \ | ((uint64) *((str) + 2) << 40) \ | ((uint64) *((str) + 1) << 48) \ | ((uint64) *((str) + 0) << 56); \ } /* Macros used for loops unrolling */ #define SHA256_SCR(i) \ { \ w[i] = SHA256_F4(w[i - 2]) + w[i - 7] \ + SHA256_F3(w[i - 15]) + w[i - 16]; \ } #define SHA512_SCR(i) \ { \ w[i] = SHA512_F4(w[i - 2]) + w[i - 7] \ + SHA512_F3(w[i - 15]) + w[i - 16]; \ } #define SHA256_EXP(a, b, c, d, e, f, g, h, j) \ { \ t1 = wv[h] + SHA256_F2(wv[e]) + CH(wv[e], wv[f], wv[g]) \ + sha256_k[j] + w[j]; \ t2 = SHA256_F1(wv[a]) + MAJ(wv[a], wv[b], wv[c]); \ wv[d] += t1; \ wv[h] = t1 + t2; \ } #define SHA512_EXP(a, b, c, d, e, f, g ,h, j) \ { \ t1 = wv[h] + SHA512_F2(wv[e]) + CH(wv[e], wv[f], wv[g]) \ + sha512_k[j] + w[j]; \ t2 = SHA512_F1(wv[a]) + MAJ(wv[a], wv[b], wv[c]); \ wv[d] += t1; \ wv[h] = t1 + t2; \ } uint32 sha224_h0[8] = {0xc1059ed8, 0x367cd507, 0x3070dd17, 0xf70e5939, 0xffc00b31, 0x68581511, 0x64f98fa7, 0xbefa4fa4}; uint32 sha256_h0[8] = {0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a, 0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19}; uint64 sha384_h0[8] = {0xcbbb9d5dc1059ed8ULL, 0x629a292a367cd507ULL, 0x9159015a3070dd17ULL, 0x152fecd8f70e5939ULL, 0x67332667ffc00b31ULL, 0x8eb44a8768581511ULL, 0xdb0c2e0d64f98fa7ULL, 0x47b5481dbefa4fa4ULL}; uint64 sha512_h0[8] = {0x6a09e667f3bcc908ULL, 0xbb67ae8584caa73bULL, 0x3c6ef372fe94f82bULL, 0xa54ff53a5f1d36f1ULL, 0x510e527fade682d1ULL, 0x9b05688c2b3e6c1fULL, 0x1f83d9abfb41bd6bULL, 0x5be0cd19137e2179ULL}; uint32 sha256_k[64] = {0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5, 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174, 0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da, 0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967, 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85, 0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070, 0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3, 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2}; uint64 sha512_k[80] = {0x428a2f98d728ae22ULL, 0x7137449123ef65cdULL, 0xb5c0fbcfec4d3b2fULL, 0xe9b5dba58189dbbcULL, 0x3956c25bf348b538ULL, 0x59f111f1b605d019ULL, 0x923f82a4af194f9bULL, 0xab1c5ed5da6d8118ULL, 0xd807aa98a3030242ULL, 0x12835b0145706fbeULL, 0x243185be4ee4b28cULL, 0x550c7dc3d5ffb4e2ULL, 0x72be5d74f27b896fULL, 0x80deb1fe3b1696b1ULL, 0x9bdc06a725c71235ULL, 0xc19bf174cf692694ULL, 0xe49b69c19ef14ad2ULL, 0xefbe4786384f25e3ULL, 0x0fc19dc68b8cd5b5ULL, 0x240ca1cc77ac9c65ULL, 0x2de92c6f592b0275ULL, 0x4a7484aa6ea6e483ULL, 0x5cb0a9dcbd41fbd4ULL, 0x76f988da831153b5ULL, 0x983e5152ee66dfabULL, 0xa831c66d2db43210ULL, 0xb00327c898fb213fULL, 0xbf597fc7beef0ee4ULL, 0xc6e00bf33da88fc2ULL, 0xd5a79147930aa725ULL, 0x06ca6351e003826fULL, 0x142929670a0e6e70ULL, 0x27b70a8546d22ffcULL, 0x2e1b21385c26c926ULL, 0x4d2c6dfc5ac42aedULL, 0x53380d139d95b3dfULL, 0x650a73548baf63deULL, 0x766a0abb3c77b2a8ULL, 0x81c2c92e47edaee6ULL, 0x92722c851482353bULL, 0xa2bfe8a14cf10364ULL, 0xa81a664bbc423001ULL, 0xc24b8b70d0f89791ULL, 0xc76c51a30654be30ULL, 0xd192e819d6ef5218ULL, 0xd69906245565a910ULL, 0xf40e35855771202aULL, 0x106aa07032bbd1b8ULL, 0x19a4c116b8d2d0c8ULL, 0x1e376c085141ab53ULL, 0x2748774cdf8eeb99ULL, 0x34b0bcb5e19b48a8ULL, 0x391c0cb3c5c95a63ULL, 0x4ed8aa4ae3418acbULL, 0x5b9cca4f7763e373ULL, 0x682e6ff3d6b2b8a3ULL, 0x748f82ee5defb2fcULL, 0x78a5636f43172f60ULL, 0x84c87814a1f0ab72ULL, 0x8cc702081a6439ecULL, 0x90befffa23631e28ULL, 0xa4506cebde82bde9ULL, 0xbef9a3f7b2c67915ULL, 0xc67178f2e372532bULL, 0xca273eceea26619cULL, 0xd186b8c721c0c207ULL, 0xeada7dd6cde0eb1eULL, 0xf57d4f7fee6ed178ULL, 0x06f067aa72176fbaULL, 0x0a637dc5a2c898a6ULL, 0x113f9804bef90daeULL, 0x1b710b35131c471bULL, 0x28db77f523047d84ULL, 0x32caab7b40c72493ULL, 0x3c9ebe0a15c9bebcULL, 0x431d67c49c100d4cULL, 0x4cc5d4becb3e42b6ULL, 0x597f299cfc657e2aULL, 0x5fcb6fab3ad6faecULL, 0x6c44198c4a475817ULL}; /* SHA-256 functions */ void sha256_transf(sha256_ctx *ctx, const unsigned char *message, unsigned int block_nb) { uint32 w[64]; uint32 wv[8]; uint32 t1, t2; const unsigned char *sub_block; int i; #ifndef UNROLL_LOOPS int j; #endif for (i = 0; i < (int) block_nb; i++) { sub_block = message + (i << 6); #ifndef UNROLL_LOOPS for (j = 0; j < 16; j++) { PACK32(&sub_block[j << 2], &w[j]); } for (j = 16; j < 64; j++) { SHA256_SCR(j); } for (j = 0; j < 8; j++) { wv[j] = ctx->h[j]; } for (j = 0; j < 64; j++) { t1 = wv[7] + SHA256_F2(wv[4]) + CH(wv[4], wv[5], wv[6]) + sha256_k[j] + w[j]; t2 = SHA256_F1(wv[0]) + MAJ(wv[0], wv[1], wv[2]); wv[7] = wv[6]; wv[6] = wv[5]; wv[5] = wv[4]; wv[4] = wv[3] + t1; wv[3] = wv[2]; wv[2] = wv[1]; wv[1] = wv[0]; wv[0] = t1 + t2; } for (j = 0; j < 8; j++) { ctx->h[j] += wv[j]; } #else PACK32(&sub_block[ 0], &w[ 0]); PACK32(&sub_block[ 4], &w[ 1]); PACK32(&sub_block[ 8], &w[ 2]); PACK32(&sub_block[12], &w[ 3]); PACK32(&sub_block[16], &w[ 4]); PACK32(&sub_block[20], &w[ 5]); PACK32(&sub_block[24], &w[ 6]); PACK32(&sub_block[28], &w[ 7]); PACK32(&sub_block[32], &w[ 8]); PACK32(&sub_block[36], &w[ 9]); PACK32(&sub_block[40], &w[10]); PACK32(&sub_block[44], &w[11]); PACK32(&sub_block[48], &w[12]); PACK32(&sub_block[52], &w[13]); PACK32(&sub_block[56], &w[14]); PACK32(&sub_block[60], &w[15]); SHA256_SCR(16); SHA256_SCR(17); SHA256_SCR(18); SHA256_SCR(19); SHA256_SCR(20); SHA256_SCR(21); SHA256_SCR(22); SHA256_SCR(23); SHA256_SCR(24); SHA256_SCR(25); SHA256_SCR(26); SHA256_SCR(27); SHA256_SCR(28); SHA256_SCR(29); SHA256_SCR(30); SHA256_SCR(31); SHA256_SCR(32); SHA256_SCR(33); SHA256_SCR(34); SHA256_SCR(35); SHA256_SCR(36); SHA256_SCR(37); SHA256_SCR(38); SHA256_SCR(39); SHA256_SCR(40); SHA256_SCR(41); SHA256_SCR(42); SHA256_SCR(43); SHA256_SCR(44); SHA256_SCR(45); SHA256_SCR(46); SHA256_SCR(47); SHA256_SCR(48); SHA256_SCR(49); SHA256_SCR(50); SHA256_SCR(51); SHA256_SCR(52); SHA256_SCR(53); SHA256_SCR(54); SHA256_SCR(55); SHA256_SCR(56); SHA256_SCR(57); SHA256_SCR(58); SHA256_SCR(59); SHA256_SCR(60); SHA256_SCR(61); SHA256_SCR(62); SHA256_SCR(63); wv[0] = ctx->h[0]; wv[1] = ctx->h[1]; wv[2] = ctx->h[2]; wv[3] = ctx->h[3]; wv[4] = ctx->h[4]; wv[5] = ctx->h[5]; wv[6] = ctx->h[6]; wv[7] = ctx->h[7]; SHA256_EXP(0,1,2,3,4,5,6,7, 0); SHA256_EXP(7,0,1,2,3,4,5,6, 1); SHA256_EXP(6,7,0,1,2,3,4,5, 2); SHA256_EXP(5,6,7,0,1,2,3,4, 3); SHA256_EXP(4,5,6,7,0,1,2,3, 4); SHA256_EXP(3,4,5,6,7,0,1,2, 5); SHA256_EXP(2,3,4,5,6,7,0,1, 6); SHA256_EXP(1,2,3,4,5,6,7,0, 7); SHA256_EXP(0,1,2,3,4,5,6,7, 8); SHA256_EXP(7,0,1,2,3,4,5,6, 9); SHA256_EXP(6,7,0,1,2,3,4,5,10); SHA256_EXP(5,6,7,0,1,2,3,4,11); SHA256_EXP(4,5,6,7,0,1,2,3,12); SHA256_EXP(3,4,5,6,7,0,1,2,13); SHA256_EXP(2,3,4,5,6,7,0,1,14); SHA256_EXP(1,2,3,4,5,6,7,0,15); SHA256_EXP(0,1,2,3,4,5,6,7,16); SHA256_EXP(7,0,1,2,3,4,5,6,17); SHA256_EXP(6,7,0,1,2,3,4,5,18); SHA256_EXP(5,6,7,0,1,2,3,4,19); SHA256_EXP(4,5,6,7,0,1,2,3,20); SHA256_EXP(3,4,5,6,7,0,1,2,21); SHA256_EXP(2,3,4,5,6,7,0,1,22); SHA256_EXP(1,2,3,4,5,6,7,0,23); SHA256_EXP(0,1,2,3,4,5,6,7,24); SHA256_EXP(7,0,1,2,3,4,5,6,25); SHA256_EXP(6,7,0,1,2,3,4,5,26); SHA256_EXP(5,6,7,0,1,2,3,4,27); SHA256_EXP(4,5,6,7,0,1,2,3,28); SHA256_EXP(3,4,5,6,7,0,1,2,29); SHA256_EXP(2,3,4,5,6,7,0,1,30); SHA256_EXP(1,2,3,4,5,6,7,0,31); SHA256_EXP(0,1,2,3,4,5,6,7,32); SHA256_EXP(7,0,1,2,3,4,5,6,33); SHA256_EXP(6,7,0,1,2,3,4,5,34); SHA256_EXP(5,6,7,0,1,2,3,4,35); SHA256_EXP(4,5,6,7,0,1,2,3,36); SHA256_EXP(3,4,5,6,7,0,1,2,37); SHA256_EXP(2,3,4,5,6,7,0,1,38); SHA256_EXP(1,2,3,4,5,6,7,0,39); SHA256_EXP(0,1,2,3,4,5,6,7,40); SHA256_EXP(7,0,1,2,3,4,5,6,41); SHA256_EXP(6,7,0,1,2,3,4,5,42); SHA256_EXP(5,6,7,0,1,2,3,4,43); SHA256_EXP(4,5,6,7,0,1,2,3,44); SHA256_EXP(3,4,5,6,7,0,1,2,45); SHA256_EXP(2,3,4,5,6,7,0,1,46); SHA256_EXP(1,2,3,4,5,6,7,0,47); SHA256_EXP(0,1,2,3,4,5,6,7,48); SHA256_EXP(7,0,1,2,3,4,5,6,49); SHA256_EXP(6,7,0,1,2,3,4,5,50); SHA256_EXP(5,6,7,0,1,2,3,4,51); SHA256_EXP(4,5,6,7,0,1,2,3,52); SHA256_EXP(3,4,5,6,7,0,1,2,53); SHA256_EXP(2,3,4,5,6,7,0,1,54); SHA256_EXP(1,2,3,4,5,6,7,0,55); SHA256_EXP(0,1,2,3,4,5,6,7,56); SHA256_EXP(7,0,1,2,3,4,5,6,57); SHA256_EXP(6,7,0,1,2,3,4,5,58); SHA256_EXP(5,6,7,0,1,2,3,4,59); SHA256_EXP(4,5,6,7,0,1,2,3,60); SHA256_EXP(3,4,5,6,7,0,1,2,61); SHA256_EXP(2,3,4,5,6,7,0,1,62); SHA256_EXP(1,2,3,4,5,6,7,0,63); ctx->h[0] += wv[0]; ctx->h[1] += wv[1]; ctx->h[2] += wv[2]; ctx->h[3] += wv[3]; ctx->h[4] += wv[4]; ctx->h[5] += wv[5]; ctx->h[6] += wv[6]; ctx->h[7] += wv[7]; #endif /* !UNROLL_LOOPS */ } } void sha256(const unsigned char *message, unsigned int len, unsigned char *digest) { sha256_ctx ctx; sha256_init(&ctx); sha256_update(&ctx, message, len); sha256_final(&ctx, digest); } void sha256_init(sha256_ctx *ctx) { #ifndef UNROLL_LOOPS int i; for (i = 0; i < 8; i++) { ctx->h[i] = sha256_h0[i]; } #else ctx->h[0] = sha256_h0[0]; ctx->h[1] = sha256_h0[1]; ctx->h[2] = sha256_h0[2]; ctx->h[3] = sha256_h0[3]; ctx->h[4] = sha256_h0[4]; ctx->h[5] = sha256_h0[5]; ctx->h[6] = sha256_h0[6]; ctx->h[7] = sha256_h0[7]; #endif /* !UNROLL_LOOPS */ ctx->len = 0; ctx->tot_len = 0; } void sha256_update(sha256_ctx *ctx, const unsigned char *message, unsigned int len) { unsigned int block_nb; unsigned int new_len, rem_len, tmp_len; const unsigned char *shifted_message; tmp_len = SHA256_BLOCK_SIZE - ctx->len; rem_len = len < tmp_len ? len : tmp_len; memcpy(&ctx->block[ctx->len], message, rem_len); if (ctx->len + len < SHA256_BLOCK_SIZE) { ctx->len += len; return; } new_len = len - rem_len; block_nb = new_len / SHA256_BLOCK_SIZE; shifted_message = message + rem_len; sha256_transf(ctx, ctx->block, 1); sha256_transf(ctx, shifted_message, block_nb); rem_len = new_len % SHA256_BLOCK_SIZE; memcpy(ctx->block, &shifted_message[block_nb << 6], rem_len); ctx->len = rem_len; ctx->tot_len += (block_nb + 1) << 6; } void sha256_final(sha256_ctx *ctx, unsigned char *digest) { unsigned int block_nb; unsigned int pm_len; unsigned int len_b; #ifndef UNROLL_LOOPS int i; #endif block_nb = (1 + ((SHA256_BLOCK_SIZE - 9) < (ctx->len % SHA256_BLOCK_SIZE))); len_b = (ctx->tot_len + ctx->len) << 3; pm_len = block_nb << 6; memset(ctx->block + ctx->len, 0, pm_len - ctx->len); ctx->block[ctx->len] = 0x80; UNPACK32(len_b, ctx->block + pm_len - 4); sha256_transf(ctx, ctx->block, block_nb); #ifndef UNROLL_LOOPS for (i = 0 ; i < 8; i++) { UNPACK32(ctx->h[i], &digest[i << 2]); } #else UNPACK32(ctx->h[0], &digest[ 0]); UNPACK32(ctx->h[1], &digest[ 4]); UNPACK32(ctx->h[2], &digest[ 8]); UNPACK32(ctx->h[3], &digest[12]); UNPACK32(ctx->h[4], &digest[16]); UNPACK32(ctx->h[5], &digest[20]); UNPACK32(ctx->h[6], &digest[24]); UNPACK32(ctx->h[7], &digest[28]); #endif /* !UNROLL_LOOPS */ } /* SHA-512 functions */ void sha512_transf(sha512_ctx *ctx, const unsigned char *message, unsigned int block_nb) { uint64 w[80]; uint64 wv[8]; uint64 t1, t2; const unsigned char *sub_block; int i, j; for (i = 0; i < (int) block_nb; i++) { sub_block = message + (i << 7); #ifndef UNROLL_LOOPS for (j = 0; j < 16; j++) { PACK64(&sub_block[j << 3], &w[j]); } for (j = 16; j < 80; j++) { SHA512_SCR(j); } for (j = 0; j < 8; j++) { wv[j] = ctx->h[j]; } for (j = 0; j < 80; j++) { t1 = wv[7] + SHA512_F2(wv[4]) + CH(wv[4], wv[5], wv[6]) + sha512_k[j] + w[j]; t2 = SHA512_F1(wv[0]) + MAJ(wv[0], wv[1], wv[2]); wv[7] = wv[6]; wv[6] = wv[5]; wv[5] = wv[4]; wv[4] = wv[3] + t1; wv[3] = wv[2]; wv[2] = wv[1]; wv[1] = wv[0]; wv[0] = t1 + t2; } for (j = 0; j < 8; j++) { ctx->h[j] += wv[j]; } #else PACK64(&sub_block[ 0], &w[ 0]); PACK64(&sub_block[ 8], &w[ 1]); PACK64(&sub_block[ 16], &w[ 2]); PACK64(&sub_block[ 24], &w[ 3]); PACK64(&sub_block[ 32], &w[ 4]); PACK64(&sub_block[ 40], &w[ 5]); PACK64(&sub_block[ 48], &w[ 6]); PACK64(&sub_block[ 56], &w[ 7]); PACK64(&sub_block[ 64], &w[ 8]); PACK64(&sub_block[ 72], &w[ 9]); PACK64(&sub_block[ 80], &w[10]); PACK64(&sub_block[ 88], &w[11]); PACK64(&sub_block[ 96], &w[12]); PACK64(&sub_block[104], &w[13]); PACK64(&sub_block[112], &w[14]); PACK64(&sub_block[120], &w[15]); SHA512_SCR(16); SHA512_SCR(17); SHA512_SCR(18); SHA512_SCR(19); SHA512_SCR(20); SHA512_SCR(21); SHA512_SCR(22); SHA512_SCR(23); SHA512_SCR(24); SHA512_SCR(25); SHA512_SCR(26); SHA512_SCR(27); SHA512_SCR(28); SHA512_SCR(29); SHA512_SCR(30); SHA512_SCR(31); SHA512_SCR(32); SHA512_SCR(33); SHA512_SCR(34); SHA512_SCR(35); SHA512_SCR(36); SHA512_SCR(37); SHA512_SCR(38); SHA512_SCR(39); SHA512_SCR(40); SHA512_SCR(41); SHA512_SCR(42); SHA512_SCR(43); SHA512_SCR(44); SHA512_SCR(45); SHA512_SCR(46); SHA512_SCR(47); SHA512_SCR(48); SHA512_SCR(49); SHA512_SCR(50); SHA512_SCR(51); SHA512_SCR(52); SHA512_SCR(53); SHA512_SCR(54); SHA512_SCR(55); SHA512_SCR(56); SHA512_SCR(57); SHA512_SCR(58); SHA512_SCR(59); SHA512_SCR(60); SHA512_SCR(61); SHA512_SCR(62); SHA512_SCR(63); SHA512_SCR(64); SHA512_SCR(65); SHA512_SCR(66); SHA512_SCR(67); SHA512_SCR(68); SHA512_SCR(69); SHA512_SCR(70); SHA512_SCR(71); SHA512_SCR(72); SHA512_SCR(73); SHA512_SCR(74); SHA512_SCR(75); SHA512_SCR(76); SHA512_SCR(77); SHA512_SCR(78); SHA512_SCR(79); wv[0] = ctx->h[0]; wv[1] = ctx->h[1]; wv[2] = ctx->h[2]; wv[3] = ctx->h[3]; wv[4] = ctx->h[4]; wv[5] = ctx->h[5]; wv[6] = ctx->h[6]; wv[7] = ctx->h[7]; j = 0; do { SHA512_EXP(0,1,2,3,4,5,6,7,j); j++; SHA512_EXP(7,0,1,2,3,4,5,6,j); j++; SHA512_EXP(6,7,0,1,2,3,4,5,j); j++; SHA512_EXP(5,6,7,0,1,2,3,4,j); j++; SHA512_EXP(4,5,6,7,0,1,2,3,j); j++; SHA512_EXP(3,4,5,6,7,0,1,2,j); j++; SHA512_EXP(2,3,4,5,6,7,0,1,j); j++; SHA512_EXP(1,2,3,4,5,6,7,0,j); j++; } while (j < 80); ctx->h[0] += wv[0]; ctx->h[1] += wv[1]; ctx->h[2] += wv[2]; ctx->h[3] += wv[3]; ctx->h[4] += wv[4]; ctx->h[5] += wv[5]; ctx->h[6] += wv[6]; ctx->h[7] += wv[7]; #endif /* !UNROLL_LOOPS */ } } void sha512(const unsigned char *message, unsigned int len, unsigned char *digest) { sha512_ctx ctx; sha512_init(&ctx); sha512_update(&ctx, message, len); sha512_final(&ctx, digest); } void sha512_init(sha512_ctx *ctx) { #ifndef UNROLL_LOOPS int i; for (i = 0; i < 8; i++) { ctx->h[i] = sha512_h0[i]; } #else ctx->h[0] = sha512_h0[0]; ctx->h[1] = sha512_h0[1]; ctx->h[2] = sha512_h0[2]; ctx->h[3] = sha512_h0[3]; ctx->h[4] = sha512_h0[4]; ctx->h[5] = sha512_h0[5]; ctx->h[6] = sha512_h0[6]; ctx->h[7] = sha512_h0[7]; #endif /* !UNROLL_LOOPS */ ctx->len = 0; ctx->tot_len = 0; } void sha512_update(sha512_ctx *ctx, const unsigned char *message, unsigned int len) { unsigned int block_nb; unsigned int new_len, rem_len, tmp_len; const unsigned char *shifted_message; tmp_len = SHA512_BLOCK_SIZE - ctx->len; rem_len = len < tmp_len ? len : tmp_len; memcpy(&ctx->block[ctx->len], message, rem_len); if (ctx->len + len < SHA512_BLOCK_SIZE) { ctx->len += len; return; } new_len = len - rem_len; block_nb = new_len / SHA512_BLOCK_SIZE; shifted_message = message + rem_len; sha512_transf(ctx, ctx->block, 1); sha512_transf(ctx, shifted_message, block_nb); rem_len = new_len % SHA512_BLOCK_SIZE; memcpy(ctx->block, &shifted_message[block_nb << 7], rem_len); ctx->len = rem_len; ctx->tot_len += (block_nb + 1) << 7; } void sha512_final(sha512_ctx *ctx, unsigned char *digest) { unsigned int block_nb; unsigned int pm_len; unsigned int len_b; #ifndef UNROLL_LOOPS int i; #endif block_nb = 1 + ((SHA512_BLOCK_SIZE - 17) < (ctx->len % SHA512_BLOCK_SIZE)); len_b = (ctx->tot_len + ctx->len) << 3; pm_len = block_nb << 7; memset(ctx->block + ctx->len, 0, pm_len - ctx->len); ctx->block[ctx->len] = 0x80; UNPACK32(len_b, ctx->block + pm_len - 4); sha512_transf(ctx, ctx->block, block_nb); #ifndef UNROLL_LOOPS for (i = 0 ; i < 8; i++) { UNPACK64(ctx->h[i], &digest[i << 3]); } #else UNPACK64(ctx->h[0], &digest[ 0]); UNPACK64(ctx->h[1], &digest[ 8]); UNPACK64(ctx->h[2], &digest[16]); UNPACK64(ctx->h[3], &digest[24]); UNPACK64(ctx->h[4], &digest[32]); UNPACK64(ctx->h[5], &digest[40]); UNPACK64(ctx->h[6], &digest[48]); UNPACK64(ctx->h[7], &digest[56]); #endif /* !UNROLL_LOOPS */ } /* SHA-384 functions */ void sha384(const unsigned char *message, unsigned int len, unsigned char *digest) { sha384_ctx ctx; sha384_init(&ctx); sha384_update(&ctx, message, len); sha384_final(&ctx, digest); } void sha384_init(sha384_ctx *ctx) { #ifndef UNROLL_LOOPS int i; for (i = 0; i < 8; i++) { ctx->h[i] = sha384_h0[i]; } #else ctx->h[0] = sha384_h0[0]; ctx->h[1] = sha384_h0[1]; ctx->h[2] = sha384_h0[2]; ctx->h[3] = sha384_h0[3]; ctx->h[4] = sha384_h0[4]; ctx->h[5] = sha384_h0[5]; ctx->h[6] = sha384_h0[6]; ctx->h[7] = sha384_h0[7]; #endif /* !UNROLL_LOOPS */ ctx->len = 0; ctx->tot_len = 0; } void sha384_update(sha384_ctx *ctx, const unsigned char *message, unsigned int len) { unsigned int block_nb; unsigned int new_len, rem_len, tmp_len; const unsigned char *shifted_message; tmp_len = SHA384_BLOCK_SIZE - ctx->len; rem_len = len < tmp_len ? len : tmp_len; memcpy(&ctx->block[ctx->len], message, rem_len); if (ctx->len + len < SHA384_BLOCK_SIZE) { ctx->len += len; return; } new_len = len - rem_len; block_nb = new_len / SHA384_BLOCK_SIZE; shifted_message = message + rem_len; sha512_transf(ctx, ctx->block, 1); sha512_transf(ctx, shifted_message, block_nb); rem_len = new_len % SHA384_BLOCK_SIZE; memcpy(ctx->block, &shifted_message[block_nb << 7], rem_len); ctx->len = rem_len; ctx->tot_len += (block_nb + 1) << 7; } void sha384_final(sha384_ctx *ctx, unsigned char *digest) { unsigned int block_nb; unsigned int pm_len; unsigned int len_b; #ifndef UNROLL_LOOPS int i; #endif block_nb = (1 + ((SHA384_BLOCK_SIZE - 17) < (ctx->len % SHA384_BLOCK_SIZE))); len_b = (ctx->tot_len + ctx->len) << 3; pm_len = block_nb << 7; memset(ctx->block + ctx->len, 0, pm_len - ctx->len); ctx->block[ctx->len] = 0x80; UNPACK32(len_b, ctx->block + pm_len - 4); sha512_transf(ctx, ctx->block, block_nb); #ifndef UNROLL_LOOPS for (i = 0 ; i < 6; i++) { UNPACK64(ctx->h[i], &digest[i << 3]); } #else UNPACK64(ctx->h[0], &digest[ 0]); UNPACK64(ctx->h[1], &digest[ 8]); UNPACK64(ctx->h[2], &digest[16]); UNPACK64(ctx->h[3], &digest[24]); UNPACK64(ctx->h[4], &digest[32]); UNPACK64(ctx->h[5], &digest[40]); #endif /* !UNROLL_LOOPS */ } /* SHA-224 functions */ void sha224(const unsigned char *message, unsigned int len, unsigned char *digest) { sha224_ctx ctx; sha224_init(&ctx); sha224_update(&ctx, message, len); sha224_final(&ctx, digest); } void sha224_init(sha224_ctx *ctx) { #ifndef UNROLL_LOOPS int i; for (i = 0; i < 8; i++) { ctx->h[i] = sha224_h0[i]; } #else ctx->h[0] = sha224_h0[0]; ctx->h[1] = sha224_h0[1]; ctx->h[2] = sha224_h0[2]; ctx->h[3] = sha224_h0[3]; ctx->h[4] = sha224_h0[4]; ctx->h[5] = sha224_h0[5]; ctx->h[6] = sha224_h0[6]; ctx->h[7] = sha224_h0[7]; #endif /* !UNROLL_LOOPS */ ctx->len = 0; ctx->tot_len = 0; } void sha224_update(sha224_ctx *ctx, const unsigned char *message, unsigned int len) { unsigned int block_nb; unsigned int new_len, rem_len, tmp_len; const unsigned char *shifted_message; tmp_len = SHA224_BLOCK_SIZE - ctx->len; rem_len = len < tmp_len ? len : tmp_len; memcpy(&ctx->block[ctx->len], message, rem_len); if (ctx->len + len < SHA224_BLOCK_SIZE) { ctx->len += len; return; } new_len = len - rem_len; block_nb = new_len / SHA224_BLOCK_SIZE; shifted_message = message + rem_len; sha256_transf(ctx, ctx->block, 1); sha256_transf(ctx, shifted_message, block_nb); rem_len = new_len % SHA224_BLOCK_SIZE; memcpy(ctx->block, &shifted_message[block_nb << 6], rem_len); ctx->len = rem_len; ctx->tot_len += (block_nb + 1) << 6; } void sha224_final(sha224_ctx *ctx, unsigned char *digest) { unsigned int block_nb; unsigned int pm_len; unsigned int len_b; #ifndef UNROLL_LOOPS int i; #endif block_nb = (1 + ((SHA224_BLOCK_SIZE - 9) < (ctx->len % SHA224_BLOCK_SIZE))); len_b = (ctx->tot_len + ctx->len) << 3; pm_len = block_nb << 6; memset(ctx->block + ctx->len, 0, pm_len - ctx->len); ctx->block[ctx->len] = 0x80; UNPACK32(len_b, ctx->block + pm_len - 4); sha256_transf(ctx, ctx->block, block_nb); #ifndef UNROLL_LOOPS for (i = 0 ; i < 7; i++) { UNPACK32(ctx->h[i], &digest[i << 2]); } #else UNPACK32(ctx->h[0], &digest[ 0]); UNPACK32(ctx->h[1], &digest[ 4]); UNPACK32(ctx->h[2], &digest[ 8]); UNPACK32(ctx->h[3], &digest[12]); UNPACK32(ctx->h[4], &digest[16]); UNPACK32(ctx->h[5], &digest[20]); UNPACK32(ctx->h[6], &digest[24]); #endif /* !UNROLL_LOOPS */ } #ifdef TEST_VECTORS /* FIPS 180-2 Validation tests */ #include <stdio.h> #include <stdlib.h> void test(const char *vector, unsigned char *digest, unsigned int digest_size) { char output[2 * SHA512_DIGEST_SIZE + 1]; int i; output[2 * digest_size] = '\0'; for (i = 0; i < (int) digest_size ; i++) { sprintf(output + 2 * i, "%02x", digest[i]); } printf("H: %s\n", output); if (strcmp(vector, output)) { fprintf(stderr, "Test failed.\n"); exit(EXIT_FAILURE); } } int main(void) { static const char *vectors[4][3] = { /* SHA-224 */ { "23097d223405d8228642a477bda255b32aadbce4bda0b3f7e36c9da7", "75388b16512776cc5dba5da1fd890150b0c6455cb4f58b1952522525", "20794655980c91d8bbb4c1ea97618a4bf03f42581948b2ee4ee7ad67", }, /* SHA-256 */ { "ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad", "248d6a61d20638b8e5c026930c3e6039a33ce45964ff2167f6ecedd419db06c1", "cdc76e5c9914fb9281a1c7e284d73e67f1809a48a497200e046d39ccc7112cd0", }, /* SHA-384 */ { "cb00753f45a35e8bb5a03d699ac65007272c32ab0eded1631a8b605a43ff5bed" "8086072ba1e7cc2358baeca134c825a7", "09330c33f71147e83d192fc782cd1b4753111b173b3b05d22fa08086e3b0f712" "fcc7c71a557e2db966c3e9fa91746039", "9d0e1809716474cb086e834e310a4a1ced149e9c00f248527972cec5704c2a5b" "07b8b3dc38ecc4ebae97ddd87f3d8985", }, /* SHA-512 */ { "ddaf35a193617abacc417349ae20413112e6fa4e89a97ea20a9eeee64b55d39a" "2192992a274fc1a836ba3c23a3feebbd454d4423643ce80e2a9ac94fa54ca49f", "8e959b75dae313da8cf4f72814fc143f8f7779c6eb9f7fa17299aeadb6889018" "501d289e4900f7e4331b99dec4b5433ac7d329eeb6dd26545e96e55b874be909", "e718483d0ce769644e2e42c7bc15b4638e1f98b13b2044285632a803afa973eb" "de0ff244877ea60a4cb0432ce577c31beb009c5c2c49aa2e4eadb217ad8cc09b" } }; static const char message1[] = "abc"; static const char message2a[] = "abcdbcdecdefdefgefghfghighijhi" "jkijkljklmklmnlmnomnopnopq"; static const char message2b[] = "abcdefghbcdefghicdefghijdefghijkefghij" "klfghijklmghijklmnhijklmnoijklmnopjklm" "nopqklmnopqrlmnopqrsmnopqrstnopqrstu"; unsigned char *message3; unsigned int message3_len = 1000000; unsigned char digest[SHA512_DIGEST_SIZE]; message3 = malloc(message3_len); if (message3 == NULL) { fprintf(stderr, "Can't allocate memory\n"); return -1; } memset(message3, 'a', message3_len); printf("SHA-2 FIPS 180-2 Validation tests\n\n"); printf("SHA-224 Test vectors\n"); sha224((const unsigned char *) message1, strlen(message1), digest); test(vectors[0][0], digest, SHA224_DIGEST_SIZE); sha224((const unsigned char *) message2a, strlen(message2a), digest); test(vectors[0][1], digest, SHA224_DIGEST_SIZE); sha224(message3, message3_len, digest); test(vectors[0][2], digest, SHA224_DIGEST_SIZE); printf("\n"); printf("SHA-256 Test vectors\n"); sha256((const unsigned char *) message1, strlen(message1), digest); test(vectors[1][0], digest, SHA256_DIGEST_SIZE); sha256((const unsigned char *) message2a, strlen(message2a), digest); test(vectors[1][1], digest, SHA256_DIGEST_SIZE); sha256(message3, message3_len, digest); test(vectors[1][2], digest, SHA256_DIGEST_SIZE); printf("\n"); printf("SHA-384 Test vectors\n"); sha384((const unsigned char *) message1, strlen(message1), digest); test(vectors[2][0], digest, SHA384_DIGEST_SIZE); sha384((const unsigned char *)message2b, strlen(message2b), digest); test(vectors[2][1], digest, SHA384_DIGEST_SIZE); sha384(message3, message3_len, digest); test(vectors[2][2], digest, SHA384_DIGEST_SIZE); printf("\n"); printf("SHA-512 Test vectors\n"); sha512((const unsigned char *) message1, strlen(message1), digest); test(vectors[3][0], digest, SHA512_DIGEST_SIZE); sha512((const unsigned char *) message2b, strlen(message2b), digest); test(vectors[3][1], digest, SHA512_DIGEST_SIZE); sha512(message3, message3_len, digest); test(vectors[3][2], digest, SHA512_DIGEST_SIZE); printf("\n"); printf("All tests passed.\n"); return 0; } #endif /* TEST_VECTORS */ �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/vendor/sha2/sha2.h�������������������������������������������������������������������0000664�0000000�0000000�00000007335�13554550454�0016513�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * FIPS 180-2 SHA-224/256/384/512 implementation * Last update: 02/02/2007 * Issue date: 04/30/2005 * * Copyright (C) 2005, 2007 Olivier Gay <olivier.gay@a3.epfl.ch> * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the project nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #ifndef SHA2_H #define SHA2_H #define SHA224_DIGEST_SIZE ( 224 / 8) #define SHA256_DIGEST_SIZE ( 256 / 8) #define SHA384_DIGEST_SIZE ( 384 / 8) #define SHA512_DIGEST_SIZE ( 512 / 8) #define SHA256_BLOCK_SIZE ( 512 / 8) #define SHA512_BLOCK_SIZE (1024 / 8) #define SHA384_BLOCK_SIZE SHA512_BLOCK_SIZE #define SHA224_BLOCK_SIZE SHA256_BLOCK_SIZE #ifndef SHA2_TYPES #define SHA2_TYPES typedef unsigned char uint8; typedef unsigned int uint32; typedef unsigned long long uint64; #endif #ifdef __cplusplus extern "C" { #endif typedef struct { unsigned int tot_len; unsigned int len; unsigned char block[2 * SHA256_BLOCK_SIZE]; uint32 h[8]; } sha256_ctx; typedef struct { unsigned int tot_len; unsigned int len; unsigned char block[2 * SHA512_BLOCK_SIZE]; uint64 h[8]; } sha512_ctx; typedef sha512_ctx sha384_ctx; typedef sha256_ctx sha224_ctx; void sha224_init(sha224_ctx *ctx); void sha224_update(sha224_ctx *ctx, const unsigned char *message, unsigned int len); void sha224_final(sha224_ctx *ctx, unsigned char *digest); void sha224(const unsigned char *message, unsigned int len, unsigned char *digest); void sha256_init(sha256_ctx * ctx); void sha256_update(sha256_ctx *ctx, const unsigned char *message, unsigned int len); void sha256_final(sha256_ctx *ctx, unsigned char *digest); void sha256(const unsigned char *message, unsigned int len, unsigned char *digest); void sha384_init(sha384_ctx *ctx); void sha384_update(sha384_ctx *ctx, const unsigned char *message, unsigned int len); void sha384_final(sha384_ctx *ctx, unsigned char *digest); void sha384(const unsigned char *message, unsigned int len, unsigned char *digest); void sha512_init(sha512_ctx *ctx); void sha512_update(sha512_ctx *ctx, const unsigned char *message, unsigned int len); void sha512_final(sha512_ctx *ctx, unsigned char *digest); void sha512(const unsigned char *message, unsigned int len, unsigned char *digest); #ifdef __cplusplus } #endif #endif /* !SHA2_H */ ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/vendor/utfcpp/�����������������������������������������������������������������������0000775�0000000�0000000�00000000000�13554550454�0016141�5����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/vendor/utfcpp/utf8.h�����������������������������������������������������������������0000664�0000000�0000000�00000003122�13554550454�0017176�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������// Copyright 2006 Nemanja Trifunovic /* Permission is hereby granted, free of charge, to any person or organization obtaining a copy of the software and accompanying documentation covered by this license (the "Software") to use, reproduce, display, distribute, execute, and transmit the Software, and to prepare derivative works of the Software, and to permit third-parties to whom the Software is furnished to do so, all subject to the following: The copyright notices in the Software and this entire statement, including the above license grant, this restriction and the following disclaimer, must be included in all copies of the Software, in whole or in part, and all derivative works of the Software, unless such copies or derivative works are solely in the form of machine-executable object code generated by a source language processor. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #ifndef UTF8_FOR_CPP_2675DCD0_9480_4c0c_B92A_CC14C027B731 #define UTF8_FOR_CPP_2675DCD0_9480_4c0c_B92A_CC14C027B731 #include "utf8/checked.h" #include "utf8/unchecked.h" #if __cplusplus >= 201103L // C++ 11 or later #include "utf8/cpp11.h" #endif // C++ 11 or later #endif // header guard ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/vendor/utfcpp/utf8/������������������������������������������������������������������0000775�0000000�0000000�00000000000�13554550454�0017027�5����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/vendor/utfcpp/utf8/checked.h���������������������������������������������������������0000664�0000000�0000000�00000027424�13554550454�0020577�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������// Copyright 2006-2016 Nemanja Trifunovic /* Permission is hereby granted, free of charge, to any person or organization obtaining a copy of the software and accompanying documentation covered by this license (the "Software") to use, reproduce, display, distribute, execute, and transmit the Software, and to prepare derivative works of the Software, and to permit third-parties to whom the Software is furnished to do so, all subject to the following: The copyright notices in the Software and this entire statement, including the above license grant, this restriction and the following disclaimer, must be included in all copies of the Software, in whole or in part, and all derivative works of the Software, unless such copies or derivative works are solely in the form of machine-executable object code generated by a source language processor. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #ifndef UTF8_FOR_CPP_CHECKED_H_2675DCD0_9480_4c0c_B92A_CC14C027B731 #define UTF8_FOR_CPP_CHECKED_H_2675DCD0_9480_4c0c_B92A_CC14C027B731 #include "core.h" #include <stdexcept> namespace utf8 { // Base for the exceptions that may be thrown from the library class exception : public ::std::exception { }; // Exceptions that may be thrown from the library functions. class invalid_code_point : public exception { uint32_t cp; public: invalid_code_point(uint32_t codepoint) : cp(codepoint) {} virtual const char* what() const throw() { return "Invalid code point"; } uint32_t code_point() const {return cp;} }; class invalid_utf8 : public exception { uint8_t u8; public: invalid_utf8 (uint8_t u) : u8(u) {} virtual const char* what() const throw() { return "Invalid UTF-8"; } uint8_t utf8_octet() const {return u8;} }; class invalid_utf16 : public exception { uint16_t u16; public: invalid_utf16 (uint16_t u) : u16(u) {} virtual const char* what() const throw() { return "Invalid UTF-16"; } uint16_t utf16_word() const {return u16;} }; class not_enough_room : public exception { public: virtual const char* what() const throw() { return "Not enough space"; } }; /// The library API - functions intended to be called by the users template <typename octet_iterator> octet_iterator append(uint32_t cp, octet_iterator result) { if (!utf8::internal::is_code_point_valid(cp)) throw invalid_code_point(cp); if (cp < 0x80) // one octet *(result++) = static_cast<uint8_t>(cp); else if (cp < 0x800) { // two octets *(result++) = static_cast<uint8_t>((cp >> 6) | 0xc0); *(result++) = static_cast<uint8_t>((cp & 0x3f) | 0x80); } else if (cp < 0x10000) { // three octets *(result++) = static_cast<uint8_t>((cp >> 12) | 0xe0); *(result++) = static_cast<uint8_t>(((cp >> 6) & 0x3f) | 0x80); *(result++) = static_cast<uint8_t>((cp & 0x3f) | 0x80); } else { // four octets *(result++) = static_cast<uint8_t>((cp >> 18) | 0xf0); *(result++) = static_cast<uint8_t>(((cp >> 12) & 0x3f) | 0x80); *(result++) = static_cast<uint8_t>(((cp >> 6) & 0x3f) | 0x80); *(result++) = static_cast<uint8_t>((cp & 0x3f) | 0x80); } return result; } template <typename octet_iterator, typename output_iterator> output_iterator replace_invalid(octet_iterator start, octet_iterator end, output_iterator out, uint32_t replacement) { while (start != end) { octet_iterator sequence_start = start; internal::utf_error err_code = utf8::internal::validate_next(start, end); switch (err_code) { case internal::UTF8_OK : for (octet_iterator it = sequence_start; it != start; ++it) *out++ = *it; break; case internal::NOT_ENOUGH_ROOM: out = utf8::append (replacement, out); start = end; break; case internal::INVALID_LEAD: out = utf8::append (replacement, out); ++start; break; case internal::INCOMPLETE_SEQUENCE: case internal::OVERLONG_SEQUENCE: case internal::INVALID_CODE_POINT: out = utf8::append (replacement, out); ++start; // just one replacement mark for the sequence while (start != end && utf8::internal::is_trail(*start)) ++start; break; } } return out; } template <typename octet_iterator, typename output_iterator> inline output_iterator replace_invalid(octet_iterator start, octet_iterator end, output_iterator out) { static const uint32_t replacement_marker = utf8::internal::mask16(0xfffd); return utf8::replace_invalid(start, end, out, replacement_marker); } template <typename octet_iterator> uint32_t next(octet_iterator& it, octet_iterator end) { uint32_t cp = 0; internal::utf_error err_code = utf8::internal::validate_next(it, end, cp); switch (err_code) { case internal::UTF8_OK : break; case internal::NOT_ENOUGH_ROOM : throw not_enough_room(); case internal::INVALID_LEAD : case internal::INCOMPLETE_SEQUENCE : case internal::OVERLONG_SEQUENCE : throw invalid_utf8(*it); case internal::INVALID_CODE_POINT : throw invalid_code_point(cp); } return cp; } template <typename octet_iterator> uint32_t peek_next(octet_iterator it, octet_iterator end) { return utf8::next(it, end); } template <typename octet_iterator> uint32_t prior(octet_iterator& it, octet_iterator start) { // can't do much if it == start if (it == start) throw not_enough_room(); octet_iterator end = it; // Go back until we hit either a lead octet or start while (utf8::internal::is_trail(*(--it))) if (it == start) throw invalid_utf8(*it); // error - no lead byte in the sequence return utf8::peek_next(it, end); } template <typename octet_iterator, typename distance_type> void advance (octet_iterator& it, distance_type n, octet_iterator end) { const distance_type zero(0); if (n < zero) { // backward for (distance_type i = n; i < zero; ++i) utf8::prior(it, end); } else { // forward for (distance_type i = zero; i < n; ++i) utf8::next(it, end); } } template <typename octet_iterator> typename std::iterator_traits<octet_iterator>::difference_type distance (octet_iterator first, octet_iterator last) { typename std::iterator_traits<octet_iterator>::difference_type dist; for (dist = 0; first < last; ++dist) utf8::next(first, last); return dist; } template <typename u16bit_iterator, typename octet_iterator> octet_iterator utf16to8 (u16bit_iterator start, u16bit_iterator end, octet_iterator result) { while (start != end) { uint32_t cp = utf8::internal::mask16(*start++); // Take care of surrogate pairs first if (utf8::internal::is_lead_surrogate(cp)) { if (start != end) { uint32_t trail_surrogate = utf8::internal::mask16(*start++); if (utf8::internal::is_trail_surrogate(trail_surrogate)) cp = (cp << 10) + trail_surrogate + internal::SURROGATE_OFFSET; else throw invalid_utf16(static_cast<uint16_t>(trail_surrogate)); } else throw invalid_utf16(static_cast<uint16_t>(cp)); } // Lone trail surrogate else if (utf8::internal::is_trail_surrogate(cp)) throw invalid_utf16(static_cast<uint16_t>(cp)); result = utf8::append(cp, result); } return result; } template <typename u16bit_iterator, typename octet_iterator> u16bit_iterator utf8to16 (octet_iterator start, octet_iterator end, u16bit_iterator result) { while (start < end) { uint32_t cp = utf8::next(start, end); if (cp > 0xffff) { //make a surrogate pair *result++ = static_cast<uint16_t>((cp >> 10) + internal::LEAD_OFFSET); *result++ = static_cast<uint16_t>((cp & 0x3ff) + internal::TRAIL_SURROGATE_MIN); } else *result++ = static_cast<uint16_t>(cp); } return result; } template <typename octet_iterator, typename u32bit_iterator> octet_iterator utf32to8 (u32bit_iterator start, u32bit_iterator end, octet_iterator result) { while (start != end) result = utf8::append(*(start++), result); return result; } template <typename octet_iterator, typename u32bit_iterator> u32bit_iterator utf8to32 (octet_iterator start, octet_iterator end, u32bit_iterator result) { while (start < end) (*result++) = utf8::next(start, end); return result; } // The iterator class template <typename octet_iterator> class iterator : public std::iterator <std::bidirectional_iterator_tag, uint32_t> { octet_iterator it; octet_iterator range_start; octet_iterator range_end; public: iterator () {} explicit iterator (const octet_iterator& octet_it, const octet_iterator& rangestart, const octet_iterator& rangeend) : it(octet_it), range_start(rangestart), range_end(rangeend) { if (it < range_start || it > range_end) throw std::out_of_range("Invalid utf-8 iterator position"); } // the default "big three" are OK octet_iterator base () const { return it; } uint32_t operator * () const { octet_iterator temp = it; return utf8::next(temp, range_end); } bool operator == (const iterator& rhs) const { if (range_start != rhs.range_start || range_end != rhs.range_end) throw std::logic_error("Comparing utf-8 iterators defined with different ranges"); return (it == rhs.it); } bool operator != (const iterator& rhs) const { return !(operator == (rhs)); } iterator& operator ++ () { utf8::next(it, range_end); return *this; } iterator operator ++ (int) { iterator temp = *this; utf8::next(it, range_end); return temp; } iterator& operator -- () { utf8::prior(it, range_start); return *this; } iterator operator -- (int) { iterator temp = *this; utf8::prior(it, range_start); return temp; } }; // class iterator } // namespace utf8 #endif //header guard ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/vendor/utfcpp/utf8/core.h������������������������������������������������������������0000664�0000000�0000000�00000024322�13554550454�0020133�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������// Copyright 2006 Nemanja Trifunovic /* Permission is hereby granted, free of charge, to any person or organization obtaining a copy of the software and accompanying documentation covered by this license (the "Software") to use, reproduce, display, distribute, execute, and transmit the Software, and to prepare derivative works of the Software, and to permit third-parties to whom the Software is furnished to do so, all subject to the following: The copyright notices in the Software and this entire statement, including the above license grant, this restriction and the following disclaimer, must be included in all copies of the Software, in whole or in part, and all derivative works of the Software, unless such copies or derivative works are solely in the form of machine-executable object code generated by a source language processor. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #ifndef UTF8_FOR_CPP_CORE_H_2675DCD0_9480_4c0c_B92A_CC14C027B731 #define UTF8_FOR_CPP_CORE_H_2675DCD0_9480_4c0c_B92A_CC14C027B731 #include <iterator> namespace utf8 { // The typedefs for 8-bit, 16-bit and 32-bit unsigned integers // You may need to change them to match your system. // These typedefs have the same names as ones from cstdint, or boost/cstdint typedef unsigned char uint8_t; typedef unsigned short uint16_t; typedef unsigned int uint32_t; // Helper code - not intended to be directly called by the library users. May be changed at any time namespace internal { // Unicode constants // Leading (high) surrogates: 0xd800 - 0xdbff // Trailing (low) surrogates: 0xdc00 - 0xdfff const uint16_t LEAD_SURROGATE_MIN = 0xd800u; const uint16_t LEAD_SURROGATE_MAX = 0xdbffu; const uint16_t TRAIL_SURROGATE_MIN = 0xdc00u; const uint16_t TRAIL_SURROGATE_MAX = 0xdfffu; const uint16_t LEAD_OFFSET = 0xd7c0u; // LEAD_SURROGATE_MIN - (0x10000 >> 10) const uint32_t SURROGATE_OFFSET = 0xfca02400u; // 0x10000u - (LEAD_SURROGATE_MIN << 10) - TRAIL_SURROGATE_MIN // Maximum valid value for a Unicode code point const uint32_t CODE_POINT_MAX = 0x0010ffffu; template<typename octet_type> inline uint8_t mask8(octet_type oc) { return static_cast<uint8_t>(0xff & oc); } template<typename u16_type> inline uint16_t mask16(u16_type oc) { return static_cast<uint16_t>(0xffff & oc); } template<typename octet_type> inline bool is_trail(octet_type oc) { return ((utf8::internal::mask8(oc) >> 6) == 0x2); } template <typename u16> inline bool is_lead_surrogate(u16 cp) { return (cp >= LEAD_SURROGATE_MIN && cp <= LEAD_SURROGATE_MAX); } template <typename u16> inline bool is_trail_surrogate(u16 cp) { return (cp >= TRAIL_SURROGATE_MIN && cp <= TRAIL_SURROGATE_MAX); } template <typename u16> inline bool is_surrogate(u16 cp) { return (cp >= LEAD_SURROGATE_MIN && cp <= TRAIL_SURROGATE_MAX); } template <typename u32> inline bool is_code_point_valid(u32 cp) { return (cp <= CODE_POINT_MAX && !utf8::internal::is_surrogate(cp)); } template <typename octet_iterator> inline typename std::iterator_traits<octet_iterator>::difference_type sequence_length(octet_iterator lead_it) { uint8_t lead = utf8::internal::mask8(*lead_it); if (lead < 0x80) return 1; else if ((lead >> 5) == 0x6) return 2; else if ((lead >> 4) == 0xe) return 3; else if ((lead >> 3) == 0x1e) return 4; else return 0; } template <typename octet_difference_type> inline bool is_overlong_sequence(uint32_t cp, octet_difference_type length) { if (cp < 0x80) { if (length != 1) return true; } else if (cp < 0x800) { if (length != 2) return true; } else if (cp < 0x10000) { if (length != 3) return true; } return false; } enum utf_error {UTF8_OK, NOT_ENOUGH_ROOM, INVALID_LEAD, INCOMPLETE_SEQUENCE, OVERLONG_SEQUENCE, INVALID_CODE_POINT}; /// Helper for get_sequence_x template <typename octet_iterator> utf_error increase_safely(octet_iterator& it, octet_iterator end) { if (++it == end) return NOT_ENOUGH_ROOM; if (!utf8::internal::is_trail(*it)) return INCOMPLETE_SEQUENCE; return UTF8_OK; } #define UTF8_CPP_INCREASE_AND_RETURN_ON_ERROR(IT, END) {utf_error ret = increase_safely(IT, END); if (ret != UTF8_OK) return ret;} /// get_sequence_x functions decode utf-8 sequences of the length x template <typename octet_iterator> utf_error get_sequence_1(octet_iterator& it, octet_iterator end, uint32_t& code_point) { if (it == end) return NOT_ENOUGH_ROOM; code_point = utf8::internal::mask8(*it); return UTF8_OK; } template <typename octet_iterator> utf_error get_sequence_2(octet_iterator& it, octet_iterator end, uint32_t& code_point) { if (it == end) return NOT_ENOUGH_ROOM; code_point = utf8::internal::mask8(*it); UTF8_CPP_INCREASE_AND_RETURN_ON_ERROR(it, end) code_point = ((code_point << 6) & 0x7ff) + ((*it) & 0x3f); return UTF8_OK; } template <typename octet_iterator> utf_error get_sequence_3(octet_iterator& it, octet_iterator end, uint32_t& code_point) { if (it == end) return NOT_ENOUGH_ROOM; code_point = utf8::internal::mask8(*it); UTF8_CPP_INCREASE_AND_RETURN_ON_ERROR(it, end) code_point = ((code_point << 12) & 0xffff) + ((utf8::internal::mask8(*it) << 6) & 0xfff); UTF8_CPP_INCREASE_AND_RETURN_ON_ERROR(it, end) code_point += (*it) & 0x3f; return UTF8_OK; } template <typename octet_iterator> utf_error get_sequence_4(octet_iterator& it, octet_iterator end, uint32_t& code_point) { if (it == end) return NOT_ENOUGH_ROOM; code_point = utf8::internal::mask8(*it); UTF8_CPP_INCREASE_AND_RETURN_ON_ERROR(it, end) code_point = ((code_point << 18) & 0x1fffff) + ((utf8::internal::mask8(*it) << 12) & 0x3ffff); UTF8_CPP_INCREASE_AND_RETURN_ON_ERROR(it, end) code_point += (utf8::internal::mask8(*it) << 6) & 0xfff; UTF8_CPP_INCREASE_AND_RETURN_ON_ERROR(it, end) code_point += (*it) & 0x3f; return UTF8_OK; } #undef UTF8_CPP_INCREASE_AND_RETURN_ON_ERROR template <typename octet_iterator> utf_error validate_next(octet_iterator& it, octet_iterator end, uint32_t& code_point) { if (it == end) return NOT_ENOUGH_ROOM; // Save the original value of it so we can go back in case of failure // Of course, it does not make much sense with i.e. stream iterators octet_iterator original_it = it; uint32_t cp = 0; // Determine the sequence length based on the lead octet typedef typename std::iterator_traits<octet_iterator>::difference_type octet_difference_type; const octet_difference_type length = utf8::internal::sequence_length(it); // Get trail octets and calculate the code point utf_error err = UTF8_OK; switch (length) { case 0: return INVALID_LEAD; case 1: err = utf8::internal::get_sequence_1(it, end, cp); break; case 2: err = utf8::internal::get_sequence_2(it, end, cp); break; case 3: err = utf8::internal::get_sequence_3(it, end, cp); break; case 4: err = utf8::internal::get_sequence_4(it, end, cp); break; } if (err == UTF8_OK) { // Decoding succeeded. Now, security checks... if (utf8::internal::is_code_point_valid(cp)) { if (!utf8::internal::is_overlong_sequence(cp, length)){ // Passed! Return here. code_point = cp; ++it; return UTF8_OK; } else err = OVERLONG_SEQUENCE; } else err = INVALID_CODE_POINT; } // Failure branch - restore the original value of the iterator it = original_it; return err; } template <typename octet_iterator> inline utf_error validate_next(octet_iterator& it, octet_iterator end) { uint32_t ignored; return utf8::internal::validate_next(it, end, ignored); } } // namespace internal /// The library API - functions intended to be called by the users // Byte order mark const uint8_t bom[] = {0xef, 0xbb, 0xbf}; template <typename octet_iterator> octet_iterator find_invalid(octet_iterator start, octet_iterator end) { octet_iterator result = start; while (result != end) { utf8::internal::utf_error err_code = utf8::internal::validate_next(result, end); if (err_code != internal::UTF8_OK) return result; } return result; } template <typename octet_iterator> inline bool is_valid(octet_iterator start, octet_iterator end) { return (utf8::find_invalid(start, end) == end); } template <typename octet_iterator> inline bool starts_with_bom (octet_iterator it, octet_iterator end) { return ( ((it != end) && (utf8::internal::mask8(*it++)) == bom[0]) && ((it != end) && (utf8::internal::mask8(*it++)) == bom[1]) && ((it != end) && (utf8::internal::mask8(*it)) == bom[2]) ); } } // namespace utf8 #endif // header guard ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/vendor/utfcpp/utf8/cpp11.h�����������������������������������������������������������0000664�0000000�0000000�00000006352�13554550454�0020132�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������// Copyright 2018 Nemanja Trifunovic /* Permission is hereby granted, free of charge, to any person or organization obtaining a copy of the software and accompanying documentation covered by this license (the "Software") to use, reproduce, display, distribute, execute, and transmit the Software, and to prepare derivative works of the Software, and to permit third-parties to whom the Software is furnished to do so, all subject to the following: The copyright notices in the Software and this entire statement, including the above license grant, this restriction and the following disclaimer, must be included in all copies of the Software, in whole or in part, and all derivative works of the Software, unless such copies or derivative works are solely in the form of machine-executable object code generated by a source language processor. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #ifndef UTF8_FOR_CPP_a184c22c_d012_11e8_a8d5_f2801f1b9fd1 #define UTF8_FOR_CPP_a184c22c_d012_11e8_a8d5_f2801f1b9fd1 #include "checked.h" #include <string> namespace utf8 { inline void append(char32_t cp, std::string& s) { append(uint32_t(cp), std::back_inserter(s)); } inline std::string utf16to8(const std::u16string& s) { std::string result; utf16to8(s.begin(), s.end(), std::back_inserter(result)); return result; } inline std::u16string utf8to16(const std::string& s) { std::u16string result; utf8to16(s.begin(), s.end(), std::back_inserter(result)); return result; } inline std::string utf32to8(const std::u32string& s) { std::string result; utf32to8(s.begin(), s.end(), std::back_inserter(result)); return result; } inline std::u32string utf8to32(const std::string& s) { std::u32string result; utf8to32(s.begin(), s.end(), std::back_inserter(result)); return result; } inline std::size_t find_invalid(const std::string& s) { std::string::const_iterator invalid = find_invalid(s.begin(), s.end()); return (invalid == s.end()) ? std::string::npos : (invalid - s.begin()); } inline bool is_valid(const std::string& s) { return is_valid(s.begin(), s.end()); } inline std::string replace_invalid(const std::string& s, char32_t replacement) { std::string result; replace_invalid(s.begin(), s.end(), std::back_inserter(result), replacement); return result; } inline std::string replace_invalid(const std::string& s) { std::string result; replace_invalid(s.begin(), s.end(), std::back_inserter(result)); return result; } inline bool starts_with_bom(const std::string& s) { return starts_with_bom(s.begin(), s.end()); } } // namespace utf8 #endif // header guard ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/vendor/utfcpp/utf8/unchecked.h�������������������������������������������������������0000664�0000000�0000000�00000025075�13554550454�0021142�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������// Copyright 2006 Nemanja Trifunovic /* Permission is hereby granted, free of charge, to any person or organization obtaining a copy of the software and accompanying documentation covered by this license (the "Software") to use, reproduce, display, distribute, execute, and transmit the Software, and to prepare derivative works of the Software, and to permit third-parties to whom the Software is furnished to do so, all subject to the following: The copyright notices in the Software and this entire statement, including the above license grant, this restriction and the following disclaimer, must be included in all copies of the Software, in whole or in part, and all derivative works of the Software, unless such copies or derivative works are solely in the form of machine-executable object code generated by a source language processor. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #ifndef UTF8_FOR_CPP_UNCHECKED_H_2675DCD0_9480_4c0c_B92A_CC14C027B731 #define UTF8_FOR_CPP_UNCHECKED_H_2675DCD0_9480_4c0c_B92A_CC14C027B731 #include "core.h" namespace utf8 { namespace unchecked { template <typename octet_iterator> octet_iterator append(uint32_t cp, octet_iterator result) { if (cp < 0x80) // one octet *(result++) = static_cast<uint8_t>(cp); else if (cp < 0x800) { // two octets *(result++) = static_cast<uint8_t>((cp >> 6) | 0xc0); *(result++) = static_cast<uint8_t>((cp & 0x3f) | 0x80); } else if (cp < 0x10000) { // three octets *(result++) = static_cast<uint8_t>((cp >> 12) | 0xe0); *(result++) = static_cast<uint8_t>(((cp >> 6) & 0x3f) | 0x80); *(result++) = static_cast<uint8_t>((cp & 0x3f) | 0x80); } else { // four octets *(result++) = static_cast<uint8_t>((cp >> 18) | 0xf0); *(result++) = static_cast<uint8_t>(((cp >> 12) & 0x3f)| 0x80); *(result++) = static_cast<uint8_t>(((cp >> 6) & 0x3f) | 0x80); *(result++) = static_cast<uint8_t>((cp & 0x3f) | 0x80); } return result; } template <typename octet_iterator, typename output_iterator> output_iterator replace_invalid(octet_iterator start, octet_iterator end, output_iterator out, uint32_t replacement) { while (start != end) { octet_iterator sequence_start = start; internal::utf_error err_code = utf8::internal::validate_next(start, end); switch (err_code) { case internal::UTF8_OK : for (octet_iterator it = sequence_start; it != start; ++it) *out++ = *it; break; case internal::NOT_ENOUGH_ROOM: out = utf8::unchecked::append (replacement, out); start = end; break; case internal::INVALID_LEAD: out = utf8::unchecked::append (replacement, out); ++start; break; case internal::INCOMPLETE_SEQUENCE: case internal::OVERLONG_SEQUENCE: case internal::INVALID_CODE_POINT: out = utf8::unchecked::append (replacement, out); ++start; // just one replacement mark for the sequence while (start != end && utf8::internal::is_trail(*start)) ++start; break; } } return out; } template <typename octet_iterator, typename output_iterator> inline output_iterator replace_invalid(octet_iterator start, octet_iterator end, output_iterator out) { static const uint32_t replacement_marker = utf8::internal::mask16(0xfffd); return utf8::unchecked::replace_invalid(start, end, out, replacement_marker); } template <typename octet_iterator> uint32_t next(octet_iterator& it) { uint32_t cp = utf8::internal::mask8(*it); typename std::iterator_traits<octet_iterator>::difference_type length = utf8::internal::sequence_length(it); switch (length) { case 1: break; case 2: it++; cp = ((cp << 6) & 0x7ff) + ((*it) & 0x3f); break; case 3: ++it; cp = ((cp << 12) & 0xffff) + ((utf8::internal::mask8(*it) << 6) & 0xfff); ++it; cp += (*it) & 0x3f; break; case 4: ++it; cp = ((cp << 18) & 0x1fffff) + ((utf8::internal::mask8(*it) << 12) & 0x3ffff); ++it; cp += (utf8::internal::mask8(*it) << 6) & 0xfff; ++it; cp += (*it) & 0x3f; break; } ++it; return cp; } template <typename octet_iterator> uint32_t peek_next(octet_iterator it) { return utf8::unchecked::next(it); } template <typename octet_iterator> uint32_t prior(octet_iterator& it) { while (utf8::internal::is_trail(*(--it))) ; octet_iterator temp = it; return utf8::unchecked::next(temp); } template <typename octet_iterator, typename distance_type> void advance (octet_iterator& it, distance_type n) { const distance_type zero(0); if (n < zero) { // backward for (distance_type i = n; i < zero; ++i) utf8::unchecked::prior(it); } else { // forward for (distance_type i = zero; i < n; ++i) utf8::unchecked::next(it); } } template <typename octet_iterator> typename std::iterator_traits<octet_iterator>::difference_type distance (octet_iterator first, octet_iterator last) { typename std::iterator_traits<octet_iterator>::difference_type dist; for (dist = 0; first < last; ++dist) utf8::unchecked::next(first); return dist; } template <typename u16bit_iterator, typename octet_iterator> octet_iterator utf16to8 (u16bit_iterator start, u16bit_iterator end, octet_iterator result) { while (start != end) { uint32_t cp = utf8::internal::mask16(*start++); // Take care of surrogate pairs first if (utf8::internal::is_lead_surrogate(cp)) { uint32_t trail_surrogate = utf8::internal::mask16(*start++); cp = (cp << 10) + trail_surrogate + internal::SURROGATE_OFFSET; } result = utf8::unchecked::append(cp, result); } return result; } template <typename u16bit_iterator, typename octet_iterator> u16bit_iterator utf8to16 (octet_iterator start, octet_iterator end, u16bit_iterator result) { while (start < end) { uint32_t cp = utf8::unchecked::next(start); if (cp > 0xffff) { //make a surrogate pair *result++ = static_cast<uint16_t>((cp >> 10) + internal::LEAD_OFFSET); *result++ = static_cast<uint16_t>((cp & 0x3ff) + internal::TRAIL_SURROGATE_MIN); } else *result++ = static_cast<uint16_t>(cp); } return result; } template <typename octet_iterator, typename u32bit_iterator> octet_iterator utf32to8 (u32bit_iterator start, u32bit_iterator end, octet_iterator result) { while (start != end) result = utf8::unchecked::append(*(start++), result); return result; } template <typename octet_iterator, typename u32bit_iterator> u32bit_iterator utf8to32 (octet_iterator start, octet_iterator end, u32bit_iterator result) { while (start < end) (*result++) = utf8::unchecked::next(start); return result; } // The iterator class template <typename octet_iterator> class iterator : public std::iterator <std::bidirectional_iterator_tag, uint32_t> { octet_iterator it; public: iterator () {} explicit iterator (const octet_iterator& octet_it): it(octet_it) {} // the default "big three" are OK octet_iterator base () const { return it; } uint32_t operator * () const { octet_iterator temp = it; return utf8::unchecked::next(temp); } bool operator == (const iterator& rhs) const { return (it == rhs.it); } bool operator != (const iterator& rhs) const { return !(operator == (rhs)); } iterator& operator ++ () { ::std::advance(it, utf8::internal::sequence_length(it)); return *this; } iterator operator ++ (int) { iterator temp = *this; ::std::advance(it, utf8::internal::sequence_length(it)); return temp; } iterator& operator -- () { utf8::unchecked::prior(it); return *this; } iterator operator -- (int) { iterator temp = *this; utf8::unchecked::prior(it); return temp; } }; // class iterator } // namespace utf8::unchecked } // namespace utf8 #endif // header guard �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/win/���������������������������������������������������������������������������������0000775�0000000�0000000�00000000000�13554550454�0014140�5����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/win/.gitignore�����������������������������������������������������������������������0000664�0000000�0000000�00000000027�13554550454�0016127�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������config.h inspircd.rc ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/win/CMakeLists.txt�������������������������������������������������������������������0000664�0000000�0000000�00000012215�13554550454�0016701�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������cmake_minimum_required(VERSION 2.8) project(InspIRCd CXX) set(CONFIG_DIR "conf" CACHE PATH "Configuration file path") set(MODULE_DIR "modules" CACHE PATH "Module path") set(DATA_DIR "data" CACHE PATH "Data path") set(LOG_DIR "logs" CACHE PATH "Log file path") set(EXTRA_INCLUDES "" CACHE PATH "Extra include paths") set(EXTRA_LIBS "" CACHE PATH "Extra library paths") set(INSPIRCD_BASE "${CMAKE_CURRENT_SOURCE_DIR}/../") # Build with multiple processes set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /MP") # Use our own NSIS template set(CMAKE_MODULE_PATH "${INSPIRCD_BASE}/win") # Grab version info from version.sh file(STRINGS "${INSPIRCD_BASE}/src/version.sh" VERSIONSH) string(REGEX REPLACE ".*InspIRCd-([0-9]*).*" "\\1" VERSION_MAJOR "${VERSIONSH}") string(REGEX REPLACE ".*InspIRCd-[0-9]*\\.([0-9]*).*" "\\1" VERSION_MINOR "${VERSIONSH}") string(REGEX REPLACE ".*InspIRCd-[0-9]*\\.[0-9]*\\.([0-9]*).*" "\\1" VERSION_PATCH "${VERSIONSH}") string(REGEX REPLACE ".*InspIRCd-([^\"]+).*" "\\1" VERSION_FULL "${VERSIONSH}") if(MSVC) # Without /SAFESEH:NO old libraries compiled with VS 2010 or older won't link correctly to VS2012 (eg, extra module libs) set(CMAKE_EXE_LINKER_FLAGS_DEBUG "${CMAKE_EXE_LINKER_FLAGS_DEBUG} /SAFESEH:NO") set(CMAKE_EXE_LINKER_FLAGS_MINSIZEREL "${CMAKE_EXE_LINKER_FLAGS_MINSIZEREL} /SAFESEH:NO") set(CMAKE_EXE_LINKER_FLAGS_RELEASE "${CMAKE_EXE_LINKER_FLAGS_RELEASE} /SAFESEH:NO") set(CMAKE_EXE_LINKER_FLAGS_RELWITHDEBINFO "${CMAKE_EXE_LINKER_FLAGS_RELWITHDEBINFO} /SAFESEH:NO") set(CMAKE_SHARED_LINKER_FLAGS_DEBUG "${CMAKE_SHARED_LINKER_FLAGS_DEBUG} /SAFESEH:NO") set(CMAKE_SHARED_LINKER_FLAGS_MINSIZEREL "${CMAKE_SHARED_LINKER_FLAGS_MINSIZEREL} /SAFESEH:NO") set(CMAKE_SHARED_LINKER_FLAGS_RELEASE "${CMAKE_SHARED_LINKER_FLAGS_RELEASE} /SAFESEH:NO") set(CMAKE_SHARED_LINKER_FLAGS_RELWITHDEBINFO "${CMAKE_SHARED_LINKER_FLAGS_RELWITHDEBINFO} /SAFESEH:NO") set(CMAKE_MODULE_LINKER_FLAGS_DEBUG "${CMAKE_MODULE_LINKER_FLAGS_DEBUG} /SAFESEH:NO") set(CMAKE_MODULE_LINKER_FLAGS_MINSIZEREL "${CMAKE_MODULE_LINKER_FLAGS_MINSIZEREL} /SAFESEH:NO") set(CMAKE_MODULE_LINKER_FLAGS_RELEASE "${CMAKE_MODULE_LINKER_FLAGS_RELEASE} /SAFESEH:NO") set(CMAKE_MODULE_LINKER_FLAGS_RELWITHDEBINFO "${CMAKE_MODULE_LINKER_FLAGS_RELWITHDEBINFO} /SAFESEH:NO") endif(MSVC) file(GLOB INSPIRCD_SOURCES RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} "${INSPIRCD_BASE}/win/inspircd_win32wrapper.cpp" "${INSPIRCD_BASE}/win/win32service.cpp" "${INSPIRCD_BASE}/src/*.cpp" "${INSPIRCD_BASE}/src/socketengines/socketengine_select.cpp" "${INSPIRCD_BASE}/src/threadengines/threadengine_win32.cpp") list(SORT INSPIRCD_SOURCES) include_directories("${INSPIRCD_BASE}/win" "${INSPIRCD_BASE}/include") include_directories(${EXTRA_INCLUDES}) link_directories(${EXTRA_LIBS}) if(MSVC) add_library(win32_memory STATIC "${INSPIRCD_BASE}/win/inspircd_memory_functions.cpp") endif(MSVC) configure_file("${INSPIRCD_BASE}/win/inspircd.rc.cmake" "${INSPIRCD_BASE}/win/inspircd.rc") configure_file("${INSPIRCD_BASE}/make/template/config.h" "${INSPIRCD_BASE}/include/config.h") add_executable(inspircd ${INSPIRCD_SOURCES} "${INSPIRCD_BASE}/win/inspircd.rc") target_link_libraries(inspircd win32_memory) set_target_properties(inspircd PROPERTIES ENABLE_EXPORTS ON) install(TARGETS inspircd DESTINATION .) add_subdirectory(modules) # Package any DLLs in win/ file(GLOB EXTRA_DLLS RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} "${INSPIRCD_BASE}/win/*.dll") install(FILES ${EXTRA_DLLS} DESTINATION .) # Install example configs file(GLOB_RECURSE EXAMPLE_CONFIGS RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} "${INSPIRCD_BASE}/docs/conf/*.example") install(FILES ${EXAMPLE_CONFIGS} DESTINATION conf) # Install nationalchars files file(GLOB_RECURSE EXAMPLE_LOCALES RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} "${INSPIRCD_BASE}/locales/*") install(FILES ${EXAMPLE_LOCALES} DESTINATION locales) # Create an empty data and logs directory and install them file(MAKE_DIRECTORY ${DATA_DIR}) install(DIRECTORY ${DATA_DIR} DESTINATION .) file(MAKE_DIRECTORY ${LOG_DIR}) install(DIRECTORY ${LOG_DIR} 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") set(CPACK_PACKAGE_VENDOR "InspIRCd Development Team") set(CPACK_PACKAGE_VERSION_MAJOR ${VERSION_MAJOR}) set(CPACK_PACKAGE_VERSION_MINOR ${VERSION_MINOR}) set(CPACK_PACKAGE_VERSION_PATCH ${VERSION_PATCH}) set(CPACK_PACKAGE_FILE_NAME "InspIRCd-${VERSION_MAJOR}.${VERSION_MINOR}.${VERSION_PATCH}") set(CPACK_RESOURCE_FILE_LICENSE "${CMAKE_CURRENT_SOURCE_DIR}/../docs/LICENSE.txt") set(CPACK_GENERATOR "NSIS") set(CPACK_PACKAGE_INSTALL_DIRECTORY "InspIRCd") # NSIS has a bug with full nix paths, so this must contain at least one backslash set(CPACK_PACKAGE_ICON "${INSPIRCD_BASE}/win\\\\inspircd.ico") set(CPACK_NSIS_MUI_ICON "${INSPIRCD_BASE}/win\\\\inspircd.ico") set(CPACK_NSIS_MUI_UNIICON "${INSPIRCD_BASE}/win\\\\inspircd.ico") set(CPACK_NSIS_INSTALLED_ICON_NAME "inspircd.exe") set(CPACK_NSIS_URL_INFO_ABOUT "https://www.inspircd.org") set(CPACK_NSIS_COMPRESSOR "/SOLID zlib") include(CPack) endif(EXISTS "${CMAKE_ROOT}/Modules/CPack.cmake") �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/win/NSIS.template.in�����������������������������������������������������������������0000664�0000000�0000000�00000071717�13554550454�0017073�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������; CPack install script designed for a nmake build ;-------------------------------- ; You must define these values !define VERSION "@CPACK_PACKAGE_VERSION@" !define PATCH "@CPACK_PACKAGE_VERSION_PATCH@" !define INST_DIR "@CPACK_TEMPORARY_DIRECTORY@" ;-------------------------------- ;Variables Var MUI_TEMP Var STARTMENU_FOLDER Var SV_ALLUSERS Var START_MENU Var DO_NOT_ADD_TO_PATH Var ADD_TO_PATH_ALL_USERS Var ADD_TO_PATH_CURRENT_USER Var INSTALL_DESKTOP Var IS_DEFAULT_INSTALLDIR ;-------------------------------- ;Include Modern UI !include "MUI.nsh" ;Default installation folder InstallDir "@CPACK_NSIS_INSTALL_ROOT@\@CPACK_PACKAGE_INSTALL_DIRECTORY@" ;-------------------------------- ;General ;Name and file Name "@CPACK_NSIS_PACKAGE_NAME@" OutFile "@CPACK_TOPLEVEL_DIRECTORY@/@CPACK_OUTPUT_FILE_NAME@" ;Set compression SetCompressor @CPACK_NSIS_COMPRESSOR@ @CPACK_NSIS_DEFINES@ !include Sections.nsh ;--- Component support macros: --- ; The code for the add/remove functionality is from: ; https://nsis.sourceforge.io/Add/Remove_Functionality ; It has been modified slightly and extended to provide ; inter-component dependencies. Var AR_SecFlags Var AR_RegFlags @CPACK_NSIS_SECTION_SELECTED_VARS@ ; Loads the "selected" flag for the section named SecName into the ; variable VarName. !macro LoadSectionSelectedIntoVar SecName VarName SectionGetFlags ${${SecName}} $${VarName} IntOp $${VarName} $${VarName} & ${SF_SELECTED} ;Turn off all other bits !macroend ; Loads the value of a variable... can we get around this? !macro LoadVar VarName IntOp $R0 0 + $${VarName} !macroend ; Sets the value of a variable !macro StoreVar VarName IntValue IntOp $${VarName} 0 + ${IntValue} !macroend !macro InitSection SecName ; This macro reads component installed flag from the registry and ;changes checked state of the section on the components page. ;Input: section index constant name specified in Section command. ClearErrors ;Reading component status from registry ReadRegDWORD $AR_RegFlags HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\@CPACK_PACKAGE_INSTALL_REGISTRY_KEY@\Components\${SecName}" "Installed" IfErrors "default_${SecName}" ;Status will stay default if registry value not found ;(component was never installed) IntOp $AR_RegFlags $AR_RegFlags & ${SF_SELECTED} ;Turn off all other bits SectionGetFlags ${${SecName}} $AR_SecFlags ;Reading default section flags IntOp $AR_SecFlags $AR_SecFlags & 0xFFFE ;Turn lowest (enabled) bit off IntOp $AR_SecFlags $AR_RegFlags | $AR_SecFlags ;Change lowest bit ; Note whether this component was installed before !insertmacro StoreVar ${SecName}_was_installed $AR_RegFlags IntOp $R0 $AR_RegFlags & $AR_RegFlags ;Writing modified flags SectionSetFlags ${${SecName}} $AR_SecFlags "default_${SecName}:" !insertmacro LoadSectionSelectedIntoVar ${SecName} ${SecName}_selected !macroend !macro FinishSection SecName ; This macro reads section flag set by user and removes the section ;if it is not selected. ;Then it writes component installed flag to registry ;Input: section index constant name specified in Section command. SectionGetFlags ${${SecName}} $AR_SecFlags ;Reading section flags ;Checking lowest bit: IntOp $AR_SecFlags $AR_SecFlags & ${SF_SELECTED} IntCmp $AR_SecFlags 1 "leave_${SecName}" ;Section is not selected: ;Calling Section uninstall macro and writing zero installed flag !insertmacro "Remove_${${SecName}}" WriteRegDWORD HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\@CPACK_PACKAGE_INSTALL_REGISTRY_KEY@\Components\${SecName}" \ "Installed" 0 Goto "exit_${SecName}" "leave_${SecName}:" ;Section is selected: WriteRegDWORD HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\@CPACK_PACKAGE_INSTALL_REGISTRY_KEY@\Components\${SecName}" \ "Installed" 1 "exit_${SecName}:" !macroend !macro RemoveSection SecName ; This macro is used to call section's Remove_... macro ;from the uninstaller. ;Input: section index constant name specified in Section command. !insertmacro "Remove_${${SecName}}" !macroend ; Determine whether the selection of SecName changed !macro MaybeSelectionChanged SecName !insertmacro LoadVar ${SecName}_selected SectionGetFlags ${${SecName}} $R1 IntOp $R1 $R1 & ${SF_SELECTED} ;Turn off all other bits ; See if the status has changed: IntCmp $R0 $R1 "${SecName}_unchanged" !insertmacro LoadSectionSelectedIntoVar ${SecName} ${SecName}_selected IntCmp $R1 ${SF_SELECTED} "${SecName}_was_selected" !insertmacro "Deselect_required_by_${SecName}" goto "${SecName}_unchanged" "${SecName}_was_selected:" !insertmacro "Select_${SecName}_depends" "${SecName}_unchanged:" !macroend ;--- End of Add/Remove macros --- ;-------------------------------- ;Interface Settings !define MUI_HEADERIMAGE !define MUI_ABORTWARNING ;-------------------------------- ; path functions !verbose 3 !include "WinMessages.NSH" !verbose 4 ;---------------------------------------- ; based upon a script of "Written by KiCHiK 2003-01-18 05:57:02" ;---------------------------------------- !verbose 3 !include "WinMessages.NSH" !verbose 4 ;==================================================== ; get_NT_environment ; Returns: the selected environment ; Output : head of the stack ;==================================================== !macro select_NT_profile UN Function ${UN}select_NT_profile StrCmp $ADD_TO_PATH_ALL_USERS "1" 0 environment_single DetailPrint "Selected environment for all users" Push "all" Return environment_single: DetailPrint "Selected environment for current user only." Push "current" Return FunctionEnd !macroend !insertmacro select_NT_profile "" !insertmacro select_NT_profile "un." ;---------------------------------------------------- !define NT_current_env 'HKCU "Environment"' !define NT_all_env 'HKLM "SYSTEM\CurrentControlSet\Control\Session Manager\Environment"' !ifndef WriteEnvStr_RegKey !ifdef ALL_USERS !define WriteEnvStr_RegKey \ 'HKLM "SYSTEM\CurrentControlSet\Control\Session Manager\Environment"' !else !define WriteEnvStr_RegKey 'HKCU "Environment"' !endif !endif ; AddToPath - Adds the given dir to the search path. ; Input - head of the stack ; Note - Win9x systems requires reboot Function AddToPath Exch $0 Push $1 Push $2 Push $3 # don't add if the path doesn't exist IfFileExists "$0\*.*" "" AddToPath_done ReadEnvStr $1 PATH ; if the path is too long for a NSIS variable NSIS will return a 0 ; length string. If we find that, then warn and skip any path ; modification as it will trash the existing path. StrLen $2 $1 IntCmp $2 0 CheckPathLength_ShowPathWarning CheckPathLength_Done CheckPathLength_Done CheckPathLength_ShowPathWarning: Messagebox MB_OK|MB_ICONEXCLAMATION "Warning! PATH too long installer unable to modify PATH!" Goto AddToPath_done CheckPathLength_Done: Push "$1;" Push "$0;" Call StrStr Pop $2 StrCmp $2 "" "" AddToPath_done Push "$1;" Push "$0\;" Call StrStr Pop $2 StrCmp $2 "" "" AddToPath_done GetFullPathName /SHORT $3 $0 Push "$1;" Push "$3;" Call StrStr Pop $2 StrCmp $2 "" "" AddToPath_done Push "$1;" Push "$3\;" Call StrStr Pop $2 StrCmp $2 "" "" AddToPath_done Call IsNT Pop $1 StrCmp $1 1 AddToPath_NT ; Not on NT StrCpy $1 $WINDIR 2 FileOpen $1 "$1\autoexec.bat" a FileSeek $1 -1 END FileReadByte $1 $2 IntCmp $2 26 0 +2 +2 # DOS EOF FileSeek $1 -1 END # write over EOF FileWrite $1 "$\r$\nSET PATH=%PATH%;$3$\r$\n" FileClose $1 SetRebootFlag true Goto AddToPath_done AddToPath_NT: StrCmp $ADD_TO_PATH_ALL_USERS "1" ReadAllKey ReadRegStr $1 ${NT_current_env} "PATH" Goto DoTrim ReadAllKey: ReadRegStr $1 ${NT_all_env} "PATH" DoTrim: StrCmp $1 "" AddToPath_NTdoIt Push $1 Call Trim Pop $1 StrCpy $0 "$1;$0" AddToPath_NTdoIt: StrCmp $ADD_TO_PATH_ALL_USERS "1" WriteAllKey WriteRegExpandStr ${NT_current_env} "PATH" $0 Goto DoSend WriteAllKey: WriteRegExpandStr ${NT_all_env} "PATH" $0 DoSend: SendMessage ${HWND_BROADCAST} ${WM_WININICHANGE} 0 "STR:Environment" /TIMEOUT=5000 AddToPath_done: Pop $3 Pop $2 Pop $1 Pop $0 FunctionEnd ; RemoveFromPath - Remove a given dir from the path ; Input: head of the stack Function un.RemoveFromPath Exch $0 Push $1 Push $2 Push $3 Push $4 Push $5 Push $6 IntFmt $6 "%c" 26 # DOS EOF Call un.IsNT Pop $1 StrCmp $1 1 unRemoveFromPath_NT ; Not on NT StrCpy $1 $WINDIR 2 FileOpen $1 "$1\autoexec.bat" r GetTempFileName $4 FileOpen $2 $4 w GetFullPathName /SHORT $0 $0 StrCpy $0 "SET PATH=%PATH%;$0" Goto unRemoveFromPath_dosLoop unRemoveFromPath_dosLoop: FileRead $1 $3 StrCpy $5 $3 1 -1 # read last char StrCmp $5 $6 0 +2 # if DOS EOF StrCpy $3 $3 -1 # remove DOS EOF so we can compare StrCmp $3 "$0$\r$\n" unRemoveFromPath_dosLoopRemoveLine StrCmp $3 "$0$\n" unRemoveFromPath_dosLoopRemoveLine StrCmp $3 "$0" unRemoveFromPath_dosLoopRemoveLine StrCmp $3 "" unRemoveFromPath_dosLoopEnd FileWrite $2 $3 Goto unRemoveFromPath_dosLoop unRemoveFromPath_dosLoopRemoveLine: SetRebootFlag true Goto unRemoveFromPath_dosLoop unRemoveFromPath_dosLoopEnd: FileClose $2 FileClose $1 StrCpy $1 $WINDIR 2 Delete "$1\autoexec.bat" CopyFiles /SILENT $4 "$1\autoexec.bat" Delete $4 Goto unRemoveFromPath_done unRemoveFromPath_NT: StrCmp $ADD_TO_PATH_ALL_USERS "1" unReadAllKey ReadRegStr $1 ${NT_current_env} "PATH" Goto unDoTrim unReadAllKey: ReadRegStr $1 ${NT_all_env} "PATH" unDoTrim: StrCpy $5 $1 1 -1 # copy last char StrCmp $5 ";" +2 # if last char != ; StrCpy $1 "$1;" # append ; Push $1 Push "$0;" Call un.StrStr ; Find `$0;` in $1 Pop $2 ; pos of our dir StrCmp $2 "" unRemoveFromPath_done ; else, it is in path # $0 - path to add # $1 - path var StrLen $3 "$0;" StrLen $4 $2 StrCpy $5 $1 -$4 # $5 is now the part before the path to remove StrCpy $6 $2 "" $3 # $6 is now the part after the path to remove StrCpy $3 $5$6 StrCpy $5 $3 1 -1 # copy last char StrCmp $5 ";" 0 +2 # if last char == ; StrCpy $3 $3 -1 # remove last char StrCmp $ADD_TO_PATH_ALL_USERS "1" unWriteAllKey WriteRegExpandStr ${NT_current_env} "PATH" $3 Goto unDoSend unWriteAllKey: WriteRegExpandStr ${NT_all_env} "PATH" $3 unDoSend: SendMessage ${HWND_BROADCAST} ${WM_WININICHANGE} 0 "STR:Environment" /TIMEOUT=5000 unRemoveFromPath_done: Pop $6 Pop $5 Pop $4 Pop $3 Pop $2 Pop $1 Pop $0 FunctionEnd ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; Uninstall sutff ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ########################################### # Utility Functions # ########################################### ;==================================================== ; IsNT - Returns 1 if the current system is NT, 0 ; otherwise. ; Output: head of the stack ;==================================================== ; IsNT ; no input ; output, top of the stack = 1 if NT or 0 if not ; ; Usage: ; Call IsNT ; Pop $R0 ; ($R0 at this point is 1 or 0) !macro IsNT un Function ${un}IsNT Push $0 ReadRegStr $0 HKLM "SOFTWARE\Microsoft\Windows NT\CurrentVersion" CurrentVersion StrCmp $0 "" 0 IsNT_yes ; we are not NT. Pop $0 Push 0 Return IsNT_yes: ; NT!!! Pop $0 Push 1 FunctionEnd !macroend !insertmacro IsNT "" !insertmacro IsNT "un." ; StrStr ; input, top of stack = string to search for ; top of stack-1 = string to search in ; output, top of stack (replaces with the portion of the string remaining) ; modifies no other variables. ; ; Usage: ; Push "this is a long ass string" ; Push "ass" ; Call StrStr ; Pop $R0 ; ($R0 at this point is "ass string") !macro StrStr un Function ${un}StrStr Exch $R1 ; st=haystack,old$R1, $R1=needle Exch ; st=old$R1,haystack Exch $R2 ; st=old$R1,old$R2, $R2=haystack Push $R3 Push $R4 Push $R5 StrLen $R3 $R1 StrCpy $R4 0 ; $R1=needle ; $R2=haystack ; $R3=len(needle) ; $R4=cnt ; $R5=tmp loop: StrCpy $R5 $R2 $R3 $R4 StrCmp $R5 $R1 done StrCmp $R5 "" done IntOp $R4 $R4 + 1 Goto loop done: StrCpy $R1 $R2 "" $R4 Pop $R5 Pop $R4 Pop $R3 Pop $R2 Exch $R1 FunctionEnd !macroend !insertmacro StrStr "" !insertmacro StrStr "un." Function Trim ; Added by Pelaca Exch $R1 Push $R2 Loop: StrCpy $R2 "$R1" 1 -1 StrCmp "$R2" " " RTrim StrCmp "$R2" "$\n" RTrim StrCmp "$R2" "$\r" RTrim StrCmp "$R2" ";" RTrim GoTo Done RTrim: StrCpy $R1 "$R1" -1 Goto Loop Done: Pop $R2 Exch $R1 FunctionEnd Function ConditionalAddToRegisty Pop $0 Pop $1 StrCmp "$0" "" ConditionalAddToRegisty_EmptyString WriteRegStr SHCTX "Software\Microsoft\Windows\CurrentVersion\Uninstall\@CPACK_PACKAGE_INSTALL_REGISTRY_KEY@" \ "$1" "$0" ;MessageBox MB_OK "Set Registry: '$1' to '$0'" DetailPrint "Set install registry entry: '$1' to '$0'" ConditionalAddToRegisty_EmptyString: FunctionEnd ;-------------------------------- !ifdef CPACK_USES_DOWNLOAD Function DownloadFile IfFileExists $INSTDIR\* +2 CreateDirectory $INSTDIR Pop $0 ; Skip if already downloaded IfFileExists $INSTDIR\$0 0 +2 Return StrCpy $1 "@CPACK_DOWNLOAD_SITE@" try_again: NSISdl::download "$1/$0" "$INSTDIR\$0" Pop $1 StrCmp $1 "success" success StrCmp $1 "Cancelled" cancel MessageBox MB_OK "Download failed: $1" cancel: Return success: FunctionEnd !endif ;-------------------------------- ; Installation types @CPACK_NSIS_INSTALLATION_TYPES@ ;-------------------------------- ; Component sections @CPACK_NSIS_COMPONENT_SECTIONS@ ;-------------------------------- ; Define some macro setting for the gui @CPACK_NSIS_INSTALLER_MUI_ICON_CODE@ @CPACK_NSIS_INSTALLER_ICON_CODE@ @CPACK_NSIS_INSTALLER_MUI_COMPONENTS_DESC@ @CPACK_NSIS_INSTALLER_MUI_FINISHPAGE_RUN_CODE@ ;-------------------------------- ;Pages !insertmacro MUI_PAGE_WELCOME !insertmacro MUI_PAGE_LICENSE "@CPACK_RESOURCE_FILE_LICENSE@" Page custom InstallOptionsPage !insertmacro MUI_PAGE_DIRECTORY ;Start Menu Folder Page Configuration !define MUI_STARTMENUPAGE_REGISTRY_ROOT "SHCTX" !define MUI_STARTMENUPAGE_REGISTRY_KEY "Software\@CPACK_PACKAGE_VENDOR@\@CPACK_PACKAGE_INSTALL_REGISTRY_KEY@" !define MUI_STARTMENUPAGE_REGISTRY_VALUENAME "Start Menu Folder" !insertmacro MUI_PAGE_STARTMENU Application $STARTMENU_FOLDER @CPACK_NSIS_PAGE_COMPONENTS@ !insertmacro MUI_PAGE_INSTFILES !insertmacro MUI_PAGE_FINISH !insertmacro MUI_UNPAGE_CONFIRM !insertmacro MUI_UNPAGE_INSTFILES ;-------------------------------- ;Languages !insertmacro MUI_LANGUAGE "English" ;first language is the default language !insertmacro MUI_LANGUAGE "Albanian" !insertmacro MUI_LANGUAGE "Arabic" !insertmacro MUI_LANGUAGE "Basque" !insertmacro MUI_LANGUAGE "Belarusian" !insertmacro MUI_LANGUAGE "Bosnian" !insertmacro MUI_LANGUAGE "Breton" !insertmacro MUI_LANGUAGE "Bulgarian" !insertmacro MUI_LANGUAGE "Croatian" !insertmacro MUI_LANGUAGE "Czech" !insertmacro MUI_LANGUAGE "Danish" !insertmacro MUI_LANGUAGE "Dutch" !insertmacro MUI_LANGUAGE "Estonian" !insertmacro MUI_LANGUAGE "Farsi" !insertmacro MUI_LANGUAGE "Finnish" !insertmacro MUI_LANGUAGE "French" !insertmacro MUI_LANGUAGE "German" !insertmacro MUI_LANGUAGE "Greek" !insertmacro MUI_LANGUAGE "Hebrew" !insertmacro MUI_LANGUAGE "Hungarian" !insertmacro MUI_LANGUAGE "Icelandic" !insertmacro MUI_LANGUAGE "Indonesian" !insertmacro MUI_LANGUAGE "Irish" !insertmacro MUI_LANGUAGE "Italian" !insertmacro MUI_LANGUAGE "Japanese" !insertmacro MUI_LANGUAGE "Korean" !insertmacro MUI_LANGUAGE "Kurdish" !insertmacro MUI_LANGUAGE "Latvian" !insertmacro MUI_LANGUAGE "Lithuanian" !insertmacro MUI_LANGUAGE "Luxembourgish" !insertmacro MUI_LANGUAGE "Macedonian" !insertmacro MUI_LANGUAGE "Malay" !insertmacro MUI_LANGUAGE "Mongolian" !insertmacro MUI_LANGUAGE "Norwegian" !insertmacro MUI_LANGUAGE "Polish" !insertmacro MUI_LANGUAGE "Portuguese" !insertmacro MUI_LANGUAGE "PortugueseBR" !insertmacro MUI_LANGUAGE "Romanian" !insertmacro MUI_LANGUAGE "Russian" !insertmacro MUI_LANGUAGE "Serbian" !insertmacro MUI_LANGUAGE "SerbianLatin" !insertmacro MUI_LANGUAGE "SimpChinese" !insertmacro MUI_LANGUAGE "Slovak" !insertmacro MUI_LANGUAGE "Slovenian" !insertmacro MUI_LANGUAGE "Spanish" !insertmacro MUI_LANGUAGE "Swedish" !insertmacro MUI_LANGUAGE "Thai" !insertmacro MUI_LANGUAGE "TradChinese" !insertmacro MUI_LANGUAGE "Turkish" !insertmacro MUI_LANGUAGE "Ukrainian" !insertmacro MUI_LANGUAGE "Welsh" ;-------------------------------- ;Reserve Files ;These files should be inserted before other files in the data block ;Keep these lines before any File command ;Only for solid compression (by default, solid compression is enabled for BZIP2 and LZMA) ReserveFile "NSIS.InstallOptions.ini" !insertmacro MUI_RESERVEFILE_INSTALLOPTIONS ;-------------------------------- ;Installer Sections Section "-Core installation" ;Use the entire tree produced by the INSTALL target. Keep the ;list of directories here in sync with the RMDir commands below. SetOutPath "$INSTDIR" @CPACK_NSIS_EXTRA_PREINSTALL_COMMANDS@ @CPACK_NSIS_FULL_INSTALL@ ;Store installation folder WriteRegStr SHCTX "Software\@CPACK_PACKAGE_VENDOR@\@CPACK_PACKAGE_INSTALL_REGISTRY_KEY@" "" $INSTDIR ;Create uninstaller WriteUninstaller "$INSTDIR\Uninstall.exe" Push "DisplayName" Push "@CPACK_NSIS_DISPLAY_NAME@" Call ConditionalAddToRegisty Push "DisplayVersion" Push "@CPACK_PACKAGE_VERSION@" Call ConditionalAddToRegisty Push "Publisher" Push "@CPACK_PACKAGE_VENDOR@" Call ConditionalAddToRegisty Push "UninstallString" Push "$INSTDIR\Uninstall.exe" Call ConditionalAddToRegisty Push "NoRepair" Push "1" Call ConditionalAddToRegisty !ifdef CPACK_NSIS_ADD_REMOVE ;Create add/remove functionality Push "ModifyPath" Push "$INSTDIR\AddRemove.exe" Call ConditionalAddToRegisty !else Push "NoModify" Push "1" Call ConditionalAddToRegisty !endif ; Optional registration Push "DisplayIcon" Push "$INSTDIR\@CPACK_NSIS_INSTALLED_ICON_NAME@" Call ConditionalAddToRegisty Push "HelpLink" Push "@CPACK_NSIS_HELP_LINK@" Call ConditionalAddToRegisty Push "URLInfoAbout" Push "@CPACK_NSIS_URL_INFO_ABOUT@" Call ConditionalAddToRegisty Push "Contact" Push "@CPACK_NSIS_CONTACT@" Call ConditionalAddToRegisty !insertmacro MUI_INSTALLOPTIONS_READ $INSTALL_DESKTOP "NSIS.InstallOptions.ini" "Field 5" "State" !insertmacro MUI_STARTMENU_WRITE_BEGIN Application ;Create shortcuts CreateDirectory "$SMPROGRAMS\$STARTMENU_FOLDER" @CPACK_NSIS_CREATE_ICONS@ @CPACK_NSIS_CREATE_ICONS_EXTRA@ CreateShortCut "$SMPROGRAMS\$STARTMENU_FOLDER\Uninstall.lnk" "$INSTDIR\Uninstall.exe" ;Read a value from an InstallOptions INI file !insertmacro MUI_INSTALLOPTIONS_READ $DO_NOT_ADD_TO_PATH "NSIS.InstallOptions.ini" "Field 2" "State" !insertmacro MUI_INSTALLOPTIONS_READ $ADD_TO_PATH_ALL_USERS "NSIS.InstallOptions.ini" "Field 3" "State" !insertmacro MUI_INSTALLOPTIONS_READ $ADD_TO_PATH_CURRENT_USER "NSIS.InstallOptions.ini" "Field 4" "State" ; Write special uninstall registry entries Push "StartMenu" Push "$STARTMENU_FOLDER" Call ConditionalAddToRegisty Push "DoNotAddToPath" Push "$DO_NOT_ADD_TO_PATH" Call ConditionalAddToRegisty Push "AddToPathAllUsers" Push "$ADD_TO_PATH_ALL_USERS" Call ConditionalAddToRegisty Push "AddToPathCurrentUser" Push "$ADD_TO_PATH_CURRENT_USER" Call ConditionalAddToRegisty Push "InstallToDesktop" Push "$INSTALL_DESKTOP" Call ConditionalAddToRegisty !insertmacro MUI_STARTMENU_WRITE_END detailPrint "Installing InspIRCd service..." nsExec::Exec /TIMEOUT=30000 '"$INSTDIR\inspircd.exe" --installservice' @CPACK_NSIS_EXTRA_INSTALL_COMMANDS@ SectionEnd Section "-Add to path" Push $INSTDIR\bin StrCmp "@CPACK_NSIS_MODIFY_PATH@" "ON" 0 doNotAddToPath StrCmp $DO_NOT_ADD_TO_PATH "1" doNotAddToPath 0 Call AddToPath doNotAddToPath: SectionEnd ;-------------------------------- ; Create custom pages Function InstallOptionsPage !insertmacro MUI_HEADER_TEXT "Install Options" "Choose options for installing @CPACK_NSIS_PACKAGE_NAME@" !insertmacro MUI_INSTALLOPTIONS_DISPLAY "NSIS.InstallOptions.ini" FunctionEnd ;-------------------------------- ; determine admin versus local install Function un.onInit ClearErrors UserInfo::GetName IfErrors noLM Pop $0 UserInfo::GetAccountType Pop $1 StrCmp $1 "Admin" 0 +3 SetShellVarContext all ;MessageBox MB_OK 'User "$0" is in the Admin group' Goto done StrCmp $1 "Power" 0 +3 SetShellVarContext all ;MessageBox MB_OK 'User "$0" is in the Power Users group' Goto done noLM: ;Get installation folder from registry if available done: FunctionEnd ;--- Add/Remove callback functions: --- !macro SectionList MacroName ;This macro used to perform operation on multiple sections. ;List all of your components in following manner here. @CPACK_NSIS_COMPONENT_SECTION_LIST@ !macroend Section -FinishComponents ;Removes unselected components and writes component status to registry !insertmacro SectionList "FinishSection" !ifdef CPACK_NSIS_ADD_REMOVE ; Get the name of the installer executable System::Call 'kernel32::GetModuleFileNameA(i 0, t .R0, i 1024) i r1' StrCpy $R3 $R0 ; Strip off the last 13 characters, to see if we have AddRemove.exe StrLen $R1 $R0 IntOp $R1 $R0 - 13 StrCpy $R2 $R0 13 $R1 StrCmp $R2 "AddRemove.exe" addremove_installed ; We're not running AddRemove.exe, so install it CopyFiles $R3 $INSTDIR\AddRemove.exe addremove_installed: !endif SectionEnd ;--- End of Add/Remove callback functions --- ;-------------------------------- ; Component dependencies Function .onSelChange !insertmacro SectionList MaybeSelectionChanged FunctionEnd ;-------------------------------- ;Uninstaller Section Section "Uninstall" DetailPrint "Uninstalling InspIRCd service..." nsExec::Exec /TIMEOUT=30000 '"$INSTDIR\inspircd.exe" --removeservice' ReadRegStr $START_MENU SHCTX \ "Software\Microsoft\Windows\CurrentVersion\Uninstall\@CPACK_PACKAGE_INSTALL_REGISTRY_KEY@" "StartMenu" ;MessageBox MB_OK "Start menu is in: $START_MENU" ReadRegStr $DO_NOT_ADD_TO_PATH SHCTX \ "Software\Microsoft\Windows\CurrentVersion\Uninstall\@CPACK_PACKAGE_INSTALL_REGISTRY_KEY@" "DoNotAddToPath" ReadRegStr $ADD_TO_PATH_ALL_USERS SHCTX \ "Software\Microsoft\Windows\CurrentVersion\Uninstall\@CPACK_PACKAGE_INSTALL_REGISTRY_KEY@" "AddToPathAllUsers" ReadRegStr $ADD_TO_PATH_CURRENT_USER SHCTX \ "Software\Microsoft\Windows\CurrentVersion\Uninstall\@CPACK_PACKAGE_INSTALL_REGISTRY_KEY@" "AddToPathCurrentUser" ;MessageBox MB_OK "Add to path: $DO_NOT_ADD_TO_PATH all users: $ADD_TO_PATH_ALL_USERS" ReadRegStr $INSTALL_DESKTOP SHCTX \ "Software\Microsoft\Windows\CurrentVersion\Uninstall\@CPACK_PACKAGE_INSTALL_REGISTRY_KEY@" "InstallToDesktop" ;MessageBox MB_OK "Install to desktop: $INSTALL_DESKTOP " @CPACK_NSIS_EXTRA_UNINSTALL_COMMANDS@ ;Remove files we installed. ;Keep the list of directories here in sync with the File commands above. @CPACK_NSIS_DELETE_FILES@ @CPACK_NSIS_DELETE_DIRECTORIES@ !ifdef CPACK_NSIS_ADD_REMOVE ;Remove the add/remove program Delete "$INSTDIR\AddRemove.exe" !endif ;Remove the uninstaller itself. Delete "$INSTDIR\Uninstall.exe" DeleteRegKey SHCTX "Software\Microsoft\Windows\CurrentVersion\Uninstall\@CPACK_PACKAGE_INSTALL_REGISTRY_KEY@" ;Remove the installation directory if it is empty. RMDir "$INSTDIR" ; Remove the registry entries. DeleteRegKey SHCTX "Software\@CPACK_PACKAGE_VENDOR@\@CPACK_PACKAGE_INSTALL_REGISTRY_KEY@" ; Removes all optional components !insertmacro SectionList "RemoveSection" !insertmacro MUI_STARTMENU_GETFOLDER Application $MUI_TEMP Delete "$SMPROGRAMS\$MUI_TEMP\Uninstall.lnk" @CPACK_NSIS_DELETE_ICONS@ @CPACK_NSIS_DELETE_ICONS_EXTRA@ ;Delete empty start menu parent diretories StrCpy $MUI_TEMP "$SMPROGRAMS\$MUI_TEMP" startMenuDeleteLoop: ClearErrors RMDir $MUI_TEMP GetFullPathName $MUI_TEMP "$MUI_TEMP\.." IfErrors startMenuDeleteLoopDone StrCmp "$MUI_TEMP" "$SMPROGRAMS" startMenuDeleteLoopDone startMenuDeleteLoop startMenuDeleteLoopDone: ; If the user changed the shortcut, then untinstall may not work. This should ; try to fix it. StrCpy $MUI_TEMP "$START_MENU" Delete "$SMPROGRAMS\$MUI_TEMP\Uninstall.lnk" @CPACK_NSIS_DELETE_ICONS_EXTRA@ ;Delete empty start menu parent diretories StrCpy $MUI_TEMP "$SMPROGRAMS\$MUI_TEMP" secondStartMenuDeleteLoop: ClearErrors RMDir $MUI_TEMP GetFullPathName $MUI_TEMP "$MUI_TEMP\.." IfErrors secondStartMenuDeleteLoopDone StrCmp "$MUI_TEMP" "$SMPROGRAMS" secondStartMenuDeleteLoopDone secondStartMenuDeleteLoop secondStartMenuDeleteLoopDone: DeleteRegKey /ifempty SHCTX "Software\@CPACK_PACKAGE_VENDOR@\@CPACK_PACKAGE_INSTALL_REGISTRY_KEY@" Push $INSTDIR\bin StrCmp $DO_NOT_ADD_TO_PATH_ "1" doNotRemoveFromPath 0 Call un.RemoveFromPath doNotRemoveFromPath: SectionEnd ;-------------------------------- ; determine admin versus local install ; Is install for "AllUsers" or "JustMe"? ; Default to "JustMe" - set to "AllUsers" if admin or on Win9x ; This function is used for the very first "custom page" of the installer. ; This custom page does not show up visibly, but it executes prior to the ; first visible page and sets up $INSTDIR properly... ; Choose different default installation folder based on SV_ALLUSERS... ; "Program Files" for AllUsers, "My Documents" for JustMe... Function .onInit StrCmp "@CPACK_NSIS_ENABLE_UNINSTALL_BEFORE_INSTALL@" "ON" 0 inst ReadRegStr $0 HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\@CPACK_PACKAGE_NAME@" "UninstallString" StrCmp $0 "" inst MessageBox MB_YESNOCANCEL|MB_ICONEXCLAMATION \ "@CPACK_NSIS_PACKAGE_NAME@ is already installed. $\n$\nDo you want to uninstall the old version before installing the new one?" \ IDYES uninst IDNO inst Abort ;Run the uninstaller uninst: ClearErrors ExecWait '$0 _?=$INSTDIR' ;Do not copy the uninstaller to a temp file IfErrors uninst_failed inst uninst_failed: MessageBox MB_OK|MB_ICONSTOP "Uninstall failed." Abort inst: ; Reads components status for registry !insertmacro SectionList "InitSection" ; check to see if /D has been used to change ; the install directory by comparing it to the ; install directory that is expected to be the ; default StrCpy $IS_DEFAULT_INSTALLDIR 0 StrCmp "$INSTDIR" "@CPACK_NSIS_INSTALL_ROOT@\@CPACK_PACKAGE_INSTALL_DIRECTORY@" 0 +2 StrCpy $IS_DEFAULT_INSTALLDIR 1 StrCpy $SV_ALLUSERS "JustMe" ; if default install dir then change the default ; if it is installed for JustMe StrCmp "$IS_DEFAULT_INSTALLDIR" "1" 0 +2 StrCpy $INSTDIR "$DOCUMENTS\@CPACK_PACKAGE_INSTALL_DIRECTORY@" ClearErrors UserInfo::GetName IfErrors noLM Pop $0 UserInfo::GetAccountType Pop $1 StrCmp $1 "Admin" 0 +4 SetShellVarContext all ;MessageBox MB_OK 'User "$0" is in the Admin group' StrCpy $SV_ALLUSERS "AllUsers" Goto done StrCmp $1 "Power" 0 +4 SetShellVarContext all ;MessageBox MB_OK 'User "$0" is in the Power Users group' StrCpy $SV_ALLUSERS "AllUsers" Goto done noLM: StrCpy $SV_ALLUSERS "AllUsers" ;Get installation folder from registry if available done: StrCmp $SV_ALLUSERS "AllUsers" 0 +3 StrCmp "$IS_DEFAULT_INSTALLDIR" "1" 0 +2 StrCpy $INSTDIR "@CPACK_NSIS_INSTALL_ROOT@\@CPACK_PACKAGE_INSTALL_DIRECTORY@" StrCmp "@CPACK_NSIS_MODIFY_PATH@" "ON" 0 noOptionsPage !insertmacro MUI_INSTALLOPTIONS_EXTRACT "NSIS.InstallOptions.ini" noOptionsPage: FunctionEnd �������������������������������������������������inspircd-3.4.0/win/README.txt�����������������������������������������������������������������������0000664�0000000�0000000�00000005434�13554550454�0015644�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������Building InspIRCd for Windows: Prerequisites: Visual Studio 2015 or newer (https://www.visualstudio.com) CMake 2.8 or newer (https://cmake.org) If building the installer, NSIS (https://nsis.sourceforge.io) Configuring: First copy any extra modules from extras (such as m_mysql) to the modules directory that you want to build. Run CMake to generate build files. This can be done using the CMake GUI by setting the source code path to "win", and the binary path to "win/build", followed by pressing "Configure". Modify any variables you need, such as install prefix, and then press "Generate". Alternatively CMake can be run from Command Prompt from the "win\build" directory, eg: c:\Users\Adam\Desktop\inspircd\win\build>cmake -G "Visual Studio 11" .. -- Check for working CXX compiler using: Visual Studio 11 -- Check for working CXX compiler using: Visual Studio 11 -- works -- Detecting CXX compiler ABI info -- Detecting CXX compiler ABI info - done -- Configuring done -- Generating done -- Build files have been written to: C:/Users/Adam/Desktop/inspircd/win/build This generates project files for Visual Studio 11 (2012). Available generators can be seen in cmake --help, such as Visual Studio 10 and NMake Makefiles. If some of the modules you are building require libraries that are not in the default system path (and thus not found by CMake), you can inform CMake about them by defining EXTRA_INCLUDES and EXTRA_LIBS when configuring, eg; cmake -DEXTRA_INCLUDES:STRING="C:\inspircd-includes" -DEXTRA_LIBS:STRING="C:\inspircd-libs" -G "Visual Studio 11" .. See the CMake GUI for a full list of variables that can be set. Additionally, place any DLL files required by any extra modules in to the win directory for the installer to pick up. Building: Open the InspIRCd Microsoft Visual Studio Solution file. If you are building a release, be sure to change the Solution Configuration to Release before starting the build. Start the build by right clicking the InspIRCd solution in the solution explorer and clicking "Build Solution" If you are building using NMake Makefiles, simply use "nmake". Installing: If you do not want to build the installer you can simply build the INSTALL target, which will probably install InspIRCd into C:\Program Files\InspIRCd. This may require administrative privileges by Visual Studio. If you are building using NMake Makefiles, simply use "nmake install". Building the installer: Locate the PACKAGE project on Visual Studio's Solution Explorer and build it. This will generate an InspIRCd-x.x.x.exe installer in the build directory which is ready to be distributed. If you are building using NMake Makefiles or do not want to build the installer in Visual Studio, simply use "cpack". ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/win/build/���������������������������������������������������������������������������0000775�0000000�0000000�00000000000�13554550454�0015237�5����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/win/build/.gitignore�����������������������������������������������������������������0000664�0000000�0000000�00000000003�13554550454�0017220�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������* �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/win/inspircd.ico���������������������������������������������������������������������0000664�0000000�0000000�00000052176�13554550454�0016462�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000��������������������������������������������������������������������������������������������������������������������������������������������������������������������������� ������(���������h��������h��&�� ������� �� ������v �� ���� ����00�����h��"��00������.)��00������7��(������ �������������������������������������������������������������������������xpxw������������������������������������������������������������������������(������ ���������@�����������������������������������pnn������fff�wvv������zzz���mmm�����omf���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������_I?��������������������������������������������������#��!"�� ���������� �����������������������������������������������������������������������������������������(������ ���������@���������������������������������������������������������������������_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?������_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?������_I?_I?_I?_I?_I?_I?_I?_I?omf_I?_I?_I?_I?_I?������_I?_I?_I?_I?_I?_I?_I?_I?ӳ_I?_I?_I?_I?������_I?_I?_I?_I?_I?_I?mmm_I?������_I?_I?_I?_I?_I?zzz������_I?_I?_I?_I?������_I?wvv������pnn𽽽fff������ۜ_I?_I?������_I?_I?_I?_I?_I?_I?_I?_I?������_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?������_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?������_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?�������������������������������������������������������������������������������������������������������������������(��� ���@��������������������������������������������������������������������������������xpwxxwwwwwwwx������������������������������������������������������������������������������������������������������������������������������������������������(��� ���@�������������������������������UUU�kkk���yvv�ccc��������OMM��������www���������eee�����������������___�������```������VVV�#$$�spp�333���YYY��NNN�OOO�hhh�����HHH�����][[����ttt�vuu���LLL�III�GGG���222�MMM������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������_I?��������������������������������������������������������������������������_`M��\ ]^��VWXYZ[��QRSB TU��MN!  OP��J ! KL��GH! I��2DE, !F��>3?@AB C��7 89 &:;4!<=��23+ 4- 56��1  "-+0��*+ ,-  ./0�� ! "#$%& &'()�� �� �� �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������(��� ���@��������� ���������������������������������������������������������������������������������������������������������������������_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?������_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?������_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?������_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?������_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?������_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?������_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?MMMՇ_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?������_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?222_I?_I?_I?_I?_I?_I?_I?_I?_I?������_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?vuuLLLIIIGGG_I?_I?_I?_I?_I?_I?������_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?][[ttt_I?_I?_I?_I?������_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?껻_I?_I?_I?������_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?HHH_I?������_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?hhh_I?������_I?_I?_I?_I?_I?_I?NNN_I?_I?OOO������_I?_I?_I?_I?_I?_I?#$$spp333YYY������_I?_I?_I?_I?```䳳VVV������_I?_I?_I?߮_I?������_I?_I?Ӯ____I?������_I?_I?Ǯ____I?_I?������_I?_I?Ӱ؍_I?_I?_I?_I?������_I?_I?酄eee_I?_I?_I?_I?_I?_I?������_I?_I?_I?www_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?������_I?_I?_I?_I?OMM_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?������_I?_I?_I?_I?_I?_I?UUUkkkyvvccc_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?������_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?������_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?������_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?������_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?������_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?������_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?�����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������(���0���`�����������������������������������������������������������������������������������������xxxwwxxxxwwwxwxwxwwwwwwwwxxww������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������(���0���`��������� ��������������������������������������ʦ�����������������������k�H�%������z��b��Js��2P����k�Hs�%W��U��I��=��1��%s��P����kk�HH�%%���������������s���P��DZ��k�sH�W%�U��I��=��1��%�s��P���Ԏ�k�H�%�����z��b��J�s�2�P����k�H�%���������s�s�P�P����k�H�%������z��b�s�J�P�2����k�Hs�%W��U��I��=��1�s�%�P�����kk�HH�%%�������������s���P����DZ��k�sH�W%�U��I��=��1��s%��P����Ԏ�k�H�%���ܒ��z��b��sJ��P2�����k�H�%���������ss��PP�����k�H�%�����z��b��Js��2P�����k�sH�W%�U��I��=��1��%s��P�����kk�HH�%%��������������s���P�����k�Hs�%W��U��I��=��1��s%��P����k�H�%����ܒ��z��b��sJ��P2����k�H�%����������ss��PP�����������zzz�nnn�_I?�VVV�JJJ�>>>�222�&&&��M������������������������������������������������������������%%%%%%%%%%%%%%%��%%%%%%%��%%%%%%%%%%���������������������� ������ ���� ���������������� �������� ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������(���0���`������������������������������������������������������������������������������������������������������������������������������������������������������������������������������_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?��_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?������_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?��_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?������_I?_I?_I?_I?_I?_I?�_I?�_I?�_I?��_I?_I?���_I?_I?�_I?�_I?_I?_I?�_I?_I?���_I?_I?_I?���_I?_I?_I?_I?_I?_I?_I?������_I?_I?_I?_I?_I?_I?�_I?�_I?�_I?_I?_I?�_I?�_I?_I?�_I?�_I?�_I?_I?_I?�_I?�_I?_I?_I?�_I?�_I?_I?�_I?_I?_I?_I?_I?_I?_I?������_I?_I?_I?_I?_I?_I?�*_I?�*_I?�*_I?�*_I?_I?_I?�*_I?_I?�*_I?�*_I?�*�*�*�*_I?_I?�*_I?_I?_I?_I?_I?�*_I?_I?�*_I?_I?_I?_I?_I?_I?_I?������_I?_I?_I?_I?_I?_I?%W_I?%W%W_I?_I?_I?%W%W_I?%W%W%W_I?_I?%W_I?%W_I?_I?_I?%W_I?%W_I?_I?_I?_I?_I?_I?%W%W%W_I?_I?_I?_I?_I?_I?_I?������_I?_I?_I?_I?_I?_I?%W_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?%W_I?%W_I?_I?_I?%W_I?%W_I?_I?_I?%W_I?_I?_I?_I?%W_I?_I?_I?_I?_I?_I?_I?������_I?_I?_I?_I?_I?_I?%W_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?%W_I?%W%W%W%W_I?_I?_I?%W%W%W_I?_I?_I?_I?_I?%W_I?_I?_I?_I?_I?_I?_I?������_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?������_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?nnnnnn_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?������_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?VVVΒVVV_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?������_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?nnn椠VVV_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?������_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?VVV椠VVV_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?������_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?VVVnnn򶶶zzznnnnnnVVV_I?_I?_I?_I?_I?_I?_I?_I?_I?������_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?VVVnnnΪnnn_I?_I?_I?_I?_I?_I?_I?������_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?nnn’VVV_I?_I?_I?_I?_I?������_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?涶nnn_I?_I?_I?_I?������_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?zzz_I?_I?_I?������_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?nnn_I?_I?������_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?VVV򤠠VVV_I?������_I?_I?_I?_I?_I?_I?_I?_I?_I?VVVnnn_I?_I?_I?_I?nnn_I?������_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?nnn憆VVV_I?_I?怀_I?������_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?VVV椠nnnnnn򆆆_I?������_I?_I?_I?_I?_I?_I?_I?VVVzzz怀_I?������_I?_I?_I?_I?_I?_I?nnn򪪪nnn_I?������_I?_I?_I?_I?_I?򪪪򤠠_I?_I?������_I?_I?_I?_I?򪪪VVV_I?_I?������_I?_I?_I?zzz򪪪nnn_I?_I?_I?������_I?_I?_I?򪪪ڪVVV_I?_I?_I?_I?������_I?_I?_I?򪪪ڶ_I?_I?_I?_I?_I?_I?������_I?_I?_I?򪪪ζzzzVVV_I?_I?_I?_I?_I?_I?_I?������_I?_I?_I?nnn椠VVVnnnnnnzzzzzzzzzzzznnnVVV_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?������_I?_I?_I?_I?zzz򪪪VVV_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?������_I?_I?_I?_I?_I?nnn椠VVV_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?������_I?_I?_I?_I?_I?_I?_I?nnnΒVVV_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?������_I?_I?_I?_I?_I?_I?_I?_I?_I?nnnzzz_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?������_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?������_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?������_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?������_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?������_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?������_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?������_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?������_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?������_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?������_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?_I?�����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/win/inspircd.rc.cmake����������������������������������������������������������������0000664�0000000�0000000�00000002065�13554550454�0017363�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������101 ICON "inspircd.ico" 1 VERSIONINFO FILEVERSION @VERSION_MAJOR@,@VERSION_MINOR@,@VERSION_PATCH@ PRODUCTVERSION @VERSION_MAJOR@,@VERSION_MINOR@,@VERSION_PATCH@ FILEFLAGSMASK 0x3fL #ifdef _DEBUG FILEFLAGS 0x1L #else FILEFLAGS 0x0L #endif FILEOS 0x40004L FILETYPE 0x1L FILESUBTYPE 0x0L BEGIN BLOCK "StringFileInfo" BEGIN BLOCK "040904b0" BEGIN VALUE "Comments", "InspIRCd @VERSION_MAJOR@.@VERSION_MINOR@ IRC Daemon" VALUE "CompanyName", "InspIRCd Development Team" VALUE "FileDescription", "InspIRCd" VALUE "FileVersion", "@FULL_VERSION@" VALUE "InternalName", "InspIRCd" VALUE "LegalCopyright", "Copyright (C) InspIRCd Development Team" VALUE "OriginalFilename", "inspircd.exe" VALUE "ProductName", "InspIRCd - Internet Relay Chat Daemon" VALUE "ProductVersion", "@FULL_VERSION@" END END BLOCK "VarFileInfo" BEGIN VALUE "Translation", 0x809, 1200 END END ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/win/inspircd_memory_functions.cpp����������������������������������������������������0000664�0000000�0000000�00000003701�13554550454�0022140�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * InspIRCd -- Internet Relay Chat Daemon * * Copyright (C) 2007 Dennis Friis <peavey@inspircd.org> * * This file is part of InspIRCd. InspIRCd is free software: you can * redistribute it and/or modify it under the terms of the GNU General Public * License as published by the Free Software Foundation, version 2. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <windows.h> #include <exception> #include <new> #include <new.h> /** On windows, all dll files and executables have their own private heap, * whereas on POSIX systems, shared objects loaded into an executable share * the executable's heap. This means that if we pass an arbitrary pointer to * a windows DLL which is not allocated in that dll, without some form of * marshalling, we get a page fault. To fix this, these overrided operators * new and delete use the windows HeapAlloc and HeapFree functions to claim * memory from the windows global heap. This makes windows 'act like' POSIX * when it comes to memory usage between dlls and exes. */ void * ::operator new(size_t iSize) { void* ptr = HeapAlloc(GetProcessHeap(), 0, iSize); /* This is the correct behaviour according to C++ standards for out of memory, * not returning null -- Brain */ if (!ptr) throw std::bad_alloc(); else return ptr; } void ::operator delete(void * ptr) { if (ptr) HeapFree(GetProcessHeap(), 0, ptr); } void * operator new[] (size_t iSize) { void* ptr = HeapAlloc(GetProcessHeap(), 0, iSize); if (!ptr) throw std::bad_alloc(); else return ptr; } void operator delete[] (void* ptr) { if (ptr) HeapFree(GetProcessHeap(), 0, ptr); } ���������������������������������������������������������������inspircd-3.4.0/win/inspircd_win32wrapper.cpp��������������������������������������������������������0000664�0000000�0000000�00000007112�13554550454�0021103�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * InspIRCd -- Internet Relay Chat Daemon * * Copyright (C) 2011 Adam <Adam@anope.org> * Copyright (C) 2007, 2009 Dennis Friis <peavey@inspircd.org> * Copyright (C) 2009 Daniel De Graaf <danieldg@inspircd.org> * Copyright (C) 2007-2009 Craig Edwards <craigedwards@brainbox.cc> * Copyright (C) 2008 John Brooks <john.brooks@dereferenced.net> * Copyright (C) 2007 Burlex <???@???> * Copyright (C) 2007 Robin Burchell <robin+git@viroteck.net> * * 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 "inspircd_win32wrapper.h" #include "inspircd.h" #include "configreader.h" #include <string> #include <errno.h> #include <assert.h> int optind = 1; char optarg[514]; int getopt_long(int ___argc, char *const *___argv, const char *__shortopts, const struct option *__longopts, int *__longind) { // burlex todo: handle the shortops, at the moment it only works with longopts. if (___argc == 1 || optind == ___argc) // No arguments (apart from filename) return -1; const char * opt = ___argv[optind]; optind++; // if we're not an option, return an error. if (strnicmp(opt, "--", 2) != 0) return 1; else opt += 2; // parse argument list int i = 0; for (; __longopts[i].name != 0; ++i) { if (!strnicmp(__longopts[i].name, opt, strlen(__longopts[i].name))) { // woot, found a valid argument =) char * par = 0; if ((optind) != ___argc) { // grab the parameter from the next argument (if its not another argument) if (strnicmp(___argv[optind], "--", 2) != 0) { // optind++; // Trash this next argument, we won't be needing it. par = ___argv[optind-1]; } } // increment the argument for next time // optind++; // determine action based on type if (__longopts[i].has_arg == required_argument && !par) { // parameter missing and its a required parameter option return 1; } // store argument in optarg if (par) strncpy(optarg, par, 514); if (__longopts[i].flag != 0) { // this is a variable, we have to set it if this argument is found. *__longopts[i].flag = 1; return 0; } else { if (__longopts[i].val == -1 || par == 0) return 1; return __longopts[i].val; } break; } } // return 1 (invalid argument) return 1; } CWin32Exception::CWin32Exception() : exception() { dwErrorCode = GetLastError(); if( FormatMessageA( FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, dwErrorCode, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPSTR)szErrorString, _countof(szErrorString), NULL) == 0 ) sprintf_s(szErrorString, _countof(szErrorString), "Error code: %u", dwErrorCode); for (size_t i = 0; i < _countof(szErrorString); i++) { if ((szErrorString[i] == '\r') || (szErrorString[i] == '\n')) szErrorString[i] = 0; } } CWin32Exception::CWin32Exception(const CWin32Exception& other) { strcpy_s(szErrorString, _countof(szErrorString), other.szErrorString); } const char* CWin32Exception::what() const throw() { return szErrorString; } DWORD CWin32Exception::GetErrorCode() { return dwErrorCode; } ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/win/inspircd_win32wrapper.h����������������������������������������������������������0000664�0000000�0000000�00000013514�13554550454�0020553�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * InspIRCd -- Internet Relay Chat Daemon * * Copyright (C) 2007 Dennis Friis <peavey@inspircd.org> * Copyright (C) 2007 Craig Edwards <craigedwards@brainbox.cc> * Copyright (C) 2007 Robin Burchell <robin+git@viroteck.net> * * This file is part of InspIRCd. InspIRCd is free software: you can * redistribute it and/or modify it under the terms of the GNU General Public * License as published by the Free Software Foundation, version 2. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once /* Windows Port Wrapper Functions/Definitions By Burlex */ /* * Starting with PSAPI version 2 for Windows 7 and Windows Server 2008 R2, this function is defined as K32GetProcessMemoryInfo in Psapi.h and exported * in Kernel32.lib and Kernel32.dll. However, you should always call this function as GetProcessMemoryInfo. To ensure correct resolution of symbols * for programs that will run on earlier versions of Windows, add Psapi.lib to the TARGETLIBS macro and compile the program with PSAPI_VERSION=1. * * We do this before anything to make sure it's done. */ #define PSAPI_VERSION 1 #include "win32service.h" /* This defaults to 64, way too small for an ircd! */ #define FD_SETSIZE 24000 /* Make builds smaller, leaner and faster */ #define VC_EXTRALEAN #define WIN32_LEAN_AND_MEAN /* Macros for exporting symbols - dependant on what is being compiled */ #ifdef DLL_BUILD #define CoreExport __declspec(dllimport) #define DllExport __declspec(dllexport) #else #define CoreExport __declspec(dllexport) #define DllExport __declspec(dllimport) #endif /* Redirect main() through a different method in win32service.cpp, to intercept service startup */ #define ENTRYPOINT CoreExport int smain(int argc, char** argv) /* 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> #pragma comment(lib, "Ws2_32.lib") #include <windows.h> #include <ws2tcpip.h> #include <sys/types.h> #include <sys/stat.h> #include <direct.h> #include <process.h> #include <io.h> #define F_OK 0 /* test for existence of file */ #define X_OK (1<<0) /* test for execute or search permission */ #define W_OK (1<<1) /* test for write permission */ #define R_OK (1<<2) /* test for read permission */ // Windows defines these already. #undef ERROR #undef min #undef max /* strcasecmp is not defined on windows by default */ #define strcasecmp _stricmp #define strncasecmp _strnicmp typedef SSIZE_T ssize_t; /* _popen, _pclose */ #define popen _popen #define pclose _pclose /* getopt() wrapper */ #define no_argument 0 #define required_argument 1 #define optional_argument 2 struct option { char *name; int has_arg; int *flag; int val; }; extern int optind; extern char optarg[514]; int getopt_long(int ___argc, char *const *___argv, const char *__shortopts, const struct option *__longopts, int *__longind); // warning: 'identifier' : class 'type' needs to have dll-interface to be used by clients of class 'type2' // Normally, this is a huge problem, but due to our new/delete remap, we can ignore it. #pragma warning(disable:4251) // warning: DLL-interface classkey 'identifier' used as base for DLL-interface classkey 'identifier' #pragma warning(disable:4275) // warning: unreferenced formal parameter // Unimportant for now, but for the next version, we should take a look at these again. #pragma warning(disable:4100) // warning: 'class' : assignment operator could not be generated #pragma warning(disable:4512) // warning C4127: conditional expression is constant // This will be triggered like crazy because FOREACH_MOD and similar macros are wrapped in do { ... } while(0) constructs #pragma warning(disable:4127) // warning C4996: The POSIX name for this item is deprecated. #pragma warning(disable:4996) // warning C4244: conversion from 'x' to 'y', possible loss of data #pragma warning(disable:4244) // warning C4267: 'var' : conversion from 'size_t' to 'type', possible loss of data #pragma warning(disable:4267) // warning C4706: assignment within conditional expression #pragma warning(disable:4706) /* Shared memory allocation functions */ void * ::operator new(size_t iSize); void ::operator delete(void * ptr); #include <exception> class CWin32Exception : public std::exception { public: CWin32Exception(); CWin32Exception(const CWin32Exception& other); virtual const char* what() const throw(); DWORD GetErrorCode(); private: char szErrorString[500]; DWORD dwErrorCode; }; // Same value as EXIT_STATUS_FORK (EXIT_STATUS_FORK is unused on Windows) #define EXIT_STATUS_SERVICE 4 // POSIX iovec struct iovec { void* iov_base; // Starting address size_t iov_len; // Number of bytes to transfer }; // Windows WSABUF with POSIX field names struct WindowsIOVec { // POSIX iovec has iov_base then iov_len, WSABUF in Windows has the fields in reverse order u_long iov_len; // Number of bytes to transfer char FAR* iov_base; // Starting address }; inline ssize_t writev(int fd, const WindowsIOVec* iov, int count) { DWORD sent; int ret = WSASend(fd, reinterpret_cast<LPWSABUF>(const_cast<WindowsIOVec*>(iov)), count, &sent, 0, NULL, NULL); if (ret == 0) return sent; return -1; } // This wrapper is just so we don't need to do #ifdef _WIN32 everywhere in the socket code. It is // not actually used and does not need to be the same size as sockaddr_un on UNIX systems. struct sockaddr_un { ADDRESS_FAMILY sun_family; char sun_path[6]; }; ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/win/make_gnutls_cert.bat�������������������������������������������������������������0000664�0000000�0000000�00000000666�13554550454�0020166�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������@echo off echo This program will generate SSL certificates for m_ssl_gnutls.so echo Ensure certtool.exe is in your system path. It can be downloaded echo at ftp://ftp.gnu.org/gnu/gnutls/w32/. If you do not know the answer echo to one of the questions just press enter. echo. pause certtool --generate-privkey --outfile conf/key.pem certtool --generate-self-signed --load-privkey conf/key.pem --outfile conf/cert.pem pause��������������������������������������������������������������������������inspircd-3.4.0/win/modules/�������������������������������������������������������������������������0000775�0000000�0000000�00000000000�13554550454�0015610�5����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/win/modules/CMakeLists.txt�����������������������������������������������������������0000664�0000000�0000000�00000003642�13554550454�0020355�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������# m_regex_stdlib is supported by every version of Visual Studio we support, # so copy the file out of extra/ file(COPY "${INSPIRCD_BASE}/src/modules/extra/m_regex_stdlib.cpp" DESTINATION "${INSPIRCD_BASE}/src/modules/") file(GLOB INSPIRCD_MODULES "${INSPIRCD_BASE}/src/coremods/core_*" "${INSPIRCD_BASE}/src/modules/m_*") list(SORT INSPIRCD_MODULES) add_definitions("-DDLL_BUILD") file(GLOB INSPIRCD_VENDORS "${INSPIRCD_BASE}/vendor/**") foreach(INSPIRCD_VENDOR ${INSPIRCD_VENDORS}) if(NOT IS_DIRECTORY ${INSPIRCD_VENDOR}) list(REMOVE_ITEM INSPIRCD_VENDORS ${INSPIRCD_VENDOR}) endif() endforeach() foreach(MODULE_NAME ${INSPIRCD_MODULES}) if(IS_DIRECTORY "${MODULE_NAME}") string(REGEX REPLACE "^.*[/\\](.*)$" "\\1" BASE_NAME ${MODULE_NAME}) else(IS_DIRECTORY "${MODULE_NAME}") string(REGEX REPLACE "^.*[/\\](.*).cpp$" "\\1" BASE_NAME ${MODULE_NAME}) endif(IS_DIRECTORY "${MODULE_NAME}") set(SO_NAME "${BASE_NAME}.so") if(IS_DIRECTORY "${MODULE_NAME}") file(GLOB MODULES_SUBDIR_SRCS "${MODULE_NAME}/*.cpp") list(SORT MODULES_SUBDIR_SRCS) add_library(${SO_NAME} MODULE ${MODULES_SUBDIR_SRCS}) else(IS_DIRECTORY "${MODULE_NAME}") add_library(${SO_NAME} MODULE ${MODULE_NAME}) endif(IS_DIRECTORY "${MODULE_NAME}") # Generate the module and set its linker flags, also set it to depend on the main executable to be built beforehand target_link_libraries(${SO_NAME} inspircd) add_dependencies(${SO_NAME} inspircd) target_include_directories(${SO_NAME} PRIVATE ${INSPIRCD_VENDORS}) if(MSVC) target_link_libraries(${SO_NAME} win32_memory) add_dependencies(${SO_NAME} win32_memory) endif(MSVC) set_target_properties(${SO_NAME} PROPERTIES PREFIX "" SUFFIX "" COMPILE_DEFINITIONS "MODNAME=\"${BASE_NAME}\"" ) # Set the module to be installed to the module directory install(TARGETS ${SO_NAME} DESTINATION ${MODULE_DIR}) endforeach(MODULE_NAME ${INSPIRCD_MODULES}) ����������������������������������������������������������������������������������������������inspircd-3.4.0/win/win32service.cpp�����������������������������������������������������������������0000664�0000000�0000000�00000017341�13554550454�0017175�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * InspIRCd -- Internet Relay Chat Daemon * * Copyright (C) 2008 Craig Edwards <craigedwards@brainbox.cc> * * This file is part of InspIRCd. InspIRCd is free software: you can * redistribute it and/or modify it under the terms of the GNU General Public * License as published by the Free Software Foundation, version 2. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include "config.h" #include "inspircd.h" #include "exitcodes.h" #include <windows.h> #include <cstdlib> #include <cstring> #include <cstdio> #include <iostream> static SERVICE_STATUS_HANDLE g_ServiceStatusHandle; static SERVICE_STATUS g_ServiceStatus; static bool g_bRunningAsService; struct Service_Data { DWORD argc; LPSTR *argv; }; static Service_Data g_ServiceData; /** The main part of inspircd runs within this thread function. This allows the service part to run * seperately on its own and to be able to kill the worker thread when its time to quit. */ DWORD WINAPI WorkerThread(LPVOID param) { smain(g_ServiceData.argc, g_ServiceData.argv); return 0; } /* This is called when all startup is done */ void SetServiceRunning() { if (!g_bRunningAsService) return; g_ServiceStatus.dwCurrentState = SERVICE_RUNNING; g_ServiceStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_SHUTDOWN; if( !SetServiceStatus( g_ServiceStatusHandle, &g_ServiceStatus ) ) throw CWin32Exception(); } /* In windows we hook this to InspIRCd::Exit() */ void SetServiceStopped(DWORD dwStatus) { if (!g_bRunningAsService) return; g_ServiceStatus.dwCurrentState = SERVICE_STOPPED; if(dwStatus != EXIT_STATUS_NOERROR) { g_ServiceStatus.dwServiceSpecificExitCode = dwStatus; g_ServiceStatus.dwWin32ExitCode = ERROR_SERVICE_SPECIFIC_ERROR; } else { g_ServiceStatus.dwWin32ExitCode = ERROR_SUCCESS; } SetServiceStatus( g_ServiceStatusHandle, &g_ServiceStatus ); } /** This callback is called by windows when the state of the service has been changed */ VOID ServiceCtrlHandler(DWORD controlCode) { switch(controlCode) { case SERVICE_CONTROL_SHUTDOWN: case SERVICE_CONTROL_STOP: g_ServiceStatus.dwCurrentState = SERVICE_STOPPED; SetServiceStatus( g_ServiceStatusHandle, &g_ServiceStatus ); break; } } /** This callback is called by windows when the service is started */ VOID ServiceMain(DWORD argc, LPCSTR *argv) { g_ServiceStatusHandle = RegisterServiceCtrlHandler(TEXT("InspIRCd"), (LPHANDLER_FUNCTION)ServiceCtrlHandler); if( !g_ServiceStatusHandle ) return; g_ServiceStatus.dwCheckPoint = 1; g_ServiceStatus.dwControlsAccepted = 0; g_ServiceStatus.dwServiceType = SERVICE_WIN32_OWN_PROCESS; g_ServiceStatus.dwWaitHint = 5000; g_ServiceStatus.dwWin32ExitCode = NO_ERROR; g_ServiceStatus.dwCurrentState = SERVICE_START_PENDING; if( !SetServiceStatus( g_ServiceStatusHandle, &g_ServiceStatus ) ) return; char szModuleName[MAX_PATH]; if(GetModuleFileNameA(NULL, szModuleName, MAX_PATH)) { if(!argc) argc = 1; g_ServiceData.argc = argc; // Note: since this memory is going to stay allocated for the rest of the execution, // it doesn't make sense to free it, as it's going to be "freed" on process termination try { g_ServiceData.argv = new char*[argc]; uint32_t allocsize = strnlen_s(szModuleName, MAX_PATH) + 1; g_ServiceData.argv[0] = new char[allocsize]; strcpy_s(g_ServiceData.argv[0], allocsize, szModuleName); for(uint32_t i = 1; i < argc; i++) { allocsize = strnlen_s(argv[i], MAX_PATH) + 1; g_ServiceData.argv[i] = new char[allocsize]; strcpy_s(g_ServiceData.argv[i], allocsize, argv[i]); } *(strrchr(szModuleName, '\\') + 1) = NULL; SetCurrentDirectoryA(szModuleName); HANDLE hThread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)WorkerThread, NULL, 0, NULL); if (hThread != NULL) { WaitForSingleObject(hThread, INFINITE); CloseHandle(hThread); } } catch(...) { g_ServiceStatus.dwCurrentState = SERVICE_STOPPED; g_ServiceStatus.dwWin32ExitCode = ERROR_OUTOFMEMORY; SetServiceStatus( g_ServiceStatusHandle, &g_ServiceStatus ); } } if(g_ServiceStatus.dwCurrentState == SERVICE_STOPPED) return; g_ServiceStatus.dwCurrentState = SERVICE_STOPPED; g_ServiceStatus.dwWin32ExitCode = GetLastError(); SetServiceStatus( g_ServiceStatusHandle, &g_ServiceStatus ); } /** Install the windows service. This requires administrator privileges. */ void InstallService() { SC_HANDLE InspServiceHandle = 0, SCMHandle = 0; try { TCHAR tszBinaryPath[MAX_PATH]; if(!GetModuleFileName(NULL, tszBinaryPath, _countof(tszBinaryPath))) { throw CWin32Exception(); } SCMHandle = OpenSCManager(0, 0, SC_MANAGER_ALL_ACCESS); if (!SCMHandle) { throw CWin32Exception(); } InspServiceHandle = CreateService(SCMHandle, TEXT("InspIRCd"),TEXT("InspIRCd Daemon"), SERVICE_CHANGE_CONFIG, SERVICE_WIN32_OWN_PROCESS, SERVICE_AUTO_START, SERVICE_ERROR_NORMAL, tszBinaryPath, 0, 0, 0, TEXT("NT AUTHORITY\\NetworkService"), NULL); if (!InspServiceHandle) { throw CWin32Exception(); } TCHAR tszDescription[] = TEXT("The InspIRCd service hosts IRC channels and conversations. If this service is stopped, the IRC server will be unavailable."); SERVICE_DESCRIPTION svDescription = { tszDescription }; if(!ChangeServiceConfig2(InspServiceHandle, SERVICE_CONFIG_DESCRIPTION, &svDescription)) { throw CWin32Exception(); } CloseServiceHandle(InspServiceHandle); CloseServiceHandle(SCMHandle); std::cout << "Service installed." << std::endl; } catch(CWin32Exception e) { if(InspServiceHandle) CloseServiceHandle(InspServiceHandle); if(SCMHandle) CloseServiceHandle(SCMHandle); std::cout << "Service installation failed: " << e.what() << std::endl; } } /** Remove the windows service. This requires administrator privileges. */ void UninstallService() { SC_HANDLE InspServiceHandle = 0, SCMHandle = 0; try { SCMHandle = OpenSCManager(NULL, SERVICES_ACTIVE_DATABASE, DELETE); if (!SCMHandle) throw CWin32Exception(); InspServiceHandle = OpenService(SCMHandle, TEXT("InspIRCd"), DELETE); if (!InspServiceHandle) throw CWin32Exception(); if (!DeleteService(InspServiceHandle) && GetLastError() != ERROR_SERVICE_MARKED_FOR_DELETE) { throw CWin32Exception(); } CloseServiceHandle(InspServiceHandle); CloseServiceHandle(SCMHandle); std::cout << "Service removed." << std::endl; } catch(CWin32Exception e) { if(InspServiceHandle) CloseServiceHandle(InspServiceHandle); if(SCMHandle) CloseServiceHandle(SCMHandle); std::cout << "Service deletion failed: " << e.what() << std::endl; } } /* In windows, our main() flows through here, before calling the 'real' main, smain() in inspircd.cpp */ int main(int argc, char* argv[]) { /* Check for parameters */ if (argc > 1) { for (int i = 1; i < argc; i++) { if(!_stricmp(argv[i], "--installservice")) { InstallService(); return 0; } if(!_stricmp(argv[i], "--uninstallservice") || !_stricmp(argv[i], "--removeservice")) { UninstallService(); return 0; } } } SERVICE_TABLE_ENTRY serviceTable[] = { { TEXT("InspIRCd"), (LPSERVICE_MAIN_FUNCTION)ServiceMain }, { NULL, NULL } }; g_bRunningAsService = true; if( !StartServiceCtrlDispatcher(serviceTable) ) { // This error means that the program was not started as service. if( GetLastError() == ERROR_FAILED_SERVICE_CONTROLLER_CONNECT ) { g_bRunningAsService = false; return smain(argc, argv); } else { return EXIT_STATUS_SERVICE; } } return 0; } �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������inspircd-3.4.0/win/win32service.h�������������������������������������������������������������������0000664�0000000�0000000�00000001653�13554550454�0016641�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * InspIRCd -- Internet Relay Chat Daemon * * * This file is part of InspIRCd. InspIRCd is free software: you can * redistribute it and/or modify it under the terms of the GNU General Public * License as published by the Free Software Foundation, version 2. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #ifdef _WIN32 /* Hook for win32service.cpp to exit properly with the service specific error code */ void SetServiceStopped(unsigned long dwStatus); /* Marks the service as running, not called until the config is parsed */ void SetServiceRunning(); #endif �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������