AUTHORS | 2 +- ChangeLog | 26 ++++ Makefile.am | 2 +- NEWS | 14 ++ configure.in | 19 ++- contrib/Debian/changelog | 12 ++ contrib/Debian/ngircd.init | 4 +- contrib/MacOSX/ngIRCd.xcodeproj/project.pbxproj | 57 +++++++- contrib/Makefile.am | 2 +- contrib/README | 3 + contrib/ngircd.spec | 2 +- contrib/platformtest.sh | 143 +++++++++++++++++++ doc/Platforms.txt | 29 ++-- doc/sample-ngircd.conf | 4 + man/ngircd.conf.5.tmpl | 14 ++- src/ipaddr/ng_ipaddr.c | 11 ++- src/ipaddr/ng_ipaddr.h | 5 +- src/ngircd/Makefile.am | 4 +- src/ngircd/channel.c | 2 +- src/ngircd/client.c | 6 +- src/ngircd/conf.c | 172 +++++++++++++++-------- src/ngircd/conf.h | 13 +- src/ngircd/conn-ssl.c | 46 ++---- src/ngircd/conn.c | 160 +++++++++++++-------- src/ngircd/conn.h | 6 +- src/ngircd/hash.c | 7 +- src/ngircd/irc-info.c | 4 +- src/ngircd/irc-login.c | 1 - src/ngircd/irc-mode.c | 40 +++--- src/ngircd/irc-oper.c | 174 ++++++++++++++--------- src/ngircd/irc-server.c | 145 +++++++++++++------ src/ngircd/irc-write.c | 49 ++++++- src/ngircd/irc-write.h | 3 + src/ngircd/ngircd.c | 4 +- src/ngircd/op.c | 82 +++++++++++ src/ngircd/op.h | 22 +++ src/ngircd/parse.c | 4 +- src/ngircd/resolve.c | 9 +- src/tool/tool.c | 15 ++- 39 files changed, 964 insertions(+), 353 deletions(-) diff --git a/AUTHORS b/AUTHORS index b9e3eea..e0e1d07 100644 --- a/AUTHORS +++ b/AUTHORS @@ -19,7 +19,7 @@ directly, if possible! Main Authors ~~~~~~~~~~~~ Alexander Barton, (alex) -Florian Westphal, (fw) +Florian Westphal, Contributors diff --git a/ChangeLog b/ChangeLog index adba5f6..9b38170 100644 --- a/ChangeLog +++ b/ChangeLog @@ -10,6 +10,32 @@ -- ChangeLog -- +ngIRCd Release 15 (2009-11-07) + + - "ngircd --configtest": print SSL configuration options even when unset. + + ngIRCd 15~rc1 (2009-10-15) + - Do not add default listening port (6667) if SSL ports were specified, so + ngIRCd can be configured to only accept SSL-encrypted connections now. + - Enable IRC operators to use the IRC command SQUIT (insted of the already + implemented but non-standard DISCONNECT command). + - New configuration option "AllowRemoteOper" (disabled by default) that + enables remote IRC operators to use the IRC commands SQUIT and CONNECT + on the local server. + - Mac OS X: fix test for packagemaker(1) tool in Makefile and use gcc 4.0 + for Mac OS X 10.4 compatibility in the Xcode project file. + - Fix --with-{openssl|gnutls} to accept path names. + - Fix LSB header of Debian init script. + - Updated doc/Platforms.txt and include new script contrib/platformtest.sh + to ease generating platform reports. + - Fix connection information for already registered connections. + - Enforce upper limit on maximum number of handled commands. This implements + a throttling scheme: an IRC client can send up to 3 commands or 256 bytes + per second before a one second pause is enforced. + - Fix connection counter. + - Fix a few error handling glitches for SSL/TLS connections. + - Minor fixes to manual pages and documentation. + ngIRCd Release 14.1 (2009-05-05) - Security: fix remotely triggerable crash in SSL/TLS code. diff --git a/Makefile.am b/Makefile.am index 0fd0622..bea1cfc 100644 --- a/Makefile.am +++ b/Makefile.am @@ -56,7 +56,7 @@ deb: dpkg-buildpackage -rfakeroot -i osxpkg: have-xcodebuild - @packagemaker >/dev/null 2>&1; [ $$? -ge 1 ] \ + @packagemaker >/dev/null 2>&1; [ $$? -le 1 ] \ || ( echo; echo "Error: \"packagemaker\" not found!"; echo; exit 2) make clean ./configure --prefix=/opt/ngircd diff --git a/NEWS b/NEWS index 25494c2..5a0a9dd 100644 --- a/NEWS +++ b/NEWS @@ -10,6 +10,20 @@ -- NEWS -- +ngIRCd Release 15 (2009-11-07) + + ngIRCd 15~rc1 (2009-10-15) + - Do not add default listening port (6667) if SSL ports were specified, so + ngIRCd can be configured to only accept SSL-encrypted connections now. + - Enable IRC operators to use the IRC command SQUIT (insted of the already + implemented but non-standard DISCONNECT command). + - New configuration option "AllowRemoteOper" (disabled by default) that + enables remote IRC operators to use the IRC commands SQUIT and CONNECT + on the local server. + - Enforce upper limit on maximum number of handled commands. This implements + a throttling scheme: an IRC client can send up to 3 commands or 256 bytes + per second before a one second pause is enforced. + ngIRCd Release 14.1 (2009-05-05) - Security: fix remotely triggerable crash in SSL/TLS code. diff --git a/configure.in b/configure.in index 6738dd6..3d4c640 100644 --- a/configure.in +++ b/configure.in @@ -1,6 +1,6 @@ # # ngIRCd -- The Next Generation IRC Daemon -# Copyright (c)2001-2008 Alexander Barton +# Copyright (c)2001-2009 Alexander Barton # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by @@ -12,12 +12,14 @@ # -- Initialisation -- AC_PREREQ(2.50) -AC_INIT(ngircd, 14.1) +AC_INIT(ngircd, 15) AC_CONFIG_SRCDIR(src/ngircd/ngircd.c) AC_CANONICAL_TARGET AM_INIT_AUTOMAKE(1.6) AM_CONFIG_HEADER(src/config.h) +m4_ifdef([AM_SILENT_RULES], [AM_SILENT_RULES([yes])]) + # -- Templates for config.h -- AH_TEMPLATE([DEBUG], [Define if debug-mode should be enabled]) @@ -31,6 +33,7 @@ AH_TEMPLATE([IRCPLUS], [Define if IRC+ protocol should be used]) AH_TEMPLATE([WANT_IPV6], [Define if IPV6 protocol should be enabled]) AH_TEMPLATE([ZEROCONF], [Define if support for Zeroconf should be included]) AH_TEMPLATE([IDENTAUTH], [Define if the server should do IDENT requests]) +AH_TEMPLATE([HAVE_sockaddr_in_len], [Define if sockaddr_in.sin_len exists]) AH_TEMPLATE([TARGET_OS], [Target operating system name]) AH_TEMPLATE([TARGET_VENDOR], [Target system vendor]) @@ -71,7 +74,6 @@ AC_DEFUN([GCC_STACK_PROTECT_CC],[ fi ]) - if test "$GCC" = "yes"; then # We are using the GNU C compiler. Good! CFLAGS="$CFLAGS -pipe -W -Wall -Wpointer-arith -Wstrict-prototypes" @@ -123,6 +125,8 @@ AC_TRY_COMPILE([ AC_TYPE_SIGNAL AC_TYPE_SIZE_T +AC_CHECK_MEMBER([struct sockaddr_in.sin_len], AC_DEFINE(HAVE_sockaddr_in_len),, + [#include ]) # -- Libraries -- @@ -139,7 +143,8 @@ AC_CHECK_FUNCS([ \ bind gethostbyaddr gethostbyname gethostname inet_ntoa \ setsid setsockopt socket strcasecmp waitpid],,AC_MSG_ERROR([required function missing!])) -AC_CHECK_FUNCS(inet_aton isdigit sigaction snprintf vsnprintf strdup strlcpy strlcat strtok_r) +AC_CHECK_FUNCS(getaddrinfo getnameinfo inet_aton isdigit sigaction snprintf \ + vsnprintf strdup strlcpy strlcat strtok_r) # -- Configuration options -- @@ -313,7 +318,7 @@ fi AC_ARG_WITH(openssl, [ --with-openssl enable SSL support using OpenSSL], - [ if test "$withval" = "yes"; then + [ if test "$withval" != "no"; then if test "$withval" != "yes"; then CFLAGS="-I$withval/include $CFLAGS" CPPFLAGS="-I$withval/include $CPPFLAGS" @@ -330,7 +335,7 @@ AC_ARG_WITH(openssl, AC_ARG_WITH(gnutls, [ --with-gnutls enable SSL support using gnutls], - [ if test "$withval" = "yes"; then + [ if test "$withval" != "no"; then if test "$withval" != "yes"; then CFLAGS="-I$withval/include $CFLAGS" CPPFLAGS="-I$withval/include $CPPFLAGS" @@ -477,6 +482,8 @@ AC_ARG_ENABLE(ipv6, if test "$enableval" = "yes"; then x_ipv6_on=yes; fi ) if test "$x_ipv6_on" = "yes"; then + # getaddrinfo() and getnameinfo() are optional when not compiling + # with IPv6 support, but are required for IPv6 to work! AC_CHECK_FUNCS([ \ getaddrinfo getnameinfo \ ],,AC_MSG_ERROR([required function missing for IPv6 support!])) diff --git a/contrib/Debian/changelog b/contrib/Debian/changelog index abfad7f..0f76b3d 100644 --- a/contrib/Debian/changelog +++ b/contrib/Debian/changelog @@ -1,3 +1,15 @@ +ngircd (15-0ab1) unstable; urgency=low + + * New "upstream" release: ngIRCd 15. + + -- Alexander Barton Thu, 7 Nov 2009 12:07:08 +0200 + +ngircd (15~rc1-0ab1) unstable; urgency=low + + * New "upstream" release candidate 1 for ngIRCd Release 15. + + -- Alexander Barton Thu, 15 Oct 2009 10:01:08 +0200 + ngircd (14.1-0ab1) unstable; urgency=high * New "upstream" release ngIRCd 14.1, fixing a security-related bug. diff --git a/contrib/Debian/ngircd.init b/contrib/Debian/ngircd.init index f308dd2..e550747 100755 --- a/contrib/Debian/ngircd.init +++ b/contrib/Debian/ngircd.init @@ -5,8 +5,8 @@ # ### BEGIN INIT INFO -# Provides: ngircd ircd -# Required-Start: $network $local_fs +# Provides: ngircd +# Required-Start: $network $remote_fs # Required-Stop: # Should-Start: $syslog $named # Should-Stop: $syslog diff --git a/contrib/MacOSX/ngIRCd.xcodeproj/project.pbxproj b/contrib/MacOSX/ngIRCd.xcodeproj/project.pbxproj index 2d65649..a7cc74f 100644 --- a/contrib/MacOSX/ngIRCd.xcodeproj/project.pbxproj +++ b/contrib/MacOSX/ngIRCd.xcodeproj/project.pbxproj @@ -35,6 +35,7 @@ FA322DBE0CEF7766001761B3 /* tool.c in Sources */ = {isa = PBXBuildFile; fileRef = FA322D330CEF74B1001761B3 /* tool.c */; }; FA322DC10CEF77CB001761B3 /* libz.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = FA322DC00CEF77CB001761B3 /* libz.dylib */; }; FA407F2E0DB159F400271AF1 /* ng_ipaddr.c in Sources */ = {isa = PBXBuildFile; fileRef = FA407F2C0DB159F400271AF1 /* ng_ipaddr.c */; }; + FA85178C0FA061EC006A1F5A /* op.c in Sources */ = {isa = PBXBuildFile; fileRef = FA85178B0FA061EC006A1F5A /* op.c */; }; FAA3D27B0F139CDC00B2447E /* conn-ssl.c in Sources */ = {isa = PBXBuildFile; fileRef = FAA3D2790F139CDC00B2447E /* conn-ssl.c */; }; FAE5CC2E0CF2308A007D69B6 /* numeric.c in Sources */ = {isa = PBXBuildFile; fileRef = FAE5CC2D0CF2308A007D69B6 /* numeric.c */; }; /* End PBXBuildFile section */ @@ -193,6 +194,8 @@ FA407F2C0DB159F400271AF1 /* ng_ipaddr.c */ = {isa = PBXFileReference; fileEncoding = 5; lastKnownFileType = sourcecode.c.c; name = ng_ipaddr.c; path = ipaddr/ng_ipaddr.c; sourceTree = ""; }; FA407F2D0DB159F400271AF1 /* ng_ipaddr.h */ = {isa = PBXFileReference; fileEncoding = 5; lastKnownFileType = sourcecode.c.h; name = ng_ipaddr.h; path = ipaddr/ng_ipaddr.h; sourceTree = ""; }; FA407F380DB15AC700271AF1 /* GIT.txt */ = {isa = PBXFileReference; fileEncoding = 5; lastKnownFileType = text; path = GIT.txt; sourceTree = ""; }; + FA85178A0FA061EC006A1F5A /* op.h */ = {isa = PBXFileReference; fileEncoding = 5; lastKnownFileType = sourcecode.c.h; path = op.h; sourceTree = ""; }; + FA85178B0FA061EC006A1F5A /* op.c */ = {isa = PBXFileReference; fileEncoding = 5; lastKnownFileType = sourcecode.c.c; path = op.c; sourceTree = ""; }; FAA3D2700F139CB300B2447E /* invite-test.e */ = {isa = PBXFileReference; fileEncoding = 5; lastKnownFileType = text; path = "invite-test.e"; sourceTree = ""; }; FAA3D2710F139CB300B2447E /* join-test.e */ = {isa = PBXFileReference; fileEncoding = 5; lastKnownFileType = text; path = "join-test.e"; sourceTree = ""; }; FAA3D2720F139CB300B2447E /* kick-test.e */ = {isa = PBXFileReference; fileEncoding = 5; lastKnownFileType = text; path = "kick-test.e"; sourceTree = ""; }; @@ -332,6 +335,8 @@ FA322D070CEF74B1001761B3 /* ngircd.h */, FAE5CC2D0CF2308A007D69B6 /* numeric.c */, FAE5CC2C0CF2308A007D69B6 /* numeric.h */, + FA85178A0FA061EC006A1F5A /* op.h */, + FA85178B0FA061EC006A1F5A /* op.c */, FA322D080CEF74B1001761B3 /* parse.c */, FA322D090CEF74B1001761B3 /* parse.h */, FA322D0A0CEF74B1001761B3 /* rendezvous.c */, @@ -676,6 +681,7 @@ FAE5CC2E0CF2308A007D69B6 /* numeric.c in Sources */, FA407F2E0DB159F400271AF1 /* ng_ipaddr.c in Sources */, FAA3D27B0F139CDC00B2447E /* conn-ssl.c in Sources */, + FA85178C0FA061EC006A1F5A /* op.c in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -712,10 +718,9 @@ 1DEB928B08733DD80010E9CD /* Default */ = { isa = XCBuildConfiguration; buildSettings = { - ARCHS = ( - ppc, - i386, - ); + ARCHS = "$(ARCHS_STANDARD_32_64_BIT_PRE_XCODE_3_1)"; + ARCHS_STANDARD_32_64_BIT_PRE_XCODE_3_1 = "x86_64 i386 ppc"; + GCC_VERSION = 4.0; GCC_WARN_ABOUT_RETURN_TYPE = YES; GCC_WARN_UNUSED_VARIABLE = YES; PREBINDING = NO; @@ -723,6 +728,48 @@ }; name = Default; }; + FAB0570C105D917F006AF9E2 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ARCHS = "$(ARCHS_STANDARD_32_64_BIT_PRE_XCODE_3_1)"; + ARCHS_STANDARD_32_64_BIT_PRE_XCODE_3_1 = "x86_64 i386 ppc"; + GCC_DEBUGGING_SYMBOLS = full; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_VERSION = 4.0; + GCC_WARN_ABOUT_RETURN_TYPE = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + PREBINDING = NO; + SDKROOT = "$(DEVELOPER_SDK_DIR)/MacOSX10.4u.sdk"; + }; + name = Debug; + }; + FAB0570D105D917F006AF9E2 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + GCC_TREAT_IMPLICIT_FUNCTION_DECLARATIONS_AS_ERRORS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_MISSING_NEWLINE = YES; + GCC_WARN_ABOUT_MISSING_PROTOTYPES = YES; + GCC_WARN_CHECK_SWITCH_STATEMENTS = YES; + GCC_WARN_FOUR_CHARACTER_CONSTANTS = YES; + GCC_WARN_INITIALIZER_NOT_FULLY_BRACKETED = YES; + GCC_WARN_MISSING_PARENTHESES = YES; + GCC_WARN_PEDANTIC = YES; + GCC_WARN_SHADOW = YES; + GCC_WARN_SIGN_COMPARE = YES; + GCC_WARN_TYPECHECK_CALLS_TO_PRINTF = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES; + GCC_WARN_UNKNOWN_PRAGMAS = YES; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_LABEL = YES; + GCC_WARN_UNUSED_PARAMETER = YES; + GCC_WARN_UNUSED_VALUE = YES; + INSTALL_PATH = /usr/local/bin; + PRODUCT_NAME = ngIRCd; + SDKROOT = "$(DEVELOPER_SDK_DIR)/MacOSX10.4u.sdk"; + }; + name = Debug; + }; /* End XCBuildConfiguration section */ /* Begin XCConfigurationList section */ @@ -730,6 +777,7 @@ isa = XCConfigurationList; buildConfigurations = ( 1DEB928708733DD80010E9CD /* Default */, + FAB0570D105D917F006AF9E2 /* Debug */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Default; @@ -738,6 +786,7 @@ isa = XCConfigurationList; buildConfigurations = ( 1DEB928B08733DD80010E9CD /* Default */, + FAB0570C105D917F006AF9E2 /* Debug */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Default; diff --git a/contrib/Makefile.am b/contrib/Makefile.am index ab6b342..10cbf78 100644 --- a/contrib/Makefile.am +++ b/contrib/Makefile.am @@ -12,7 +12,7 @@ SUBDIRS = Debian MacOSX EXTRA_DIST = README ngircd.spec systrace.policy ngindent ngircd-bsd.sh \ - ngircd-redhat.init + ngircd-redhat.init platformtest.sh maintainer-clean-local: rm -f Makefile Makefile.in diff --git a/contrib/README b/contrib/README index 353e2bb..6593fdd 100644 --- a/contrib/README +++ b/contrib/README @@ -28,5 +28,8 @@ ngircd-redhat.init ngircd.spec - RPM "spec" file. +platformtest.sh + - Build ngIRCd and output a "result line" suitable for doc/Platforms.txt. + systrace.policy - Systrace policy file for OpenBSD (and probably NetBSD). diff --git a/contrib/ngircd.spec b/contrib/ngircd.spec index 1e72f30..bce620a 100644 --- a/contrib/ngircd.spec +++ b/contrib/ngircd.spec @@ -1,5 +1,5 @@ %define name ngircd -%define version 14.1 +%define version 15 %define release 1 %define prefix %{_prefix} diff --git a/contrib/platformtest.sh b/contrib/platformtest.sh new file mode 100755 index 0000000..aee7f29 --- /dev/null +++ b/contrib/platformtest.sh @@ -0,0 +1,143 @@ +#!/bin/sh +# +# ngIRCd -- The Next Generation IRC Daemon +# Copyright (c)2001-2009 Alexander Barton +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# Please read the file COPYING, README and AUTHORS for more information. +# + +# This script analyzes the build process of ngIRCd and generates output +# suitable for inclusion in doc/Platforms.txt -- please send reports +# to the ngIRCd mailing list: . + +NAME=`basename "$0"` +VERBOSE= + +PLATFORM= +COMPILER="unknown" +VERSION="unknown" +DATE=`date "+%y-%m-%d"` + +CONFIGURE= +MAKE= +CHECK= +RUN= +COMMENT= + +while [ $# -gt 0 ]; do + case "$1" in + "-v") + VERBOSE=1 + ;; + *) + echo "Usage: $NAME [-v]" + exit 2 + esac + shift +done + +echo "$NAME: Checking ngIRCd base source directory ..." +grep "ngIRCd" ./ChangeLog >/dev/null 2>&1 +if [ $? -ne 0 ]; then + grep "ngIRCd" ../ChangeLog >/dev/null 2>&1 + if [ $? -ne 0 ]; then + echo "$NAME: ngIRCd base source directory not found!?" + exit 1 + fi + cd .. +fi + +echo "$NAME: Checking for ./configure script ..." +if [ ! -e ./configure ]; then + echo "$NAME: Not found. Running ./autogen.sh ..." + [ -n "$VERBOSE" ] && ./autogen.sh || ./autogen.sh >/dev/null +fi + +if [ -e ./configure ]; then + echo "$NAME: Running \"./configure\" script ..." + [ -n "$VERBOSE" ] && ./configure || ./configure >/dev/null + if [ $? -eq 0 -a -e ./Makefile ]; then + CONFIGURE=1 + echo "$NAME: Running \"make\" ..." + [ -n "$VERBOSE" ] && make || make >/dev/null + if [ $? -eq 0 -a -x src/ngircd/ngircd ]; then + MAKE=1 + echo "$NAME: Running \"make check\" ..." + [ -n "$VERBOSE" ] && make check || make check >/dev/null + if [ $? -eq 0 ]; then + CHECK=1 + RUN=$CHECK + else + ./src/ngircd/ngircd --help 2>/dev/null \ + | grep "^ngircd" >/dev/null + [ $? -eq 0 ] && RUN=1 + fi + fi + fi +fi + +# Get target platform information +if [ -r "src/config.h" ]; then + CPU=`grep "TARGET_CPU" "src/config.h" | cut -d'"' -f2` + OS=`grep "TARGET_OS" "src/config.h" | cut -d'"' -f2` + VENDOR=`grep "TARGET_VENDOR" "src/config.h" | cut -d'"' -f2` + PLATFORM="$CPU/$VENDOR/$OS" +fi +if [ -z "$PLATFORM" ]; then + PLATFORM="`uname 2>/dev/null` `uname -r 2>/dev/null`, `uname -m 2>/dev/null`" +fi + +# Get compiler information +if [ -r "Makefile" ]; then + eval $(grep "^CC = " Makefile | sed -e 's/ //g') + $CC --version 2>&1 | grep -i "GCC" >/dev/null + if [ $? -eq 0 ]; then + COMPILER=$($CC --version | head -n 1 | awk "{ print \$3 }" \ + | cut -d'-' -f1) + COMPILER="gcc $COMPILER" + fi +fi + +# Get ngIRCd version information +if [ -d ".git" ]; then + VERSION=`git log --abbrev-commit --pretty=oneline HEAD~1.. \ + | cut -d' ' -f1 | tr -d '.'` +elif [ -r "Makefile" ]; then + eval $(grep "^VERSION = " Makefile | sed -e 's/ //g') +fi +[ -n "$VERSION" ] || VERSION="unknown" + +# Get IO interface information +if [ "$OS" = "linux-gnu" ]; then + COMMENT="(1)" +else + grep "^#define HAVE_SYS_DEVPOLL_H 1" src/config.h >/dev/null 2>&1 + [ $? -eq 0 ] && COMMENT="(4)" + grep "^#define HAVE_EPOLL_CREATE 1" src/config.h >/dev/null 2>&1 + [ $? -eq 0 ] && COMMENT="(5)" + grep "^#define HAVE_KQUEUE 1" src/config.h >/dev/null 2>&1 + [ $? -eq 0 ] && COMMENT="(3)" +fi + +[ -n "$CONFIGURE" ] && C="Y" || C="N" +[ -n "$MAKE" ] && M="Y" || M="N" +[ -n "$CHECK" ] && T="Y" || T="N" +[ -n "$RUN" ] && R="Y" || R="N" +[ -n "$COMMENT" ] && COMMENT=" $COMMENT" + +echo +echo " the executable works (\"runs\") as expected --+" +echo " tests run successfully (\"make check\") --+ |" +echo " ngIRCd compiles (\"make\") --+ | |" +echo " ./configure works --+ | | |" +echo " | | | |" +echo "Platform Compiler ngIRCd Date Tester C M T R See" +echo "--------------------------- ------------ ---------- -------- ------ - - - - ---" +printf "%-27s %-12s %-10s %s %-6s %s %s %s %s%s" \ + "$PLATFORM" "$COMPILER" "$VERSION" "$DATE" "$USER" \ + "$C" "$M" "$T" "$R" "$COMMENT" +echo; echo diff --git a/doc/Platforms.txt b/doc/Platforms.txt index a77cc88..8a1282e 100644 --- a/doc/Platforms.txt +++ b/doc/Platforms.txt @@ -1,7 +1,7 @@ ngIRCd - Next Generation IRC Server - (c)2001-2008 Alexander Barton + (c)2001-2009 Alexander Barton alex@barton.de, http://www.barton.de/ ngIRCd is free software and published under the @@ -30,26 +30,29 @@ alpha/unknown/netbsd3.0 gcc 3.3.3 CVSHEAD 06-05-07 fw Y Y Y Y (3) hppa/unknown/openbsd3.5 gcc 2.95.3 CVSHEAD 04-05-25 alex Y Y Y Y hppa1.1/unknown/linux-gnu gcc 3.3.3 0.8.0 04-05-30 alex Y Y Y Y hppa2.0/unknown/linux-gnu gcc 3.3.5 13~rc1 08-12-02 alex Y Y Y Y -i386/apple/darwin9.5.1 gcc 4.0.1 13~rc1 08-12-02 alex Y Y Y Y (3) +hppa2.0w-hp-hpux11.11 gcc 4.2.3 14.1 09-07-22 goetz Y Y Y Y +i386/apple/darwin9.7.0 gcc 4.0.1 14.1 09-08-04 alex Y Y Y Y (3) +i386/apple/darwin10.0.0b2 gcc 4.2.1 14.1 09-07-27 alex Y Y Y Y (3) i386/pc/solaris2.9 gcc 3.2.2 CVSHEAD 04-02-24 alex Y Y Y Y -i386/pc/solaris2.11 gcc 3.4.3 13~rc1 08-12-03 alex Y Y Y Y (4) +i386/pc/solaris2.11 gcc 3.4.3 14.1 09-08-03 alex Y Y Y Y (4) i386/unknown/freebsd5.2.1 gcc 3.3.3 0.8.0 04-05-30 alex Y Y Y Y i386/unknown/freebsd6.0 gcc 3.4.4 0.10.0-p1 06-08-04 alex Y Y Y Y (3) i386/unknown/freebsd6.1 gcc 3.4.4 CVSHEAD 06-05-07 fw Y Y Y Y (3) -i386/unknown/freebsd6.2 gcc 3.4.6 13~rc1 08-12-04 alex Y Y Y Y (3) -i386/unknown/freebsd7.0 gcc 4.2.1 13~rc1 08-12-04 alex Y Y Y Y (3) +i386/unknown/freebsd6.2 gcc 3.4.6 14.1 09-07-27 alex Y Y Y Y (3) +i386/unknown/freebsd7.0 gcc 4.2.1 14.1 09-07-28 alex Y Y Y Y (3) +i386/unknown/freebsd7.2 gcc 4.2.1 14.1 09-08-03 alex Y Y Y Y (3) i386/unknown/gnu0.3 gcc 3.3.3 0.8.0 04-05-30 alex Y Y n Y -i686/unknown/gnu0.3 gcc 4.3.1 13~rc1 08-12-05 alex Y Y Y Y +i686/unknown/gnu0.3 gcc 4.3.1 14.1 09-07-28 alex Y Y Y Y i386/unknown/netbsdelf1.6.1 gcc 2.95.3 CVSHEAD 04-02-24 alex Y Y Y Y i386/unknown/netbsdelf3.0.1 gcc 3.3.3 0.10.0-p1 06-08-30 alex Y Y Y Y (3) -i386/unknown/netbsdelf4.0 gcc 4.1.2 13~rc1 08-12-05 alex Y Y Y Y (3) +i386/unknown/netbsdelf4.0 gcc 4.1.2 14.1 09-07-28 alex Y Y Y Y (3) i386/unknown/openbsd3.9 gcc 3.3.5 0.10.0-p1 06-08-30 alex Y Y Y Y (3) -i386/unknown/openbsd4.1 gcc 3.3.5 13~rc1 08-12-05 alex Y Y Y Y (3) +i386/unknown/openbsd4.1 gcc 3.3.5 14.1 09-07-28 alex Y Y Y Y (3) i686/pc/cygwin gcc 3.3.1 0.8.0 04-05-30 alex Y Y n Y i686/pc/linux-gnu gcc 2.95.4 0.8.0 04-05-30 alex Y Y Y Y (1) -i686/pc/linux-gnu gcc 3.3.5 13~rc1 08-12-05 alex Y Y Y Y (1) +i686/pc/linux-gnu gcc 3.3.5 14.1 09-08-04 alex Y Y Y Y (1) i386/pc/linux-gnu gcc 4.1.2 13~rc1 08-12-05 alex Y Y Y Y (1) -i386/pc/linux-gnu gcc 4.3.2 13~rc1 08-12-05 alex Y Y Y Y (1) +i686/pc/linux-gnu gcc 4.3.2 14.1 09-08-04 alex Y Y Y Y (1) m68k/apple/aux3.1.1 Orig. A/UX 0.7.x-CVS 03-04-22 alex Y Y Y Y (2) m68k/hp/hp-ux9.10 Orig. HPUX 0.7.x-CVS 03-04-30 goetz Y Y Y Y m88k/dg/dgux5.4R3.10 gcc 2.5.8 CVSHEAD 04-03-15 alex Y Y ? ? @@ -62,19 +65,19 @@ powerpc/unknown/openbsd3.6 gcc 2.95.3 0.10.0 06-10-08 alex Y Y n Y sparc/sun/solaris2.6 gcc 2.95.3 0.7.x-CVS 03-04-22 alex Y Y Y Y sparc/sun/solaris2.7 gcc 3.3 0.8.0 04-05-30 alex Y Y Y Y sparc/unkn./netbsdelf1.6.1 gcc 2.95.3 0.8.0 04-05-30 alex Y Y Y Y -x86_64/unknown/linux-gnu 4.3.2 13~rc1 08-12-05 alex Y Y Y Y (5) +x86_64/unknown/linux-gnu gcc 4.3.2 14.1 09-08-04 alex Y Y Y Y (1) Notes ~~~~~ -(1) i686/pc/linux-gnu: +(1) i686/pc/linux-gnu & x86_64/unknown/linux-gnu: ngIRCd has been tested with various Linux distributions, such as SuSE, RedHat, Debian, and Gentoo using Kernels 2.2.x, 2.4.x and 2.6.x with various versions of the GNU C compiler (starting with 2.95.x and up to version 4.3.x). The eldest glibc used was glibc-2.0.7. ngIRCd compiled and run on all these systems without problems. - Actual Linux kernels (2.6.x) and glic's support the epoll() IO interface. + Actual Linux kernels (2.6.x) and glibc's support the epoll() IO interface. (2) This compiler is an pre-ANSI C compiler, therefore the source code is automatically converted using the included ansi2knr tool while building. diff --git a/doc/sample-ngircd.conf b/doc/sample-ngircd.conf index 0d0061b..b945224 100644 --- a/doc/sample-ngircd.conf +++ b/doc/sample-ngircd.conf @@ -115,6 +115,10 @@ # server? (This is a compatibility hack for ircd-irc2 servers) ;OperServerMode = no + # Are remote IRC operators allowed to control this server, e. g. + # use commands like CONNECT, SQUIT, DIE, ...? + ;AllowRemoteOper = no + # Allow Pre-Defined Channels only (see Section [Channels]) ;PredefChannelsOnly = no diff --git a/man/ngircd.conf.5.tmpl b/man/ngircd.conf.5.tmpl index df15b77..d9e6f46 100644 --- a/man/ngircd.conf.5.tmpl +++ b/man/ngircd.conf.5.tmpl @@ -75,7 +75,8 @@ command. .TP \fBPorts\fR Ports on which the server should listen. There may be more than one port, -separated with commas (","). Default: 6667. +separated with commas (","). Default: 6667, unless \fBSSL_Ports\fR are also +specified. .TP \fBSSLPorts\fR Same as \fBPorts\fR , except that ngIRCd will expect incoming connections @@ -178,6 +179,11 @@ If \fBOperCanUseMode\fR is enabled, this may lead the compatibility problems wit Servers that run the ircd-irc2 Software. This Option "masks" mode requests by non-chanops as if they were coming from the server. Default: no. .TP +\fBAllowRemoteOper\fR +Are IRC operators connected to remote servers allowed to control this server, +e. g. are they allowed to use administrative commands like CONNECT, DIE, +SQUIT, ... that affect this server? Default: no. +.TP \fBPredefChannelsOnly\fR If enabled, no new channels can be created. Useful if you do not want to have channels other than those defined in @@ -221,9 +227,6 @@ Default: 10. Maximum length of an user nick name (Default: 9, as in RFC 2812). Please note that all servers in an IRC network MUST use the same maximum nick name length! -.TP -\fBSSLConnect\fR -Connect to the remote server using TLS/SSL. Default: false. .SH [OPERATOR] .I [Operator] sections are used to define IRC Operators. There may be more than one @@ -287,6 +290,9 @@ Group of this server (optional). Disable automatic connection even if port value is specified. Default: false. You can use the IRC Operator command CONNECT later on to create the link. .TP +\fBSSLConnect\fR +Connect to the remote server using TLS/SSL. Default: false. +.TP \fBServiceMask\fR Define a (case insensitive) mask matching nick names that should be treated as IRC services when introduced via this remote server. REGULAR SERVERS DON'T NEED diff --git a/src/ipaddr/ng_ipaddr.c b/src/ipaddr/ng_ipaddr.c index b412cc8..af524d0 100644 --- a/src/ipaddr/ng_ipaddr.c +++ b/src/ipaddr/ng_ipaddr.c @@ -30,6 +30,9 @@ ng_ipaddr_init(ng_ipaddr_t *addr, const char *ip_str, UINT16 port) memset(&hints, 0, sizeof(hints)); hints.ai_flags = AI_NUMERICHOST; +#ifndef WANT_IPV6 /* do not convert ipv6 addresses */ + hints.ai_family = AF_INET; +#endif /* some getaddrinfo implementations require that ai_socktype is set. */ hints.ai_socktype = SOCK_STREAM; @@ -38,7 +41,6 @@ ng_ipaddr_init(ng_ipaddr_t *addr, const char *ip_str, UINT16 port) snprintf(portstr, sizeof(portstr), "%u", (unsigned int) port); ret = getaddrinfo(ip_str, portstr, &hints, &res0); - assert(ret == 0); if (ret != 0) return false; @@ -51,6 +53,10 @@ ng_ipaddr_init(ng_ipaddr_t *addr, const char *ip_str, UINT16 port) return ret == 0; #else /* HAVE_GETADDRINFO */ assert(ip_str); + memset(addr, 0, sizeof *addr); +#ifdef HAVE_sockaddr_in_len + addr->sin4.sin_len = sizeof(addr->sin4); +#endif addr->sin4.sin_family = AF_INET; # ifdef HAVE_INET_ATON if (inet_aton(ip_str, &addr->sin4.sin_addr) == 0) @@ -151,7 +157,8 @@ ng_ipaddr_tostr_r(const ng_ipaddr_t *addr, char *str) if (*str == ':') { char tmp[NG_INET_ADDRSTRLEN] = "0"; ret = getnameinfo(sa, ng_ipaddr_salen(addr), - tmp+1, sizeof(tmp) -1, NULL, 0, NI_NUMERICHOST); + tmp + 1, (socklen_t)sizeof(tmp) - 1, + NULL, 0, NI_NUMERICHOST); if (ret == 0) strlcpy(str, tmp, NG_INET_ADDRSTRLEN); } diff --git a/src/ipaddr/ng_ipaddr.h b/src/ipaddr/ng_ipaddr.h index 6490a07..32b1ec0 100644 --- a/src/ipaddr/ng_ipaddr.h +++ b/src/ipaddr/ng_ipaddr.h @@ -58,10 +58,10 @@ ng_ipaddr_salen(const ng_ipaddr_t *a) #ifdef WANT_IPV6 assert(a->sa.sa_family == AF_INET || a->sa.sa_family == AF_INET6); if (a->sa.sa_family == AF_INET6) - return sizeof(a->sin6); + return (socklen_t)sizeof(a->sin6); #endif assert(a->sin4.sin_family == AF_INET); - return sizeof(a->sin4); + return (socklen_t)sizeof(a->sin4); } @@ -115,4 +115,3 @@ ng_ipaddr_tostr_r(const ng_ipaddr_t *addr, char *d) #endif /* -eof- */ - diff --git a/src/ngircd/Makefile.am b/src/ngircd/Makefile.am index fca531d..f94f8d9 100644 --- a/src/ngircd/Makefile.am +++ b/src/ngircd/Makefile.am @@ -23,7 +23,7 @@ sbin_PROGRAMS = ngircd ngircd_SOURCES = ngircd.c array.c channel.c client.c conf.c conn.c conn-func.c \ conn-ssl.c conn-zip.c hash.c io.c irc.c irc-channel.c irc-info.c irc-login.c \ irc-mode.c irc-op.c irc-oper.c irc-server.c irc-write.c lists.c log.c \ - match.c numeric.c parse.c rendezvous.c resolve.c + match.c op.c numeric.c parse.c rendezvous.c resolve.c ngircd_LDFLAGS = -L../portab -L../tool -L../ipaddr @@ -32,7 +32,7 @@ ngircd_LDADD = -lngportab -lngtool -lngipaddr noinst_HEADERS = ngircd.h array.h channel.h client.h conf.h conf-ssl.h conn.h \ conn-func.h conn-ssl.h conn-zip.h hash.h io.h irc.h irc-channel.h \ irc-info.h irc-login.h irc-mode.h irc-op.h irc-oper.h irc-server.h \ - irc-write.h lists.h log.h match.h numeric.h parse.h rendezvous.h \ + irc-write.h lists.h log.h match.h numeric.h op.h parse.h rendezvous.h \ resolve.h defines.h messages.h clean-local: diff --git a/src/ngircd/channel.c b/src/ngircd/channel.c index 6f85072..6e9e0f4 100644 --- a/src/ngircd/channel.c +++ b/src/ngircd/channel.c @@ -1085,7 +1085,7 @@ Channel_CheckKey(CHANNEL *Chan, CLIENT *Client, const char *Key) return false; } - while (fgets(line, sizeof(line), fd) != NULL) { + while (fgets(line, (int)sizeof(line), fd) != NULL) { ngt_TrimStr(line); if (! (nick = strchr(line, ':'))) continue; diff --git a/src/ngircd/client.c b/src/ngircd/client.c index 50648c9..1edc755 100644 --- a/src/ngircd/client.c +++ b/src/ngircd/client.c @@ -758,18 +758,18 @@ Client_CheckID( CLIENT *Client, char *ID ) assert( Client->conn_id > NONE ); assert( ID != NULL ); - /* Nick too long? */ + /* ID too long? */ if (strlen(ID) > CLIENT_ID_LEN) { IRC_WriteStrClient(Client, ERR_ERRONEUSNICKNAME_MSG, Client_ID(Client), ID); return false; } - /* does ID already exist? */ + /* ID already in use? */ c = My_Clients; while (c) { if (strcasecmp(c->id, ID) == 0) { snprintf(str, sizeof(str), "ID \"%s\" already registered", ID); - if (Client->conn_id != c->conn_id) + if (c->conn_id != NONE) Log(LOG_ERR, "%s (on connection %d)!", str, c->conn_id); else Log(LOG_ERR, "%s (via network)!", str); diff --git a/src/ngircd/conf.c b/src/ngircd/conf.c index a3c9afe..2b592b1 100644 --- a/src/ngircd/conf.c +++ b/src/ngircd/conf.c @@ -1,6 +1,6 @@ /* * ngIRCd -- The Next Generation IRC Daemon - * Copyright (c)2001-2008 Alexander Barton (alex@barton.de) + * Copyright (c)2001-2009 Alexander Barton (alex@barton.de) * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -95,19 +95,46 @@ ConfSSL_Init(void) array_free_wipe(&Conf_SSLOptions.KeyFilePassword); } +static bool +ssl_print_configvar(const char *name, const char *file) +{ + FILE *fp; -static void + if (!file) { + printf(" %s =\n", name); + return true; + } + + fp = fopen(file, "r"); + if (fp) + fclose(fp); + else + fprintf(stderr, "ERROR: %s \"%s\": %s\n", + name, file, strerror(errno)); + + printf(" %s = %s\n", name, file); + return fp != NULL; +} + +static bool ConfSSL_Puts(void) { - if (Conf_SSLOptions.KeyFile) - printf( " SSLKeyFile = %s\n", Conf_SSLOptions.KeyFile); - if (Conf_SSLOptions.CertFile) - printf( " SSLCertFile = %s\n", Conf_SSLOptions.CertFile); - if (Conf_SSLOptions.DHFile) - printf( " SSLDHFile = %s\n", Conf_SSLOptions.DHFile); + bool ret; + + ret = ssl_print_configvar("SSLKeyFile", Conf_SSLOptions.KeyFile); + + if (!ssl_print_configvar("SSLCertFile", Conf_SSLOptions.CertFile)) + ret = false; + + if (!ssl_print_configvar("SSLDHFile", Conf_SSLOptions.DHFile)) + ret = false; + if (array_bytes(&Conf_SSLOptions.KeyFilePassword)) - puts(" SSLKeyFilePassword = " ); + puts(" SSLKeyFilePassword = "); + array_free_wipe(&Conf_SSLOptions.KeyFilePassword); + + return ret; } #endif @@ -152,8 +179,8 @@ ports_parse(array *a, int Line, char *Arg) * must be separated by "," */ ptr = strtok( Arg, "," ); while (ptr) { - ngt_TrimStr( ptr ); - port = atol( ptr ); + ngt_TrimStr(ptr); + port = atoi(ptr); if (port > 0 && port < 0xFFFF) { port16 = (UINT16) port; if (!array_catb(a, (char*)&port16, sizeof port16)) @@ -240,37 +267,42 @@ Conf_Test( void ) printf( " PidFile = %s\n", Conf_PidFile); printf(" Listen = %s\n", Conf_ListenAddress); fputs(" Ports = ", stdout); - ports_puts(&Conf_ListenPorts); #ifdef SSL_SUPPORT fputs(" SSLPorts = ", stdout); ports_puts(&Conf_SSLOptions.ListenPorts); - ConfSSL_Puts(); + if (!ConfSSL_Puts()) + config_valid = false; #endif - pwd = getpwuid( Conf_UID ); - if( pwd ) printf( " ServerUID = %s\n", pwd->pw_name ); - else printf( " ServerUID = %ld\n", (long)Conf_UID ); - grp = getgrgid( Conf_GID ); - if( grp ) printf( " ServerGID = %s\n", grp->gr_name ); - else printf( " ServerGID = %ld\n", (long)Conf_GID ); - printf( " PingTimeout = %d\n", Conf_PingTimeout ); - printf( " PongTimeout = %d\n", Conf_PongTimeout ); - printf( " ConnectRetry = %d\n", Conf_ConnectRetry ); - printf( " OperCanUseMode = %s\n", yesno_to_str(Conf_OperCanMode)); - printf( " OperServerMode = %s\n", yesno_to_str(Conf_OperServerMode)); - printf( " PredefChannelsOnly = %s\n", yesno_to_str(Conf_PredefChannelsOnly)); - printf( " NoDNS = %s\n", yesno_to_str(Conf_NoDNS)); - printf( " NoIdent = %s\n", yesno_to_str(Conf_NoIdent)); + pwd = getpwuid(Conf_UID); + if (pwd) + printf(" ServerUID = %s\n", pwd->pw_name); + else + printf(" ServerUID = %ld\n", (long)Conf_UID); + grp = getgrgid(Conf_GID); + if (grp) + printf(" ServerGID = %s\n", grp->gr_name); + else + printf(" ServerGID = %ld\n", (long)Conf_GID); + printf(" PingTimeout = %d\n", Conf_PingTimeout); + printf(" PongTimeout = %d\n", Conf_PongTimeout); + printf(" ConnectRetry = %d\n", Conf_ConnectRetry); + printf(" OperCanUseMode = %s\n", yesno_to_str(Conf_OperCanMode)); + printf(" OperServerMode = %s\n", yesno_to_str(Conf_OperServerMode)); + printf(" AllowRemoteOper = %s\n", yesno_to_str(Conf_AllowRemoteOper)); + printf(" PredefChannelsOnly = %s\n", yesno_to_str(Conf_PredefChannelsOnly)); + printf(" NoDNS = %s\n", yesno_to_str(Conf_NoDNS)); + printf(" NoIdent = %s\n", yesno_to_str(Conf_NoIdent)); #ifdef WANT_IPV6 printf(" ConnectIPv4 = %s\n", yesno_to_str(Conf_ConnectIPv6)); printf(" ConnectIPv6 = %s\n", yesno_to_str(Conf_ConnectIPv4)); #endif - printf( " MaxConnections = %ld\n", Conf_MaxConnections); - printf( " MaxConnectionsIP = %d\n", Conf_MaxConnectionsIP); - printf( " MaxJoins = %d\n", Conf_MaxJoins>0 ? Conf_MaxJoins : -1); - printf( " MaxNickLength = %u\n\n", Conf_MaxNickLength - 1); + printf(" MaxConnections = %ld\n", Conf_MaxConnections); + printf(" MaxConnectionsIP = %d\n", Conf_MaxConnectionsIP); + printf(" MaxJoins = %d\n", Conf_MaxJoins > 0 ? Conf_MaxJoins : -1); + printf(" MaxNickLength = %u\n\n", Conf_MaxNickLength - 1); for( i = 0; i < Conf_Oper_Count; i++ ) { if( ! Conf_Oper[i].name[0] ) continue; @@ -400,7 +432,7 @@ Conf_EnableServer( const char *Name, UINT16 Port ) /* Gotcha! Set port and enable server: */ Conf_Server[i].port = Port; Conf_Server[i].flags &= ~CONF_SFLAG_DISABLED; - return true; + return (Conf_Server[i].port && Conf_Server[i].host[0]); } } return false; @@ -487,47 +519,47 @@ Conf_IsService(int ConfServer, const char *Nick) } /* Conf_IsService */ +/** + * Initialize configuration settings with their default values. + */ static void -Set_Defaults( bool InitServers ) +Set_Defaults(bool InitServers) { - /* Initialize configuration variables with default values. */ - int i; - strcpy( Conf_ServerName, "" ); - snprintf( Conf_ServerInfo, sizeof Conf_ServerInfo, "%s %s", PACKAGE_NAME, PACKAGE_VERSION ); - strcpy( Conf_ServerPwd, "" ); - - strcpy( Conf_ServerAdmin1, "" ); - strcpy( Conf_ServerAdmin2, "" ); - strcpy( Conf_ServerAdminMail, "" ); + strcpy(Conf_ServerName, ""); + snprintf(Conf_ServerInfo, sizeof Conf_ServerInfo, "%s %s", + PACKAGE_NAME, PACKAGE_VERSION); + strcpy(Conf_ServerPwd, ""); - strlcpy( Conf_MotdFile, SYSCONFDIR, sizeof( Conf_MotdFile )); - strlcat( Conf_MotdFile, MOTD_FILE, sizeof( Conf_MotdFile )); + strcpy(Conf_ServerAdmin1, ""); + strcpy(Conf_ServerAdmin2, ""); + strcpy(Conf_ServerAdminMail, ""); - strlcpy( Conf_MotdPhrase, MOTD_PHRASE, sizeof( Conf_MotdPhrase )); + strlcpy(Conf_MotdFile, SYSCONFDIR, sizeof(Conf_MotdFile)); + strlcat(Conf_MotdFile, MOTD_FILE, sizeof(Conf_MotdFile)); + strlcpy(Conf_MotdPhrase, MOTD_PHRASE, sizeof(Conf_MotdPhrase)); - strlcpy( Conf_Chroot, CHROOT_DIR, sizeof( Conf_Chroot )); - - strlcpy( Conf_PidFile, PID_FILE, sizeof( Conf_PidFile )); + Conf_UID = Conf_GID = 0; + strlcpy(Conf_Chroot, CHROOT_DIR, sizeof(Conf_Chroot)); + strlcpy(Conf_PidFile, PID_FILE, sizeof(Conf_PidFile)); free(Conf_ListenAddress); Conf_ListenAddress = NULL; - Conf_UID = Conf_GID = 0; Conf_PingTimeout = 120; Conf_PongTimeout = 20; - Conf_ConnectRetry = 60; + Conf_NoDNS = false; + Conf_NoIdent = false; Conf_Oper_Count = 0; Conf_Channel_Count = 0; Conf_OperCanMode = false; - Conf_NoDNS = false; - Conf_NoIdent = false; - Conf_PredefChannelsOnly = false; Conf_OperServerMode = false; + Conf_AllowRemoteOper = false; + Conf_PredefChannelsOnly = false; Conf_ConnectIPv4 = true; Conf_ConnectIPv6 = true; @@ -538,11 +570,24 @@ Set_Defaults( bool InitServers ) Conf_MaxNickLength = CLIENT_NICK_LEN_DEFAULT; /* Initialize server configuration structures */ - if( InitServers ) for( i = 0; i < MAX_SERVERS; Init_Server_Struct( &Conf_Server[i++] )); + if (InitServers) { + for (i = 0; i < MAX_SERVERS; + Init_Server_Struct(&Conf_Server[i++])); + } } /* Set_Defaults */ static bool +no_listenports(void) +{ + size_t cnt = array_bytes(&Conf_ListenPorts); +#ifdef SSL_SUPPORT + cnt += array_bytes(&Conf_SSLOptions.ListenPorts); +#endif + return cnt == 0; +} + +static bool Read_Config( bool ngircd_starting ) { /* Read configuration file. */ @@ -698,12 +743,14 @@ Read_Config( bool ngircd_starting ) Conf_Server[New_Server_Idx] = New_Server; } - if (0 == array_length(&Conf_ListenPorts, sizeof(UINT16))) { - if (!array_copyb(&Conf_ListenPorts, (char*) &defaultport, sizeof defaultport)) { - Config_Error( LOG_ALERT, "Could not add default listening Port %u: %s", - (unsigned int) defaultport, strerror(errno)); - exit( 1 ); - } + /* not a single listening port? Add default. */ + if (no_listenports() && + !array_copyb(&Conf_ListenPorts, (char*) &defaultport, sizeof defaultport)) + { + Config_Error(LOG_ALERT, "Could not add default listening Port %u: %s", + (unsigned int) defaultport, strerror(errno)); + + exit(1); } if (!Conf_ListenAddress) @@ -938,6 +985,11 @@ Handle_GLOBAL( int Line, char *Var, char *Arg ) Conf_OperServerMode = Check_ArgIsTrue( Arg ); return; } + if(strcasecmp(Var, "AllowRemoteOper") == 0) { + /* Are remote IRC operators allowed to control this server? */ + Conf_AllowRemoteOper = Check_ArgIsTrue(Arg); + return; + } if( strcasecmp( Var, "MaxConnections" ) == 0 ) { /* Maximum number of connections. 0 -> "no limit". */ #ifdef HAVE_ISDIGIT diff --git a/src/ngircd/conf.h b/src/ngircd/conf.h index 9bdecde..2308e4c 100644 --- a/src/ngircd/conf.h +++ b/src/ngircd/conf.h @@ -140,6 +140,14 @@ GLOBAL bool Conf_PredefChannelsOnly; /* Are IRC operators allowed to always use MODE? */ GLOBAL bool Conf_OperCanMode; +/* If an IRC op gives chanop privileges without being a chanop, + * ircd2 will ignore the command. This enables a workaround: + * It masks the command as coming from the server */ +GLOBAL bool Conf_OperServerMode; + +/* Are remote IRC operators allowed to manage this server? */ +GLOBAL bool Conf_AllowRemoteOper; + /* Disable all DNS functions? */ GLOBAL bool Conf_NoDNS; @@ -155,11 +163,6 @@ GLOBAL bool Conf_ConnectIPv6; /* same as above, but for ipv4 hosts, default: yes */ GLOBAL bool Conf_ConnectIPv4; -/* If an IRC op gives chanop privileges without being a chanop, - * ircd2 will ignore the command. This enables a workaround: - * It masks the command as coming from the server */ -GLOBAL bool Conf_OperServerMode; - /* Maximum number of connections to this server */ GLOBAL long Conf_MaxConnections; diff --git a/src/ngircd/conn-ssl.c b/src/ngircd/conn-ssl.c index 4ef8f66..ae1646c 100644 --- a/src/ngircd/conn-ssl.c +++ b/src/ngircd/conn-ssl.c @@ -383,7 +383,6 @@ ConnSSL_Init_SSL(CONNECTION *c) int ret; assert(c != NULL); #ifdef HAVE_LIBSSL - assert(ssl_ctx); if (!ssl_ctx) /* NULL when library initialization failed */ return false; @@ -407,6 +406,7 @@ ConnSSL_Init_SSL(CONNECTION *c) if (ret < 0) { Log(LOG_ERR, "gnutls_set_default_priority: %s", gnutls_strerror(ret)); ConnSSL_Free(c); + return false; } /* * The intermediate (long) cast is here to avoid a warning like: @@ -419,6 +419,7 @@ ConnSSL_Init_SSL(CONNECTION *c) if (ret < 0) { Log(LOG_ERR, "gnutls_credentials_set: %s", gnutls_strerror(ret)); ConnSSL_Free(c); + return false; } gnutls_dh_set_prime_bits(c->ssl_state.gnutls_session, DH_BITS); #endif @@ -433,10 +434,7 @@ ConnSSL_PrepareConnect(CONNECTION *c, UNUSED CONF_SERVER *s) bool ret; #ifdef HAVE_LIBGNUTLS int err; -#endif - assert(c != NULL); - assert(s != NULL); -#ifdef HAVE_LIBGNUTLS + err = gnutls_init(&c->ssl_state.gnutls_session, GNUTLS_CLIENT); if (err) { Log(LOG_ERR, "gnutls_init: %s", gnutls_strerror(err)); @@ -471,8 +469,6 @@ ConnSSL_HandleError( CONNECTION *c, const int code, const char *fname ) unsigned long sslerr; int real_errno = errno; - assert( fname ); - ret = SSL_get_error(c->ssl_state.ssl, code); switch (ret) { case SSL_ERROR_WANT_READ: @@ -518,15 +514,14 @@ ConnSSL_HandleError( CONNECTION *c, const int code, const char *fname ) switch (code) { case GNUTLS_E_AGAIN: case GNUTLS_E_INTERRUPTED: - if (gnutls_record_get_direction(c->ssl_state.gnutls_session)) { /* need write */ - io_event_del(c->sock, IO_WANTREAD); - Conn_OPTION_ADD(c, CONN_SSL_WANT_WRITE); /* fall through */ - break; - } else { /* need read */ - io_event_del(c->sock, IO_WANTWRITE); - Conn_OPTION_ADD(c, CONN_SSL_WANT_READ); + if (gnutls_record_get_direction(c->ssl_state.gnutls_session)) { + Conn_OPTION_ADD(c, CONN_SSL_WANT_WRITE); + io_event_del(c->sock, IO_WANTREAD); + } else { + Conn_OPTION_ADD(c, CONN_SSL_WANT_READ); + io_event_del(c->sock, IO_WANTWRITE); + } break; - } default: assert(code < 0); if (gnutls_error_is_fatal(code)) { @@ -546,8 +541,7 @@ ConnSSL_LogCertInfo( CONNECTION *c ) #ifdef HAVE_LIBSSL SSL *ssl = c->ssl_state.ssl; - assert( c ); - assert( ssl ); + assert(ssl); Log(LOG_INFO, "New %s connection using cipher %s on socket %d.", SSL_get_version(ssl), SSL_get_cipher(ssl), c->sock); @@ -575,11 +569,8 @@ int ConnSSL_Accept( CONNECTION *c ) { assert(c != NULL); -#ifdef HAVE_LIBSSL - if (!c->ssl_state.ssl) { -#endif -#ifdef HAVE_LIBGNUTLS if (!Conn_OPTION_ISSET(c, CONN_SSL)) { +#ifdef HAVE_LIBGNUTLS int err = gnutls_init(&c->ssl_state.gnutls_session, GNUTLS_SERVER); if (err) { Log(LOG_ERR, "gnutls_init: %s", gnutls_strerror(err)); @@ -601,9 +592,7 @@ ConnSSL_Connect( CONNECTION *c ) #ifdef HAVE_LIBSSL assert(c->ssl_state.ssl); #endif -#ifdef HAVE_LIBGNUTLS assert(Conn_OPTION_ISSET(c, CONN_SSL)); -#endif return ConnectAccept(c, true); } @@ -623,7 +612,6 @@ ConnectAccept( CONNECTION *c, bool connect) #endif #ifdef HAVE_LIBGNUTLS (void) connect; - assert(Conn_OPTION_ISSET(c, CONN_SSL)); ret = gnutls_handshake(c->ssl_state.gnutls_session); if (ret) return ConnSSL_HandleError(c, ret, "gnutls_handshake"); @@ -648,7 +636,8 @@ ConnSSL_Write(CONNECTION *c, const void *buf, size_t count) #ifdef HAVE_LIBGNUTLS bw = gnutls_write(c->ssl_state.gnutls_session, buf, count); #endif - if ( bw > 0 ) return bw; + if (bw > 0) + return bw; if (ConnSSL_HandleError( c, bw, "ConnSSL_Write") == 0) errno = EAGAIN; /* try again */ return -1; @@ -685,11 +674,8 @@ ConnSSL_GetCipherInfo(CONNECTION *c, char *buf, size_t len) { #ifdef HAVE_LIBSSL char *nl; + SSL *ssl = c->ssl_state.ssl; - SSL *ssl; - assert(c != NULL); - assert(len >= 128); - ssl = c->ssl_state.ssl; if (!ssl) return false; *buf = 0; @@ -700,8 +686,6 @@ ConnSSL_GetCipherInfo(CONNECTION *c, char *buf, size_t len) return true; #endif #ifdef HAVE_LIBGNUTLS - assert(c != NULL); - assert(len >= 128); if (Conn_OPTION_ISSET(c, CONN_SSL)) { const char *name_cipher, *name_mac, *name_proto, *name_keyexchange; unsigned keysize; diff --git a/src/ngircd/conn.c b/src/ngircd/conn.c index c6095a3..731647d 100644 --- a/src/ngircd/conn.c +++ b/src/ngircd/conn.c @@ -1,6 +1,6 @@ /* * ngIRCd -- The Next Generation IRC Daemon - * Copyright (c)2001-2007 Alexander Barton (alex@barton.de) + * Copyright (c)2001-2009 Alexander Barton (alex@barton.de) * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -75,13 +75,16 @@ #define SERVER_WAIT (NONE - 1) +#define MAX_COMMANDS 3 +#define MAX_COMMANDS_SERVER 10 + static bool Handle_Write PARAMS(( CONN_ID Idx )); static bool Conn_Write PARAMS(( CONN_ID Idx, char *Data, size_t Len )); static int New_Connection PARAMS(( int Sock )); static CONN_ID Socket2Index PARAMS(( int Sock )); static void Read_Request PARAMS(( CONN_ID Idx )); -static void Handle_Buffer PARAMS(( CONN_ID Idx )); +static unsigned int Handle_Buffer PARAMS(( CONN_ID Idx )); static void Check_Connections PARAMS(( void )); static void Check_Servers PARAMS(( void )); static void Init_Conn_Struct PARAMS(( CONN_ID Idx )); @@ -140,21 +143,33 @@ cb_listen_ssl(int sock, short irrelevant) static void cb_connserver(int sock, UNUSED short what) { - int res, err; + int res, err, server; socklen_t sock_len; CONN_ID idx = Socket2Index( sock ); + if (idx <= NONE) { LogDebug("cb_connserver wants to write on unknown socket?!"); io_close(sock); return; } - assert( what & IO_WANTWRITE); + assert(what & IO_WANTWRITE); + + /* Make sure that the server is still configured; it could have been + * removed in the meantime! */ + server = Conf_GetServer(idx); + if (server < 0) { + Log(LOG_ERR, "Connection on socket %d to \"%s\" aborted!", + sock, My_Connections[idx].host); + Conn_Close(idx, "Connection aborted!", NULL, false); + return; + } /* connect() finished, get result. */ - sock_len = sizeof( err ); - res = getsockopt( My_Connections[idx].sock, SOL_SOCKET, SO_ERROR, &err, &sock_len ); - assert( sock_len == sizeof( err )); + sock_len = (socklen_t)sizeof(err); + res = getsockopt(My_Connections[idx].sock, SOL_SOCKET, SO_ERROR, + &err, &sock_len ); + assert(sock_len == sizeof(err)); /* Error while connecting? */ if ((res != 0) || (err != 0)) { @@ -164,32 +179,28 @@ cb_connserver(int sock, UNUSED short what) else Log(LOG_CRIT, "Can't connect socket to \"%s:%d\" (connection %d): %s!", - My_Connections[idx].host, - Conf_Server[Conf_GetServer(idx)].port, + My_Connections[idx].host, Conf_Server[server].port, idx, strerror(err)); - res = Conf_GetServer(idx); - assert(res >= 0); - Conn_Close(idx, "Can't connect!", NULL, false); - if (res < 0) - return; - if (ng_ipaddr_af(&Conf_Server[res].dst_addr[0])) { + if (ng_ipaddr_af(&Conf_Server[server].dst_addr[0])) { /* more addresses to try... */ - New_Server(res, &Conf_Server[res].dst_addr[0]); - /* connection to dst_addr[0] in progress, remove this address... */ - Conf_Server[res].dst_addr[0] = Conf_Server[res].dst_addr[1]; - - memset(&Conf_Server[res].dst_addr[1], 0, sizeof(&Conf_Server[res].dst_addr[1])); + New_Server(res, &Conf_Server[server].dst_addr[0]); + /* connection to dst_addr[0] is now in progress, so + * remove this address... */ + Conf_Server[server].dst_addr[0] = + Conf_Server[server].dst_addr[1]; + memset(&Conf_Server[server].dst_addr[1], 0, + sizeof(Conf_Server[server].dst_addr[1])); } return; } - res = Conf_GetServer(idx); - assert(res >= 0); - if (res >= 0) /* connect succeeded, remove all additional addresses */ - memset(&Conf_Server[res].dst_addr, 0, sizeof(&Conf_Server[res].dst_addr)); + /* connect() succeeded, remove all additional addresses */ + memset(&Conf_Server[server].dst_addr, 0, + sizeof(Conf_Server[server].dst_addr)); + Conn_OPTION_DEL( &My_Connections[idx], CONN_ISCONNECTING ); #ifdef SSL_SUPPORT if ( Conn_OPTION_ISSET( &My_Connections[idx], CONN_SSL_CONNECT )) { @@ -482,7 +493,7 @@ set_v6_only(int af, int sock) if (af != AF_INET6) return; - if (setsockopt(sock, IPPROTO_IPV6, IPV6_V6ONLY, &on, sizeof(on))) + if (setsockopt(sock, IPPROTO_IPV6, IPV6_V6ONLY, &on, (socklen_t)sizeof(on))) Log(LOG_ERR, "Could not set IPV6_V6ONLY: %s", strerror(errno)); #else (void)af; @@ -622,7 +633,7 @@ GLOBAL void Conn_Handler(void) { int i; - unsigned int wdatalen; + unsigned int wdatalen, bytes_processed; struct timeval tv; time_t t; @@ -645,9 +656,19 @@ Conn_Handler(void) for (i = 0; i < Pool_Size; i++) { if ((My_Connections[i].sock > NONE) && (array_bytes(&My_Connections[i].rbuf) > 0) - && (My_Connections[i].delaytime < t)) { + && (My_Connections[i].delaytime <= t)) { /* ... and try to handle the received data */ - Handle_Buffer(i); + bytes_processed = Handle_Buffer(i); + /* if we processed data, and there might be + * more commands in the input buffer, do not + * try to read any more data now */ + if (bytes_processed && + array_bytes(&My_Connections[i].rbuf) > 2) { + LogDebug + ("Throttling connection %d: command limit reached!", + i); + Conn_SetPenalty(i, 1); + } } } @@ -887,7 +908,6 @@ Conn_Close( CONN_ID Idx, const char *LogMsg, const char *FwdMsg, bool InformClie * sub-processes are closed down. */ CLIENT *c; - const char *txt; double in_k, out_k; UINT16 port; #ifdef ZLIB @@ -910,13 +930,6 @@ Conn_Close( CONN_ID Idx, const char *LogMsg, const char *FwdMsg, bool InformClie /* Mark link as "closing" */ Conn_OPTION_ADD( &My_Connections[Idx], CONN_ISCLOSING ); - if (LogMsg) - txt = LogMsg; - else - txt = FwdMsg; - if (! txt) - txt = "Reason unknown"; - port = ng_ipaddr_getport(&My_Connections[Idx].addr); Log(LOG_INFO, "Shutting down connection %d (%s) with %s:%d ...", Idx, LogMsg ? LogMsg : FwdMsg, My_Connections[Idx].host, port); @@ -937,7 +950,7 @@ Conn_Close( CONN_ID Idx, const char *LogMsg, const char *FwdMsg, bool InformClie (double)My_Connections[Idx].bytes_out / 1024); } #endif - /* Send ERROR to client (see RFC!) */ + /* Send ERROR to client (see RFC 2812, section 3.1.7) */ if (FwdMsg) Conn_WriteStr(Idx, "ERROR :%s", FwdMsg); else @@ -1307,7 +1320,9 @@ static void Read_Request( CONN_ID Idx ) { ssize_t len; + static const unsigned int maxbps = COMMAND_LEN / 2; char readbuf[READBUFFER_LEN]; + time_t t; CLIENT *c; assert( Idx > NONE ); assert( My_Connections[Idx].sock > NONE ); @@ -1384,21 +1399,34 @@ Read_Request( CONN_ID Idx ) if (c && (Client_Type(c) == CLIENT_USER || Client_Type(c) == CLIENT_SERVER || Client_Type(c) == CLIENT_SERVICE)) { - My_Connections[Idx].lastdata = time(NULL); + t = time(NULL); + if (My_Connections[Idx].lastdata != t) + My_Connections[Idx].bps = 0; + + My_Connections[Idx].lastdata = t; My_Connections[Idx].lastping = My_Connections[Idx].lastdata; } /* Look at the data in the (read-) buffer of this connection */ - Handle_Buffer(Idx); + My_Connections[Idx].bps += Handle_Buffer(Idx); + if (Client_Type(c) != CLIENT_SERVER + && My_Connections[Idx].bps >= maxbps) { + LogDebug("Throttling connection %d: BPS exceeded! (%u >= %u)", + Idx, My_Connections[Idx].bps, maxbps); + Conn_SetPenalty(Idx, 1); + } } /* Read_Request */ /** * Handle all data in the connection read-buffer. - * All data is precessed until no complete command is left. When a fatal - * error occurs, the connection is shut down. + * Data is processed until no complete command is left in the read buffer, + * or MAX_COMMANDS[_SERVER] commands were processed. + * When a fatal error occurs, the connection is shut down. + * @param Idx Index of the connection. + * @return number of bytes processed. */ -static void +static unsigned int Handle_Buffer(CONN_ID Idx) { #ifndef STRICT_RFC @@ -1410,31 +1438,41 @@ Handle_Buffer(CONN_ID Idx) #ifdef ZLIB bool old_z; #endif + unsigned int i, maxcmd = MAX_COMMANDS, len_processed = 0; + CLIENT *c; + + c = Conn_GetClient(Idx); + assert( c != NULL); + + /* Servers do get special command limits, so they can process + * all the messages that are required while peering. */ + if (Client_Type(c) == CLIENT_SERVER) + maxcmd = MAX_COMMANDS_SERVER; starttime = time(NULL); - for (;;) { + for (i=0; i < maxcmd; i++) { /* Check penalty */ if (My_Connections[Idx].delaytime > starttime) - return; + return 0; #ifdef ZLIB /* Unpack compressed data, if compression is in use */ if (Conn_OPTION_ISSET(&My_Connections[Idx], CONN_ZIP)) { /* When unzipping fails, Unzip_Buffer() shuts * down the connection itself */ if (!Unzip_Buffer(Idx)) - return; + return 0; } #endif if (0 == array_bytes(&My_Connections[Idx].rbuf)) - return; + break; /* Make sure that the buffer is NULL terminated */ if (!array_cat0_temporary(&My_Connections[Idx].rbuf)) { Conn_Close(Idx, NULL, "Can't allocate memory [Handle_Buffer]", true); - return; + return 0; } /* RFC 2812, section "2.3 Messages", 5th paragraph: @@ -1470,7 +1508,7 @@ Handle_Buffer(CONN_ID Idx) #endif if (!ptr) - return; + break; /* Complete (=line terminated) request found, handle it! */ *ptr = '\0'; @@ -1485,16 +1523,16 @@ Handle_Buffer(CONN_ID Idx) Idx, array_bytes(&My_Connections[Idx].rbuf), COMMAND_LEN - 1); Conn_Close(Idx, NULL, "Request too long", true); - return; + return 0; } + len_processed += (unsigned int)len; if (len <= delta) { /* Request is empty (only '\r\n', '\r' or '\n'); * delta is 2 ('\r\n') or 1 ('\r' or '\n'), see above */ array_moveleft(&My_Connections[Idx].rbuf, 1, len); - return; + continue; } - #ifdef ZLIB /* remember if stream is already compressed */ old_z = My_Connections[Idx].options & CONN_ZIP; @@ -1503,7 +1541,7 @@ Handle_Buffer(CONN_ID Idx) My_Connections[Idx].msg_in++; if (!Parse_Request (Idx, (char *)array_start(&My_Connections[Idx].rbuf))) - return; + return 0; /* error -> connection has been closed */ array_moveleft(&My_Connections[Idx].rbuf, 1, len); LogDebug("Connection %d: %d bytes left in read buffer.", @@ -1520,7 +1558,7 @@ Handle_Buffer(CONN_ID Idx) Conn_Close(Idx, NULL, "Can't allocate memory [Handle_Buffer]", true); - return; + return 0; } array_trunc(&My_Connections[Idx].rbuf); @@ -1530,6 +1568,7 @@ Handle_Buffer(CONN_ID Idx) } #endif } + return len_processed; } /* Handle_Buffer */ @@ -1696,6 +1735,8 @@ New_Server( int Server , ng_ipaddr_t *dest) return; } + /* Conn_Close() decrements this counter again */ + NumConnections++; Client_SetIntroducer( c, c ); Client_SetToken( c, TOKEN_OUTBOUND ); @@ -1722,9 +1763,9 @@ New_Server( int Server , ng_ipaddr_t *dest) Conn_Close( new_sock, "Could not initialize SSL for outgoing connection", NULL, false ); Init_Conn_Struct( new_sock ); Conf_Server[Server].conn_id = NONE; + return; } #endif - NumConnections++; LogDebug("Registered new connection %d on socket %d (%ld in total).", new_sock, My_Connections[new_sock].sock, NumConnections); Conn_OPTION_ADD( &My_Connections[new_sock], CONN_ISCONNECTING ); @@ -1793,7 +1834,8 @@ cb_Connect_to_Server(int fd, UNUSED short events) size_t len; ng_ipaddr_t dest_addrs[4]; /* we can handle at most 3; but we read up to four so we can log the 'more than we can handle' - condition */ + condition. First result is tried immediately, rest + is saved for later if needed. */ LogDebug("Resolver: Got forward lookup callback on fd %d, events %d", fd, events); @@ -1818,13 +1860,13 @@ cb_Connect_to_Server(int fd, UNUSED short events) LogDebug("Got result from resolver: %u structs (%u bytes).", len/sizeof(ng_ipaddr_t), len); - memset(&Conf_Server[i].dst_addr, 0, sizeof(&Conf_Server[i].dst_addr)); + memset(&Conf_Server[i].dst_addr, 0, sizeof(Conf_Server[i].dst_addr)); if (len > sizeof(ng_ipaddr_t)) { /* more than one address for this hostname, remember them * in case first address is unreachable/not available */ len -= sizeof(ng_ipaddr_t); - if (len > sizeof(&Conf_Server[i].dst_addr)) { - len = sizeof(&Conf_Server[i].dst_addr); + if (len > sizeof(Conf_Server[i].dst_addr)) { + len = sizeof(Conf_Server[i].dst_addr); Log(LOG_NOTICE, "Notice: Resolver returned more IP Addresses for host than we can handle, additional addresses dropped."); } @@ -1967,4 +2009,6 @@ Conn_UsesSSL(CONN_ID Idx) return Conn_OPTION_ISSET(&My_Connections[Idx], CONN_SSL); } #endif + + /* -eof- */ diff --git a/src/ngircd/conn.h b/src/ngircd/conn.h index 28bbda3..983c884 100644 --- a/src/ngircd/conn.h +++ b/src/ngircd/conn.h @@ -1,6 +1,6 @@ /* * ngIRCd -- The Next Generation IRC Daemon - * Copyright (c)2001-2008 by Alexander Barton (alex@barton.de) + * Copyright (c)2001-2009 by Alexander Barton (alex@barton.de) * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -41,7 +41,7 @@ #define CONN_SSL_WANT_READ 128 /* SSL/TLS library needs to read protocol data */ #define CONN_SSL_FLAGS_ALL (CONN_SSL_CONNECT|CONN_SSL|CONN_SSL_WANT_WRITE|CONN_SSL_WANT_READ) #endif -typedef int CONN_ID; +typedef long CONN_ID; #include "client.h" @@ -82,6 +82,7 @@ typedef struct _Connection long msg_in, msg_out; /* Received and sent IRC messages */ int flag; /* Flag (see "irc-write" module) */ UINT16 options; /* Link options / connection state */ + UINT16 bps; /* bytes processed within last second */ CLIENT *client; /* pointer to client structure */ #ifdef ZLIB ZIPDATA zip; /* Compression information */ @@ -121,4 +122,5 @@ static inline bool Conn_UsesSSL(UNUSED CONN_ID Idx) { return false; } #endif #endif + /* -eof- */ diff --git a/src/ngircd/hash.c b/src/ngircd/hash.c index d9aa79b..1b2f4e6 100644 --- a/src/ngircd/hash.c +++ b/src/ngircd/hash.c @@ -1,6 +1,6 @@ /* * ngIRCd -- The Next Generation IRC Daemon - * Copyright (c)2001,2002 by Alexander Barton (alex@barton.de) + * Copyright (c)2001-2009 Alexander Barton (alex@barton.de) * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -37,8 +37,9 @@ Hash( const char *String ) char buffer[LINE_LEN]; - strlcpy( buffer, String, sizeof( buffer )); - return jenkins_hash( (UINT8 *)ngt_LowerStr( buffer ), strlen( buffer ), 42 ); + strlcpy(buffer, String, sizeof(buffer)); + return jenkins_hash((UINT8 *)ngt_LowerStr(buffer), + (UINT32)strlen(buffer), 42); } /* Hash */ diff --git a/src/ngircd/irc-info.c b/src/ngircd/irc-info.c index f57a6a1..5a8555a 100644 --- a/src/ngircd/irc-info.c +++ b/src/ngircd/irc-info.c @@ -1,6 +1,6 @@ /* * ngIRCd -- The Next Generation IRC Daemon - * Copyright (c)2001-2008 Alexander Barton (alex@barton.de) + * Copyright (c)2001-2009 Alexander Barton (alex@barton.de) * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -440,7 +440,7 @@ t_diff(time_t *t, const time_t d) remain = diff * d; *t -= remain; - return diff; + return (unsigned int)diff; } diff --git a/src/ngircd/irc-login.c b/src/ngircd/irc-login.c index 16d1641..7b73d40 100644 --- a/src/ngircd/irc-login.c +++ b/src/ngircd/irc-login.c @@ -148,7 +148,6 @@ IRC_PASS( CLIENT *Client, REQUEST *Req ) } else { /* The peer seems to be a server supporting the * "original" IRC protocol (RFC 2813). */ - serverver = ""; if (strchr(orig_flags, 'Z')) flags = "Z"; else diff --git a/src/ngircd/irc-mode.c b/src/ngircd/irc-mode.c index 8e08565..9509fb0 100644 --- a/src/ngircd/irc-mode.c +++ b/src/ngircd/irc-mode.c @@ -284,7 +284,7 @@ Channel_Mode(CLIENT *Client, REQUEST *Req, CLIENT *Origin, CHANNEL *Channel) { char the_modes[COMMAND_LEN], the_args[COMMAND_LEN], x[2], argadd[CLIENT_PASS_LEN], *mode_ptr; - bool ok, set, modeok = true, skiponce, use_servermode = false, retval; + bool connected, set, modeok = true, skiponce, use_servermode = false, retval; int mode_arg, arg_arg; CLIENT *client; long l; @@ -344,7 +344,7 @@ Channel_Mode(CLIENT *Client, REQUEST *Req, CLIENT *Origin, CHANNEL *Channel) the_args[0] = '\0'; x[1] = '\0'; - ok = CONNECTED; + connected = CONNECTED; while (mode_ptr) { if (!skiponce) mode_ptr++; @@ -404,7 +404,7 @@ Channel_Mode(CLIENT *Client, REQUEST *Req, CLIENT *Origin, CHANNEL *Channel) if (modeok) x[0] = *mode_ptr; else - ok = IRC_WriteStrClient(Origin, + connected = IRC_WriteStrClient(Origin, ERR_CHANOPRIVSNEEDED_MSG, Client_ID(Origin), Channel_Name(Channel)); break; @@ -413,7 +413,7 @@ Channel_Mode(CLIENT *Client, REQUEST *Req, CLIENT *Origin, CHANNEL *Channel) if (modeok) x[0] = *mode_ptr; else - ok = IRC_WriteStrClient(Origin, + connected = IRC_WriteStrClient(Origin, ERR_CHANOPRIVSNEEDED_MSG, Client_ID(Origin), Channel_Name(Channel)); @@ -428,7 +428,7 @@ Channel_Mode(CLIENT *Client, REQUEST *Req, CLIENT *Origin, CHANNEL *Channel) sizeof(argadd)); x[0] = *mode_ptr; } else { - ok = IRC_WriteStrClient(Origin, + connected = IRC_WriteStrClient(Origin, ERR_CHANOPRIVSNEEDED_MSG, Client_ID(Origin), Channel_Name(Channel)); @@ -436,7 +436,7 @@ Channel_Mode(CLIENT *Client, REQUEST *Req, CLIENT *Origin, CHANNEL *Channel) Req->argv[arg_arg][0] = '\0'; arg_arg++; } else { - ok = IRC_WriteStrClient(Origin, + connected = IRC_WriteStrClient(Origin, ERR_NEEDMOREPARAMS_MSG, Client_ID(Origin), Req->command); goto chan_exit; @@ -447,7 +447,7 @@ Channel_Mode(CLIENT *Client, REQUEST *Req, CLIENT *Origin, CHANNEL *Channel) if (modeok) x[0] = *mode_ptr; else - ok = IRC_WriteStrClient(Origin, + connected = IRC_WriteStrClient(Origin, ERR_CHANOPRIVSNEEDED_MSG, Client_ID(Origin), Channel_Name(Channel)); @@ -464,7 +464,7 @@ Channel_Mode(CLIENT *Client, REQUEST *Req, CLIENT *Origin, CHANNEL *Channel) x[0] = *mode_ptr; } } else { - ok = IRC_WriteStrClient(Origin, + connected = IRC_WriteStrClient(Origin, ERR_CHANOPRIVSNEEDED_MSG, Client_ID(Origin), Channel_Name(Channel)); @@ -472,7 +472,7 @@ Channel_Mode(CLIENT *Client, REQUEST *Req, CLIENT *Origin, CHANNEL *Channel) Req->argv[arg_arg][0] = '\0'; arg_arg++; } else { - ok = IRC_WriteStrClient(Origin, + connected = IRC_WriteStrClient(Origin, ERR_NEEDMOREPARAMS_MSG, Client_ID(Origin), Req->command); goto chan_exit; @@ -484,13 +484,13 @@ Channel_Mode(CLIENT *Client, REQUEST *Req, CLIENT *Origin, CHANNEL *Channel) * set the 'P' channel mode! */ if (set && !(Client_OperByMe(Client) || Client_Type(Client) == CLIENT_SERVER)) - ok = IRC_WriteStrClient(Origin, + connected = IRC_WriteStrClient(Origin, ERR_NOPRIVILEGES_MSG, Client_ID(Origin)); else x[0] = 'P'; } else - ok = IRC_WriteStrClient(Origin, + connected = IRC_WriteStrClient(Origin, ERR_CHANOPRIVSNEEDED_MSG, Client_ID(Origin), Channel_Name(Channel)); @@ -504,12 +504,12 @@ Channel_Mode(CLIENT *Client, REQUEST *Req, CLIENT *Origin, CHANNEL *Channel) if (client) x[0] = *mode_ptr; else - ok = IRC_WriteStrClient(Client, + connected = IRC_WriteStrClient(Client, ERR_NOSUCHNICK_MSG, Client_ID(Client), Req->argv[arg_arg]); } else { - ok = IRC_WriteStrClient(Origin, + connected = IRC_WriteStrClient(Origin, ERR_CHANOPRIVSNEEDED_MSG, Client_ID(Origin), Channel_Name(Channel)); @@ -517,7 +517,7 @@ Channel_Mode(CLIENT *Client, REQUEST *Req, CLIENT *Origin, CHANNEL *Channel) Req->argv[arg_arg][0] = '\0'; arg_arg++; } else { - ok = IRC_WriteStrClient(Origin, + connected = IRC_WriteStrClient(Origin, ERR_NEEDMOREPARAMS_MSG, Client_ID(Origin), Req->command); goto chan_exit; @@ -529,7 +529,7 @@ Channel_Mode(CLIENT *Client, REQUEST *Req, CLIENT *Origin, CHANNEL *Channel) if (arg_arg > mode_arg) { /* modify list */ if (modeok) { - ok = set + connected = set ? Add_Ban_Invite(*mode_ptr, Origin, Client, Channel, Req->argv[arg_arg]) @@ -537,7 +537,7 @@ Channel_Mode(CLIENT *Client, REQUEST *Req, CLIENT *Origin, CHANNEL *Channel) Client, Channel, Req->argv[arg_arg]); } else { - ok = IRC_WriteStrClient(Origin, + connected = IRC_WriteStrClient(Origin, ERR_CHANOPRIVSNEEDED_MSG, Client_ID(Origin), Channel_Name(Channel)); @@ -557,7 +557,7 @@ Channel_Mode(CLIENT *Client, REQUEST *Req, CLIENT *Origin, CHANNEL *Channel) set ? '+' : '-', *mode_ptr, Client_ID(Origin), Channel_Name(Channel)); if (Client_Type(Client) != CLIENT_SERVER) - ok = IRC_WriteStrClient(Origin, + connected = IRC_WriteStrClient(Origin, ERR_UMODEUNKNOWNFLAG2_MSG, Client_ID(Origin), set ? '+' : '-', *mode_ptr); @@ -565,7 +565,7 @@ Channel_Mode(CLIENT *Client, REQUEST *Req, CLIENT *Origin, CHANNEL *Channel) goto chan_exit; } /* switch() */ - if (!ok) + if (!connected) break; /* Is there a valid mode change? */ @@ -646,7 +646,7 @@ Channel_Mode(CLIENT *Client, REQUEST *Req, CLIENT *Origin, CHANNEL *Channel) if (use_servermode) Origin = Client_ThisServer(); /* Send reply to client and inform other servers and channel users */ - ok = IRC_WriteStrClientPrefix(Client, Origin, + connected = IRC_WriteStrClientPrefix(Client, Origin, "MODE %s %s%s", Channel_Name(Channel), the_modes, the_args); /* Only forward requests for non-local channels */ @@ -661,7 +661,7 @@ Channel_Mode(CLIENT *Client, REQUEST *Req, CLIENT *Origin, CHANNEL *Channel) } IRC_SetPenalty(Client, 1); - return CONNECTED; + return connected; } /* Channel_Mode */ diff --git a/src/ngircd/irc-oper.c b/src/ngircd/irc-oper.c index b0271df..17b6044 100644 --- a/src/ngircd/irc-oper.c +++ b/src/ngircd/irc-oper.c @@ -1,6 +1,6 @@ /* * ngIRCd -- The Next Generation IRC Daemon - * Copyright (c)2001,2002 by Alexander Barton (alex@barton.de) + * Copyright (c)2001-2008 Alexander Barton (alex@barton.de) * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -16,6 +16,7 @@ #include "imp.h" #include +#include #include #include @@ -30,19 +31,25 @@ #include "match.h" #include "messages.h" #include "parse.h" +#include "op.h" #include #include "irc-oper.h" +/** + * Handle invalid received OPER command. + * Log OPER attempt and send error message to client. + */ static bool Bad_OperPass(CLIENT *Client, char *errtoken, char *errmsg) { - Log( LOG_WARNING, "Got invalid OPER from \"%s\": \"%s\" -- %s", Client_Mask( Client ), - errtoken, errmsg); + Log(LOG_WARNING, "Got invalid OPER from \"%s\": \"%s\" -- %s", + Client_Mask(Client), errtoken, errmsg); IRC_SetPenalty(Client, 3); - return IRC_WriteStrClient( Client, ERR_PASSWDMISMATCH_MSG, Client_ID( Client )); -} + return IRC_WriteStrClient(Client, ERR_PASSWDMISMATCH_MSG, + Client_ID(Client)); +} /* Bad_OperPass */ GLOBAL bool @@ -63,7 +70,7 @@ IRC_OPER( CLIENT *Client, REQUEST *Req ) return Bad_OperPass(Client, Req->argv[0], "not configured"); if( strcmp( Conf_Oper[i].pwd, Req->argv[1] ) != 0 ) - return Bad_OperPass(Client, Conf_Oper[i].name, "Bad password"); + return Bad_OperPass(Client, Conf_Oper[i].name, "bad password"); if( Conf_Oper[i].mask && (! Match( Conf_Oper[i].mask, Client_Mask( Client ) ))) return Bad_OperPass(Client, Conf_Oper[i].mask, "hostmask check failed" ); @@ -93,10 +100,8 @@ IRC_DIE(CLIENT * Client, REQUEST * Req) assert(Client != NULL); assert(Req != NULL); - /* Not a local IRC operator? */ - if ((!Client_HasMode(Client, 'o')) || (!Client_OperByMe(Client))) - return IRC_WriteStrClient(Client, ERR_NOPRIVILEGES_MSG, - Client_ID(Client)); + if (!Op_Check(Client, Req)) + return Op_NoPrivileges(Client, Req); /* Bad number of parameters? */ #ifdef STRICT_RFC @@ -135,8 +140,8 @@ IRC_REHASH( CLIENT *Client, REQUEST *Req ) assert( Client != NULL ); assert( Req != NULL ); - /* Not a local IRC operator? */ - if(( ! Client_HasMode( Client, 'o' )) || ( ! Client_OperByMe( Client ))) return IRC_WriteStrClient( Client, ERR_NOPRIVILEGES_MSG, Client_ID( Client )); + if (!Op_Check(Client, Req)) + return Op_NoPrivileges(Client, Req); /* Bad number of parameters? */ if( Req->argc != 0 ) return IRC_WriteStrClient( Client, ERR_NEEDMOREPARAMS_MSG, Client_ID( Client ), Req->command ); @@ -156,8 +161,8 @@ IRC_RESTART( CLIENT *Client, REQUEST *Req ) assert( Client != NULL ); assert( Req != NULL ); - /* Not a local IRC operator? */ - if(( ! Client_HasMode( Client, 'o' )) || ( ! Client_OperByMe( Client ))) return IRC_WriteStrClient( Client, ERR_NOPRIVILEGES_MSG, Client_ID( Client )); + if (!Op_Check(Client, Req)) + return Op_NoPrivileges(Client, Req); /* Bad number of parameters? */ if( Req->argc != 0 ) return IRC_WriteStrClient( Client, ERR_NEEDMOREPARAMS_MSG, Client_ID( Client ), Req->command ); @@ -174,17 +179,18 @@ IRC_RESTART( CLIENT *Client, REQUEST *Req ) GLOBAL bool IRC_CONNECT(CLIENT * Client, REQUEST * Req) { + CLIENT *from, *target; assert(Client != NULL); assert(Req != NULL); - /* Not a local IRC operator? */ - if ((!Client_HasMode(Client, 'o')) || (!Client_OperByMe(Client))) - return IRC_WriteStrClient(Client, ERR_NOPRIVILEGES_MSG, - Client_ID(Client)); + if (Client_Type(Client) != CLIENT_SERVER + && !Client_HasMode(Client, 'o')) + return Op_NoPrivileges(Client, Req); /* Bad number of parameters? */ - if ((Req->argc != 1) && (Req->argc != 2) && (Req->argc != 5)) + if (Req->argc != 1 && Req->argc != 2 && Req->argc != 3 && + Req->argc != 5 && Req->argc != 6) return IRC_WriteStrClient(Client, ERR_NEEDMOREPARAMS_MSG, Client_ID(Client), Req->command); @@ -193,74 +199,125 @@ IRC_CONNECT(CLIENT * Client, REQUEST * Req) return IRC_WriteStrClient(Client, ERR_NEEDMOREPARAMS_MSG, Client_ID(Client), Req->command); - Log(LOG_NOTICE | LOG_snotice, - "Got CONNECT command from \"%s\" for \"%s\".", Client_Mask(Client), - Req->argv[0]); + from = Client; + target = Client_ThisServer(); + + if (Req->argc == 3 || Req->argc == 6) { + /* This CONNECT has a target parameter */ + if (Client_Type(Client) == CLIENT_SERVER && Req->prefix) + from = Client_Search(Req->prefix); + if (! from) + return IRC_WriteStrClient(Client, ERR_NOSUCHNICK_MSG, + Client_ID(Client), Req->prefix); + + target = (Req->argc == 3) ? Client_Search(Req->argv[2]) + : Client_Search(Req->argv[5]); + if (! target || Client_Type(target) != CLIENT_SERVER) + return IRC_WriteStrClient(from, ERR_NOSUCHSERVER_MSG, + Client_ID(from), Req->argv[0]); + } + + if (target != Client_ThisServer()) { + /* Forward CONNECT command ... */ + if (Req->argc == 3) + IRC_WriteStrClientPrefix(target, from, + "CONNECT %s %s :%s", Req->argv[0], + Req->argv[1], Req->argv[2]); + else + IRC_WriteStrClientPrefix(target, from, + "CONNECT %s %s %s %s %s :%s", Req->argv[0], + Req->argv[1], Req->argv[2], Req->argv[3], + Req->argv[4], Req->argv[5]); + return CONNECTED; + } + + if (!Op_Check(from, Req)) + return Op_NoPrivileges(Client, Req); switch (Req->argc) { case 1: if (!Conf_EnablePassiveServer(Req->argv[0])) - return IRC_WriteStrClient(Client, ERR_NOSUCHSERVER_MSG, - Client_ID(Client), + return IRC_WriteStrClient(from, ERR_NOSUCHSERVER_MSG, + Client_ID(from), Req->argv[0]); - break; + break; case 2: + case 3: /* Connect configured server */ if (!Conf_EnableServer (Req->argv[0], (UINT16) atoi(Req->argv[1]))) - return IRC_WriteStrClient(Client, ERR_NOSUCHSERVER_MSG, - Client_ID(Client), + return IRC_WriteStrClient(from, ERR_NOSUCHSERVER_MSG, + Client_ID(from), Req->argv[0]); - break; + break; default: /* Add server */ if (!Conf_AddServer (Req->argv[0], (UINT16) atoi(Req->argv[1]), Req->argv[2], Req->argv[3], Req->argv[4])) - return IRC_WriteStrClient(Client, ERR_NOSUCHSERVER_MSG, - Client_ID(Client), + return IRC_WriteStrClient(from, ERR_NOSUCHSERVER_MSG, + Client_ID(from), Req->argv[0]); } + Log(LOG_NOTICE | LOG_snotice, + "Got CONNECT command from \"%s\" for \"%s\".", Client_Mask(from), + Req->argv[0]); + IRC_SendWallops(Client_ThisServer(), Client_ThisServer(), + "Received CONNECT %s from %s", + Req->argv[0], Client_ID(from)); + return CONNECTED; } /* IRC_CONNECT */ +/** + * Disconnect (and disable) configured server. + */ GLOBAL bool -IRC_DISCONNECT(CLIENT *Client, REQUEST *Req ) +IRC_DISCONNECT(CLIENT * Client, REQUEST * Req) { - /* Disconnect and disable configured server */ - CONN_ID my_conn; - assert( Client != NULL ); - assert( Req != NULL ); + assert(Client != NULL); + assert(Req != NULL); - /* Not a local IRC operator? */ - if(( ! Client_HasMode( Client, 'o' )) || ( ! Client_OperByMe( Client ))) return IRC_WriteStrClient( Client, ERR_NOPRIVILEGES_MSG, Client_ID( Client )); + if (!Op_Check(Client, Req)) + return Op_NoPrivileges(Client, Req); /* Bad number of parameters? */ - if( Req->argc != 1 ) return IRC_WriteStrClient( Client, ERR_NEEDMOREPARAMS_MSG, Client_ID( Client ), Req->command ); + if (Req->argc != 1) + return IRC_WriteStrClient(Client, ERR_NEEDMOREPARAMS_MSG, + Client_ID(Client), Req->command); - Log( LOG_NOTICE|LOG_snotice, "Got DISCONNECT command from \"%s\" for0 \"%s\".", Client_Mask( Client ), Req->argv[0]); + IRC_SendWallops(Client_ThisServer(), Client_ThisServer(), + "Received DISCONNECT %s from %s", + Req->argv[0], Client_ID(Client)); + + Log(LOG_NOTICE | LOG_snotice, + "Got DISCONNECT command from \"%s\" for \"%s\".", + Client_Mask(Client), Req->argv[0]); /* Save ID of this connection */ - my_conn = Client_Conn( Client ); + my_conn = Client_Conn(Client); - /* Connect configured server */ - if( ! Conf_DisableServer( Req->argv[0] )) return IRC_WriteStrClient( Client, ERR_NOSUCHSERVER_MSG, Client_ID( Client ), Req->argv[0] ); + /* Disconnect configured server */ + if (!Conf_DisableServer(Req->argv[0])) + return IRC_WriteStrClient(Client, ERR_NOSUCHSERVER_MSG, + Client_ID(Client), Req->argv[0]); /* Are we still connected or were we killed, too? */ - if( Conn_GetClient( my_conn )) return CONNECTED; - else return DISCONNECTED; -} /* IRC_CONNECT */ + if (Conn_GetClient(my_conn)) + return CONNECTED; + else + return DISCONNECTED; +} /* IRC_DISCONNECT */ GLOBAL bool IRC_WALLOPS( CLIENT *Client, REQUEST *Req ) { - CLIENT *to, *from; - int client_type; + CLIENT *from; assert( Client != NULL ); assert( Req != NULL ); @@ -268,8 +325,7 @@ IRC_WALLOPS( CLIENT *Client, REQUEST *Req ) if (Req->argc != 1) return IRC_WriteStrClient(Client, ERR_NEEDMOREPARAMS_MSG, Client_ID(Client), Req->command); - client_type = Client_Type(Client); - switch (client_type) { + switch (Client_Type(Client)) { case CLIENT_USER: if (!Client_OperByMe(Client)) return IRC_WriteStrClient(Client, ERR_NOPRIVILEGES_MSG, Client_ID(Client)); @@ -285,25 +341,9 @@ IRC_WALLOPS( CLIENT *Client, REQUEST *Req ) if (!from) return IRC_WriteStrClient(Client, ERR_NOSUCHNICK_MSG, Client_ID(Client), Req->prefix); - for (to=Client_First(); to != NULL; to=Client_Next(to)) { - if (Client_Conn(to) < 0) /* no local connection or WALLOPS origin */ - continue; - - client_type = Client_Type(to); - switch (client_type) { - case CLIENT_USER: - if (Client_HasMode(to, 'w')) - IRC_WriteStrClientPrefix(to, from, "WALLOPS :%s", Req->argv[0]); - break; - case CLIENT_SERVER: - if (to != Client) - IRC_WriteStrClientPrefix(to, from, "WALLOPS :%s", Req->argv[0]); - break; - } - } + IRC_SendWallops(Client, from, "%s", Req->argv[0]); return CONNECTED; -} - +} /* IRC_WALLOPS */ /* -eof- */ diff --git a/src/ngircd/irc-server.c b/src/ngircd/irc-server.c index 7236d9a..a0a9468 100644 --- a/src/ngircd/irc-server.c +++ b/src/ngircd/irc-server.c @@ -37,6 +37,7 @@ #include "numeric.h" #include "ngircd.h" #include "irc-info.h" +#include "op.h" #include "exp.h" #include "irc-server.h" @@ -51,7 +52,6 @@ IRC_SERVER( CLIENT *Client, REQUEST *Req ) { char str[LINE_LEN]; CLIENT *from, *c; - bool ok; int i; CONN_ID con; @@ -97,25 +97,25 @@ IRC_SERVER( CLIENT *Client, REQUEST *Req ) /* Is this server registering on our side, or are we connecting to * a remote server? */ - con = Client_Conn( Client ); - if( Client_Token( Client ) != TOKEN_OUTBOUND ) - { + con = Client_Conn(Client); + if (Client_Token(Client) != TOKEN_OUTBOUND) { /* Incoming connection, send user/pass */ - ok = true; - if( ! IRC_WriteStrClient( Client, "PASS %s %s", Conf_Server[i].pwd_out, NGIRCd_ProtoID )) ok = false; - else ok = IRC_WriteStrClient( Client, "SERVER %s 1 :%s", Conf_ServerName, Conf_ServerInfo ); - if( ! ok ) - { - Conn_Close( con, "Unexpected server behavior!", NULL, false ); - return DISCONNECTED; + if (!IRC_WriteStrClient(Client, "PASS %s %s", + Conf_Server[i].pwd_out, + NGIRCd_ProtoID) + || !IRC_WriteStrClient(Client, "SERVER %s 1 :%s", + Conf_ServerName, + Conf_ServerInfo)) { + Conn_Close(con, "Unexpected server behavior!", + NULL, false); + return DISCONNECTED; } - Client_SetIntroducer( Client, Client ); - Client_SetToken( Client, 1 ); - } - else - { - /* outgoing connect, we already sent SERVER and PASS to the peer */ - Client_SetToken( Client, atoi( Req->argv[1] )); + Client_SetIntroducer(Client, Client); + Client_SetToken(Client, 1); + } else { + /* outgoing connect, we already sent a SERVER and PASS + * command to the peer */ + Client_SetToken(Client, atoi(Req->argv[1])); } /* Mark this connection as belonging to an configured server */ @@ -267,46 +267,99 @@ IRC_NJOIN( CLIENT *Client, REQUEST *Req ) } /* IRC_NJOIN */ +/** + * Handler for the IRC command "SQUIT". + * See RFC 2813 section 4.1.2 and RFC 2812 section 3.1.8. + */ GLOBAL bool -IRC_SQUIT( CLIENT *Client, REQUEST *Req ) +IRC_SQUIT(CLIENT * Client, REQUEST * Req) { - CLIENT *target; - char msg[LINE_LEN + 64]; + char msg[COMMAND_LEN], logmsg[COMMAND_LEN]; + CLIENT *from, *target; + CONN_ID con; - assert( Client != NULL ); - assert( Req != NULL ); + assert(Client != NULL); + assert(Req != NULL); - if( Req->argc != 2 ) return IRC_WriteStrClient( Client, ERR_NEEDMOREPARAMS_MSG, Client_ID( Client ), Req->command ); + if (Client_Type(Client) != CLIENT_SERVER + && !Client_HasMode(Client, 'o')) + return Op_NoPrivileges(Client, Req); - Log( LOG_DEBUG, "Got SQUIT from %s for \"%s\": \"%s\" ...", Client_ID( Client ), Req->argv[0], Req->argv[1] ); + /* Bad number of arguments? */ + if (Req->argc != 2) + return IRC_WriteStrClient(Client, ERR_NEEDMOREPARAMS_MSG, + Client_ID(Client), Req->command); - target = Client_Search( Req->argv[0] ); - if( ! target ) - { - Log( LOG_WARNING, "Got SQUIT from %s for unknown server \"%s\"!?", Client_ID( Client ), Req->argv[0] ); + if (Client_Type(Client) == CLIENT_SERVER && Req->prefix) { + from = Client_Search(Req->prefix); + if (Client_Type(from) != CLIENT_SERVER + && !Op_Check(Client, Req)) + return Op_NoPrivileges(Client, Req); + } else + from = Client; + if (!from) + return IRC_WriteStrClient(Client, ERR_NOSUCHNICK_MSG, + Client_ID(Client), Req->prefix); + + Log(LOG_DEBUG, "Got SQUIT from %s for \"%s\": \"%s\" ...", + Client_ID(from), Req->argv[0], Req->argv[1]); + + target = Client_Search(Req->argv[0]); + if (Client_Type(Client) != CLIENT_SERVER && + target == Client_ThisServer()) + return Op_NoPrivileges(Client, Req); + if (!target) { + /* The server is (already) unknown */ + Log(LOG_WARNING, + "Got SQUIT from %s for unknown server \"%s\"!?", + Client_ID(Client), Req->argv[0]); return CONNECTED; } - if( Req->argv[1][0] ) - { - if( strlen( Req->argv[1] ) > LINE_LEN ) Req->argv[1][LINE_LEN] = '\0'; - snprintf( msg, sizeof( msg ), "%s (SQUIT from %s).", Req->argv[1], Client_ID( Client )); - } - else snprintf( msg, sizeof( msg ), "Got SQUIT from %s.", Client_ID( Client )); + con = Client_Conn(target); - if( Client_Conn( target ) > NONE ) - { - /* This server has the connection */ - if( Req->argv[1][0] ) Conn_Close( Client_Conn( target ), msg, Req->argv[1], true); - else Conn_Close( Client_Conn( target ), msg, NULL, true); - return DISCONNECTED; - } + if (Req->argv[1][0]) + if (Client_NextHop(from) != Client || con > NONE) + snprintf(msg, sizeof(msg), "%s (SQUIT from %s)", + Req->argv[1], Client_ID(from)); + else + strlcpy(msg, Req->argv[1], sizeof(msg)); else - { - /* connection was on another server */ - Client_Destroy( target, msg, Req->argv[1], false ); - return CONNECTED; + snprintf(msg, sizeof(msg), "Got SQUIT from %s", + Client_ID(from)); + + if (con > NONE) { + /* We are directly connected to the target server, so we + * have to tear down the connection and to inform all the + * other remaining servers in the network */ + IRC_SendWallops(Client_ThisServer(), Client_ThisServer(), + "Received SQUIT %s from %s: %s", + Req->argv[0], Client_ID(from), + Req->argv[1][0] ? Req->argv[1] : "-"); + Conn_Close(con, NULL, msg, true); + if (con == Client_Conn(Client)) + return DISCONNECTED; + } else { + /* This server is not directly connected, so the SQUIT must + * be forwarded ... */ + if (Client_Type(from) != CLIENT_SERVER) { + /* The origin is not an IRC server, so don't evaluate + * this SQUIT but simply forward it */ + IRC_WriteStrClientPrefix(Client_NextHop(target), + from, "SQUIT %s :%s", Req->argv[0], Req->argv[1]); + } else { + /* SQUIT has been generated by another server, so + * remove the target server from the network! */ + logmsg[0] = '\0'; + if (!strchr(msg, '(')) + snprintf(logmsg, sizeof(logmsg), + "%s (SQUIT from %s)", Req->argv[1], + Client_ID(from)); + Client_Destroy(target, logmsg[0] ? logmsg : msg, + msg, false); + } } + return CONNECTED; } /* IRC_SQUIT */ /* -eof- */ diff --git a/src/ngircd/irc-write.c b/src/ngircd/irc-write.c index ea0f5f8..9b5b5e2 100644 --- a/src/ngircd/irc-write.c +++ b/src/ngircd/irc-write.c @@ -1,6 +1,6 @@ /* * ngIRCd -- The Next Generation IRC Daemon - * Copyright (c)2001-2005 by Alexander Barton (alex@barton.de) + * Copyright (c)2001-2008 Alexander Barton (alex@barton.de) * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -405,6 +405,53 @@ va_dcl } /* IRC_WriteStrRelatedPrefix */ +/** + * Send WALLOPS message. + */ +#ifdef PROTOTYPES +GLOBAL void +IRC_SendWallops(CLIENT *Client, CLIENT *From, const char *Format, ...) +#else +GLOBAL void +IRC_SendWallops(Client, From, Format, va_alist ) +CLIENT *Client; +CLIENT *From; +char *Format; +va_dcl +#endif +{ + va_list ap; + char msg[1000]; + CLIENT *to; + +#ifdef PROTOTYPES + va_start(ap, Format); +#else + va_start(ap); +#endif + vsnprintf(msg, 1000, Format, ap); + va_end(ap); + + for (to=Client_First(); to != NULL; to=Client_Next(to)) { + if (Client_Conn(to) == NONE) /* no local connection */ + continue; + + switch (Client_Type(to)) { + case CLIENT_USER: + if (Client_HasMode(to, 'w')) + IRC_WriteStrClientPrefix(to, From, + "WALLOPS :%s", msg); + break; + case CLIENT_SERVER: + if (to != Client) + IRC_WriteStrClientPrefix(to, From, + "WALLOPS :%s", msg); + break; + } + } +} /* IRC_SendWallops */ + + GLOBAL void IRC_SetPenalty( CLIENT *Client, time_t Seconds ) { diff --git a/src/ngircd/irc-write.h b/src/ngircd/irc-write.h index 51c8f0c..a984997 100644 --- a/src/ngircd/irc-write.h +++ b/src/ngircd/irc-write.h @@ -35,6 +35,9 @@ GLOBAL void IRC_WriteStrServersPrefixFlag_CB PARAMS((CLIENT *ExceptOf, GLOBAL bool IRC_WriteStrRelatedPrefix PARAMS((CLIENT *Client, CLIENT *Prefix, bool Remote, char *Format, ...)); +GLOBAL void IRC_SendWallops PARAMS((CLIENT *Client, CLIENT *From, + const char *Format, ...)); + GLOBAL void IRC_SetPenalty PARAMS((CLIENT *Client, time_t Seconds)); #endif diff --git a/src/ngircd/ngircd.c b/src/ngircd/ngircd.c index 95c377a..5fc88c9 100644 --- a/src/ngircd/ngircd.c +++ b/src/ngircd/ngircd.c @@ -1,6 +1,6 @@ /* * ngIRCd -- The Next Generation IRC Daemon - * Copyright (c)2001-2008 Alexander Barton (alex@barton.de). + * Copyright (c)2001-2009 Alexander Barton (alex@barton.de). * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -562,7 +562,7 @@ static void Show_Version( void ) { puts( NGIRCd_Version ); - puts( "Copyright (c)2001-2008 Alexander Barton () and Contributors." ); + puts( "Copyright (c)2001-2009 Alexander Barton () and Contributors." ); puts( "Homepage: \n" ); puts( "This is free software; see the source for copying conditions. There is NO" ); puts( "warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE." ); diff --git a/src/ngircd/op.c b/src/ngircd/op.c new file mode 100644 index 0000000..031bc28 --- /dev/null +++ b/src/ngircd/op.c @@ -0,0 +1,82 @@ +/* + * ngIRCd -- The Next Generation IRC Daemon + * Copyright (c)2001-2008 Alexander Barton (alex@barton.de) + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * Please read the file COPYING, README and AUTHORS for more information. + * + * IRC operator functions + */ + + +#include "portab.h" + +#include "imp.h" +#include +#include + +#include "conn.h" +#include "client.h" +#include "channel.h" +#include "conf.h" +#include "log.h" +#include "parse.h" +#include "messages.h" +#include "irc-write.h" + +#include +#include "op.h" + +/** + * Return and log a "no privileges" message. + */ +GLOBAL bool +Op_NoPrivileges(CLIENT * Client, REQUEST * Req) +{ + CLIENT *from = NULL; + + if (Req->prefix) + from = Client_Search(Req->prefix); + + if (from) { + Log(LOG_NOTICE, "No privileges: client \"%s\" (%s), command \"%s\"", + Req->prefix, Client_Mask(Client), Req->command); + return IRC_WriteStrClient(from, ERR_NOPRIVILEGES_MSG, + Client_ID(from)); + } else { + Log(LOG_NOTICE, "No privileges: client \"%s\", command \"%s\"", + Client_Mask(Client), Req->command); + return IRC_WriteStrClient(Client, ERR_NOPRIVILEGES_MSG, + Client_ID(Client)); + } +} /* Op_NoPrivileges */ + + +/** + * Check that the client is an IRC operator allowed to administer this server. + */ +GLOBAL bool +Op_Check(CLIENT * Client, REQUEST * Req) +{ + CLIENT *c; + + assert(Client != NULL); + assert(Req != NULL); + + if (Client_Type(Client) == CLIENT_SERVER && Req->prefix) + c = Client_Search(Req->prefix); + else + c = Client; + if (!c) + return false; + if (!Client_HasMode(c, 'o')) + return false; + if (!Client_OperByMe(c) && !Conf_AllowRemoteOper) + return false; + /* The client is an local IRC operator, or this server is configured + * to trust remote operators. */ + return true; +} /* Op_Check */ diff --git a/src/ngircd/op.h b/src/ngircd/op.h new file mode 100644 index 0000000..544be25 --- /dev/null +++ b/src/ngircd/op.h @@ -0,0 +1,22 @@ +/* + * ngIRCd -- The Next Generation IRC Daemon + * Copyright (c)2001-2009 Alexander Barton (alex@barton.de) + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * Please read the file COPYING, README and AUTHORS for more information. + * + * Operator management (header) + */ + +#ifndef __oper_h__ +#define __oper_h__ + +GLOBAL bool Op_NoPrivileges PARAMS((CLIENT * Client, REQUEST * Req)); +GLOBAL bool Op_Check PARAMS((CLIENT * Client, REQUEST * Req)); + +#endif + +/* -eof- */ diff --git a/src/ngircd/parse.c b/src/ngircd/parse.c index 5e3f08d..2c28a30 100644 --- a/src/ngircd/parse.c +++ b/src/ngircd/parse.c @@ -59,7 +59,7 @@ static COMMAND My_Commands[] = { { "ADMIN", IRC_ADMIN, CLIENT_USER|CLIENT_SERVER, 0, 0, 0 }, { "AWAY", IRC_AWAY, CLIENT_USER, 0, 0, 0 }, - { "CONNECT", IRC_CONNECT, CLIENT_USER, 0, 0, 0 }, + { "CONNECT", IRC_CONNECT, CLIENT_USER|CLIENT_SERVER, 0, 0, 0 }, { "DIE", IRC_DIE, CLIENT_USER, 0, 0, 0 }, { "DISCONNECT", IRC_DISCONNECT, CLIENT_USER, 0, 0, 0 }, { "ERROR", IRC_ERROR, 0xFFFF, 0, 0, 0 }, @@ -92,7 +92,7 @@ static COMMAND My_Commands[] = { "SERVICE", IRC_SERVICE, 0xFFFF, 0, 0, 0 }, { "SERVLIST", IRC_SERVLIST, CLIENT_USER, 0, 0, 0 }, { "SQUERY", IRC_SQUERY, CLIENT_USER|CLIENT_SERVER, 0, 0, 0 }, - { "SQUIT", IRC_SQUIT, CLIENT_SERVER, 0, 0, 0 }, + { "SQUIT", IRC_SQUIT, CLIENT_USER|CLIENT_SERVER, 0, 0, 0 }, { "STATS", IRC_STATS, CLIENT_USER|CLIENT_SERVER, 0, 0, 0 }, { "SUMMON", IRC_SUMMON, CLIENT_USER|CLIENT_SERVER, 0, 0, 0 }, { "TIME", IRC_TIME, CLIENT_USER|CLIENT_SERVER, 0, 0, 0 }, diff --git a/src/ngircd/resolve.c b/src/ngircd/resolve.c index e7f73ad..b1487be 100644 --- a/src/ngircd/resolve.c +++ b/src/ngircd/resolve.c @@ -1,6 +1,6 @@ /* * ngIRCd -- The Next Generation IRC Daemon - * Copyright (c)2001-2003 by Alexander Barton (alex@barton.de) + * Copyright (c)2001-2009 by Alexander Barton (alex@barton.de) * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -218,7 +218,7 @@ ReverseLookup(const ng_ipaddr_t *IpAddr, char *resbuf, size_t reslen) *resbuf = 0; res = getnameinfo((struct sockaddr *) IpAddr, ng_ipaddr_salen(IpAddr), - resbuf, reslen, NULL, 0, NI_NAMEREQD); + resbuf, (socklen_t)reslen, NULL, 0, NI_NAMEREQD); if (res == 0) return true; @@ -291,6 +291,8 @@ ForwardLookup(const char *hostname, array *IpAddr) if (!Conf_ConnectIPv4) hints.ai_family = AF_INET6; #endif + memset(&addr, 0, sizeof(addr)); + res = getaddrinfo(hostname, NULL, &hints, &ai_results); switch (res) { case 0: break; @@ -540,5 +542,6 @@ Resolve_Read( RES_STAT *s, void* readbuf, size_t buflen) Resolve_Shutdown(s); return (size_t)bytes_read; } -/* -eof- */ + +/* -eof- */ diff --git a/src/tool/tool.c b/src/tool/tool.c index a24c160..c973539 100644 --- a/src/tool/tool.c +++ b/src/tool/tool.c @@ -1,6 +1,6 @@ /* * ngIRCd -- The Next Generation IRC Daemon - * Copyright (c)2001-2008 Alexander Barton (alex@barton.de) + * Copyright (c)2001-2009 Alexander Barton (alex@barton.de) * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -107,16 +107,19 @@ ngt_TrimLastChr( char *String, const char Chr) /* If last character in the string matches Chr, remove it. * Empty strings are handled correctly. */ - unsigned int len; + size_t len; - assert( String != NULL ); + assert(String != NULL); - len = strlen( String ); - if( len == 0 ) return; + len = strlen(String); + if(len == 0) + return; len--; - if( String[len] == Chr ) String[len] = '\0'; + if(String[len] == Chr) + String[len] = '\0'; } /* ngt_TrimLastChr */ + /* -eof- */