$config{HAS_OPENSSL} = "n";
}
-printf "Checking if you are running an ancient, unsupported OS... ";
-if ($config{OSNAME} =~ /FreeBSD/i)
-{
- my $version = `uname -r`;
- if ($version =~ /^4\./)
- {
- print "yes.\n";
- print "FreeBSD 4.x is no longer supported. By ANYONE.\n";
- print "To build, you will need to add the following to CXXFLAGS:\n";
- print "\t-L/usr/local/lib -lgnugetopt -DHAVE_DECL_GETOPT=1\n";
- }
- else
- {
- print "no ($version)\n";
- }
-}
-else
-{
- print "no ($config{OSNAME})\n";
-}
-
-################################################################################
-# BEGIN INTERACTIVE PART #
-################################################################################
-
-# Clear the Screen..
if ($interactive)
{
- print "\e[2J\e[0G\e[0d"; # J = Erase in Display, 2 = Entire Screen, (G, d) = Move cursor to (..,..)
- my $wholeos = $^O;
+ # Clear the screen.
+ system 'tput', 'clear';
+
+ my $revision = get_revision();
+ chomp(my $version = `sh src/version.sh`);
- my $rev = getrevision();
# Display Introduction Message..
print <<"STOP" ;
- Welcome to the \e[1mInspIRCd\e[0m Configuration program! (\e[1minteractive mode\e[0m)
+ Welcome to the \e[1mInspIRCd\e[0m configuration program! (\e[1minteractive mode\e[0m)
\e[1mPackage maintainers: Type ./configure --help for non-interactive help\e[0m
*** If you are unsure of any of these values, leave it blank for ***
# We are on a POSIX system, we can enable POSIX extras without asking
symlink "extra/m_regex_posix.cpp", "src/modules/m_regex_posix.cpp";
-dumphash();
-
-if (($config{USE_GNUTLS} eq "y") && ($config{HAS_GNUTLS} ne "y"))
+if (($config{USE_GNUTLS}) && ($config{HAS_GNUTLS} ne "y"))
{
- print "Sorry, but i couldn't detect gnutls. Make sure pkg-config is in your path.\n";
- print "Sorry, but I couldn't detect GnuTLS. Make sure gnutls-config is in your path.\n";
- exit(0);
++ print "Sorry, but I couldn't detect GnuTLS. Make sure pkg-config is in your path.\n";
+ exit 1;
}
-if (($config{USE_OPENSSL} eq "y") && ($config{HAS_OPENSSL} ne "y"))
+if (($config{USE_OPENSSL}) && ($config{HAS_OPENSSL} ne "y"))
{
- print "Sorry, but i couldn't detect openssl. Make sure pkg-config is in your path.\n";
- print "Sorry, but I couldn't detect OpenSSL. Make sure openssl is in your path.\n";
- exit(0);
++ print "Sorry, but I couldn't detect OpenSSL. Make sure pkg-config is in your path.\n";
+ exit 1;
}
-our $failed = 0;
-
-$config{CERTGEN} ||= 'y';
-yesno('CERTGEN',"Would you like to generate SSL certificates now?") if ($interactive && ($config{USE_GNUTLS} eq "y" || $config{USE_OPENSSL} eq "y"));
-if ($config{USE_GNUTLS} eq "y") {
- unless (-r "src/modules/m_ssl_gnutls.cpp") {
- print "Symlinking src/modules/m_ssl_gnutls.cpp from extra/\n";
- symlink "extra/m_ssl_gnutls.cpp", "src/modules/m_ssl_gnutls.cpp" or print STDERR "Symlink failed: $!";
- }
- if ($interactive && $config{CERTGEN} eq 'y')
- {
- unless (-r "$config{CONFIG_DIR}/key.pem" && -r "$config{CONFIG_DIR}/cert.pem") {
- print "SSL certificates not found, generating.. \n\n
-*************************************************************
-* Generating the private key may take some time, once done, *
-* answer the questions which follow. If you are unsure, *
-* just hit enter! *
-*************************************************************\n\n";
- $failed = make_gnutls_cert();
- if ($failed) {
- print "\n\e[1;32mCertificate generation failed!\e[0m\n\n";
- } else {
+if ($config{USE_GNUTLS} || $config{USE_OPENSSL}) {
+ if (my $val = prompt_bool($interactive, 'Would you like to generate SSL certificates now?', $interactive)) {
+ unless (-r "$config{CONFIG_DIR}/key.pem" && -r "$config{CONFIG_DIR}/cert.pem" && -r "$config{CONFIG_DIR}/dhparams.pem") {
+ unless (system './tools/genssl auto') {
print "\nCertificate generation complete, copying to config directory... ";
File::Copy::move("key.pem", "$config{CONFIG_DIR}/key.pem") or print STDERR "Could not copy key.pem!\n";
File::Copy::move("cert.pem", "$config{CONFIG_DIR}/cert.pem") or print STDERR "Could not copy cert.pem!\n";
+ File::Copy::move("dhparams.pem", "$config{CONFIG_DIR}/dhparams.pem") or print STDERR "Could not copy dhparams.pem!\n";
print "Done.\n\n";
}
- }
- else {
- print "SSL certificates found, skipping.\n\n";
- }
- }
- else
- {
- print "Skipping SSL certificate generation\nin non-interactive mode.\n\n";
- }
-}
-
-if ($config{USE_OPENSSL} eq "y") {
- unless (-r "src/modules/m_ssl_openssl.cpp") {
- print "Symlinking src/modules/m_ssl_openssl.cpp from extra/\n";
- symlink "extra/m_ssl_openssl.cpp", "src/modules/m_ssl_openssl.cpp" or print STDERR "Symlink failed: $!";
- }
- $failed = 0;
- if ($interactive && $config{CERTGEN} eq 'y')
- {
- unless (-r "$config{CONFIG_DIR}/key.pem" && -r "$config{CONFIG_DIR}/cert.pem") {
- print "SSL certificates not found, generating.. \n\n
-*************************************************************
-* Generating the certificates may take some time, go grab a *
-* coffee or something. *
-*************************************************************\n\n";
- make_openssl_cert();
- print "\nCertificate generation complete, copying to config directory... ";
- File::Copy::move("key.pem", "$config{CONFIG_DIR}/key.pem") or print STDERR "Could not copy key.pem!\n";
- File::Copy::move("cert.pem", "$config{CONFIG_DIR}/cert.pem") or print STDERR "Could not copy cert.pem!\n";
- File::Copy::move("dhparams.pem", "$config{CONFIG_DIR}/dhparams.pem") or print STDERR "Could not copy dhparams.pem!\n";
- print "Done.\n\n";
} else {
- print "SSL Certificates found, skipping.\n\n"
+ print "SSL certificates found, skipping.\n\n"
}
+ } else {
+ print "Skipping SSL certificate generation in non-interactive mode.\n\n";
}
- else
- {
- print "Skipping SSL certificate generation\nin non-interactive mode.\n\n";
- }
-}
-if (($config{USE_GNUTLS} eq "n") && ($config{USE_OPENSSL} eq "n")) {
- print "Skipping SSL certificate generation as SSL support is not available.\n\n";
+} else {
+ print "Skipping SSL Certificate generation, SSL support is not available.\n\n";
}
-depcheck();
-writefiles(1);
-makecache();
+print "Writing \e[1;32m.config.cache\e[0m ...\n";
+write_configure_cache(%config);
+writefiles();
+dump_hash();
-print "\n\n";
+print "\n";
print "To build your server with these settings, please run '\e[1;32mmake\e[0m' now.\n";
-if (($config{USE_GNUTLS} eq "y") || ($config{USE_OPENSSL} eq "y")) {
+if ($config{USE_GNUTLS} || $config{USE_OPENSSL}) {
print "Please note: for \e[1;32mSSL support\e[0m you will need to load required\n";
print "modules in your config. This configure script has added those modules to the\n";
- print "build process. For more info please refer to:\n";
+ print "build process. For more info, please refer to:\n";
print "\e[1;32mhttp://wiki.inspircd.org/Installation_From_Tarball\e[0m\n";
}
-print "*** \e[1;32mRemember to edit your configuration files!!!\e[0m ***\n\n\n";
-if (($config{OSNAME} eq "OpenBSD") && ($config{CC} ne "eg++")) {
- print "\e[1;32mWARNING!\e[0m You are running OpenBSD but you are using the base gcc package\nrather than eg++. This compile will most likely fail, but I'm letting you\ngo ahead with it anyway, just in case I'm wrong :-)\n";
-}
-
-if ($config{GCCVER} < "3") {
- print <<FOO2;
-\e[1;32mWARNING!\e[0m You are attempting to compile InspIRCd on GCC 2.x!
-GCC 2.x series compilers only had partial (read as broken) C++ support, and
-your compile will most likely fail horribly! If you have any problems, do NOT
-report them to the bugtracker or forums without first upgrading your compiler
-to a newer 3.x or 4.x (or whatever is available currently) version.
-FOO2
-}
-
-################################################################################
-# HELPER FUNCTIONS #
-################################################################################
-sub getcache {
- # Retrieves the .config.cache file, and loads values into the main config hash.
- open(CACHE, ".config.cache") or return 0;
- while (<CACHE>) {
- chomp;
- # Ignore Blank lines, and comments..
- next if /^\s*$/;
- next if /^\s*#/;
- my ($key, $value) = split("=", $_, 2);
- $value =~ /^\"(.*)\"$/;
- # Do something with data here!
- $config{$key} = $1;
- }
- close(CACHE);
- return 1;
-}
-
-sub makecache {
- # Dump the contents of %config
- print "Writing \e[1;32mcache file\e[0m for future ./configures ...\n";
- open(FILEHANDLE, ">.config.cache");
- foreach my $key (keys %config) {
- print FILEHANDLE "$key=\"$config{$key}\"\n";
- }
- close(FILEHANDLE);
-}
-
-sub dir_check {
- my ($desc, $hash_key) = @_;
- my $complete = 0;
- while (!$complete) {
- print "In what directory $desc?\n";
- print "[\e[1;32m$config{$hash_key}\e[0m] -> ";
- chomp(my $var = <STDIN>);
- if ($var eq "") {
- $var = $config{$hash_key};
- }
- if ($var =~ /^\~\/(.+)$/) {
- # Convert it to a full path..
- $var = resolve_directory($ENV{HOME} . "/" . $1);
- }
- elsif ((($config{OSNAME} =~ /MINGW32/i) and ($var !~ /^[A-Z]{1}:\\.*/)) and (substr($var,0,1) ne "/"))
- {
- # Assume relative Path was given.. fill in the rest.
- $var = $this . "/$var";
- }
-
- $var = resolve_directory($var);
- if (! -e $var) {
- print "$var does not exist. Create it?\n[\e[1;32my\e[0m] ";
- chomp(my $tmp = <STDIN>);
- if (($tmp eq "") || ($tmp =~ /^y/i)) {
- # Attempt to Create the Dir..
- my $chk = eval {
- use File::Path ();
- File::Path::mkpath($var, 0, 0777);
- 1;
- };
- unless (defined($chk) && -d $var) {
- print "Unable to create directory. ($var)\n\n";
- # Restart Loop..
- next;
- }
- } else {
- # They said they don't want to create, and we can't install there.
- print "\n\n";
- next;
- }
- } else {
- if (!is_dir($var)) {
- # Target exists, but is not a directory.
- print "File $var exists, but is not a directory.\n\n";
- next;
- }
- }
- # Either Dir Exists, or was created fine.
- $config{$hash_key} = $var;
- $complete = 1;
- print "\n";
- }
-}
-
-our $SHARED = "";
-
-my ($mliflags, $mfrules, $mobjs, $mfcount) = ("", "", "", 0);
+print "*** \e[1;32mRemember to edit your configuration files!!!\e[0m ***\n\n";
sub writefiles {
- my($writeheader) = @_;
- # First File.. inspircd_config.h
chomp(my $incos = `uname -n -s -r`);
chomp(my $version = `sh src/version.sh`);
- chomp(my $revision2 = getrevision());
+ my $revision = get_revision();
my $branch = "InspIRCd-0.0";
if ($version =~ /^(InspIRCd-[0-9]+\.[0-9]+)\.[0-9]+/)
{
channel halfoperator to remove a user. A removed user will part with
a message stating they were removed from the channel and by whom.">
+<helpop key="rmode" value="/RMODE [channel] [modeletter] {[pattern]}
+
+Removes listmodes from a channel.
+E.g. /RMODE #Chan b m:* will remove all mute extbans.">
+
<helpop key="fpart" value="/FPART [channel] [nick] {[reason]}
- This behaves identically to /REMOVE, the only difference is that that
+ This behaves identically to /REMOVE, the only difference is that the
[channel] and [nick] parameters are switched around to match /KICK's
syntax. Also, /REMOVE is a builtin mIRC command which caused trouble
- for some users. This feature was added in the 1.1 branch.">
+ for some users.">
<helpop key="devoice" value="/DEVOICE [channel]
# something new or different to this version and you SHOULD READ IT. #
# #
########################################################################
- # #
- # Unalphabeticalise the modules list at your own risk #
- # #
- ########################################################################
+#-#-#-#-#-#-#-#-#-# 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 <define> to create macros. #
+#<config format="compat">
+
#-#-#-#-#-#-#-#-#-# INCLUDE CONFIGURATION #-#-#-#-#-#-#-#-#-#-#-#-#-#
# #
# This optional tag allows you to include another config file #
serverpingfreq="60"
# defaultmodes: What modes are set on a empty channel when a user
- # joins it and it is unregistered. This is similar to Asuka's
- # autochanmodes.
+ # joins it and it is unregistered.
- defaultmodes="nt"
+ defaultmodes="not"
- # moronbanner: This is the text that is sent to a user when they are
+ # xlinemessage: This is the text that is sent to a user when they are
# banned from the server.
- moronbanner="You're banned! Email abuse@example.com with the ERROR line below for help."
+ xlinemessage="You're banned! Email irc@example.com with the ERROR line below for help."
# exemptchanops: exemptions for channel access restrictions based on prefix.
exemptchanops="nonick:v flood:o"
# 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.
-#<chanhistory maxlines="20" notice="yes">
+# If bots is set to yes, it will also send to users marked with +B
+#<chanhistory maxlines="20" notice="yes" bots="yes">
#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#
- # Channel logging module: used to send snotice output to channels, to
+ # 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"
allowrange="">
#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#
- # Channelban: Implements extended ban j:, which stops anyone in already
- # in a channel matching a mask like +b j:#channel*mask from joining.
+ # Channelban: Implements extended ban j:, which stops anyone already
+ # in a channel matching a ban like +b j:#channel*mask from joining.
#<module name="m_channelban.so">
-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#
-# Chanprotect module: Gives +q and +a channel modes.
-#<module name="m_chanprotect.so">
-
-<chanprotect
- # noservices: With this set to yes, when a user joins an empty channel,
- # the server will set +q on them. If set to no, it will only set +o
- # on them until they register the channel.
- noservices="no"
-
- # qprefix: Prefix (symbol) to use for +q users.
- qprefix="~"
-
- # aprefix: Prefix (symbol) to use for +a users.
- aprefix="&"
-
- # deprotectself: If this value is set (true, yes or 1), it will allow
- # +a and +q users to remove the +a and +q from themselves, otherwise,
- # the status will have to be removed by services.
- deprotectself="yes"
-
- # deprotectothers: If this value is set to yes, true, or 1, then any
- # user with +q or +a may remove the +q or +a from other users.
- deprotectothers="yes">
-
-
#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#
- # Check module: gives /check
- # Check is useful for looking up information on channels,
- # users, IP addresses and hosts.
+ # 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="m_check.so">
# or /48 subnet of the IPv6 address. #
# #
# full Cloak the users completely, using three slices for #
- # common CIDR bans (IPv4: /16, /24; IPv6: /48, /64) #
+ # common CIDR bans (IPv4: /16, /24; IPv6: /48, /64). #
# #
-# These methods use a single key that can be any length of text. #
+# The methods use a single key that can be any length of text. #
# An optional prefix may be specified to mark cloaked hosts. #
-# #
-# The following methods are maintained for backwards compatibility; #
-# they are slightly less secure, and always hide unresolved IPs. #
-# #
-# compat-host InspIRCd 1.2-compatible host-based cloaking. #
-# compat-ip InspIRCd 1.2-compatible ip-always cloaking. #
-# #
-# If you use a compat cloaking mode then you must specify key1, key2, #
-# key3, key4; the values must be less than 0x80000000 and should be #
-# picked at random. Prefix is mandatory, will default to network name #
-# if not specified, and will always have a "-" appended. #
+#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#
#
#<cloak mode="half"
# key="secret"
#<module name="m_commonchans.so">
#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#
- # Conn-Join: 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.
+ # Auto join on connect module: Allows you to force users to join one
-# or more channels automatically upon connecting to the server.
++# 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="m_conn_join.so">
#
#-#-#-#-#-#-#-#-#-#-#-#- CONNJOIN CONFIGURATION -#-#-#-#-#-#-#-#-#-#-#
#
+ # If you have m_conn_join.so loaded, you can configure it using the
+ # following values, 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">
#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#
- # Conn-Usermodes: Set modes on users when they connect
- # When this module is loaded <connect:allow> tags may have an optional
- # modes="" value, which contains modes to add or remove from users
- # when they connect to the server.
+ # 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="m_conn_umodes.so">
#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#
#<module name="m_cycle.so">
#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#
- # Connectban: Provides IP connection throttling. Any IP range that connects
- # too many times (configurable) in an hour is zlined for a (configurable)
- # duration, and their count resets to 0.
+ # 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="m_connectban.so">
#
- # 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.
+ # 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.
#
-#<connectban threshold="10" duration="10m" ipv4cidr="32" ipv6cidr="128">
+ # 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"
- # 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.">
- #
- # This allows for 10 connections in an hour with a 10 minute ban if that is exceeded.
- #
- #<module name="m_connectban.so">
++#<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. Configuration:
+ # Connection throttle module.
#<module name="m_connflood.so">
#
#-#-#-#-#-#-#-#-#-#-#- CONNTHROTTLE CONFIGURATION -#-#-#-#-#-#-#-#-#-#
# quitmsg="Throttled" bootwait="10">
#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#
- # Custom prefixes: allows for channel prefixes to be added.
+ # Custom prefixes: Allows for channel prefixes to be added.
-# This replaces m_chanprotect and m_halfop.
#<module name="m_customprefix.so">
#
- # name The name of the mode, must be unique from other modes
+ # 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
- # VOICE_VALUE is 10000, HALFOP_VALUE is 20000, OP_VALUE is 30000
+ # 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/unset this mode. Defaults to rank.
# depriv Can you remove the mode from yourself? Defaults to yes.
#<customprefix name="founder" letter="q" prefix="~" rank="50000" ranktoset="50000">
#-#-#-#-#-#-#-#-#-#-#- FILTER CONFIGURATION -#-#-#-#-#-#-#-#-#-#-#-#
# #
# Optional - If you specify to use the m_filter module, then #
- # specfiy below the path to the filter.conf file, or define some #
+ # specify below the path to the filter.conf file, or define some #
# <filter> tags. #
# #
-#<include file="conf/examples/filter.conf.example">
+#<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="m_flashpolicyd.so"> #
#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#
- # Gecosban: Implements extended ban r:, which stops anyone matching
+ # Gecos ban: Implements extended ban 'r', which stops anyone matching
# a mask like +b r:*realname?here* from joining a channel.
#<module name="m_gecosban.so">
#
#-#-#-#-#-#-#-#-#-#-#-#- HELPOP CONFIGURATION -#-#-#-#-#-#-#-#-#-#-#
# #
- # Optional - If you specify to use the m_helpop.so module, then #
- # specify below the path to the helpop.conf file, or if you like to #
- # make a mess, define your helpop tags in this conf. #
+ # If you specify to use the m_helpop.so module, then specify below #
+ # the path to the helpop.conf file. #
-#<include file="conf/examples/inspircd.helpop-full.example">
+# #
+#<include file="examples/inspircd.helpop-full.example">
#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#
- # HIDECHANS module: Allows users to hide their channels list from non-
+ # Hide chans module: Allows users to hide their channels list from non-
# opers by setting user mode +I on themselves.
#<module name="m_hidechans.so">
#
#<hostchange mask="a@b.com" action="set" value="blah.blah.blah">
#<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.
+#<module name="m_hostcycle.so">
+
#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#
- # httpd module: Provides http server support for InspIRCd
+ # httpd module: Provides HTTP server support for InspIRCd.
#<module name="m_httpd.so">
#
#-#-#-#-#-#-#-#-#-#-#-#- HTTPD CONFIGURATION -#-#-#-#-#-#-#-#-#-#-#
#<module name="m_jumpserver.so">
#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#
- # Anti-Auto-Rejoin: Adds support for prevention of auto-rejoin (+J)
+ # Anti auto rejoin: Adds support for prevention of auto-rejoin (+J).
#<module name="m_kicknorejoin.so">
-# Set the maximum time that is accepted as a parameter for +J here.
-#<kicknorejoin maxtime="1m">
#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#
- # Knock module: adds the /KNOCK command and +K channel mode
+ # Knock module: Adds the /KNOCK command and channel mode +K.
#<module name="m_knock.so">
- # This setting specifes what to do when someone successfully /KNOCKs.
+ #
+ # 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 "both" then (surprise!) both will be sent.
#<knock notify="notice">
- # This modules is in extras. Re-run configure with: ./configure --enable-extras=m_ldap.cpp
+#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#
+# 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="m_ldap.so">
+#<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. This is an extra module which must be enabled explicitly #
-# by symlinking it from modules/extra, and requires the OpenLDAP libs #
-# This module is in extras. To enable it, Re-run configure with: #
-# ./configure --enable-extras=m_ldapauth.cpp #
-# and run make install, then uncomment this module. #
+# via LDAP. #
- # #
- #<module name="m_ldapauth.so"> #
+ #<module name="m_ldapauth.so">
# #
# Configuration: #
# #
#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#
# LDAP oper configuration module: Adds the ability to authenticate #
-# opers via LDAP. This is an extra module which must be enabled #
-# explicitly by symlinking it from modules/extra, and requires the #
-# OpenLDAP libs. Re-run configure with: #
-# ./configure --enable-extras=m_ldapoper.cpp
-# and run make install, then uncomment this module to enable it. #
+# opers via LDAP. #
- # #
#<module name="m_ldapoper.so">
# #
# Configuration: #
# would likely be immediately bounced by services.
#<module name="m_mlock.so">
+#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#
+# Modenotice module: Adds the /MODENOTICE command that allows opers to
+# send notices to all users having the given user mode(s) set.
+#<module name="m_modenotice.so">
+
#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#
- # MsSQL module: Allows other SQL modules to access MS SQL Server
+ # MsSQL module: Allows other SQL modules to access MS SQL Server
# through a unified API.
- # This modules is in extras. Re-run configure with: ./configure --enable-extras=m_mssql.cpp
+ # This module is in extras. Re-run configure with:
+ # ./configure --enable-extras=m_mssql.cpp
# and run make install, then uncomment this module to enable it.
- #
#<module name="m_mssql.so">
#
#-#-#-#-#-#-#-#-#-#-#-#- SQL CONFIGURATION -#-#-#-#-#-#-#-#-#-#-#-#-#
# Read the comment above <connect:allowmotdcolors> in #
# inspircd.conf.example for details. #
# #
-#<opermotd file="conf/examples/opermotd.txt.example" onoper="yes" processcolors="false">
+#<opermotd file="examples/opermotd.txt.example" onoper="yes" processcolors="false">
#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#
- # Override module: Adds support for oper override
+ # Override module: Adds support for oper override.
# This module is oper-only.
#<module name="m_override.so">
#
# m_rline.
#<module name="m_regex_pcre.so">
+#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#
+# 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="m_regex_re2.so">
+
#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#
- # Regular Expression Provider for POSIX Regular Expressions.
+ # 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 m_filter or m_rline.
#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#
# Remove module: Adds the /REMOVE command which is a peaceful
- # alternative to /KICK
+ # alternative to /KICK.
#<module name="m_remove.so">
+#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#
+# A module to block, kick or ban upon similiar messages being uttered several times.
+# Syntax [~*][lines]:[sec]{[:difference]}{[:matchlines]}
+# ~ 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.
+# distance - Edit distance, in percent, between two strings to trigger on.
+# matchlines - 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.
+# maxsecs - Maximum value of seconds 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" maxlines="20" maxdistance="50" maxsecs="0" size="512">
+#<module name="m_repeat.so">
+
#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#
# Restricted channels module: Allows only opers to create channels.
#
# 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 mods to remove list modes en masse.
+# Syntax: /rmode <channel> <mode> [pattern]
+# E.g. '/rmode #Channel b m:*' will remove all mute-extbans on the channel.
+#<module name="m_rmode.so">
+
#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#
- # SAJOIN module: Adds the /SAJOIN command
+ # 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="m_sajoin.so">
#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#
# to a server matching a mask like +b s:server.mask.here from joining.
#<module name="m_serverban.so">
+#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#
+# 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="m_showfile.so"> #
+# #
+#-#-#-#-#-#-#-#-#-#-# 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 #
+# (similiar to /MOTD; the default). #
+# * notice: Send contents as a series of notices. #
+# * msg: Send contents as a series of private messages. #
+# colors - If true, color codes (\c, \b, \u, etc.) will be processed #
+# and sent as ANSI colors. If false (default) the file will #
+# be displayed as-is. #
+# #
+# 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"
+# colors="true"
+# introtext="Server rules:"
+# endtext="End of server rules.">
+
#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#
- # Show Whois module: Adds the +W usermode which allows opers
- # to see when they are whois'ed (can be annoying).
- # This module is oper-only.
+ # Show whois module: Adds the +W usermode which allows opers to see
+ # when they are /WHOIS'd.
+ # This module is oper-only by default.
#<module name="m_showwhois.so">
#
# 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. This setting
-# is not reloadable via /REHASH, changing it requires /RELOADMODULE.
+# 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">
+ # 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
# - servers/auspex: allows opers with this priv to see more detail 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
# - channels/high-join-limit: allows opers with this priv to join <channels:opers> total channels instead of <channels:users> total channels.
# PERMISSIONS:
+ # - 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/flood/increased-buffers: allows opers with this priv to send and receive data without worrying about being disconnected for exceeding limits (*NOTE)
#
# #
<type
- # name: Name of type. Used in actual olines below.
+ # name: Name of type. Used in actual server operator accounts below.
- # Cannot contain spaces. If you would like a space, use
- # the _ character instead and it will translate to a space on whois.
name="NetAdmin"
- # classes: classes (above blocks) that this type belongs to.
- classes="OperChat BanControl HostCloak Shutdown ServerLink"
+ # classes: Classes (blocks above) that this type belongs to.
+ classes="SACommands OperChat BanControl HostCloak Shutdown ServerLink"
- # vhost: host oper gets on oper-up. This is optional.
- vhost="netadmin.omega.org.za"
+ # vhost: Host opers of this type get when they log in (oper up). This is optional.
+ vhost="netadmin.omega.example.org"
- # modes: usermodes besides +o that are set on a oper of this type
+ # 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 that m_opermodes.so be loaded.
modes="+s +cCqQ">
*/
bool has_user = this->HasUser(user);
- const size_t maxlen = MAXBUF - 10 - ServerInstance->Config->ServerName.size();
++ const size_t maxlen = ServerInstance->Config->Limits.MaxLine - 10 - ServerInstance->Config->ServerName.size();
std::string prefixlist;
std::string nick;
for (UserMembIter i = userlist.begin(); i != userlist.end(); ++i)
*/
-/* $Core */
-
#include "inspircd.h"
- /* Used when comparing CIDR masks for the modulus bits left over.
- * A lot of ircd's seem to do this:
- * ((-1) << (8 - (mask % 8)))
- * But imho, it sucks in comparison to a nice neat lookup table.
- */
- const unsigned char inverted_bits[8] = { 0x00, /* 00000000 - 0 bits - never actually used */
- 0x80, /* 10000000 - 1 bits */
- 0xC0, /* 11000000 - 2 bits */
- 0xE0, /* 11100000 - 3 bits */
- 0xF0, /* 11110000 - 4 bits */
- 0xF8, /* 11111000 - 5 bits */
- 0xFC, /* 11111100 - 6 bits */
- 0xFE /* 11111110 - 7 bits */
- };
-
-
/* 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
- * If you have a lot of hosts to match, youre probably better off building your mask once
- * and then using the lower level MatchCIDRBits directly.
*
* This will also attempt to match any leading usernames or nicknames on the mask, using
* match(), when match_with_username is true.
}
else
{
- user->WriteNumeric(ERR_UNKNOWNCOMMAND, "%s %s :This command has been disabled.",
- user->nick.c_str(), command.c_str());
+ user->WriteNumeric(ERR_UNKNOWNCOMMAND, "%s :This command has been disabled.", command.c_str());
}
- ServerInstance->SNO->WriteToSnoMask('t', "%s denied for %s (%s@%s)",
+ ServerInstance->SNO->WriteToSnoMask('a', "%s denied for %s (%s@%s)",
command.c_str(), user->nick.c_str(), user->ident.c_str(), user->host.c_str());
- return do_more;
+ return;
}
- if ((!command_p.empty()) && (command_p.back().empty()) && (!cm->second->allow_empty_last_param))
+ if ((!command_p.empty()) && (command_p.back().empty()) && (!handler->allow_empty_last_param))
command_p.pop_back();
- if (command_p.size() < cm->second->min_params)
+ if (command_p.size() < handler->min_params)
{
- user->WriteNumeric(ERR_NEEDMOREPARAMS, "%s %s :Not enough parameters.", user->nick.c_str(), command.c_str());
- if ((ServerInstance->Config->SyntaxHints) && (user->registered == REG_ALL) && (cm->second->syntax.length()))
- user->WriteNumeric(RPL_SYNTAX, "%s :SYNTAX %s %s", user->nick.c_str(), cm->second->name.c_str(), cm->second->syntax.c_str());
- return do_more;
+ user->WriteNumeric(ERR_NEEDMOREPARAMS, "%s :Not enough parameters.", command.c_str());
+ if ((ServerInstance->Config->SyntaxHints) && (user->registered == REG_ALL) && (handler->syntax.length()))
+ user->WriteNumeric(RPL_SYNTAX, ":SYNTAX %s %s", handler->name.c_str(), handler->syntax.c_str());
+ return;
}
- if ((user->registered != REG_ALL) && (!cm->second->WorksBeforeReg()))
+
+ if ((user->registered != REG_ALL) && (!handler->WorksBeforeReg()))
{
user->WriteNumeric(ERR_NOTREGISTERED, "%s :You have not registered",command.c_str());
- return do_more;
}
else
{
User* user = useruid.empty() ? NULL : ServerInstance->FindNick(useruid);
if (!valid)
- ServerInstance->Logs->Log("CONFIG",DEFAULT, "There were errors in your configuration file:");
+ {
+ ServerInstance->Logs->Log("CONFIG", LOG_DEFAULT, "There were errors in your configuration file:");
+ Classes.clear();
+ }
while (errstr.good())
{
--- /dev/null
- if (!u || !c)
+/*
+ * 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 (const std::vector<std::string>& parameters, User *user)
+{
+ std::string reason;
+ 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]);
+
- user->WriteNumeric(ERR_NOSUCHNICK, "%s :No such nick/channel", u ? parameters[0].c_str() : parameters[1].c_str());
++ if ((!u) || (!c) || (u->registered != REG_ALL))
+ {
++ user->WriteNumeric(ERR_NOSUCHNICK, "%s :No such nick/channel", c ? parameters[1].c_str() : parameters[0].c_str());
+ return CMD_FAILURE;
+ }
+
+ Membership* srcmemb = NULL;
+ if (IS_LOCAL(user))
+ {
+ srcmemb = c->GetUser(user);
+ if (!srcmemb)
+ {
+ user->WriteNumeric(ERR_NOTONCHANNEL, "%s :You're not on that channel!", parameters[0].c_str());
+ return CMD_FAILURE;
+ }
+
+ if (u->server->IsULine())
+ {
+ user->WriteNumeric(ERR_CHANOPRIVSNEEDED, "%s :You may not kick a u-lined client", c->name.c_str());
+ return CMD_FAILURE;
+ }
+ }
+
+ if (parameters.size() > 2)
+ {
+ reason.assign(parameters[2], 0, ServerInstance->Config->Limits.MaxKick);
+ }
+ else
+ {
+ reason.assign(user->nick, 0, ServerInstance->Config->Limits.MaxKick);
+ }
+
+ c->KickUser(user, u, reason, srcmemb);
+
+ return CMD_SUCCESS;
+}
+
+RouteDescriptor CommandKick::GetRouting(User* user, const std::vector<std::string>& parameters)
+{
+ return (IS_LOCAL(user) ? ROUTE_LOCALONLY : ROUTE_BROADCAST);
+}
--- /dev/null
- if ((c->IsModeSet(secretmode)) && (!c->HasUser(user)))
- {
- user->WriteNumeric(ERR_NOSUCHNICK, "%s :No such nick/channel", c->name.c_str());
- return CMD_FAILURE;
- }
+/*
+ * 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"
+
+CommandNames::CommandNames(Module* parent)
+ : Command(parent, "NAMES", 0, 0)
+ , secretmode(parent, "secret")
+{
+ syntax = "{<channel>{,<channel>}}";
+}
+
+/** Handle /NAMES
+ */
+CmdResult CommandNames::Handle (const std::vector<std::string>& parameters, User *user)
+{
+ Channel* c;
+
+ if (!parameters.size())
+ {
+ 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)
+ {
+ c->UserList(user);
+ }
+ else
+ {
+ user->WriteNumeric(ERR_NOSUCHNICK, "%s :No such nick/channel", parameters[0].c_str());
+ }
+
+ return CMD_SUCCESS;
+}
--- /dev/null
- if (u)
+/*
+ * 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 /ISON.
+ */
+class CommandIson : public Command
+{
+ public:
+ /** Constructor for ison.
+ */
+ CommandIson ( Module* parent) : Command(parent,"ISON", 1) {
+ 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(const std::vector<std::string>& parameters, User *user);
+};
+
+/** Handle /ISON
+ */
+CmdResult CommandIson::Handle (const std::vector<std::string>& parameters, User *user)
+{
+ std::map<User*,User*> ison_already;
+ User *u;
+ std::string reply = "303 " + user->nick + " :";
+
+ for (unsigned int i = 0; i < parameters.size(); i++)
+ {
+ u = ServerInstance->FindNickOnly(parameters[i]);
+ if (ison_already.find(u) != ison_already.end())
+ continue;
+
- if (u)
++ if ((u) && (u->registered == REG_ALL))
+ {
+ reply.append(u->nick).append(" ");
+ if (reply.length() > 450)
+ {
+ user->WriteServ(reply);
+ reply = "303 " + user->nick + " :";
+ }
+ ison_already[u] = u;
+ }
+ else
+ {
+ if ((i == parameters.size() - 1) && (parameters[i].find(' ') != std::string::npos))
+ {
+ /* Its a space seperated list of nicks (RFC1459 says to support this)
+ */
+ irc::spacesepstream list(parameters[i]);
+ std::string item;
+
+ while (list.GetToken(item))
+ {
+ u = ServerInstance->FindNickOnly(item);
+ if (ison_already.find(u) != ison_already.end())
+ continue;
+
++ if ((u) && (u->registered == REG_ALL))
+ {
+ reply.append(u->nick).append(" ");
+ if (reply.length() > 450)
+ {
+ user->WriteServ(reply);
+ reply = "303 " + user->nick + " :";
+ }
+ ison_already[u] = u;
+ }
+ }
+ }
+ }
+ }
+
+ if (!reply.empty())
+ user->WriteServ(reply);
+
+ return CMD_SUCCESS;
+}
+
+
+COMMAND_INIT(CommandIson)
--- /dev/null
- if (usingwildcards && (!oper->IsModeSet(invisiblemode)) && (!user->HasPrivPermission("users/auspex")))
+/*
+ * 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>
+ *
+ * This file is part of InspIRCd. InspIRCd is free software: you can
+ * redistribute it and/or modify it under the terms of the GNU General Public
+ * License as published by the Free Software Foundation, version 2.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * details.
+ *
+ * You should have 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 /WHO.
+ */
+class CommandWho : public Command
+{
+ bool CanView(Channel* chan, User* user);
+ bool opt_viewopersonly;
+ bool opt_showrealhost;
+ bool opt_realname;
+ bool opt_mode;
+ bool opt_ident;
+ bool opt_metadata;
+ bool opt_port;
+ bool opt_away;
+ bool opt_local;
+ bool opt_far;
+ bool opt_time;
+ ChanModeReference secretmode;
+ ChanModeReference privatemode;
+ UserModeReference invisiblemode;
+
+ Membership* get_first_visible_channel(User* u)
+ {
+ for (UCListIter i = u->chans.begin(); i != u->chans.end(); ++i)
+ {
+ Membership* memb = *i;
+ if (!memb->chan->IsModeSet(secretmode))
+ return memb;
+ }
+ return NULL;
+ }
+
+ public:
+ /** Constructor for who.
+ */
+ CommandWho(Module* parent)
+ : Command(parent, "WHO", 1)
+ , secretmode(parent, "secret")
+ , privatemode(parent, "private")
+ , invisiblemode(parent, "invisible")
+ {
+ syntax = "<server>|<nickname>|<channel>|<realname>|<host>|0 [ohurmMiaplf]";
+ }
+
+ void SendWhoLine(User* user, const std::vector<std::string>& parms, const std::string& initial, Membership* memb, User* u, std::vector<std::string>& whoresults);
+ /** 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(const std::vector<std::string>& parameters, User *user);
+ bool whomatch(User* cuser, User* user, const char* matchtext);
+};
+
+bool CommandWho::whomatch(User* cuser, User* user, const char* matchtext)
+{
+ bool match = false;
+ bool positive = false;
+
+ if (user->registered != REG_ALL)
+ return false;
+
+ if (opt_local && !IS_LOCAL(user))
+ return false;
+ else if (opt_far && IS_LOCAL(user))
+ return false;
+
+ if (opt_mode)
+ {
+ for (const char* n = matchtext; *n; n++)
+ {
+ if (*n == '+')
+ {
+ positive = true;
+ continue;
+ }
+ else if (*n == '-')
+ {
+ positive = false;
+ continue;
+ }
+ if (user->IsModeSet(*n) != positive)
+ return false;
+ }
+ return true;
+ }
+ else
+ {
+ /*
+ * This was previously one awesome pile of ugly nested if, when really, it didn't need
+ * to be, since only one condition was ever checked, a chained if works just fine.
+ * -- w00t
+ */
+ if (opt_metadata)
+ {
+ match = false;
+ const Extensible::ExtensibleStore& list = user->GetExtList();
+ for(Extensible::ExtensibleStore::const_iterator i = list.begin(); i != list.end(); ++i)
+ if (InspIRCd::Match(i->first->name, matchtext))
+ match = true;
+ }
+ else if (opt_realname)
+ match = InspIRCd::Match(user->fullname, matchtext);
+ else if (opt_showrealhost)
+ match = InspIRCd::Match(user->host, matchtext, ascii_case_insensitive_map);
+ else if (opt_ident)
+ match = InspIRCd::Match(user->ident, matchtext, ascii_case_insensitive_map);
+ else if (opt_port)
+ {
+ irc::portparser portrange(matchtext, false);
+ long portno = -1;
+ while ((portno = portrange.GetToken()))
+ if (IS_LOCAL(user) && portno == IS_LOCAL(user)->GetServerPort())
+ {
+ match = true;
+ break;
+ }
+ }
+ else if (opt_away)
+ match = InspIRCd::Match(user->awaymsg, matchtext);
+ else if (opt_time)
+ {
+ long seconds = InspIRCd::Duration(matchtext);
+
+ // Okay, so time matching, we want all users connected `seconds' ago
+ if (user->age >= ServerInstance->Time() - seconds)
+ match = true;
+ }
+
+ /*
+ * Once the conditionals have been checked, only check dhost/nick/server
+ * if they didn't match this user -- and only match if we don't find a match.
+ *
+ * This should make things minutely faster, and again, less ugly.
+ * -- w00t
+ */
+ if (!match)
+ match = InspIRCd::Match(user->dhost, matchtext, ascii_case_insensitive_map);
+
+ if (!match)
+ match = InspIRCd::Match(user->nick, matchtext);
+
+ /* Don't allow server name matches if HideWhoisServer is enabled, unless the command user has the priv */
+ if (!match && (ServerInstance->Config->HideWhoisServer.empty() || cuser->HasPrivPermission("users/auspex")))
+ match = InspIRCd::Match(user->server->GetName(), matchtext);
+
+ return match;
+ }
+}
+
+bool CommandWho::CanView(Channel* chan, User* user)
+{
+ if (!user || !chan)
+ return false;
+
+ /* Bug #383 - moved higher up the list, because if we are in the channel
+ * we can see all its users
+ */
+ if (chan->HasUser(user))
+ return true;
+ /* Opers see all */
+ if (user->HasPrivPermission("users/auspex"))
+ return true;
+ /* Cant see inside a +s or a +p channel unless we are a member (see above) */
+ else if (!chan->IsModeSet(secretmode) && !chan->IsModeSet(privatemode))
+ return true;
+
+ return false;
+}
+
+void CommandWho::SendWhoLine(User* user, const std::vector<std::string>& parms, const std::string& initial, Membership* memb, User* u, std::vector<std::string>& whoresults)
+{
+ if (!memb)
+ memb = get_first_visible_channel(u);
+
+ std::string wholine = initial + (memb ? memb->chan->name : "*") + " " + u->ident + " " +
+ (opt_showrealhost ? u->host : u->dhost) + " ";
+ if (!ServerInstance->Config->HideWhoisServer.empty() && !user->HasPrivPermission("servers/auspex"))
+ wholine.append(ServerInstance->Config->HideWhoisServer);
+ else
+ wholine.append(u->server->GetName());
+
+ wholine.append(" " + u->nick + " ");
+
+ /* away? */
+ if (u->IsAway())
+ {
+ wholine.append("G");
+ }
+ else
+ {
+ wholine.append("H");
+ }
+
+ /* oper? */
+ if (u->IsOper())
+ {
+ wholine.push_back('*');
+ }
+
+ if (memb)
+ {
+ char prefix = memb->GetPrefixChar();
+ if (prefix)
+ wholine.push_back(prefix);
+ }
+
+ wholine.append(" :0 " + u->fullname);
+
+ FOREACH_MOD(OnSendWhoLine, (user, parms, u, memb, wholine));
+
+ if (!wholine.empty())
+ whoresults.push_back(wholine);
+}
+
+CmdResult CommandWho::Handle (const std::vector<std::string>& parameters, User *user)
+{
+ /*
+ * XXX - RFC says:
+ * The <name> passed to WHO is matched against users' host, server, real
+ * name and nickname
+ * Currently, we support WHO #chan, WHO nick, WHO 0, WHO *, and the addition of a 'o' flag, as per RFC.
+ */
+
+ /* WHO options */
+ opt_viewopersonly = false;
+ opt_showrealhost = false;
+ opt_realname = false;
+ opt_mode = false;
+ opt_ident = false;
+ opt_metadata = false;
+ opt_port = false;
+ opt_away = false;
+ opt_local = false;
+ opt_far = false;
+ opt_time = false;
+
+ std::vector<std::string> whoresults;
+ std::string initial = "352 " + user->nick + " ";
+
+ /* Change '0' into '*' so the wildcard matcher can grok it */
+ std::string matchtext = ((parameters[0] == "0") ? "*" : parameters[0]);
+
+ // WHO flags count as a wildcard
+ bool usingwildcards = ((parameters.size() > 1) || (matchtext.find_first_of("*?.") != std::string::npos));
+
+ if (parameters.size() > 1)
+ {
+ for (std::string::const_iterator iter = parameters[1].begin(); iter != parameters[1].end(); ++iter)
+ {
+ switch (*iter)
+ {
+ case 'o':
+ opt_viewopersonly = true;
+ break;
+ case 'h':
+ if (user->HasPrivPermission("users/auspex"))
+ opt_showrealhost = true;
+ break;
+ case 'r':
+ opt_realname = true;
+ break;
+ case 'm':
+ if (user->HasPrivPermission("users/auspex"))
+ opt_mode = true;
+ break;
+ case 'M':
+ if (user->HasPrivPermission("users/auspex"))
+ opt_metadata = true;
+ break;
+ case 'i':
+ opt_ident = true;
+ break;
+ case 'p':
+ if (user->HasPrivPermission("users/auspex"))
+ opt_port = true;
+ break;
+ case 'a':
+ opt_away = true;
+ break;
+ case 'l':
+ if (user->HasPrivPermission("users/auspex") || ServerInstance->Config->HideWhoisServer.empty())
+ opt_local = true;
+ break;
+ case 'f':
+ if (user->HasPrivPermission("users/auspex") || ServerInstance->Config->HideWhoisServer.empty())
+ opt_far = true;
+ break;
+ case 't':
+ opt_time = true;
+ break;
+ }
+ }
+ }
+
+
+ /* who on a channel? */
+ Channel* ch = ServerInstance->FindChan(matchtext);
+
+ if (ch)
+ {
+ if (CanView(ch,user))
+ {
+ bool inside = ch->HasUser(user);
+
+ /* who on a channel. */
+ const UserMembList *cu = ch->GetUsers();
+
+ for (UserMembCIter i = cu->begin(); i != cu->end(); i++)
+ {
+ /* None of this applies if we WHO ourselves */
+ if (user != i->first)
+ {
+ /* opers only, please */
+ if (opt_viewopersonly && !i->first->IsOper())
+ continue;
+
+ /* If we're not inside the channel, hide +i users */
+ if (i->first->IsModeSet(invisiblemode) && !inside && !user->HasPrivPermission("users/auspex"))
+ continue;
+ }
+
+ SendWhoLine(user, parameters, initial, i->second, i->first, whoresults);
+ }
+ }
+ }
+ else
+ {
+ /* Match against wildcard of nick, server or host */
+ if (opt_viewopersonly)
+ {
+ /* Showing only opers */
+ const UserManager::OperList& opers = ServerInstance->Users->all_opers;
+ for (UserManager::OperList::const_iterator i = opers.begin(); i != opers.end(); ++i)
+ {
+ User* oper = *i;
+
+ if (whomatch(user, oper, matchtext.c_str()))
+ {
+ if (!user->SharesChannelWith(oper))
+ {
++ if (usingwildcards && (oper->IsModeSet(invisiblemode)) && (!user->HasPrivPermission("users/auspex")))
+ continue;
+ }
+
+ SendWhoLine(user, parameters, initial, NULL, oper, whoresults);
+ }
+ }
+ }
+ else
+ {
+ const user_hash& users = ServerInstance->Users->GetUsers();
+ for (user_hash::const_iterator i = users.begin(); i != users.end(); ++i)
+ {
+ if (whomatch(user, i->second, matchtext.c_str()))
+ {
+ if (!user->SharesChannelWith(i->second))
+ {
+ if (usingwildcards && (i->second->IsModeSet(invisiblemode)) && (!user->HasPrivPermission("users/auspex")))
+ continue;
+ }
+
+ SendWhoLine(user, parameters, initial, NULL, i->second, whoresults);
+ }
+ }
+ }
+ }
+ /* Send the results out */
+ for (std::vector<std::string>::const_iterator n = whoresults.begin(); n != whoresults.end(); n++)
+ user->WriteServ(*n);
+ user->WriteNumeric(RPL_ENDOFWHO, "%s :End of /WHO list.", *parameters[0].c_str() ? parameters[0].c_str() : "*");
+
+ // Penalize the user a bit for large queries
+ // (add one unit of penalty per 200 results)
+ if (IS_LOCAL(user))
+ IS_LOCAL(user)->CommandFloodPenalty += whoresults.size() * 5;
+ return CMD_SUCCESS;
+}
+
+COMMAND_INIT(CommandWho)
/* Set the finished argument values */
Config->cmdline.nofork = (do_nofork != 0);
Config->cmdline.forcedebug = (do_debug != 0);
- Config->cmdline.writelog = (!do_nolog != 0);
+ Config->cmdline.writelog = !do_nolog;
- Config->cmdline.TestSuite = (do_testsuite != 0);
if (do_debug)
{
return ERR_error_string(ERR_get_error(), NULL);
}
-static int error_callback(const char *str, size_t len, void *u);
+static int OnVerify(int preverify_ok, X509_STORE_CTX* ctx);
-/** Represents an SSL user's extra data
- */
-class issl_session
+namespace OpenSSL
{
-public:
- SSL* sess;
- issl_status status;
- reference<ssl_cert> cert;
-
- bool outbound;
- bool data_to_write;
-
- issl_session()
+ class Exception : public ModuleException
{
- outbound = false;
- data_to_write = false;
- }
-};
-
-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 ModuleSSLOpenSSL : public Module
-{
- issl_session* sessions;
-
- SSL_CTX* ctx;
- SSL_CTX* clictx;
+ public:
+ Exception(const std::string& reason)
+ : ModuleException(reason) { }
+ };
- std::string sslports;
- bool use_sha;
-
- ServiceProvider iohook;
- public:
-
- ModuleSSLOpenSSL() : iohook(this, "ssl/openssl", SERVICE_IOHOOK)
+ class DHParams
{
- sessions = new issl_session[ServerInstance->SE->GetMaxFds()];
+ DH* dh;
- /* Global SSL library initialization*/
- SSL_library_init();
- SSL_load_error_strings();
+ public:
+ DHParams(const std::string& filename)
+ {
+ FILE* dhpfile = fopen(filename.c_str(), "r");
+ if (dhpfile == NULL)
+ throw Exception("Couldn't open DH file " + filename + ": " + strerror(errno));
+
+ dh = PEM_read_DHparams(dhpfile, NULL, NULL, NULL);
+ fclose(dhpfile);
+ if (!dh)
+ throw Exception("Couldn't read DH params from file " + filename);
+ }
- /* Build our SSL contexts:
- * NOTE: OpenSSL makes us have two contexts, one for servers and one for clients. ICK.
- */
- ctx = SSL_CTX_new( SSLv23_server_method() );
- clictx = SSL_CTX_new( SSLv23_client_method() );
+ ~DHParams()
+ {
+ DH_free(dh);
+ }
- SSL_CTX_set_mode(ctx, SSL_MODE_ENABLE_PARTIAL_WRITE | SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER);
- SSL_CTX_set_mode(clictx, SSL_MODE_ENABLE_PARTIAL_WRITE | SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER);
+ DH* get()
+ {
+ return dh;
+ }
+ };
- SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER | SSL_VERIFY_CLIENT_ONCE, OnVerify);
- SSL_CTX_set_verify(clictx, SSL_VERIFY_PEER | SSL_VERIFY_CLIENT_ONCE, OnVerify);
+ class Context
+ {
+ SSL_CTX* const ctx;
- const unsigned char session_id[] = "inspircd";
- SSL_CTX_set_session_id_context(ctx, session_id, sizeof(session_id) - 1);
- }
+ public:
+ Context(SSL_CTX* context)
+ : ctx(context)
+ {
+ SSL_CTX_set_mode(ctx, SSL_MODE_ENABLE_PARTIAL_WRITE | SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER);
+ SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER | SSL_VERIFY_CLIENT_ONCE, OnVerify);
+
- void init()
- {
- // Needs the flag as it ignores a plain /rehash
- OnModuleRehash(NULL,"ssl");
- Implementation eventlist[] = { I_On005Numeric, I_OnRehash, I_OnModuleRehash, I_OnHookIO, I_OnUserConnect };
- ServerInstance->Modules->Attach(eventlist, this, sizeof(eventlist)/sizeof(Implementation));
- ServerInstance->Modules->AddService(iohook);
- }
++ const unsigned char session_id[] = "inspircd";
++ SSL_CTX_set_session_id_context(ctx, session_id, sizeof(session_id) - 1);
+ }
- void OnHookIO(StreamSocket* user, ListenSocket* lsb)
- {
- if (!user->GetIOHook() && lsb->bind_tag->getString("ssl") == "openssl")
+ ~Context()
{
- /* Hook the user with our module */
- user->AddIOHook(this);
+ SSL_CTX_free(ctx);
}
- }
- void OnRehash(User* user)
- {
- sslports.clear();
+ bool SetDH(DHParams& dh)
+ {
+ return (SSL_CTX_set_tmp_dh(ctx, dh.get()) >= 0);
+ }
- ConfigTag* Conf = ServerInstance->Config->ConfValue("openssl");
+ bool SetCiphers(const std::string& ciphers)
+ {
+ return SSL_CTX_set_cipher_list(ctx, ciphers.c_str());
+ }
- if (Conf->getBool("showports", true))
+ bool SetCerts(const std::string& filename)
{
- sslports = Conf->getString("advertisedports");
- if (!sslports.empty())
- return;
+ return SSL_CTX_use_certificate_chain_file(ctx, filename.c_str());
+ }
- for (size_t i = 0; i < ServerInstance->ports.size(); i++)
- {
- ListenSocket* port = ServerInstance->ports[i];
- if (port->bind_tag->getString("ssl") != "openssl")
- continue;
+ bool SetPrivateKey(const std::string& filename)
+ {
+ return SSL_CTX_use_PrivateKey_file(ctx, filename.c_str(), SSL_FILETYPE_PEM);
+ }
- const std::string& portid = port->bind_desc;
- ServerInstance->Logs->Log("m_ssl_openssl", DEFAULT, "m_ssl_openssl.so: Enabling SSL for port %s", portid.c_str());
+ bool SetCA(const std::string& filename)
+ {
+ return SSL_CTX_load_verify_locations(ctx, filename.c_str(), 0);
+ }
- if (port->bind_tag->getString("type", "clients") == "clients" && port->bind_addr != "127.0.0.1")
- {
- /*
- * Found an SSL port for clients that is not bound to 127.0.0.1 and handled by us, display
- * the IP:port in ISUPPORT.
- *
- * We used to advertise all ports seperated by a ';' char that matched the above criteria,
- * but this resulted in too long ISUPPORT lines if there were lots of ports to be displayed.
- * To solve this by default we now only display the first IP:port found and let the user
- * configure the exact value for the 005 token, if necessary.
- */
- sslports = portid;
- break;
- }
- }
+ SSL* CreateSession()
+ {
+ return SSL_new(ctx);
}
- }
+ };
- void OnModuleRehash(User* user, const std::string ¶m)
+ class Profile : public refcountbase
{
- if (param != "ssl")
- return;
+ /** Name of this profile
+ */
+ const std::string name;
- std::string keyfile;
- std::string certfile;
- std::string cafile;
- std::string dhfile;
- OnRehash(user);
+ /** DH parameters in use
+ */
+ DHParams dh;
- ConfigTag* conf = ServerInstance->Config->ConfValue("openssl");
+ /** OpenSSL makes us have two contexts, one for servers and one for clients
+ */
+ Context ctx;
+ Context clictx;
- cafile = conf->getString("cafile", CONFIG_PATH "/ca.pem");
- certfile = conf->getString("certfile", CONFIG_PATH "/cert.pem");
- keyfile = conf->getString("keyfile", CONFIG_PATH "/key.pem");
- dhfile = conf->getString("dhfile", CONFIG_PATH "/dhparams.pem");
- std::string hash = conf->getString("hash", "md5");
- if (hash != "sha1" && hash != "md5")
- throw ModuleException("Unknown hash type " + hash);
- use_sha = (hash == "sha1");
+ /** Digest to use when generating fingerprints
+ */
+ const EVP_MD* digest;
- std::string ciphers = conf->getString("ciphers", "");
+ /** Last error, set by error_callback()
+ */
+ std::string lasterr;
- if (!ciphers.empty())
+ static int error_callback(const char* str, size_t len, void* u)
{
- if ((!SSL_CTX_set_cipher_list(ctx, ciphers.c_str())) || (!SSL_CTX_set_cipher_list(clictx, ciphers.c_str())))
- {
- ServerInstance->Logs->Log("m_ssl_openssl",DEFAULT, "m_ssl_openssl.so: Can't set cipher list to %s.", ciphers.c_str());
- ERR_print_errors_cb(error_callback, this);
- }
+ Profile* profile = reinterpret_cast<Profile*>(u);
+ profile->lasterr = std::string(str, len - 1);
+ return 0;
}
- /* Load our keys and certificates
- * NOTE: OpenSSL's error logging API sucks, don't blame us for this clusterfuck.
- */
- if ((!SSL_CTX_use_certificate_chain_file(ctx, certfile.c_str())) || (!SSL_CTX_use_certificate_chain_file(clictx, certfile.c_str())))
+ public:
+ Profile(const std::string& profilename, ConfigTag* tag)
+ : name(profilename)
+ , dh(ServerInstance->Config->Paths.PrependConfig(tag->getString("dhfile", "dh.pem")))
+ , ctx(SSL_CTX_new(SSLv23_server_method()))
+ , clictx(SSL_CTX_new(SSLv23_client_method()))
{
- ServerInstance->Logs->Log("m_ssl_openssl",DEFAULT, "m_ssl_openssl.so: Can't read certificate file %s. %s", certfile.c_str(), strerror(errno));
- ERR_print_errors_cb(error_callback, this);
- }
+ if ((!ctx.SetDH(dh)) || (!clictx.SetDH(dh)))
+ throw Exception("Couldn't set DH parameters");
- if (((!SSL_CTX_use_PrivateKey_file(ctx, keyfile.c_str(), SSL_FILETYPE_PEM))) || (!SSL_CTX_use_PrivateKey_file(clictx, keyfile.c_str(), SSL_FILETYPE_PEM)))
- {
- ServerInstance->Logs->Log("m_ssl_openssl",DEFAULT, "m_ssl_openssl.so: Can't read key file %s. %s", keyfile.c_str(), strerror(errno));
- ERR_print_errors_cb(error_callback, this);
- }
+ std::string hash = tag->getString("hash", "md5");
+ digest = EVP_get_digestbyname(hash.c_str());
+ if (digest == NULL)
+ throw Exception("Unknown hash type " + hash);
- /* Load the CAs we trust*/
- if (((!SSL_CTX_load_verify_locations(ctx, cafile.c_str(), 0))) || (!SSL_CTX_load_verify_locations(clictx, cafile.c_str(), 0)))
- {
- ServerInstance->Logs->Log("m_ssl_openssl",DEFAULT, "m_ssl_openssl.so: 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", cafile.c_str(), strerror(errno));
- ERR_print_errors_cb(error_callback, this);
- }
+ 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);
+ }
+ }
- FILE* dhpfile = fopen(dhfile.c_str(), "r");
- DH* ret;
+ /* 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);
+ }
- if (dhpfile == NULL)
- {
- ServerInstance->Logs->Log("m_ssl_openssl",DEFAULT, "m_ssl_openssl.so Couldn't open DH file %s: %s", dhfile.c_str(), strerror(errno));
- throw ModuleException("Couldn't open DH file " + dhfile + ": " + strerror(errno));
- }
- else
- {
- ret = PEM_read_DHparams(dhpfile, NULL, NULL, NULL);
- if ((SSL_CTX_set_tmp_dh(ctx, ret) < 0) || (SSL_CTX_set_tmp_dh(clictx, ret) < 0))
+ 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)))
{
- ServerInstance->Logs->Log("m_ssl_openssl",DEFAULT, "m_ssl_openssl.so: Couldn't set DH parameters %s. SSL errors follow:", dhfile.c_str());
ERR_print_errors_cb(error_callback, this);
+ 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());
}
- DH_free(ret);
}
- fclose(dhpfile);
- }
+ const std::string& GetName() const { return name; }
+ SSL* CreateServerSession() { return ctx.CreateSession(); }
+ SSL* CreateClientSession() { return clictx.CreateSession(); }
+ const EVP_MD* GetDigest() { return digest; }
+ };
+}
- void On005Numeric(std::string &output)
- {
- if (!sslports.empty())
- output.append(" SSL=" + sslports);
- }
+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);
- ~ModuleSSLOpenSSL()
- {
- SSL_CTX_free(ctx);
- SSL_CTX_free(clictx);
- delete[] sessions;
- }
+ SelfSigned = (ve == X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT);
+
+ return 1;
+}
+
+class OpenSSLIOHook : public SSLIOHook
+{
+ private:
+ SSL* sess;
+ issl_status status;
+ const bool outbound;
+ bool data_to_write;
+ reference<OpenSSL::Profile> profile;
- void OnUserConnect(LocalUser* user)
+ bool Handshake(StreamSocket* user)
{
- if (user->eh.GetIOHook() == this)
+ int ret;
+
+ if (outbound)
+ ret = SSL_connect(sess);
+ else
+ ret = SSL_accept(sess);
+
+ if (ret < 0)
{
- if (sessions[user->eh.GetFd()].sess)
+ int err = SSL_get_error(sess, ret);
+
+ if (err == SSL_ERROR_WANT_READ)
{
- if (!sessions[user->eh.GetFd()].cert->fingerprint.empty())
- user->WriteServ("NOTICE %s :*** You are connected using SSL cipher \"%s\""
- " and your SSL fingerprint is %s", user->nick.c_str(), SSL_get_cipher(sessions[user->eh.GetFd()].sess), sessions[user->eh.GetFd()].cert->fingerprint.c_str());
- else
- user->WriteServ("NOTICE %s :*** You are connected using SSL cipher \"%s\"", user->nick.c_str(), SSL_get_cipher(sessions[user->eh.GetFd()].sess));
+ SocketEngine::ChangeEventMask(user, FD_WANT_POLL_READ | FD_WANT_NO_WRITE);
+ this->status = ISSL_HANDSHAKING;
+ return true;
+ }
+ else if (err == SSL_ERROR_WANT_WRITE)
+ {
+ SocketEngine::ChangeEventMask(user, FD_WANT_NO_READ | FD_WANT_SINGLE_WRITE);
+ this->status = ISSL_HANDSHAKING;
+ return true;
+ }
+ else
+ {
+ CloseSession();
}
- }
- }
- void OnCleanup(int target_type, void* item)
- {
- if (target_type == TYPE_USER)
+ return false;
+ }
+ else if (ret > 0)
{
- LocalUser* user = IS_LOCAL((User*)item);
+ // Handshake complete.
+ VerifyCertificate();
- if (user && user->eh.GetIOHook() == 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");
- }
+ status = ISSL_OPEN;
+
+ SocketEngine::ChangeEventMask(user, FD_WANT_POLL_READ | FD_WANT_NO_WRITE | FD_ADD_TRIAL_WRITE);
+
+ return true;
+ }
+ else if (ret == 0)
+ {
+ CloseSession();
+ return true;
}
- }
- Version GetVersion()
- {
- return Version("Provides SSL support for clients", VF_VENDOR);
+ return true;
}
- void OnRequest(Request& request)
+ void CloseSession()
{
- if (strcmp("GET_SSL_CERT", request.id) == 0)
+ if (sess)
{
- SocketCertificateRequest& req = static_cast<SocketCertificateRequest&>(request);
- int fd = req.sock->GetFd();
- issl_session* session = &sessions[fd];
-
- req.cert = session->cert;
+ SSL_shutdown(sess);
+ SSL_free(sess);
}
+ sess = NULL;
+ certificate = NULL;
+ status = ISSL_NONE;
+ errno = EIO;
}
- void OnStreamSocketAccept(StreamSocket* user, irc::sockets::sockaddrs* client, irc::sockets::sockaddrs* server)
+ void VerifyCertificate()
{
- int fd = user->GetFd();
-
- issl_session* session = &sessions[fd];
-
- session->sess = SSL_new(ctx);
- session->status = ISSL_NONE;
- session->outbound = false;
- session->cert = NULL;
+ X509* cert;
+ ssl_cert* certinfo = new ssl_cert;
+ this->certificate = certinfo;
+ unsigned int n;
+ unsigned char md[EVP_MAX_MD_SIZE];
- if (session->sess == NULL)
- return;
+ cert = SSL_get_peer_certificate(sess);
- if (SSL_set_fd(session->sess, fd) == 0)
+ if (!cert)
{
- ServerInstance->Logs->Log("m_ssl_openssl",DEBUG,"BUG: Can't set fd with SSL_set_fd: %d", fd);
+ certinfo->error = "Could not get peer certificate: "+std::string(get_error());
return;
}
- Handshake(user, session);
- }
-
- void OnStreamSocketConnect(StreamSocket* user)
- {
- int fd = user->GetFd();
- /* Are there any possibilities of an out of range fd? Hope not, but lets be paranoid */
- if ((fd < 0) || (fd > ServerInstance->SE->GetMaxFds() -1))
- return;
+ certinfo->invalid = (SSL_get_verify_result(sess) != X509_V_OK);
- issl_session* session = &sessions[fd];
+ if (!SelfSigned)
+ {
+ certinfo->unknownsigner = false;
+ certinfo->trusted = true;
+ }
+ else
+ {
+ certinfo->unknownsigner = true;
+ certinfo->trusted = false;
+ }
- certinfo->dn = X509_NAME_oneline(X509_get_subject_name(cert),0,0);
- certinfo->issuer = X509_NAME_oneline(X509_get_issuer_name(cert),0,0);
- session->sess = SSL_new(clictx);
- session->status = ISSL_NONE;
- session->outbound = true;
++ char buf[512];
++ X509_NAME_oneline(X509_get_subject_name(cert), buf, sizeof(buf));
++ certinfo->dn = buf;
++ X509_NAME_oneline(X509_get_issuer_name(cert), buf, sizeof(buf));
++ certinfo->issuer = buf;
- if (session->sess == NULL)
- return;
+ if (!X509_digest(cert, profile->GetDigest(), md, &n))
+ {
+ certinfo->error = "Out of memory generating fingerprint";
+ }
+ else
+ {
+ certinfo->fingerprint = BinToHex(md, n);
+ }
- if (SSL_set_fd(session->sess, fd) == 0)
+ if ((ASN1_UTCTIME_cmp_time_t(X509_get_notAfter(cert), ServerInstance->Time()) == -1) || (ASN1_UTCTIME_cmp_time_t(X509_get_notBefore(cert), ServerInstance->Time()) == 0))
{
- ServerInstance->Logs->Log("m_ssl_openssl",DEBUG,"BUG: Can't set fd with SSL_set_fd: %d", fd);
- return;
+ certinfo->error = "Not activated, or expired certificate";
}
- Handshake(user, session);
+ X509_free(cert);
}
- void OnStreamSocketClose(StreamSocket* user)
+ public:
+ OpenSSLIOHook(IOHookProvider* hookprov, StreamSocket* sock, bool is_outbound, SSL* session, const reference<OpenSSL::Profile>& sslprofile)
+ : SSLIOHook(hookprov)
+ , sess(session)
+ , status(ISSL_NONE)
+ , outbound(is_outbound)
+ , data_to_write(false)
+ , profile(sslprofile)
{
- int fd = user->GetFd();
- /* Are there any possibilities of an out of range fd? Hope not, but lets be paranoid */
- if ((fd < 0) || (fd > ServerInstance->SE->GetMaxFds() - 1))
+ if (sess == NULL)
return;
+ if (SSL_set_fd(sess, sock->GetFd()) == 0)
+ throw ModuleException("Can't set fd with SSL_set_fd: " + ConvToStr(sock->GetFd()));
- CloseSession(&sessions[fd]);
+ sock->AddIOHook(this);
+ Handshake(sock);
}
- int OnStreamSocketRead(StreamSocket* user, std::string& recvq)
+ void OnStreamSocketClose(StreamSocket* user) CXX11_OVERRIDE
{
- int fd = user->GetFd();
- /* Are there any possibilities of an out of range fd? Hope not, but lets be paranoid */
- if ((fd < 0) || (fd > ServerInstance->SE->GetMaxFds() - 1))
- return -1;
-
- issl_session* session = &sessions[fd];
+ CloseSession();
+ }
- if (!session->sess)
+ int OnStreamSocketRead(StreamSocket* user, std::string& recvq) CXX11_OVERRIDE
+ {
+ if (!sess)
{
- CloseSession(session);
+ CloseSession();
return -1;
}
}
else
{
- user->WriteNumeric(474, "%s %s :Cannot join channel (You are banned)", user->nick.c_str(), chan->name.c_str());
- user->WriteNumeric(470, "%s %s %s :You are banned from this channel, so you are automatically transferred to the redirected channel.", user->nick.c_str(), chan->name.c_str(), redir->targetchan.c_str());
+ user->WriteNumeric(ERR_BANNEDFROMCHAN, "%s :Cannot join channel (You are banned)", chan->name.c_str());
- user->WriteNumeric(470, "%s %s :You are banned from this channel, so you are automatically transfered to the redirected channel.", chan->name.c_str(), redir->targetchan.c_str());
++ user->WriteNumeric(470, "%s %s :You are banned from this channel, so you are automatically transferred to the redirected channel.", chan->name.c_str(), redir->targetchan.c_str());
nofollow = true;
- Channel::JoinUser(user, redir->targetchan.c_str(), false, "", false, ServerInstance->Time());
+ Channel::JoinUser(user, redir->targetchan);
nofollow = false;
return MOD_RES_DENY;
}
{
Module* m = ServerInstance->Modules->Find(parameters[0]);
if (m)
- ServerInstance->Modules->Reload(m, new GReloadModuleWorker(user->nick, user->uuid, parameters[0]));
+ {
+ GReloadModuleWorker* worker = NULL;
+ if (m != creator)
+ worker = new GReloadModuleWorker(user->nick, user->uuid, parameters[0]);
+ ServerInstance->Modules->Reload(m, worker);
+ }
else
{
- user->WriteNumeric(975, "%s %s :Could not find module by that name", user->nick.c_str(), parameters[0].c_str());
+ user->WriteNumeric(RPL_LOADEDMODULE, "%s :Could not find module by that name", parameters[0].c_str());
return CMD_FAILURE;
}
}
}
};
-void HideOperWatcher::AfterMode(User* source, User* dest, Channel* channel, const std::string& parameter, bool adding, ModeType type)
+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 (IS_LOCAL(dest))
+ // If hideoper is being unset because the user is deopering, don't set +y
- if (IS_LOCAL(dest) && IS_OPER(dest))
++ if (IS_LOCAL(dest) && dest->IsOper())
parentmod->SetOperPrefix(dest, !adding);
}
CmdResult Handle (const std::vector<std::string>& parameters, User *user)
{
-
+ if (parameters[0].c_str()[0] != '#')
+ {
+ User* target = ServerInstance->FindNickOnly(parameters[0]);
+ if ((!target) || (target->registered != REG_ALL))
+ {
+ user->WriteNumeric(ERR_NOSUCHNICK, "%s %s :No such nick/channel", user->nick.c_str(), parameters[0].c_str());
+ return CMD_FAILURE;
+ }
+ }
+ User* target = ServerInstance->FindNick(parameters[0]);
+ if ((target) && (target != user))
+ {
+ if (!user->HasPrivPermission("users/samode-usermodes", true))
+ return CMD_FAILURE;
+ }
this->active = true;
- ServerInstance->Parser->CallHandler("MODE", parameters, user);
+ ServerInstance->Modes->Process(parameters, user);
if (ServerInstance->Modes->GetLastParse().length())
ServerInstance->SNO->WriteGlobalSno('a', user->nick + " used SAMODE: " +ServerInstance->Modes->GetLastParse());
this->active = false;
CmdResult Handle (const std::vector<std::string>& parameters, User *user)
{
User* dest = ServerInstance->FindNick(parameters[0]);
- if ((dest) && (!IS_SERVER(dest)))
+ if ((dest) && (!IS_SERVER(dest)) && (dest->registered == REG_ALL))
{
- if (ServerInstance->ULine(dest->server))
+ if (dest->server->IsULine())
{
- user->WriteNumeric(ERR_NOPRIVILEGES, "%s :Cannot use an SA command on a u-lined client",user->nick.c_str());
+ user->WriteNumeric(ERR_NOPRIVILEGES, ":Cannot use an SA command on a u-lined client");
return CMD_FAILURE;
}
#include "inspircd.h"
-#include "socket.h"
-#include "xline.h"
-#include "socketengine.h"
-
-#include "main.h"
#include "utils.h"
-#include "treeserver.h"
-#include "treesocket.h"
+#include "commands.h"
-bool TreeSocket::Whois(const std::string &prefix, parameterlist ¶ms)
+CmdResult CommandIdle::HandleRemote(RemoteUser* issuer, std::vector<std::string>& params)
{
- if (params.size() < 1)
- return true;
- User* u = ServerInstance->FindNick(prefix);
- if (u)
+ /**
+ * 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) || (IS_SERVER(target)))
++ if ((!target) || (IS_SERVER(target) || (target->registered != REG_ALL)))
+ return CMD_FAILURE;
+
+ LocalUser* localtarget = IS_LOCAL(target);
+ if (!localtarget)
{
- // an incoming request
- if (params.size() == 1)
- {
- User* x = ServerInstance->FindNick(params[0]);
- if ((x) && (IS_LOCAL(x)))
- {
- long idle = abs((long)((x->idle_lastmsg) - ServerInstance->Time()));
- parameterlist par;
- par.push_back(prefix);
- par.push_back(ConvToStr(x->signon));
- par.push_back(ConvToStr(idle));
- // ours, we're done, pass it BACK
- Utils->DoOneToOne(params[0], "IDLE", par, u->server);
- }
- else
- {
- // not ours pass it on
- if (x)
- Utils->DoOneToOne(prefix, "IDLE", params, x->server);
- }
- }
- else if (params.size() == 3)
- {
- std::string who_did_the_whois = params[0];
- User* who_to_send_to = ServerInstance->FindNick(who_did_the_whois);
- if ((who_to_send_to) && (IS_LOCAL(who_to_send_to)) && (who_to_send_to->registered == REG_ALL))
- {
- // an incoming reply to a whois we sent out
- std::string nick_whoised = prefix;
- unsigned long signon = atoi(params[1].c_str());
- unsigned long idle = atoi(params[2].c_str());
- if ((who_to_send_to) && (IS_LOCAL(who_to_send_to)))
- {
- ServerInstance->DoWhois(who_to_send_to, u, signon, idle, nick_whoised.c_str());
- }
- }
- else
- {
- // not ours, pass it on
- if (who_to_send_to)
- Utils->DoOneToOne(prefix, "IDLE", params, who_to_send_to->server);
- }
- }
+ // Forward to target's server
+ return CMD_SUCCESS;
}
- return true;
-}
+ 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(params[0], "IDLE");
+ reply.push_back(issuer->uuid);
+ reply.push_back(ConvToStr(target->signon));
+ reply.push_back(ConvToStr(idle));
+ reply.Unicast(issuer);
+ }
+ return CMD_SUCCESS;
+}
}
User* target = ServerInstance->FindNick(nick);
- if (target)
+ if ((target) && (target->registered == REG_ALL))
{
(*wl)[nick] = std::string(target->ident).append(" ").append(target->dhost).append(" ").append(ConvToStr(target->age));
- user->WriteNumeric(604, "%s %s %s :is online",user->nick.c_str(), nick, (*wl)[nick].c_str());
- if (IS_AWAY(target))
+ user->WriteNumeric(604, "%s %s :is online", nick, (*wl)[nick].c_str());
+ if (target->IsAway())
{
- user->WriteNumeric(609, "%s %s %s %s %lu :is away", user->nick.c_str(), target->nick.c_str(), target->ident.c_str(), target->dhost.c_str(), (unsigned long) target->awaytime);
+ user->WriteNumeric(609, "%s %s %s %lu :is away", target->nick.c_str(), target->ident.c_str(), target->dhost.c_str(), (unsigned long) target->awaytime);
}
}
else
{
for (watchlist::iterator q = wl->begin(); q != wl->end(); q++)
{
- if (!q->second.empty())
+ User* targ = ServerInstance->FindNick(q->first.c_str());
+ if (targ && !q->second.empty())
{
- user->WriteNumeric(604, "%s %s %s :is online", user->nick.c_str(), q->first.c_str(), q->second.c_str());
- if (IS_AWAY(targ))
+ user->WriteNumeric(604, "%s %s :is online", q->first.c_str(), q->second.c_str());
- User *targ = ServerInstance->FindNick(q->first.c_str());
+ if (targ->IsAway())
{
- user->WriteNumeric(609, "%s %s %s %s %lu :is away", user->nick.c_str(), targ->nick.c_str(), targ->ident.c_str(), targ->dhost.c_str(), (unsigned long) targ->awaytime);
+ user->WriteNumeric(609, "%s %s %s %lu :is away", targ->nick.c_str(), targ->ident.c_str(), targ->dhost.c_str(), (unsigned long) targ->awaytime);
}
}
else
return !addr.empty();
}
- static const char all_zero[16] = {0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0 };
-
std::string irc::sockets::sockaddrs::str() const
{
- char buffer[MAXBUF];
if (sa.sa_family == AF_INET)
{
- const uint8_t* bits = reinterpret_cast<const uint8_t*>(&in4.sin_addr);
- sprintf(buffer, "%d.%d.%d.%d:%u", bits[0], bits[1], bits[2], bits[3], ntohs(in4.sin_port));
+ char ipaddr[INET_ADDRSTRLEN];
+ inet_ntop(AF_INET, &in4.sin_addr, ipaddr, sizeof(ipaddr));
+ return InspIRCd::Format("%s:%u", ipaddr, ntohs(in4.sin_port));
}
- else if (sa.sa_family == AF_INET6)
+
+ if (sa.sa_family == AF_INET6)
{
- buffer[0] = '[';
- if (!inet_ntop(AF_INET6, &in6.sin6_addr, buffer+1, MAXBUF - 10))
- return "<unknown>"; // should never happen, buffer is large enough
- int len = strlen(buffer);
- // no need for snprintf, buffer has at least 9 chars left, max short len = 5
- sprintf(buffer + len, "]:%u", ntohs(in6.sin6_port));
+ char ipaddr[INET6_ADDRSTRLEN];
+ inet_ntop(AF_INET6, &in6.sin6_addr, ipaddr, sizeof(ipaddr));
+ return InspIRCd::Format("[%s]:%u", ipaddr, ntohs(in6.sin6_port));
}
- else
- return "<unknown>";
- return std::string(buffer);
+
+ // This should never happen.
+ return "<unknown>";
}
int irc::sockets::sockaddrs::sa_size() const
}
}
-int SelectEngine::DispatchEvents()
+int SocketEngine::DispatchEvents()
{
- static timeval tval = { 1, 0 };
+ timeval tval;
+ tval.tv_sec = 1;
+ tval.tv_usec = 0;
fd_set rfdset = ReadSet, wfdset = WriteSet, errfdset = ErrSet;