From: Attila Molnar Date: Mon, 7 Apr 2014 11:40:51 +0000 (+0200) Subject: Merge insp20 X-Git-Url: https://git.netwichtig.de/gitweb/?a=commitdiff_plain;ds=inline;h=f71e6bf9cb41811f18864f5d4eecb26e29d03f25;p=user%2Fhenk%2Fcode%2Finspircd.git Merge insp20 --- f71e6bf9cb41811f18864f5d4eecb26e29d03f25 diff --cc configure index 4db9064b9,27f7e6f1e..0a91e65c5 --- a/configure +++ b/configure @@@ -253,17 -456,41 +253,17 @@@ if (defined($config{HAS_OPENSSL}) && (( $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 *** @@@ -390,56 -659,212 +390,56 @@@ EO # 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 <) { - 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 = ); - 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 = ); - 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]+/) { diff --cc docs/conf/helpop-full.conf.example index c7d672107,556d4c1a8..7b819845f --- a/docs/conf/helpop-full.conf.example +++ b/docs/conf/helpop-full.conf.example @@@ -97,17 -97,12 +97,17 @@@ Removes a user from a channel you speci channel halfoperator to remove a user. A removed user will part with a message stating they were removed from the channel and by whom."> + + + for some users."> to create macros. # +# + #-#-#-#-#-#-#-#-#-# INCLUDE CONFIGURATION #-#-#-#-#-#-#-#-#-#-#-#-#-# # # # This optional tag allows you to include another config file # @@@ -613,13 -593,12 +610,12 @@@ 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" diff --cc docs/conf/modules.conf.example index cfd55d84e,b4a5afab6..b17fd73fb --- a/docs/conf/modules.conf.example +++ b/docs/conf/modules.conf.example @@@ -385,11 -381,10 +382,11 @@@ # 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 +# #-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-# - # 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" @@@ -415,14 -410,40 +412,14 @@@ 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. # -#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-# -# Chanprotect module: Gives +q and +a channel modes. -# - - - - #-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-# - # 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. # @@@ -482,11 -498,21 +479,11 @@@ # 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. # +#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-# # # #-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-# - # 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. # # #-#-#-#-#-#-#-#-#-#-#-#- CONNJOIN CONFIGURATION -#-#-#-#-#-#-#-#-#-#-# # + # If you have m_conn_join.so loaded, you can configure it using the + # following values, or set autojoin="#chat,#help" in blocks. + # +# Join users immediately after connection to #one #two and #three. # +# Join users to #chat after 15 seconds if they aren't on any channels. +# #-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-# - # Conn-Usermodes: Set modes on users when they connect - # When this module is loaded 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 + # blocks may have an optional modes="" value, which contains modes to + # add or remove from users when they connect to the server. # #-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-# @@@ -555,25 -582,22 +558,24 @@@ # #-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-# - # 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. + # # - # 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. # + # This allows for 10 connections in an hour with a 10 minute ban if + # that is exceeded. -# ++# - # - # This allows for 10 connections in an hour with a 10 minute ban if that is exceeded. - # - # ++# 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. # # #-#-#-#-#-#-#-#-#-#-#- CONNTHROTTLE CONFIGURATION -#-#-#-#-#-#-#-#-#-# @@@ -593,14 -617,16 +595,15 @@@ # 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. # # - # 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. # @@@ -741,21 -764,13 +741,21 @@@ #-#-#-#-#-#-#-#-#-#-#- 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 # # tags. # # # -# +# + +#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-# +# 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 # +# # +# # +# # #-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-# - # 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. # @@@ -801,14 -821,12 +802,13 @@@ # #-#-#-#-#-#-#-#-#-#-#-#- 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. # -# +# # +# #-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-# - # 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. # # @@@ -838,13 -855,8 +837,13 @@@ # # +# 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. +# + #-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-# - # httpd module: Provides http server support for InspIRCd + # httpd module: Provides HTTP server support for InspIRCd. # # #-#-#-#-#-#-#-#-#-#-#-#- HTTPD CONFIGURATION -#-#-#-#-#-#-#-#-#-#-# @@@ -939,13 -950,16 +937,14 @@@ # #-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-# - # Anti-Auto-Rejoin: Adds support for prevention of auto-rejoin (+J) + # Anti auto rejoin: Adds support for prevention of auto-rejoin (+J). # -# Set the maximum time that is accepted as a parameter for +J here. -# #-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-# - # Knock module: adds the /KNOCK command and +K channel mode + # Knock module: Adds the /KNOCK command and channel mode +K. # - # 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. @@@ -954,31 -968,14 +953,31 @@@ # If set to "both" then (surprise!) both will be sent. # +#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-# +# 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 ++# 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. +# +# +# +# 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. # - # # - # # + # # # # Configuration: # # # @@@ -1030,8 -1041,11 +1029,7 @@@ #-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-# # 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. # - # # # # # # Configuration: # @@@ -1076,17 -1092,12 +1073,17 @@@ # would likely be immediately bounced by services. # +#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-# +# Modenotice module: Adds the /MODENOTICE command that allows opers to +# send notices to all users having the given user mode(s) set. +# + #-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-# - # 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. - # # # #-#-#-#-#-#-#-#-#-#-#-#- SQL CONFIGURATION -#-#-#-#-#-#-#-#-#-#-#-#-# @@@ -1258,10 -1264,10 +1250,10 @@@ # Read the comment above in # # inspircd.conf.example for details. # # # -# +# #-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-# - # Override module: Adds support for oper override + # Override module: Adds support for oper override. # This module is oper-only. # # @@@ -1412,14 -1416,8 +1402,14 @@@ # m_rline. # +#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-# +# 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. +# + #-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-# - # 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. @@@ -1459,29 -1457,9 +1449,29 @@@ #-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-# # Remove module: Adds the /REMOVE command which is a peaceful - # alternative to /KICK + # alternative to /KICK. # +#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-# +# 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 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. +# +# + #-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-# # Restricted channels module: Allows only opers to create channels. # @@@ -1521,19 -1499,11 +1511,20 @@@ # 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 [pattern] +# E.g. '/rmode #Channel b m:*' will remove all mute-extbans on the channel. +# + #-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-# - # 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. # #-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-# @@@ -1655,56 -1629,20 +1650,56 @@@ # to a server matching a mask like +b s:server.mask.here from joining. # +#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-# +# Showfile: Provides support for showing a text file to users when # +# they enter a command. # +# This module adds one command for each tag that shows the # +# given file to the user as a series of messages or numerics. # +# # +# # +#-#-#-#-#-#-#-#-#-#-# 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 " by default. # +# intronumeric - Numeric used for the introductory line. # +# numeric - Numeric used for sending the text itself. # +# endtext - Ending line, "End of " by default. # +# endnumeric - Numeric used for the ending line. # +# # +# + #-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-# - # 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. # # # 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. # + # 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 diff --cc docs/conf/opers.conf.example index b42f3129a,d03d019c6..524ebce34 --- a/docs/conf/opers.conf.example +++ b/docs/conf/opers.conf.example @@@ -24,9 -24,9 +24,10 @@@ # - 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 total channels instead of 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) # @@@ -53,16 -54,18 +55,16 @@@ # # diff --cc src/channels.cpp index c2060b90e,6c9bd7c85..4555deb96 --- a/src/channels.cpp +++ b/src/channels.cpp @@@ -648,6 -783,7 +648,7 @@@ void Channel::UserList(User *user */ 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) diff --cc src/cidr.cpp index d6370b06a,333875665..875b95304 --- a/src/cidr.cpp +++ b/src/cidr.cpp @@@ -19,27 -19,11 +19,9 @@@ */ -/* $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. diff --cc src/command_parse.cpp index 7133b3f05,1c72c7de4..d89d7cbb5 --- a/src/command_parse.cpp +++ b/src/command_parse.cpp @@@ -278,28 -309,29 +278,28 @@@ void CommandParser::ProcessCommand(Loca } 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 { diff --cc src/configreader.cpp index baeffb015,060f66d16..cda5e03e0 --- a/src/configreader.cpp +++ b/src/configreader.cpp @@@ -586,7 -743,10 +586,10 @@@ void ServerConfig::Apply(ServerConfig* 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()) { diff --cc src/coremods/core_channel/cmd_kick.cpp index 260264faf,000000000..715f35d54 mode 100644,000000..100644 --- a/src/coremods/core_channel/cmd_kick.cpp +++ b/src/coremods/core_channel/cmd_kick.cpp @@@ -1,86 -1,0 +1,86 @@@ +/* + * InspIRCd -- Internet Relay Chat Daemon + * + * Copyright (C) 2009 Daniel De Graaf + * Copyright (C) 2007 Robin Burchell + * + * This file is part of InspIRCd. InspIRCd is free software: you can + * redistribute it and/or modify it under the terms of the GNU General Public + * License as published by the Free Software Foundation, version 2. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + + +#include "inspircd.h" +#include "core_channel.h" + +CommandKick::CommandKick(Module* parent) + : Command(parent, "KICK", 2, 3) +{ + syntax = " {,} []"; +} + +/** Handle /KICK + */ +CmdResult CommandKick::Handle (const std::vector& 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]); + - if (!u || !c) ++ if ((!u) || (!c) || (u->registered != REG_ALL)) + { - user->WriteNumeric(ERR_NOSUCHNICK, "%s :No such nick/channel", u ? parameters[0].c_str() : parameters[1].c_str()); ++ 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& parameters) +{ + return (IS_LOCAL(user) ? ROUTE_LOCALONLY : ROUTE_BROADCAST); +} diff --cc src/coremods/core_channel/cmd_names.cpp index 81ada28bc,000000000..13d912376 mode 100644,000000..100644 --- a/src/coremods/core_channel/cmd_names.cpp +++ b/src/coremods/core_channel/cmd_names.cpp @@@ -1,62 -1,0 +1,57 @@@ +/* + * InspIRCd -- Internet Relay Chat Daemon + * + * Copyright (C) 2009 Daniel De Graaf + * Copyright (C) 2007 Robin Burchell + * + * This file is part of InspIRCd. InspIRCd is free software: you can + * redistribute it and/or modify it under the terms of the GNU General Public + * License as published by the Free Software Foundation, version 2. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + + +#include "inspircd.h" +#include "core_channel.h" + +CommandNames::CommandNames(Module* parent) + : Command(parent, "NAMES", 0, 0) + , secretmode(parent, "secret") +{ + syntax = "{{,}}"; +} + +/** Handle /NAMES + */ +CmdResult CommandNames::Handle (const std::vector& 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) + { - if ((c->IsModeSet(secretmode)) && (!c->HasUser(user))) - { - user->WriteNumeric(ERR_NOSUCHNICK, "%s :No such nick/channel", c->name.c_str()); - return CMD_FAILURE; - } + c->UserList(user); + } + else + { + user->WriteNumeric(ERR_NOSUCHNICK, "%s :No such nick/channel", parameters[0].c_str()); + } + + return CMD_SUCCESS; +} diff --cc src/coremods/core_ison.cpp index c7ead2a87,000000000..53d2e1c49 mode 100644,000000..100644 --- a/src/coremods/core_ison.cpp +++ b/src/coremods/core_ison.cpp @@@ -1,102 -1,0 +1,102 @@@ +/* + * InspIRCd -- Internet Relay Chat Daemon + * + * Copyright (C) 2009 Daniel De Graaf + * Copyright (C) 2007 Robin Burchell + * + * This file is part of InspIRCd. InspIRCd is free software: you can + * redistribute it and/or modify it under the terms of the GNU General Public + * License as published by the Free Software Foundation, version 2. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + + +#include "inspircd.h" + +/** Handle /ISON. + */ +class CommandIson : public Command +{ + public: + /** Constructor for ison. + */ + CommandIson ( Module* parent) : Command(parent,"ISON", 1) { + syntax = " {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& parameters, User *user); +}; + +/** Handle /ISON + */ +CmdResult CommandIson::Handle (const std::vector& parameters, User *user) +{ + std::map 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) ++ 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) diff --cc src/coremods/core_who.cpp index 2c120e562,000000000..6f4bc088e mode 100644,000000..100644 --- a/src/coremods/core_who.cpp +++ b/src/coremods/core_who.cpp @@@ -1,401 -1,0 +1,401 @@@ +/* + * InspIRCd -- Internet Relay Chat Daemon + * + * Copyright (C) 2009-2010 Daniel De Graaf + * Copyright (C) 2007-2008 Robin Burchell + * + * This file is part of InspIRCd. InspIRCd is free software: you can + * redistribute it and/or modify it under the terms of the GNU General Public + * License as published by the Free Software Foundation, version 2. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + + +#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 = "|||||0 [ohurmMiaplf]"; + } + + void SendWhoLine(User* user, const std::vector& parms, const std::string& initial, Membership* memb, User* u, std::vector& 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& 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& parms, const std::string& initial, Membership* memb, User* u, std::vector& 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& parameters, User *user) +{ + /* + * XXX - RFC says: + * The 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 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"))) ++ 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::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) diff --cc src/inspircd.cpp index 5097960e8,766aeaf8e..24072868a --- a/src/inspircd.cpp +++ b/src/inspircd.cpp @@@ -382,7 -476,8 +382,7 @@@ InspIRCd::InspIRCd(int argc, char** arg /* 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) { diff --cc src/modules/extra/m_ssl_openssl.cpp index ee024318b,9a54ff80b..7a8bdeeb0 --- a/src/modules/extra/m_ssl_openssl.cpp +++ b/src/modules/extra/m_ssl_openssl.cpp @@@ -60,346 -65,342 +60,352 @@@ char* get_error( 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 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(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 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(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& 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; } diff --cc src/modules/m_banredirect.cpp index b0be8d665,2e2592541..1a123e580 --- a/src/modules/m_banredirect.cpp +++ b/src/modules/m_banredirect.cpp @@@ -315,10 -320,10 +315,10 @@@ class ModuleBanRedirect : public Modul } 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; } diff --cc src/modules/m_globalload.cpp index b3c664cf1,9e0ec7705..8ee8472e6 --- a/src/modules/m_globalload.cpp +++ b/src/modules/m_globalload.cpp @@@ -153,10 -149,15 +153,15 @@@ class CommandGreloadmodule : public Com { 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; } } diff --cc src/modules/m_operprefix.cpp index 4fb4ae942,62ddb6c67..3bf4c8434 --- a/src/modules/m_operprefix.cpp +++ b/src/modules/m_operprefix.cpp @@@ -105,15 -160,10 +105,16 @@@ class ModuleOperPrefixMode : public Mod } }; -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); } diff --cc src/modules/m_samode.cpp index 129ad3f7b,ea2ae24ab..14f79aaf7 --- a/src/modules/m_samode.cpp +++ b/src/modules/m_samode.cpp @@@ -37,14 -39,18 +37,23 @@@ class CommandSamode : public Comman CmdResult Handle (const std::vector& 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; diff --cc src/modules/m_saquit.cpp index 3050e70d6,909a026ab..aa6aa0180 --- a/src/modules/m_saquit.cpp +++ b/src/modules/m_saquit.cpp @@@ -35,11 -37,11 +35,11 @@@ class CommandSaquit : public Comman CmdResult Handle (const std::vector& 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; } diff --cc src/modules/m_spanningtree/idle.cpp index d7c0cdf1b,0ea06a3cc..1b020701b --- a/src/modules/m_spanningtree/idle.cpp +++ b/src/modules/m_spanningtree/idle.cpp @@@ -18,53 -18,67 +18,53 @@@ #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& 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; +} diff --cc src/modules/m_watch.cpp index 6c7000a77,0e532d65b..57ca18a8f --- a/src/modules/m_watch.cpp +++ b/src/modules/m_watch.cpp @@@ -231,13 -238,13 +231,13 @@@ class CommandWatch : public Comman } 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 @@@ -308,13 -316,13 +308,13 @@@ { 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 diff --cc src/socket.cpp index ba35d2b0a,e73d01af9..4ff43cde7 --- a/src/socket.cpp +++ b/src/socket.cpp @@@ -219,26 -217,26 +219,24 @@@ bool irc::sockets::satoap(const irc::so 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(&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 ""; // 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 ""; - return std::string(buffer); + + // This should never happen. + return ""; } int irc::sockets::sockaddrs::sa_size() const diff --cc src/socketengines/socketengine_select.cpp index 79f1b3635,0b5abaf30..be4a7d186 --- a/src/socketengines/socketengine_select.cpp +++ b/src/socketengines/socketengine_select.cpp @@@ -109,9 -130,11 +109,11 @@@ void SocketEngine::OnSetEvent(EventHand } } -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;