AUTHORS | 4 +- ChangeLog | 44 ++++- Makefile.am | 15 ++- NEWS | 25 ++- configure.in | 2 +- contrib/Debian/changelog | 6 + contrib/Debian/ngircd.init | 154 +++++++++++----- contrib/MacOSX/config.h | 20 ++- contrib/MacOSX/ngIRCd.pmdoc/index.xml | 12 +- contrib/MacOSX/ngIRCd.xcodeproj/project.pbxproj | 56 ++++++- contrib/ngircd.spec | 27 ++- doc/README-AUX.txt | 4 +- doc/README-BeOS.txt | 2 +- doc/SSL.txt | 10 +- doc/Zeroconf.txt | 2 +- doc/sample-ngircd.conf | 10 +- man/ngircd.8.tmpl | 5 +- man/ngircd.conf.5.tmpl | 123 +++++++++---- src/ngircd/channel.c | 224 ++++++++++++++++------- src/ngircd/channel.h | 12 +- src/ngircd/client.c | 2 +- src/ngircd/conf.c | 105 ++++++----- src/ngircd/conf.h | 12 +- src/ngircd/conn-ssl.c | 7 +- src/ngircd/conn.h | 17 ++- src/ngircd/defines.h | 6 - src/ngircd/irc-channel.c | 9 +- src/ngircd/irc-info.c | 10 +- src/ngircd/irc-login.c | 6 +- src/ngircd/irc-mode.c | 182 +++++++++++++------ src/ngircd/irc.c | 29 +++- src/ngircd/log.c | 53 +++--- src/ngircd/messages.h | 3 +- src/ngircd/ngircd.c | 2 +- src/ngircd/parse.c | 2 +- src/ngircd/resolve.c | 4 +- src/testsuite/ngircd-test1.conf | 12 +- 37 files changed, 840 insertions(+), 378 deletions(-) diff --git a/AUTHORS b/AUTHORS index bb7035f..b9e3eea 100644 --- a/AUTHORS +++ b/AUTHORS @@ -1,7 +1,7 @@ ngIRCd - Next Generation IRC Server - (c)2001-2007 Alexander Barton, + (c)2001-2009 Alexander Barton, alex@barton.de, http://www.barton.de/ ngIRCd is free software and published under the @@ -25,6 +25,7 @@ Florian Westphal, (fw) Contributors ~~~~~~~~~~~~ Ali Shemiran, +Ask Bjørn Hansen, Benjamin Pineau, Brandon Beresini, Bryan Caldwell, @@ -32,6 +33,7 @@ Dana Dahlstrom, Eric Grunow, Goetz Hoffart, Ilja Osthoff, +Jari Aalto, Rolf Eike Beer, Scott Perry, Sean Reifschneider, diff --git a/ChangeLog b/ChangeLog index 8d730bf..d6acd2f 100644 --- a/ChangeLog +++ b/ChangeLog @@ -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 @@ -10,14 +10,38 @@ -- ChangeLog -- +ngIRCd Release 14 + + ngIRCd 14~rc1 (2009-03-29) + - Updated Debian/Linux init script (see contrib/Debian/ngircd.init). + - Allow creation of persistent modeless channels. + - The INFO command reports the compile time now (if available). + - Spell check and enhance ngIRCd manual pages. + - Channel mode changes: break on syntax errors in MODE command. + - Support individual channel keys for pre-defined channels: introduce + new configuration variable "KeyFile" in [Channel] sections in ngircd.conf, + here a file can be configured for each pre-defined channel which contains + individual channel keys for different users. + - Remove limit on maximum number of predefined channels in ngircd.conf. + - Updated ngircd.spec file for building RPM packages. + - Add new and missing files to Mac OS X Xcode project, and update project. + - Implement pre-defined server local channels ("&") and write some + server-specific messages to &SERVER. + - Reject masks with wildcard after last dot. + - TLS/SSL: remove useless error message when ssl connection is closed. + - Fix memory leak when a encrypted and compressed server link goes down. + (closes bug #95, reported by Christoph, fiesh@fiesh.homeip.net) + - Fix handling of channels containing dots. + (closes ug #93, reported by Gonosz Csiga) + ngIRCd Release 13 (2008-12-25) - Updated documentation, especially doc/Services.txt and doc/SSL.txt. - Make the test suite work on OpenSolaris. ngIRCd 13~rc1 (2008-11-21): - - New version numer scheme :-) - - Initial support for IRC services, using a RFC1459 styel interface, + - New version number scheme :-) + - Initial support for IRC services, using a RFC1459 style interface, tested with IRCServices (http://www.ircservices.za.net/) version 5.1.13. For this to work, ngIRCd now supports server-server links conforming to RFC 1459. New ngircd.conf(5) option: ServiceMask. @@ -49,7 +73,7 @@ ngIRCd 0.12.1 (2008-07-09) - Update ngIRCd manual pages - Add option aliases -V (for --version) and -h (for --help). - Fix 'no-ipv6' compile error. - - Make Listen parameter a comma-seperated list of addresses. This also + - Make Listen parameter a comma-separated list of addresses. This also obsoletes ListenIPv4 and ListenIPv6 options. If Listen is unset, it is treated as Listen="::,0.0.0.0". Note: ListenIPv4 and ListenIPv6 options are still recognized, @@ -59,11 +83,11 @@ ngIRCd 0.12.0 (2008-05-13) - Fix Bug: 85: "WHO #SecretChannel" that user is not a member of now returns proper RPL_ENDOFWHO_MSG instead of nothing. (Ali Shemiran) - - Fix complie on FreeBSD 5.4 and AIX. - - If bind() fails, also print ip address and not just the port number. + - Fix compile on FreeBSD 5.4 and AIX. + - If bind() fails, also print IP address and not just the port number. ngIRCd 0.12.0-pre2 (2008-04-29) - - IPv6: Add config options to disabe ipv4/ipv6 support. + - IPv6: Add config options to disable ipv4/ipv6 support. - Don't include doc/CVS.txt in distribution archive, use doc/GIT.txt now! - Documentation: get rid of some more references to CVS, switch to GIT. - Get rid of cvs-version.* and CVSDATE definition. @@ -106,11 +130,11 @@ ngIRCd 0.11.0 (2008-01-15) - Use dotted-decimal IP address if hostname is >= 64. - Add support for /STAT u (server uptime) command. - New [Server] configuration Option "Bind" allows to specify - the source ip adress to use when connecting to remote server. + the source IP address to use when connecting to remote server. - New configuration option "MaxNickLength" to specify the allowed maximum length of user nick names. Note: must be unique in an IRC network! - Enhanced the IRC+ protocol to support an enhanced "server handshake" and - enable server to recognice numeric 005 (ISUPPORT) and 376 (ENDOFMOTD). + enable server to recognize numeric 005 (ISUPPORT) and 376 (ENDOFMOTD). See doc/Protocol.txt for details. - Re-added doc/SSL.txt to distribution -- got lost somewhere!? - Fixes the wrong logging output when nested servers are introduced @@ -439,7 +463,7 @@ ngIRCd 0.7.0 (2003-05-01) - Better error reporting to clients on connect. - Enhanced manual pages ngircd(8) and ngircd.conf(5). - Documentation is now installed in $(datadir)/doc/ngircd. - - Enhanced hanling of NJOIN in case of nick collisions. + - Enhanced handling of NJOIN in case of nick collisions. ngIRCd 0.6.1, 2003-01-21 diff --git a/Makefile.am b/Makefile.am index 701bf6b..0fd0622 100644 --- a/Makefile.am +++ b/Makefile.am @@ -32,12 +32,21 @@ lint: srcdoc: make -C doc srcdoc -xcode: +have-xcodebuild: @xcodebuild -project contrib/MacOSX/ngIRCd.xcodeproj -list \ >/dev/null 2>&1 \ || ( echo; echo "Error: \"xcodebuild\" not found!"; echo; exit 1 ) + +xcode: have-xcodebuild + rel=`grep AC_INIT configure.in | cut -d' ' -f2 | cut -d')' -f1`; \ + def="GCC_PREPROCESSOR_DEFINITIONS=\"VERSION=\\\"$$rel\\\"\""; \ + xcodebuild -project contrib/MacOSX/ngIRCd.xcodeproj -alltargets \ + -configuration Default $$def build + +xcode-clean: have-xcodebuild xcodebuild -project contrib/MacOSX/ngIRCd.xcodeproj -alltargets \ - -buildstyle Development + -configuration Default clean + rm -fr contrib/MacOSX/build rpm: distcheck rpm -ta ngircd-*.tar.gz @@ -46,7 +55,7 @@ deb: [ -f debian/rules ] || ln -s contrib/Debian debian dpkg-buildpackage -rfakeroot -i -osxpkg: +osxpkg: have-xcodebuild @packagemaker >/dev/null 2>&1; [ $$? -ge 1 ] \ || ( echo; echo "Error: \"packagemaker\" not found!"; echo; exit 2) make clean diff --git a/NEWS b/NEWS index 92a6b35..27276cf 100644 --- a/NEWS +++ b/NEWS @@ -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 @@ -10,11 +10,24 @@ -- NEWS -- +ngIRCd Release 14 + + ngIRCd 14~rc1 (2009-03-29) + - Allow creation of persistent modeless channels. + - The INFO command reports the compile time now (if available). + - Support individual channel keys for pre-defined channels: introduce + new configuration variable "KeyFile" in [Channel] sections in ngircd.conf, + here a file can be configured for each pre-defined channel which contains + individual channel keys for different users. + - Remove limit on maximum number of predefined channels in ngircd.conf. + - Implement pre-defined server local channels ("&") and write some + server-specific messages to &SERVER. + ngIRCd Release 13 (2008-12-25) ngIRCd 13~rc1 (2008-11-21): - - New version numer scheme :-) - - Initial support for IRC services, using a RFC1459 styel interface, + - New version number scheme :-) + - Initial support for IRC services, using a RFC1459 style interface, tested with IRCServices (http://www.ircservices.za.net/) version 5.1.13. For this to work, ngIRCd now supports server-server links conforming to RFC 1459. New ngircd.conf(5) option: ServiceMask. @@ -33,7 +46,7 @@ ngIRCd Release 13 (2008-12-25) ngIRCd 0.12.1 (2008-07-09) - Add option aliases -V (for --version) and -h (for --help). - - Make Listen parameter a comma-seperated list of addresses. This also + - Make Listen parameter a comma-separated list of addresses. This also obsoletes ListenIPv4 and ListenIPv6 options. If Listen is unset, it is treated as Listen="::,0.0.0.0". Note: ListenIPv4 and ListenIPv6 options are still recognized, @@ -42,7 +55,7 @@ ngIRCd 0.12.1 (2008-07-09) ngIRCd 0.12.0 (2008-05-13) ngIRCd 0.12.0-pre2 (2008-04-29) - - IPv6: Add config options to disabe ipv4/ipv6 support. + - IPv6: Add config options to disable ipv4/ipv6 support. ngIRCd 0.12.0-pre1 (2008-04-20) - Add IPv6 support. @@ -61,7 +74,7 @@ ngIRCd 0.11.0 (2008-01-15) - Add support for /STAT u (server uptime) command. - New [Server] configuration Option "Bind" allows to specify - the source ip adress to use when connecting to remote server. + the source IP address to use when connecting to remote server. - New configuration option "MaxNickLength" to specify the allowed maximum length of user nick names. Note: must be unique in an IRC network! - Numeric 317: implemented "signon time" (displayed in WHOIS result). diff --git a/configure.in b/configure.in index be03945..98d9ac7 100644 --- a/configure.in +++ b/configure.in @@ -12,7 +12,7 @@ # -- Initialisation -- AC_PREREQ(2.50) -AC_INIT(ngircd, 13) +AC_INIT(ngircd, 14~rc1) AC_CONFIG_SRCDIR(src/ngircd/ngircd.c) AC_CANONICAL_TARGET AM_INIT_AUTOMAKE(1.6) diff --git a/contrib/Debian/changelog b/contrib/Debian/changelog index 1e1b0e0..1e88c6a 100644 --- a/contrib/Debian/changelog +++ b/contrib/Debian/changelog @@ -1,3 +1,9 @@ +ngircd (14~rc1-0ab1 unstable; urgency=low + + * New "upstream" release candidate for 1 for ngIRCd Release 14. + + -- Alexander Barton Sun, 29 Mar 2009 17:09:17 +0200 + ngircd (13-0ab1) unstable; urgency=low * New "upstream" release: ngIRCd 13. diff --git a/contrib/Debian/ngircd.init b/contrib/Debian/ngircd.init index 7262429..f308dd2 100755 --- a/contrib/Debian/ngircd.init +++ b/contrib/Debian/ngircd.init @@ -1,18 +1,19 @@ #!/bin/sh # # ngIRCd start and stop script for Debian-based systems -# Copyright 2008 Alexander Barton +# Copyright 2008,2009 Alexander Barton # ### BEGIN INIT INFO -# Provides: ircd -# Required-Start: $remote_fs -# Required-Stop: $remote_fs -# Should-Start: $syslog +# Provides: ngircd ircd +# Required-Start: $network $local_fs +# Required-Stop: +# Should-Start: $syslog $named # Should-Stop: $syslog # Default-Start: 2 3 4 5 # Default-Stop: 0 1 6 # Short-Description: Next Generation IRC Server +# Description: IRC daemon written from scratch ### END INIT INFO PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin @@ -20,14 +21,16 @@ DAEMON=/usr/sbin/ngircd NAME=ngIRCd DESC="IRC daemon" PARAMS="" +STARTTIME=1 +DIETIME=10 + +test -x $DAEMON || exit 5 test -h "$0" && me=`readlink $0` || me="$0" BASENAME=`basename $me` test -r /etc/default/$BASENAME && . /etc/default/$BASENAME -test -x $DAEMON || exit 0 - # LSB compatibility functions that become used if there is no local # include file available. log_daemon_msg() { @@ -39,69 +42,134 @@ log_end_msg() { log_failure_msg() { echo "$*" } +log_warning_msg() { + log_failure_msg "$*" +} # Include LSB functions, if available: test -r /lib/lsb/init-functions && . /lib/lsb/init-functions +PIDFILE=`$DAEMON $PARAMS -t | tr -d ' ' | grep "^PidFile=" | cut -d'=' -f2` +[ -n "$PIDFILE" ] || PIDFILE="/var/run/ircd/ngircd.pid" + +r=3 + Check_Config() { # Make sure that the configuration of ngIRCd is valid: - $DAEMON --configtest >/dev/null 2>&1 - if [ $? -ne 0 ]; then - log_failure_msg "Configuration of $NAME is not valid, won't (re)start!" - log_failure_msg "Run \"$DAEMON --configtest\" and fix it up ..." - exit 1 - fi + $DAEMON $PARAMS --configtest >/dev/null 2>&1 + [ $? -eq 0 ] && return 0 + log_end_msg 1 + log_failure_msg "Configuration of $NAME is not valid, won't (re)start!" + log_failure_msg "Run \"$DAEMON --configtest\" and fix it up ..." + exit 6 +} + +Prepare() { # Make sure the PID file directory exists and is writable: - if [ ! -d /var/run/ircd ]; then - mkdir -p /var/run/ircd + user=`$DAEMON $PARAMS -t|tr -d ' '|grep "^ServerUID="|cut -d'=' -f2` + group=`$DAEMON $PARAMS -t|tr -d ' '|grep "^ServerGID="|cut -d'=' -f2` + piddir=`dirname "$PIDFILE"` + [ -d "$piddir" ] || mkdir -p "$piddir" 2>/dev/null + chown "$user:$group" "$piddir" 2>/dev/null + [ $? -eq 0 ] && return 0 + log_end_msg 1 + log_failure_msg "Failed to prepare '$piddir' for user '$user'!" + exit 1 +} + +Do_Start() { + if Do_Status; then + log_end_msg 0 + log_warning_msg "$NAME seems to be already running, nothing to do." + exit 0 fi - chown irc:irc /var/run/ircd + start-stop-daemon --start \ + --quiet --exec $DAEMON -- $PARAMS + sleep $STARTTIME + Do_Status || return 7 + return 0 +} + +Do_Stop() { + if ! Do_Status; then + log_end_msg 0 + log_warning_msg "$NAME seems not to be running, nothing to do." + exit 0 + fi + Do_ForceStop + return $? +} + +Do_ForceStop() { + [ -e $PIDFILE ] \ + && pidfile="--pidfile $PIDFILE" \ + || pidfile="" + start-stop-daemon --stop \ + --quiet --oknodo --exec $DAEMON $pidfile + for i in `seq 1 $DIETIME`; do + Do_Status || return 0 + sleep 1 + done + return 1 +} + +Do_Reload() { + start-stop-daemon --stop --signal 1 --quiet --exec $DAEMON + return $? +} + +Do_Status() { + [ -e $PIDFILE ] \ + && pidfile="--pidfile $PIDFILE" \ + || pidfile="" + start-stop-daemon --stop \ + --quiet --signal 0 --exec $DAEMON $pidfile >/dev/null + return $? } case "$1" in start) - Check_Config log_daemon_msg "Starting $DESC" "$NAME" - start-stop-daemon --start \ - --quiet --exec $DAEMON -- $PARAMS - log_end_msg $? + Check_Config + Prepare + Do_Start; r=$? + log_end_msg $r ;; stop) log_daemon_msg "Stopping $DESC" "$NAME" - [ -r /var/run/ircd/ngircd.pid ] \ - && PIDFILE="--pidfile /var/run/ircd/ngircd.pid" \ - || PIDFILE="" - start-stop-daemon --stop \ - --quiet --oknodo --exec $DAEMON $PIDFILE - log_end_msg $? + Do_Stop; r=$? + log_end_msg $r ;; reload|force-reload) - Check_Config log_daemon_msg "Reloading $DESC" "$NAME" - start-stop-daemon --stop --signal 1 --quiet --exec $DAEMON - log_end_msg $? + Check_Config + Do_Reload; r=$? + log_end_msg $r ;; restart) - Check_Config log_daemon_msg "Restarting $DESC" "$NAME" - [ -r /var/run/ircd/ngircd.pid ] \ - && PIDFILE="--pidfile /var/run/ircd/ngircd.pid" \ - || PIDFILE="" - start-stop-daemon --stop \ - --quiet --oknodo --exec $DAEMON $PIDFILE - sleep 1 - start-stop-daemon --start \ - --quiet --exec $DAEMON -- $PARAMS - log_end_msg $? + Check_Config + Prepare + Do_ForceStop + Do_Start; r=$? + log_end_msg $r + ;; + status) + log_daemon_msg "Checking for $DESC" "$NAME" + Do_Status; r=$? + log_end_msg $r + ;; + test) + Check_Config + echo "Configuration of $DAEMON seems to be ok."; r=0 ;; *) - N=/etc/init.d/$NAME - echo "Usage: $N {start|stop|restart|reload|force-reload}" >&2 - exit 1 + N=/etc/init.d/$NAME; r=2 + echo "Usage: $N {start|stop|restart|reload|force-reload|status|test}" >&2 ;; esac -exit 0 +exit $r # -eof- diff --git a/contrib/MacOSX/config.h b/contrib/MacOSX/config.h index 8882e46..5ed07d9 100644 --- a/contrib/MacOSX/config.h +++ b/contrib/MacOSX/config.h @@ -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 @@ -8,15 +8,20 @@ * (at your option) any later version. * Please read the file COPYING, README and AUTHORS for more information. * - * $Id: config.h,v 1.1 2007/11/19 22:11:36 alex Exp $ - * * Static configuration file for Mac OS X Xcode project */ #define PACKAGE_NAME "ngircd" +#ifndef VERSION #define VERSION "??" +#endif #define SYSCONFDIR "/etc/ngircd" +#ifndef TARGET_VENDOR +#define TARGET_VENDOR "apple" +#define TARGET_OS "darwin" +#endif + /* -- Build options -- */ /* Define if debug-mode should be enabled */ @@ -43,6 +48,9 @@ /* Define if zlib compression should be enabled */ #define ZLIB 1 +/* Define if IPV6 protocol should be enabled */ +#define WANT_IPV6 1 + /* -- Supported features -- */ /* Define if SSP C support is enabled. */ @@ -78,6 +86,12 @@ #define HAVE_STRDUP 1 /* Define to 1 if you have the `vsnprintf' function. */ #define HAVE_VSNPRINTF 1 +/* Define to 1 if you have the `inet_aton' function. */ +#define HAVE_INET_ATON 1 +/* Define to 1 if you have the `getaddrinfo' function. */ +#define HAVE_GETADDRINFO 1 +/* Define to 1 if you have the `getnameinfo' function. */ +#define HAVE_GETNAMEINFO 1 /* Define if socklen_t exists */ #define HAVE_socklen_t 1 diff --git a/contrib/MacOSX/ngIRCd.pmdoc/index.xml b/contrib/MacOSX/ngIRCd.pmdoc/index.xml index 553e305..2881d58 100644 --- a/contrib/MacOSX/ngIRCd.pmdoc/index.xml +++ b/contrib/MacOSX/ngIRCd.pmdoc/index.xml @@ -1,10 +1,10 @@ -ngIRCd/Users/alex/Desktop/ngIRCd.mpkgde.barton.ngircdngIRCd – next generation IRC (Internet Relay Chat) server daemon//Library/LaunchDaemonsngIRCd/Users/alex/Desktop/ngIRCd.mpkgde.barton.ngircdngIRCd – next generation IRC (Internet Relay Chat) server daemon//Library/LaunchDaemons -BuildRoot: /var/tmp/%{name}-root +BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-root-%(%{__id_u} -n) +BuildRequires: zlib-devel, openssl-devel %description ngIRCd is a free open source daemon for the Internet Relay Chat (IRC), @@ -29,10 +29,13 @@ ngIRCd is compatible to the "original" ircd 2.10.3p3, so you can run mixed networks. %prep -%setup +%setup -q %build -%configure -make +%configure \ + --with-zlib \ + --with-openssl + +make %{?_smp_mflags} %install [ -n "$RPM_BUILD_ROOT" -a "$RPM_BUILD_ROOT" != / ] && rm -rf "$RPM_BUILD_ROOT" @@ -42,6 +45,7 @@ make ( cd usr/sbin; mv *-ngircd ngircd ) ( cd usr/share/man/man5; mv *-ngircd.conf.5 ngircd.conf.5 ) ( cd usr/share/man/man8; mv *-ngircd.8 ngircd.8 ) + rm -fr usr/share/doc/ngircd ) %clean @@ -49,7 +53,8 @@ make %files %defattr(755,root,root) -%doc AUTHORS COPYING ChangeLog INSTALL NEWS README +%doc AUTHORS COPYING ChangeLog INSTALL NEWS README doc/* %config(noreplace) /etc %{_prefix}/sbin -%{_prefix}/share/man/ +%{_mandir}/man5/ngircd.conf* +%{_mandir}/man8/ngircd.8* diff --git a/doc/README-AUX.txt b/doc/README-AUX.txt index 68eea21..b524294 100644 --- a/doc/README-AUX.txt +++ b/doc/README-AUX.txt @@ -37,7 +37,7 @@ The following software packages are needed: ftp://arthur.barton.de/pub/unix/aux/libraries/libUTIL-2.1.tar.gz This library contains functions that are common on other UNIX - systems but not on A/UX e.g. memmove(), strerror() und strdup(). + systems but not on A/UX e.g. memmove(), strerror() and strdup(). After installation of these packages just do a "./configure" and "make" to @@ -60,7 +60,7 @@ A few hints in case of errors: the 'config.status' script. Better rename /bin/sh to /bin/sh.AUX and replace it by a symbolic link to /bin/ksh (ln -s /bin/ksh /bin/sh as root). - These procedure should'nt cause you into problems and is recommended + These procedure shouldn't cause you into problems and is recommended even if you don't use ngIRCd. -- diff --git a/doc/README-BeOS.txt b/doc/README-BeOS.txt index ea3816d..9e8df38 100644 --- a/doc/README-BeOS.txt +++ b/doc/README-BeOS.txt @@ -24,7 +24,7 @@ mit diesem Fehler ab: select(): Bad file descriptor! Es sieht leider so aus, als ob das select() von BeOS nicht mit File-Handles -von Pipes verschiedener Prozesse umgehen kann: sobald der Resolver asyncron +von Pipes verschiedener Prozesse umgehen kann: sobald der Resolver asynchron gestartet wird, also Pipe-Handles im select() vorhanden sind, fuehrt das zu obiger Meldung. diff --git a/doc/SSL.txt b/doc/SSL.txt index 6b590b8..7207f1b 100644 --- a/doc/SSL.txt +++ b/doc/SSL.txt @@ -20,8 +20,11 @@ options of the ./configure script to enable it: --with-openssl enable SSL support using OpenSSL --with-gnutls enable SSL support using GnuTLS -You need a SSL certificate, see below for how to create a self-signed one. +You also need a key/certificate, see below for how to create a self-signed one. +From a feature point of view, ngIRCds support for both libraries is +comparable. The only major difference (at this time) is that ngircd with gnutls +does not support password protected private keys. Configuration ~~~~~~~~~~~~~ @@ -64,7 +67,7 @@ Create DH parameters (optional): Alternate approach using stunnel(1) ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -Alternatively (or if you are using ngIRCd without compiled without support +Alternatively (or if you are using ngIRCd compiled without support for GnuTLS/OpenSSL), you can use external programs/tools like stunnel(1) to get SSL encrypted connections: @@ -101,4 +104,7 @@ short "how-to", thanks Stefan! That's it. Don't forget to activate ssl support in your irc client ;) + The main drawback of this approach compared to using builtin ssl + is that from ngIRCds point of view, all ssl-enabled client connections will + originate from the host running stunnel. === snip === diff --git a/doc/Zeroconf.txt b/doc/Zeroconf.txt index 04a3232..1208922 100644 --- a/doc/Zeroconf.txt +++ b/doc/Zeroconf.txt @@ -20,7 +20,7 @@ To use this features you can use one of two APIs: of the newer Avahi[5] library. When calling the configure script using the "--with-zeroconf" switch the -avalable API will be autodetected and the required additional libraries will +available API will be autodetected and the required additional libraries will be linked to the ngircd binary as required. ngIRCd then registers a DNS-SD service for each port it is listening on using diff --git a/doc/sample-ngircd.conf b/doc/sample-ngircd.conf index 041542e..0d0061b 100644 --- a/doc/sample-ngircd.conf +++ b/doc/sample-ngircd.conf @@ -56,7 +56,7 @@ # Diffie-Hellman parameters ;SSLDHFile = /usr/local/etc/ngircd/ssl/dhparams.pem - # comma seperated list of IP addresses on which the server should + # comma separated list of IP addresses on which the server should # listen. Default values are: # "0.0.0.0" or (if compiled with IPv6 support) "::,0.0.0.0" # so the server listens on all IP addresses of the system by default. @@ -212,13 +212,13 @@ # Connect to the remote server using TLS/SSL (Default: false) ;SSLConnect = yes - # Define a (case insensitive) mask matching nick names that sould be + # 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 this parameter, so leave it empty # (which is the default). # When you are connecting IRC services which mask as a IRC server # and which use "virtual users" to communicate with, for example - # "NickServ" amd "ChanServ", you should set this parameter to + # "NickServ" and "ChanServ", you should set this parameter to # something like "*Serv". ;ServiceMask = *Serv @@ -245,6 +245,10 @@ # initial channel password (mode k) ;Key = Secret + # Key file, syntax for each line: "::". + # Default: none. + ;KeyFile = /etc/ngircd/#chan.key + # maximum users per channel (mode l) ;MaxUsers = 23 diff --git a/man/ngircd.8.tmpl b/man/ngircd.8.tmpl index 2fc7a9b..bd5b67d 100644 --- a/man/ngircd.8.tmpl +++ b/man/ngircd.8.tmpl @@ -64,15 +64,16 @@ The system wide default configuration file. .RS Default "message of the day" (MOTD). .RE +.SH HINTS +It's wise to use "ngircd \-\-configtest" to validate the configuration file +after changing it. .SH AUTHOR Alexander Barton, .UR mailto:alex@barton.de -alex@barton.de .UE .br Homepage: .UR http://ngircd.barton.de/ -http://ngircd.barton.de/ .UE .SH "SEE ALSO" .BR ngircd.conf (5), diff --git a/man/ngircd.conf.5.tmpl b/man/ngircd.conf.5.tmpl index 3c6c278..df15b77 100644 --- a/man/ngircd.conf.5.tmpl +++ b/man/ngircd.conf.5.tmpl @@ -12,6 +12,9 @@ is the configuration file of the .BR ngircd (8) Internet Relay Chat (IRC) daemon which you should adept to your local preferences and needs. +.PP +Most variables can be modified while the ngIRCd daemon is already running: +It will reload its configuration when a HUP signal is received. .SH "FILE FORMAT" The file consists of sections and parameters. A section begins with the name of the section in square brackets and continues until the next section @@ -58,7 +61,9 @@ section is used to define the server main configuration, like the server name and the ports on which the server should be listening. .TP \fBName\fR -Server name in the IRC network, must contain at least one dot ("."). +Server name in the IRC network. This is an individual name of the IRC +server, it is not related to the DNS host name. It must be unique in the +IRC network and must contain at least one dot (".") character. .TP \fBInfo\fR Info text of the server. This will be shown by WHOIS and LINKS requests for @@ -70,11 +75,12 @@ command. .TP \fBPorts\fR Ports on which the server should listen. There may be more than one port, -separated with ','. Default: 6667. +separated with commas (","). Default: 6667. .TP \fBSSLPorts\fR -Same as \fBPorts\fR , except that ngircd will expect incoming connections -to be SSL/TLS encrypted. Default: None +Same as \fBPorts\fR , except that ngIRCd will expect incoming connections +to be SSL/TLS encrypted. Common port numbers for SSL-encrypted IRC are 6669 +and 6697. Default: none. .TP \fBSSLKeyFile\fR Filename of SSL Server Key to be used for SSL connections. This is required for @@ -84,20 +90,20 @@ SSL/TLS support. (OpenSSL only:) Password to decrypt private key. .TP \fBSSLCertFile\fR -Certificate of the private key +Certificate file of the private key. .TP \fBSSLDHFile\fR Name of the Diffie-Hellman Parameter file. Can be created with gnutls "certtool \-\-generate-dh-params" or "openssl dhparam". -If this file is not present, it will be generated on startup when ngircd -was compiled with gnutls support (this may take some time). If ngircd +If this file is not present, it will be generated on startup when ngIRCd +was compiled with gnutls support (this may take some time). If ngIRCd was compiled with OpenSSL, then (Ephemeral)-Diffie-Hellman Key Exchanges and several Cipher Suites will not be available. .TP \fBListen\fR -A comma seperated list of IP address on which the server should listen. -If unset, the defaults value is "0.0.0.0", or, if ngircd was compiled -with IPv6 support, "::,0.0.0.0", so the server listens on all configured +A comma separated list of IP address on which the server should listen. +If unset, the defaults value is "0.0.0.0" or, if ngIRCd was compiled +with IPv6 support, "::,0.0.0.0". So the server listens on all configured IP addresses and interfaces by default. .TP \fBMotdFile\fR @@ -106,8 +112,8 @@ to all users connecting to the server. .TP \fBMotdPhrase\fR A simple Phrase (<256 chars) if you don't want to use a MOTD file. -If it is set no MotdFile will be read at all which can be handy if the -daemon should run inside a chroot directory. +If this variable is set, no \fBMotdFile\fR will be read at all which can be +handy if the daemon should run inside a chroot directory. .TP \fBServerUID\fR User ID under which the server should run; you can use the name of the user @@ -168,35 +174,35 @@ Should IRC Operators be allowed to use the MODE command even if they are not(!) channel-operators? Default: no. .TP \fBOperServerMode\fR -If OperCanUseMode is enabled, this may lead the compatibility problems with +If \fBOperCanUseMode\fR is enabled, this may lead the compatibility problems with 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 \fBPredefChannelsOnly\fR If enabled, no new channels can be created. Useful if you do not want to have channels other than those defined in -the config file. -Default: No. +[Channel] sections in the configuration file. +Default: no. .TP \fBNoDNS\fR -If set to true, ngircd will not make DNS lookups when clients connect. -If you configure ngircd to connect to other servers, ngircd may still +If set to true, ngIRCd will not make DNS lookups when clients connect. +If you configure the daemon to connect to other servers, ngIRCd may still perform a DNS lookup if required. -Default: false. +Default: no. .TP \fBNoIdent\fR -If ngircd is compiled with IDENT support this can be used to disable IDENT +If ngIRCd is compiled with IDENT support this can be used to disable IDENT lookups at run time. -Default: false. +Default: no. .TP \fBConnectIPv4\fR -Set this to no if you do not want ngircd to connect to other irc servers using ipv4. -This allows use of ngircd in ipv6-only setups. -Default: Yes. +Set this to no if you do not want ngIRCd to connect to other IRC servers using +IPv4. This allows usage of ngIRCd in IPv6-only setups. +Default: yes. .TP \fBConnectIPv6\fR -Set this to no if you do not want ngircd to connect to other irc servers using ipv6. -Default: Yes. +Set this to no if you do not want ngIRCd to connect to other irc servers using IPv6. +Default: yes. .TP \fBMaxConnections\fR Maximum number of simultaneous in- and outbound connections the server is @@ -215,8 +221,9 @@ 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) +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 @@ -257,21 +264,21 @@ IRC name of the remote server. Internet host name (or IP address) of the peer. .TP \fBBind\fR -IP address to use as source IP for the outgoing connection. Default ist +IP address to use as source IP for the outgoing connection. Default is to let the operating system decide. .TP \fBPort\fR Port of the remote server to which ngIRCd should connect (active). If no port is assigned to a configured server, the daemon only waits for -incoming connections (passive). +incoming connections (passive, default). .TP \fBMyPassword\fR Own password for this connection. This password has to be configured as -"PeerPassword" on the other server. Must not have ':' as first character. +\fBPeerPassword\fR on the other server. Must not have ':' as first character. .TP \fBPeerPassword\fR Foreign password for this connection. This password has to be configured as -"MyPassword" on the other server. +\fBMyPassword\fR on the other server. .TP \fBGroup\fR Group of this server (optional). @@ -281,13 +288,13 @@ 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 \fBServiceMask\fR -Define a (case insensitive) mask matching nick names that sould be treated as +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 this parameter, so leave it empty (which is the default). .PP .RS When you are connecting IRC services which mask as a IRC server and which use -"virtual users" to communicate with, for example "NickServ" amd "ChanServ", +"virtual users" to communicate with, for example "NickServ" and "ChanServ", you should set this parameter to something like "*Serv". .SH [CHANNEL] Pre-defined channels can be configured in @@ -303,7 +310,7 @@ There may be more than one block. .TP \fBName\fR -Name of the channel, including channel prefix ("#"). +Name of the channel, including channel prefix ("#" or "&"). .TP \fBTopic\fR Topic for this channel. @@ -312,10 +319,54 @@ Topic for this channel. Initial channel modes. .TP \fBKey\fR -Sets initial channel key (only relevant if mode k is set). +Sets initial channel key (only relevant if channel mode "k" is set). +.TP +\fBKeyFile\fR +Path and file name of a "key file" containing individual channel keys for +different users. The file consists of plain text lines with the following +syntax (without spaces!): +.PP +.RS +.RS +.I user +: +.I nick +: +.I key +.RE +.PP +.I user +and +.I nick +can contain the wildcard character "*". +.br +.I key +is an arbitrary password. +.PP +Valid examples are: +.PP +.RS +*:*:KeY +.br +*:nick:123 +.br +~user:*:xyz +.RE +.PP +The key file is read on each JOIN command when this channel has a key +(channel mode +k). Access is granted, if a) the channel key set using the +MODE +k command or b) one of the lines in the key file match. +.PP +.B Please note: +.br +The file is not reopened on each access, so you can modify and overwrite it +without problems, but moving or deleting the file will have not effect until +the daemon re-reads its configuration! +.RE .TP \fBMaxUsers\fR -Set maximum user limit for this channel (only relevant if mode l is set). +Set maximum user limit for this channel (only relevant if channel mode "l" +is set). .SH HINTS It's wise to use "ngircd \-\-configtest" to validate the configuration file after changing it. See @@ -324,12 +375,10 @@ for details. .SH AUTHOR Alexander Barton, .UR mailto:alex@barton.de -alex@barton.de .UE .br Homepage: .UR http://ngircd.barton.de/ -http://ngircd.barton.de/ .UE .SH "SEE ALSO" .BR ngircd (8) diff --git a/src/ngircd/channel.c b/src/ngircd/channel.c index 609bbf5..0a1ba45 100644 --- a/src/ngircd/channel.c +++ b/src/ngircd/channel.c @@ -1,6 +1,6 @@ /* * ngIRCd -- The Next Generation IRC Daemon - * Copyright (c)2001-2008 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 @@ -22,6 +22,7 @@ #include #include #include +#include #include #include "defines.h" @@ -39,6 +40,7 @@ #include "lists.h" #include "log.h" #include "messages.h" +#include "match.h" #include "exp.h" @@ -57,7 +59,9 @@ static CL2CHAN *Add_Client PARAMS(( CHANNEL *Chan, CLIENT *Client )); static bool Remove_Client PARAMS(( int Type, CHANNEL *Chan, CLIENT *Client, CLIENT *Origin, const char *Reason, bool InformServer )); static CL2CHAN *Get_First_Cl2Chan PARAMS(( CLIENT *Client, CHANNEL *Chan )); static CL2CHAN *Get_Next_Cl2Chan PARAMS(( CL2CHAN *Start, CLIENT *Client, CHANNEL *Chan )); -static bool Delete_Channel PARAMS(( CHANNEL *Chan )); +static void Delete_Channel PARAMS(( CHANNEL *Chan )); +static void Free_Channel PARAMS(( CHANNEL *Chan )); +static void Set_KeyFile PARAMS((CHANNEL *Chan, const char *KeyFile)); GLOBAL void @@ -97,58 +101,70 @@ Channel_InitPredefined( void ) { /* Generate predefined persistent channels */ - CHANNEL *chan; - char *c; - unsigned int i; + CHANNEL *new_chan; + const struct Conf_Channel *conf_chan; + const char *c; + size_t i, channel_count = array_length(&Conf_Channels, sizeof(*conf_chan)); - for( i = 0; i < Conf_Channel_Count; i++ ) - { - /* Check for Name configuration */ - if( ! Conf_Channel[i].name[0] ) continue; + conf_chan = array_start(&Conf_Channels); - /* Check for invalid channel name */ - if( ! Channel_IsValidName( Conf_Channel[i].name )) - { - Log( LOG_ERR, "Can't create pre-defined channel: invalid name: \"%s\"!", Conf_Channel[i].name ); - array_free(&Conf_Channel[i].topic); + assert(channel_count == 0 || conf_chan != NULL); + + for (i = 0; i < channel_count; i++, conf_chan++) { + if (!conf_chan->name[0] || !Channel_IsValidName(conf_chan->name)) { + Log(LOG_ERR, "Can't create pre-defined channel: invalid name: \"%s\"", + conf_chan->name); continue; } - /* Check if the channel name is already in use */ - chan = Channel_Search( Conf_Channel[i].name ); - if( chan ) - { - Log( LOG_INFO, "Can't create pre-defined channel \"%s\": name already in use.", Conf_Channel[i].name ); - array_free(&Conf_Channel[i].topic); + new_chan = Channel_Search(conf_chan->name); + if (new_chan) { + Log(LOG_INFO, + "Can't create pre-defined channel \"%s\": name already in use.", + conf_chan->name); + Set_KeyFile(new_chan, conf_chan->keyfile); continue; } - /* Create channel */ - chan = Channel_Create(Conf_Channel[i].name); - if (chan) { - Channel_ModeAdd(chan, 'P'); + new_chan = Channel_Create(conf_chan->name); + if (!new_chan) { + Log(LOG_ERR, "Can't create pre-defined channel \"%s\"", + conf_chan->name); + continue; + } + Log(LOG_INFO, "Created pre-defined channel \"%s\"", + conf_chan->name); - if (array_start(&Conf_Channel[i].topic) != NULL) - Channel_SetTopic(chan, NULL, - array_start(&Conf_Channel[i].topic)); - array_free(&Conf_Channel[i].topic); + Channel_ModeAdd(new_chan, 'P'); - c = Conf_Channel[i].modes; - while (*c) - Channel_ModeAdd(chan, *c++); + if (conf_chan->topic[0]) + Channel_SetTopic(new_chan, NULL, conf_chan->topic); - Channel_SetKey(chan, Conf_Channel[i].key); - Channel_SetMaxUsers(chan, Conf_Channel[i].maxusers); + c = conf_chan->modes; + while (*c) + Channel_ModeAdd(new_chan, *c++); - Log(LOG_INFO, "Created pre-defined channel \"%s\".", - Conf_Channel[i].name ); - } - else Log(LOG_ERR, "Can't create pre-defined channel \"%s\"!", - Conf_Channel[i].name ); + Channel_SetKey(new_chan, conf_chan->key); + Channel_SetMaxUsers(new_chan, conf_chan->maxusers); + Set_KeyFile(new_chan, conf_chan->keyfile); } + if (channel_count) + array_free(&Conf_Channels); } /* Channel_InitPredefined */ +static void +Free_Channel(CHANNEL *chan) +{ + array_free(&chan->topic); + array_free(&chan->keyfile); + Lists_Free(&chan->list_bans); + Lists_Free(&chan->list_invites); + + free(chan); +} + + GLOBAL void Channel_Exit( void ) { @@ -157,20 +173,17 @@ Channel_Exit( void ) /* free struct Channel */ c = My_Channels; - while( c ) - { + while (c) { c_next = c->next; - array_free(&c->topic); - free( c ); + Free_Channel(c); c = c_next; } /* Free Channel allocation table */ cl2chan = My_Cl2Chan; - while( c ) - { + while (cl2chan) { cl2chan_next = cl2chan->next; - free( cl2chan ); + free(cl2chan); cl2chan = cl2chan_next; } } /* Channel_Exit */ @@ -690,7 +703,7 @@ Channel_TopicWho(CHANNEL *Chan) GLOBAL void -Channel_SetTopic(CHANNEL *Chan, CLIENT *Client, char *Topic) +Channel_SetTopic(CHANNEL *Chan, CLIENT *Client, const char *Topic) { size_t len; assert( Chan != NULL ); @@ -728,7 +741,7 @@ Channel_SetModes( CHANNEL *Chan, char *Modes ) GLOBAL void -Channel_SetKey( CHANNEL *Chan, char *Key ) +Channel_SetKey( CHANNEL *Chan, const char *Key ) { assert( Chan != NULL ); assert( Key != NULL ); @@ -806,7 +819,7 @@ Channel_Write(CHANNEL *Chan, CLIENT *From, CLIENT *Client, const char *Command, GLOBAL CHANNEL * -Channel_Create( char *Name ) +Channel_Create( const char *Name ) { /* Create new CHANNEL structure and add it to linked list */ CHANNEL *c; @@ -870,7 +883,7 @@ Add_Client( CHANNEL *Chan, CLIENT *Client ) cl2chan->next = My_Cl2Chan; My_Cl2Chan = cl2chan; - Log( LOG_DEBUG, "User \"%s\" joined channel \"%s\".", Client_Mask( Client ), Chan->name ); + LogDebug("User \"%s\" joined channel \"%s\".", Client_Mask(Client), Chan->name); return cl2chan; } /* Add_Client */ @@ -1045,6 +1058,56 @@ Channel_LogServer(char *msg) } /* Channel_LogServer */ +GLOBAL bool +Channel_CheckKey(CHANNEL *Chan, CLIENT *Client, const char *Key) +{ + char *file_name, line[COMMAND_LEN], *nick, *pass; + FILE *fd; + + assert(Chan != NULL); + assert(Client != NULL); + assert(Key != NULL); + + if (!strchr(Chan->modes, 'k')) + return true; + if (strcmp(Chan->key, Key) == 0) + return true; + if (*Key == '\0') + return false; + + file_name = array_start(&Chan->keyfile); + if (!file_name) + return false; + fd = fopen(file_name, "r"); + if (!fd) { + Log(LOG_ERR, "Can't open channel key file \"%s\" for %s: %s", + file_name, Chan->name, strerror(errno)); + return false; + } + + while (fgets(line, sizeof(line), fd) != NULL) { + ngt_TrimStr(line); + if (! (nick = strchr(line, ':'))) + continue; + *nick++ = '\0'; + if (!Match(line, Client_User(Client))) + continue; + if (! (pass = strchr(nick, ':'))) + continue; + *pass++ = '\0'; + if (!Match(nick, Client_ID(Client))) + continue; + if (strcmp(Key, pass) != 0) + continue; + + fclose(fd); + return true; + } + fclose(fd); + return false; +} /* Channel_CheckKey */ + + static CL2CHAN * Get_First_Cl2Chan( CLIENT *Client, CHANNEL *Chan ) { @@ -1070,35 +1133,64 @@ Get_Next_Cl2Chan( CL2CHAN *Start, CLIENT *Client, CHANNEL *Channel ) } /* Get_Next_Cl2Chan */ -static bool -Delete_Channel( CHANNEL *Chan ) +/** + * Remove a channel and free all of its data structures. + */ +static void +Delete_Channel(CHANNEL *Chan) { - /* delete channel structure */ - CHANNEL *chan, *last_chan; last_chan = NULL; chan = My_Channels; - while( chan ) - { - if( chan == Chan ) break; + while (chan) { + if (chan == Chan) + break; last_chan = chan; chan = chan->next; } - if( ! chan ) return false; - - Log( LOG_DEBUG, "Freed channel structure for \"%s\".", Chan->name ); - /* free invite and ban lists */ - Lists_Free( &chan->list_bans ); - Lists_Free( &chan->list_invites ); + assert(chan != NULL); + if (!chan) + return; /* maintain channel list */ - if( last_chan ) last_chan->next = chan->next; - else My_Channels = chan->next; - free( chan ); + if (last_chan) + last_chan->next = chan->next; + else + My_Channels = chan->next; - return true; + LogDebug("Freed channel structure for \"%s\".", Chan->name); + Free_Channel(Chan); } /* Delete_Channel */ + +static void +Set_KeyFile(CHANNEL *Chan, const char *KeyFile) +{ + size_t len; + + assert(Chan != NULL); + assert(KeyFile != NULL); + + len = strlen(KeyFile); + if (len < array_bytes(&Chan->keyfile)) { + Log(LOG_INFO, "Channel key file of %s removed.", Chan->name); + array_free(&Chan->keyfile); + } + + if (len < 1) + return; + + if (!array_copyb(&Chan->keyfile, KeyFile, len+1)) + Log(LOG_WARNING, + "Could not set new channel key file \"%s\" for %s: %s", + KeyFile, Chan->name, strerror(errno)); + else + Log(LOG_INFO|LOG_snotice, + "New local channel key file \"%s\" for %s activated.", + KeyFile, Chan->name); +} /* Set_KeyFile */ + + /* -eof- */ diff --git a/src/ngircd/channel.h b/src/ngircd/channel.h index 91d1e21..b41cced 100644 --- a/src/ngircd/channel.h +++ b/src/ngircd/channel.h @@ -37,6 +37,7 @@ typedef struct _CHANNEL unsigned long maxusers; /* Maximum number of members (mode "l") */ struct list_head list_bans; /* list head of banned users */ struct list_head list_invites; /* list head of invited users */ + array keyfile; /* Name of the channel key file */ } CHANNEL; typedef struct _CLIENT2CHAN @@ -79,9 +80,9 @@ GLOBAL char *Channel_Topic PARAMS(( CHANNEL *Chan )); GLOBAL char *Channel_Key PARAMS(( CHANNEL *Chan )); GLOBAL unsigned long Channel_MaxUsers PARAMS(( CHANNEL *Chan )); -GLOBAL void Channel_SetTopic PARAMS(( CHANNEL *Chan, CLIENT *Client, char *Topic )); +GLOBAL void Channel_SetTopic PARAMS(( CHANNEL *Chan, CLIENT *Client, const char *Topic )); GLOBAL void Channel_SetModes PARAMS(( CHANNEL *Chan, char *Modes )); -GLOBAL void Channel_SetKey PARAMS(( CHANNEL *Chan, char *Key )); +GLOBAL void Channel_SetKey PARAMS(( CHANNEL *Chan, const char *Key )); GLOBAL void Channel_SetMaxUsers PARAMS(( CHANNEL *Chan, unsigned long Count )); GLOBAL CHANNEL *Channel_Search PARAMS(( const char *Name )); @@ -112,7 +113,7 @@ GLOBAL bool Channel_Write PARAMS((CHANNEL *Chan, CLIENT *From, CLIENT *Client, const char *Command, bool SendErrors, const char *Text)); -GLOBAL CHANNEL *Channel_Create PARAMS(( char *Name )); +GLOBAL CHANNEL *Channel_Create PARAMS(( const char *Name )); #ifndef STRICT_RFC GLOBAL unsigned int Channel_TopicTime PARAMS(( CHANNEL *Chan )); @@ -127,8 +128,11 @@ GLOBAL bool Channel_ShowInvites PARAMS((CLIENT *client, CHANNEL *c)); GLOBAL void Channel_LogServer PARAMS((char *msg)); -#define Channel_IsLocal(c) (Channel_Name(c)[0] == '&') +GLOBAL bool Channel_CheckKey PARAMS((CHANNEL *Chan, CLIENT *Client, + const char *Key)); +#define Channel_IsLocal(c) (Channel_Name(c)[0] == '&') +#define Channel_IsModeless(c) (Channel_Name(c)[0] == '+') #endif diff --git a/src/ngircd/client.c b/src/ngircd/client.c index 1d01f78..fbe130a 100644 --- a/src/ngircd/client.c +++ b/src/ngircd/client.c @@ -1047,7 +1047,7 @@ Generate_MyToken( CLIENT *Client ) else c = (CLIENT *)c->next; } Client->mytoken = token; - Log( LOG_DEBUG, "Assigned token %d to server \"%s\".", token, Client->id ); + LogDebug("Assigned token %d to server \"%s\".", token, Client->id); } /* Generate_MyToken */ diff --git a/src/ngircd/conf.c b/src/ngircd/conf.c index fe05938..71f5760 100644 --- a/src/ngircd/conf.c +++ b/src/ngircd/conf.c @@ -1,6 +1,6 @@ /* * ngIRCd -- The Next Generation IRC Daemon - * Copyright (c)2001,2002 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 @@ -40,6 +40,7 @@ #include "ngircd.h" #include "conn.h" #include "client.h" +#include "channel.h" #include "defines.h" #include "log.h" #include "match.h" @@ -54,7 +55,7 @@ static bool Use_Log = true; static CONF_SERVER New_Server; static int New_Server_Idx; - +static size_t Conf_Channel_Count; static void Set_Defaults PARAMS(( bool InitServers )); static bool Read_Config PARAMS(( bool ngircd_starting )); static bool Validate_Config PARAMS(( bool TestOnly, bool Rehash )); @@ -206,8 +207,9 @@ Conf_Test( void ) struct passwd *pwd; struct group *grp; unsigned int i; - char *topic; bool config_valid; + size_t predef_channel_count; + struct Conf_Channel *predef_chan; Use_Log = false; @@ -299,18 +301,21 @@ Conf_Test( void ) printf( " Passive = %s\n\n", Conf_Server[i].flags & CONF_SFLAG_DISABLED ? "yes" : "no"); } - for( i = 0; i < Conf_Channel_Count; i++ ) { - if( ! Conf_Channel[i].name[0] ) continue; + predef_channel_count = array_length(&Conf_Channels, sizeof(*predef_chan)); + predef_chan = array_start(&Conf_Channels); + + for (i = 0; i < predef_channel_count; i++, predef_chan++) { + if (!predef_chan->name[0]) + continue; /* Valid "Channel" section */ puts( "[CHANNEL]" ); - printf( " Name = %s\n", Conf_Channel[i].name ); - printf( " Modes = %s\n", Conf_Channel[i].modes ); - printf( " Key = %s\n", Conf_Channel[i].key ); - printf( " MaxUsers = %lu\n", Conf_Channel[i].maxusers ); - - topic = (char*)array_start(&Conf_Channel[i].topic); - printf( " Topic = %s\n\n", topic ? topic : ""); + printf(" Name = %s\n", predef_chan->name); + printf(" Modes = %s\n", predef_chan->modes); + printf(" Key = %s\n", predef_chan->key); + printf(" MaxUsers = %lu\n", predef_chan->maxusers); + printf(" Topic = %s\n", predef_chan->topic); + printf(" KeyFile = %s\n\n", predef_chan->keyfile); } return (config_valid ? 0 : 1); @@ -656,20 +661,11 @@ Read_Config( bool ngircd_starting ) else New_Server_Idx = i; continue; } - if( strcasecmp( section, "[CHANNEL]" ) == 0 ) { - if( Conf_Channel_Count + 1 > MAX_DEFCHANNELS ) { - Config_Error( LOG_ERR, "Too many pre-defined channels configured." ); - } else { - /* Initialize new channel structure */ - strcpy( Conf_Channel[Conf_Channel_Count].name, "" ); - strcpy( Conf_Channel[Conf_Channel_Count].modes, "" ); - strcpy( Conf_Channel[Conf_Channel_Count].key, "" ); - Conf_Channel[Conf_Channel_Count].maxusers = 0; - array_free(&Conf_Channel[Conf_Channel_Count].topic); - Conf_Channel_Count++; - } + if (strcasecmp(section, "[CHANNEL]") == 0) { + Conf_Channel_Count++; continue; } + Config_Error( LOG_ERR, "%s, line %d: Unknown section \"%s\"!", NGIRCd_ConfFile, line, section ); section[0] = 0x1; } @@ -1162,19 +1158,23 @@ Handle_SERVER( int Line, char *Var, char *Arg ) Config_Error_TooLong(Line, Var); return; } - + Config_Error( LOG_ERR, "%s, line %d (section \"Server\"): Unknown variable \"%s\"!", NGIRCd_ConfFile, Line, Var ); } /* Handle_SERVER */ static bool -Handle_Channelname(size_t chancount, const char *name) +Handle_Channelname(struct Conf_Channel *new_chan, const char *name) { - size_t size = sizeof( Conf_Channel[chancount].name ); - char *dest = Conf_Channel[chancount].name; + size_t size = sizeof(new_chan->name); + char *dest = new_chan->name; - if (*name && *name != '#') { + if (!Channel_IsValidName(name)) { + /* + * maybe user forgot to add a '#'. + * This is only here for user convenience. + */ *dest = '#'; --size; ++dest; @@ -1184,51 +1184,64 @@ Handle_Channelname(size_t chancount, const char *name) static void -Handle_CHANNEL( int Line, char *Var, char *Arg ) +Handle_CHANNEL(int Line, char *Var, char *Arg) { size_t len; - size_t chancount = 0; + size_t chancount; + struct Conf_Channel *chan; assert( Line > 0 ); assert( Var != NULL ); assert( Arg != NULL ); - if (Conf_Channel_Count > 0) - chancount = Conf_Channel_Count - 1; + assert(Conf_Channel_Count > 0); - if( strcasecmp( Var, "Name" ) == 0 ) { - if (!Handle_Channelname(chancount, Arg)) - Config_Error_TooLong( Line, Var ); + chancount = Conf_Channel_Count - 1; + + chan = array_alloc(&Conf_Channels, sizeof(*chan), chancount); + if (!chan) { + Config_Error(LOG_ERR, "Could not allocate memory for predefined channel (%d:%s = %s)", Line, Var, Arg); + return; + } + if (strcasecmp(Var, "Name") == 0) { + if (!Handle_Channelname(chan, Arg)) + Config_Error_TooLong(Line, Var); return; } - if( strcasecmp( Var, "Modes" ) == 0 ) { + if (strcasecmp(Var, "Modes") == 0) { /* Initial modes */ - len = strlcpy( Conf_Channel[chancount].modes, Arg, sizeof( Conf_Channel[chancount].modes )); - if (len >= sizeof( Conf_Channel[chancount].modes )) + len = strlcpy(chan->modes, Arg, sizeof(chan->modes)); + if (len >= sizeof(chan->modes)) Config_Error_TooLong( Line, Var ); return; } if( strcasecmp( Var, "Topic" ) == 0 ) { /* Initial topic */ - if (!array_copys( &Conf_Channel[chancount].topic, Arg)) + len = strlcpy(chan->topic, Arg, sizeof(chan->topic)); + if (len >= sizeof(chan->topic)) Config_Error_TooLong( Line, Var ); return; } - if( strcasecmp( Var, "Key" ) == 0 ) { /* Initial Channel Key (mode k) */ - len = strlcpy(Conf_Channel[chancount].key, Arg, sizeof(Conf_Channel[chancount].key)); - if (len >= sizeof( Conf_Channel[chancount].key )) + len = strlcpy(chan->key, Arg, sizeof(chan->key)); + if (len >= sizeof(chan->key)) Config_Error_TooLong(Line, Var); return; } - if( strcasecmp( Var, "MaxUsers" ) == 0 ) { /* maximum user limit, mode l */ - Conf_Channel[chancount].maxusers = (unsigned long) atol(Arg); - if (Conf_Channel[chancount].maxusers == 0) + chan->maxusers = (unsigned long) atol(Arg); + if (chan->maxusers == 0) Config_Error_NaN(Line, Var); return; } + if (strcasecmp(Var, "KeyFile") == 0) { + /* channel keys */ + len = strlcpy(chan->keyfile, Arg, sizeof(chan->keyfile)); + if (len >= sizeof(chan->keyfile)) + Config_Error_TooLong(Line, Var); + return; + } Config_Error( LOG_ERR, "%s, line %d (section \"Channel\"): Unknown variable \"%s\"!", NGIRCd_ConfFile, Line, Var ); diff --git a/src/ngircd/conf.h b/src/ngircd/conf.h index 5328465..4695b25 100644 --- a/src/ngircd/conf.h +++ b/src/ngircd/conf.h @@ -67,14 +67,14 @@ struct SSLOptions { #endif -typedef struct _Conf_Channel -{ +struct Conf_Channel { char name[CHANNEL_NAME_LEN]; /* Name of the channel */ char modes[CHANNEL_MODE_LEN]; /* Initial channel modes */ char key[CLIENT_PASS_LEN]; /* Channel key ("password", mode "k" ) */ + char topic[COMMAND_LEN]; /* Initial topic */ + char keyfile[512]; /* Path and name of channel key file */ unsigned long maxusers; /* maximum usercount for this channel, mode "l" */ - array topic; /* Initial topic */ -} CONF_CHANNEL; +}; #define CONF_SFLAG_ONCE 1 /* Delete this entry after next disconnect */ @@ -132,8 +132,8 @@ GLOBAL unsigned int Conf_Oper_Count; GLOBAL CONF_SERVER Conf_Server[MAX_SERVERS]; /* Pre-defined channels */ -GLOBAL CONF_CHANNEL Conf_Channel[MAX_DEFCHANNELS]; -GLOBAL unsigned int Conf_Channel_Count; +GLOBAL array Conf_Channels; + /* Pre-defined channels only */ GLOBAL bool Conf_PredefChannelsOnly; diff --git a/src/ngircd/conn-ssl.c b/src/ngircd/conn-ssl.c index dc165d7..4ef8f66 100644 --- a/src/ngircd/conn-ssl.c +++ b/src/ngircd/conn-ssl.c @@ -228,7 +228,8 @@ void ConnSSL_Free(CONNECTION *c) } #endif assert(Conn_OPTION_ISSET(c, CONN_SSL)); - Conn_OPTION_DEL(c, (CONN_SSL_CONNECT|CONN_SSL|CONN_SSL_WANT_WRITE)); + /* can't just set bitmask to 0 -- there are other, non-ssl related flags, e.g. CONN_ZIP. */ + Conn_OPTION_DEL(c, CONN_SSL_FLAGS_ALL); } @@ -483,8 +484,8 @@ ConnSSL_HandleError( CONNECTION *c, const int code, const char *fname ) Conn_OPTION_ADD(c, CONN_SSL_WANT_WRITE); /* fall through */ case SSL_ERROR_NONE: return 0; /* try again later */ - case SSL_ERROR_ZERO_RETURN: /* TLS/SSL Connection was shut down */ - LogOpenSSLError("TLS/SSL Connection shutdown", fname); + case SSL_ERROR_ZERO_RETURN: + LogDebug("TLS/SSL connection shut down normally"); break; /* SSL_ERROR_WANT_CONNECT, SSL_ERROR_WANT_ACCEPT, SSL_ERROR_WANT_X509_LOOKUP diff --git a/src/ngircd/conn.h b/src/ngircd/conn.h index 08f6dde..450d3d1 100644 --- a/src/ngircd/conn.h +++ b/src/ngircd/conn.h @@ -18,7 +18,13 @@ #include /* for time_t, see below */ - +/* + * connection state flags. this is a bitmask -- all values must + * be unique and a power of two. + * + * If you introduce new ones in between, make sure to adjust all + * remaining ones. + */ #define CONN_ISCLOSING 1 /* Conn_Close() already called */ #define CONN_ISCONNECTING 2 /* connect() in progress */ #define CONN_RFC1459 4 /* RFC 1459 compatibility mode */ @@ -29,10 +35,11 @@ #include "conf-ssl.h" #ifdef SSL_SUPPORT -#define CONN_SSL_CONNECT 8 /* wait for ssl connect to finish */ -#define CONN_SSL 16 /* this connection is SSL encrypted */ -#define CONN_SSL_WANT_WRITE 32 /* SSL/TLS library needs to write protocol data */ -#define CONN_SSL_WANT_READ 64 /* SSL/TLS library needs to read protocol data */ +#define CONN_SSL_CONNECT 16 /* wait for ssl connect to finish */ +#define CONN_SSL 32 /* this connection is SSL encrypted */ +#define CONN_SSL_WANT_WRITE 64 /* SSL/TLS library needs to write protocol data */ +#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; diff --git a/src/ngircd/defines.h b/src/ngircd/defines.h index 7abe641..905a5a6 100644 --- a/src/ngircd/defines.h +++ b/src/ngircd/defines.h @@ -30,16 +30,10 @@ #define HOST_LEN 256 /* Max. lenght of fully qualified host names (e. g. "abc.domain.tld") */ -#define MAX_LISTEN_PORTS 16 /* Max. count of listening ports */ - #define MAX_OPERATORS 16 /* Max. count of configurable IRC Ops */ #define MAX_SERVERS 16 /* Max. count of configurable servers */ -#define MAX_DEFCHANNELS 16 /* Max. count of predefined channels */ - -#define MAX_SERVICES 8 /* Max. count of services */ - #define MAX_WHOWAS 64 /* Max. number of WHOWAS items */ #define DEFAULT_WHOWAS 5 /* default count for WHOWAS command */ diff --git a/src/ngircd/irc-channel.c b/src/ngircd/irc-channel.c index 27414d3..af0f066 100644 --- a/src/ngircd/irc-channel.c +++ b/src/ngircd/irc-channel.c @@ -89,10 +89,9 @@ join_allowed(CLIENT *Client, CLIENT *target, CHANNEL *chan, } /* Is the channel protected by a key? */ - if (strchr(channel_modes, 'k') && - strcmp(Channel_Key(chan), key ? key : "")) - { - IRC_WriteStrClient(Client, ERR_BADCHANNELKEY_MSG, Client_ID(Client), channame); + if (!Channel_CheckKey(chan, target, key ? key : "")) { + IRC_WriteStrClient(Client, ERR_BADCHANNELKEY_MSG, + Client_ID(Client), channame); return false; } /* Are there already too many members? */ @@ -304,7 +303,7 @@ IRC_JOIN( CLIENT *Client, REQUEST *Req ) if (!chan) { /* channel is new; it has been created above */ chan = Channel_Search(channame); assert(chan != NULL); - if (*channame == '+') { /* modeless channel... */ + if (Channel_IsModeless(chan)) { Channel_ModeAdd(chan, 't'); /* /TOPIC not allowed */ Channel_ModeAdd(chan, 'n'); /* no external msgs */ } diff --git a/src/ngircd/irc-info.c b/src/ngircd/irc-info.c index 4ac2a47..e934521 100644 --- a/src/ngircd/irc-info.c +++ b/src/ngircd/irc-info.c @@ -133,8 +133,14 @@ IRC_INFO(CLIENT * Client, REQUEST * Req) if (!IRC_WriteStrClient(Client, RPL_INFO_MSG, Client_ID(prefix), NGIRCd_Version)) return DISCONNECTED; - - strlcpy(msg, "Server has been started ", sizeof(msg)); + +#if defined(__DATE__) && defined(__TIME__) + snprintf(msg, sizeof(msg), "Birth Date: %s at %s", __DATE__, __TIME__); + if (!IRC_WriteStrClient(Client, RPL_INFO_MSG, Client_ID(prefix), msg)) + return DISCONNECTED; +#endif + + strlcpy(msg, "On-line since ", sizeof(msg)); strlcat(msg, NGIRCd_StartStr, sizeof(msg)); if (!IRC_WriteStrClient(Client, RPL_INFO_MSG, Client_ID(prefix), msg)) return DISCONNECTED; diff --git a/src/ngircd/irc-login.c b/src/ngircd/irc-login.c index 943612e..1091852 100644 --- a/src/ngircd/irc-login.c +++ b/src/ngircd/irc-login.c @@ -242,7 +242,7 @@ IRC_NICK( CLIENT *Client, REQUEST *Req ) Client_Type(target) != CLIENT_SERVICE && Client_Type(target) != CLIENT_SERVER) { /* New client */ - Log( LOG_DEBUG, "Connection %d: got valid NICK command ...", + LogDebug("Connection %d: got valid NICK command ...", Client_Conn( Client )); /* Register new nickname of this client */ @@ -723,7 +723,7 @@ IRC_PONG(CLIENT *Client, REQUEST *Req) /* The connection timestamp has already been updated when the data has * been read from so socket, so we don't need to update it here. */ - +#ifdef DEBUG if (Client_Conn(Client) > NONE) Log(LOG_DEBUG, "Connection %d: received PONG. Lag: %ld seconds.", @@ -732,7 +732,7 @@ IRC_PONG(CLIENT *Client, REQUEST *Req) else Log(LOG_DEBUG, "Connection %d: received PONG.", Client_Conn(Client)); - +#endif return CONNECTED; } /* IRC_PONG */ diff --git a/src/ngircd/irc-mode.c b/src/ngircd/irc-mode.c index ed70a9b..ba28f83 100644 --- a/src/ngircd/irc-mode.c +++ b/src/ngircd/irc-mode.c @@ -276,20 +276,21 @@ Channel_Mode_Answer_Request(CLIENT *Origin, CHANNEL *Channel) } +/** + * Handle channel mode and channel-user mode changes + */ static bool -Channel_Mode( CLIENT *Client, REQUEST *Req, CLIENT *Origin, CHANNEL *Channel ) +Channel_Mode(CLIENT *Client, REQUEST *Req, CLIENT *Origin, CHANNEL *Channel) { - /* Handle channel and channel-user modes */ - - char the_modes[COMMAND_LEN], the_args[COMMAND_LEN], x[2], argadd[CLIENT_PASS_LEN], *mode_ptr; + 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; int mode_arg, arg_arg; CLIENT *client; long l; size_t len; - /* Are modes allowed on channel? */ - if (Channel_Name(Channel)[0] == '+') + if (Channel_IsModeless(Channel)) return IRC_WriteStrClient(Client, ERR_NOCHANMODES_MSG, Client_ID(Client), Channel_Name(Channel)); @@ -307,7 +308,7 @@ Channel_Mode( CLIENT *Client, REQUEST *Req, CLIENT *Origin, CHANNEL *Channel ) /* channel operator? */ if (strchr(Channel_UserModes(Channel, Origin), 'o')) modeok = true; - else if(Conf_OperCanMode) { + else if (Conf_OperCanMode) { /* IRC-Operators can use MODE as well */ if (Client_OperByMe(Origin)) { modeok = true; @@ -327,8 +328,12 @@ Channel_Mode( CLIENT *Client, REQUEST *Req, CLIENT *Origin, CHANNEL *Channel ) /* Initial state: set or unset modes? */ skiponce = false; switch (*mode_ptr) { - case '-': set = false; break; - case '+': set = true; break; + case '-': + set = false; + break; + case '+': + set = true; + break; default: set = true; skiponce = true; @@ -341,7 +346,7 @@ Channel_Mode( CLIENT *Client, REQUEST *Req, CLIENT *Origin, CHANNEL *Channel ) x[1] = '\0'; ok = CONNECTED; while (mode_ptr) { - if (! skiponce) + if (!skiponce) mode_ptr++; if (!*mode_ptr) { /* Try next argument if there's any */ @@ -364,10 +369,11 @@ Channel_Mode( CLIENT *Client, REQUEST *Req, CLIENT *Origin, CHANNEL *Channel ) switch (*mode_ptr) { case '+': case '-': - if (((*mode_ptr == '+') && !set) || ((*mode_ptr == '-') && set)) { + if (((*mode_ptr == '+') && !set) + || ((*mode_ptr == '-') && set)) { /* Action modifier ("+"/"-") must be changed ... */ - len = strlen( the_modes ) - 1; - if ((the_modes[len] == '+') || (the_modes[len] == '-')) { + len = strlen(the_modes) - 1; + if (the_modes[len] == '+' || the_modes[len] == '-') { /* Adjust last action modifier in result */ the_modes[len] = *mode_ptr; } else { @@ -381,7 +387,8 @@ Channel_Mode( CLIENT *Client, REQUEST *Req, CLIENT *Origin, CHANNEL *Channel ) } /* Are there arguments left? */ - if( arg_arg >= Req->argc ) arg_arg = -1; + if (arg_arg >= Req->argc) + arg_arg = -1; /* Validate modes */ x[0] = '\0'; @@ -397,29 +404,42 @@ Channel_Mode( CLIENT *Client, REQUEST *Req, CLIENT *Origin, CHANNEL *Channel ) if (modeok) x[0] = *mode_ptr; else - ok = IRC_WriteStrClient(Origin, ERR_CHANOPRIVSNEEDED_MSG, Client_ID(Origin), Channel_Name(Channel)); + ok = IRC_WriteStrClient(Origin, + ERR_CHANOPRIVSNEEDED_MSG, + Client_ID(Origin), Channel_Name(Channel)); break; case 'k': /* Channel key */ - if (! set) { + if (!set) { if (modeok) x[0] = *mode_ptr; else - ok = IRC_WriteStrClient(Origin, ERR_CHANOPRIVSNEEDED_MSG, Client_ID(Origin), Channel_Name(Channel)); + ok = IRC_WriteStrClient(Origin, + ERR_CHANOPRIVSNEEDED_MSG, + Client_ID(Origin), + Channel_Name(Channel)); break; } if (arg_arg > mode_arg) { if (modeok) { Channel_ModeDel(Channel, 'k'); - Channel_SetKey(Channel, Req->argv[arg_arg]); - strlcpy(argadd, Channel_Key(Channel), sizeof(argadd)); + Channel_SetKey(Channel, + Req->argv[arg_arg]); + strlcpy(argadd, Channel_Key(Channel), + sizeof(argadd)); x[0] = *mode_ptr; } else { - ok = IRC_WriteStrClient(Origin, ERR_CHANOPRIVSNEEDED_MSG, Client_ID(Origin), Channel_Name(Channel)); + ok = IRC_WriteStrClient(Origin, + ERR_CHANOPRIVSNEEDED_MSG, + Client_ID(Origin), + Channel_Name(Channel)); } Req->argv[arg_arg][0] = '\0'; arg_arg++; } else { - ok = IRC_WriteStrClient(Origin, ERR_NEEDMOREPARAMS_MSG, Client_ID(Origin), Req->command); + ok = IRC_WriteStrClient(Origin, + ERR_NEEDMOREPARAMS_MSG, + Client_ID(Origin), Req->command); + goto chan_exit; } break; case 'l': /* Member limit */ @@ -427,7 +447,10 @@ Channel_Mode( CLIENT *Client, REQUEST *Req, CLIENT *Origin, CHANNEL *Channel ) if (modeok) x[0] = *mode_ptr; else - ok = IRC_WriteStrClient(Origin, ERR_CHANOPRIVSNEEDED_MSG, Client_ID(Origin), Channel_Name(Channel)); + ok = IRC_WriteStrClient(Origin, + ERR_CHANOPRIVSNEEDED_MSG, + Client_ID(Origin), + Channel_Name(Channel)); break; } if (arg_arg > mode_arg) { @@ -436,28 +459,41 @@ Channel_Mode( CLIENT *Client, REQUEST *Req, CLIENT *Origin, CHANNEL *Channel ) if (l > 0 && l < 0xFFFF) { Channel_ModeDel(Channel, 'l'); Channel_SetMaxUsers(Channel, l); - snprintf(argadd, sizeof(argadd), "%ld", l); + snprintf(argadd, sizeof(argadd), + "%ld", l); x[0] = *mode_ptr; } } else { - ok = IRC_WriteStrClient(Origin, ERR_CHANOPRIVSNEEDED_MSG, Client_ID(Origin), Channel_Name(Channel)); + ok = IRC_WriteStrClient(Origin, + ERR_CHANOPRIVSNEEDED_MSG, + Client_ID(Origin), + Channel_Name(Channel)); } Req->argv[arg_arg][0] = '\0'; arg_arg++; } else { - ok = IRC_WriteStrClient(Origin, ERR_NEEDMOREPARAMS_MSG, Client_ID(Origin), Req->command); + ok = IRC_WriteStrClient(Origin, + ERR_NEEDMOREPARAMS_MSG, + Client_ID(Origin), Req->command); + goto chan_exit; } break; case 'P': /* Persistent channel */ if (modeok) { /* Only IRC operators are allowed to * set the 'P' channel mode! */ - if (set && !(Client_OperByMe(Client) || Client_Type(Client) == CLIENT_SERVER)) - ok = IRC_WriteStrClient(Origin, ERR_NOPRIVILEGES_MSG, Client_ID(Origin)); + if (set && !(Client_OperByMe(Client) + || Client_Type(Client) == CLIENT_SERVER)) + ok = IRC_WriteStrClient(Origin, + ERR_NOPRIVILEGES_MSG, + Client_ID(Origin)); else - x[0] = 'P'; + x[0] = 'P'; } else - ok = IRC_WriteStrClient(Origin, ERR_CHANOPRIVSNEEDED_MSG, Client_ID(Origin), Channel_Name(Channel)); + ok = IRC_WriteStrClient(Origin, + ERR_CHANOPRIVSNEEDED_MSG, + Client_ID(Origin), + Channel_Name(Channel)); break; /* --- Channel user modes --- */ case 'o': /* Channel operator */ @@ -468,14 +504,23 @@ Channel_Mode( CLIENT *Client, REQUEST *Req, CLIENT *Origin, CHANNEL *Channel ) if (client) x[0] = *mode_ptr; else - ok = IRC_WriteStrClient(Client, ERR_NOSUCHNICK_MSG, Client_ID(Client), Req->argv[arg_arg]); + ok = IRC_WriteStrClient(Client, + ERR_NOSUCHNICK_MSG, + Client_ID(Client), + Req->argv[arg_arg]); } else { - ok = IRC_WriteStrClient(Origin, ERR_CHANOPRIVSNEEDED_MSG, Client_ID(Origin), Channel_Name(Channel)); + ok = IRC_WriteStrClient(Origin, + ERR_CHANOPRIVSNEEDED_MSG, + Client_ID(Origin), + Channel_Name(Channel)); } Req->argv[arg_arg][0] = '\0'; arg_arg++; } else { - ok = IRC_WriteStrClient(Origin, ERR_NEEDMOREPARAMS_MSG, Client_ID(Origin), Req->command); + ok = IRC_WriteStrClient(Origin, + ERR_NEEDMOREPARAMS_MSG, + Client_ID(Origin), Req->command); + goto chan_exit; } break; /* --- Channel lists --- */ @@ -484,11 +529,18 @@ Channel_Mode( CLIENT *Client, REQUEST *Req, CLIENT *Origin, CHANNEL *Channel ) if (arg_arg > mode_arg) { /* modify list */ if (modeok) { - ok = set ? Add_Ban_Invite(*mode_ptr, Origin, Client, Channel, Req->argv[arg_arg]) - : Del_Ban_Invite(*mode_ptr, Origin, Client, Channel, Req->argv[arg_arg]); + ok = set + ? Add_Ban_Invite(*mode_ptr, Origin, + Client, Channel, + Req->argv[arg_arg]) + : Del_Ban_Invite(*mode_ptr, Origin, + Client, Channel, + Req->argv[arg_arg]); } else { - ok = IRC_WriteStrClient(Origin, ERR_CHANOPRIVSNEEDED_MSG, - Client_ID(Origin), Channel_Name(Channel)); + ok = IRC_WriteStrClient(Origin, + ERR_CHANOPRIVSNEEDED_MSG, + Client_ID(Origin), + Channel_Name(Channel)); } Req->argv[arg_arg][0] = '\0'; arg_arg++; @@ -500,13 +552,18 @@ Channel_Mode( CLIENT *Client, REQUEST *Req, CLIENT *Origin, CHANNEL *Channel ) } break; default: - Log(LOG_DEBUG, "Unknown mode \"%c%c\" from \"%s\" on %s!?", - set ? '+' : '-', *mode_ptr, Client_ID(Origin), Channel_Name(Channel)); + Log(LOG_DEBUG, + "Unknown mode \"%c%c\" from \"%s\" on %s!?", + set ? '+' : '-', *mode_ptr, Client_ID(Origin), + Channel_Name(Channel)); if (Client_Type(Client) != CLIENT_SERVER) - ok = IRC_WriteStrClient(Origin, ERR_UMODEUNKNOWNFLAG2_MSG, Client_ID(Origin), set ? '+' : '-', *mode_ptr); + ok = IRC_WriteStrClient(Origin, + ERR_UMODEUNKNOWNFLAG2_MSG, + Client_ID(Origin), + set ? '+' : '-', *mode_ptr); x[0] = '\0'; goto chan_exit; - } /* switch() */ + } /* switch() */ if (!ok) break; @@ -517,29 +574,40 @@ Channel_Mode( CLIENT *Client, REQUEST *Req, CLIENT *Origin, CHANNEL *Channel ) /* Validate target client */ if (client && (!Channel_IsMemberOf(Channel, client))) { - if (!IRC_WriteStrClient(Origin, ERR_USERNOTINCHANNEL_MSG, - Client_ID(Origin), Client_ID(client), Channel_Name(Channel))) - break; + if (!IRC_WriteStrClient + (Origin, ERR_USERNOTINCHANNEL_MSG, + Client_ID(Origin), Client_ID(client), + Channel_Name(Channel))) + break; continue; } if (client) { /* Channel-User-Mode */ - retval = set ? Channel_UserModeAdd(Channel, client, x[0]) : Channel_UserModeDel(Channel, client, x[0]); + retval = set + ? Channel_UserModeAdd(Channel, client, x[0]) + : Channel_UserModeDel(Channel, client, x[0]); if (retval) { strlcat(the_args, " ", sizeof(the_args)); - strlcat(the_args, Client_ID(client), sizeof(the_args)); + strlcat(the_args, Client_ID(client), + sizeof(the_args)); strlcat(the_modes, x, sizeof(the_modes)); - Log(LOG_DEBUG, "User \"%s\": Mode change on %s, now \"%s\"", - Client_Mask(client), Channel_Name(Channel), Channel_UserModes(Channel, client)); + LogDebug + ("User \"%s\": Mode change on %s, now \"%s\"", + Client_Mask(client), Channel_Name(Channel), + Channel_UserModes(Channel, client)); } } else { /* Channel-Mode */ - retval = set ? Channel_ModeAdd(Channel, x[0]) : Channel_ModeDel(Channel, x[0]); + retval = set + ? Channel_ModeAdd(Channel, x[0]) + : Channel_ModeDel(Channel, x[0]); if (retval) { strlcat(the_modes, x, sizeof(the_modes)); - Log(LOG_DEBUG, "Channel %s: Mode change, now \"%s\".", Channel_Name(Channel), Channel_Modes(Channel)); + LogDebug("Channel %s: Mode change, now \"%s\".", + Channel_Name(Channel), + Channel_Modes(Channel)); } } @@ -549,7 +617,8 @@ Channel_Mode( CLIENT *Client, REQUEST *Req, CLIENT *Origin, CHANNEL *Channel ) strlcat(the_args, argadd, sizeof(the_args)); } } -chan_exit: + + chan_exit: /* Are there changed modes? */ if (the_modes[1]) { /* Clean up mode string */ @@ -567,14 +636,19 @@ chan_exit: /* Forward mode changes to channel users and all the * other remote servers: */ - IRC_WriteStrServersPrefix(Client, Origin, "MODE %s %s%s", Channel_Name( Channel ), the_modes, the_args); - IRC_WriteStrChannelPrefix(Client, Channel, Origin, false, "MODE %s %s%s", Channel_Name(Channel), the_modes, the_args); + IRC_WriteStrServersPrefix(Client, Origin, + "MODE %s %s%s", Channel_Name(Channel), + the_modes, the_args); + IRC_WriteStrChannelPrefix(Client, Channel, Origin, + false, "MODE %s %s%s", Channel_Name(Channel), + the_modes, the_args); } else { if (use_servermode) Origin = Client_ThisServer(); /* Send reply to client and inform other servers and channel users */ - ok = IRC_WriteStrClientPrefix(Client, Origin, "MODE %s %s%s", - Channel_Name(Channel), the_modes, the_args); + ok = IRC_WriteStrClientPrefix(Client, Origin, + "MODE %s %s%s", Channel_Name(Channel), + the_modes, the_args); /* Only forward requests for non-local channels */ if (!Channel_IsLocal(Channel)) IRC_WriteStrServersPrefix(Client, Origin, diff --git a/src/ngircd/irc.c b/src/ngircd/irc.c index 47f8652..2466b6b 100644 --- a/src/ngircd/irc.c +++ b/src/ngircd/irc.c @@ -467,18 +467,18 @@ Send_Message(CLIENT * Client, REQUEST * Req, int ForceType, bool SendErrors) Req->argv[1])) return DISCONNECTED; } else if (ForceType != CLIENT_SERVICE + && (chan = Channel_Search(currentTarget))) { + if (!Channel_Write(chan, from, Client, Req->command, + SendErrors, Req->argv[1])) + return DISCONNECTED; + } else if (ForceType != CLIENT_SERVICE + /* $#: server/target mask, RFC 2812, sec. 3.3.1 */ && strchr("$#", currentTarget[0]) && strchr(currentTarget, '.')) { /* targetmask */ if (!Send_Message_Mask(from, Req->command, currentTarget, Req->argv[1], SendErrors)) return DISCONNECTED; - } else if (ForceType != CLIENT_SERVICE - && (chan = Channel_Search(currentTarget))) { - /* channel */ - if (!Channel_Write(chan, from, Client, Req->command, - SendErrors, Req->argv[1])) - return DISCONNECTED; } else { if (!SendErrors) return CONNECTED; @@ -501,6 +501,7 @@ Send_Message_Mask(CLIENT * from, char * command, char * targetMask, CLIENT *cl; bool client_match; char *mask = targetMask + 1; + const char *check_wildcards; cl = NULL; @@ -511,6 +512,21 @@ Send_Message_Mask(CLIENT * from, char * command, char * targetMask, Client_ID(from)); } + /* + * RFC 2812, sec. 3.3.1 requires that targetMask have at least one + * dot (".") and no wildcards ("*", "?") following the last one. + */ + check_wildcards = strrchr(targetMask, '.'); + assert(check_wildcards != NULL); + if (check_wildcards && + check_wildcards[strcspn(check_wildcards, "*?")]) + { + if (!SendErrors) + return true; + return IRC_WriteStrClient(from, ERR_WILDTOPLEVEL, targetMask); + } + + /* #: hostmask, see RFC 2812, sec. 3.3.1 */ if (targetMask[0] == '#') { for (cl = Client_First(); cl != NULL; cl = Client_Next(cl)) { if (Client_Type(cl) != CLIENT_USER) @@ -522,6 +538,7 @@ Send_Message_Mask(CLIENT * from, char * command, char * targetMask, return false; } } else { + assert(targetMask[0] == '$'); /* $: server mask, see RFC 2812, sec. 3.3.1 */ for (cl = Client_First(); cl != NULL; cl = Client_Next(cl)) { if (Client_Type(cl) != CLIENT_USER) continue; diff --git a/src/ngircd/log.c b/src/ngircd/log.c index d450bd0..5559a2c 100644 --- a/src/ngircd/log.c +++ b/src/ngircd/log.c @@ -14,8 +14,6 @@ #include "portab.h" -static char UNUSED id[] = "$Id: log.c,v 1.62 2006/08/05 09:16:21 fw Exp $"; - #include "imp.h" #include #include @@ -54,6 +52,22 @@ static char Error_File[FNAME_LEN]; static void Wall_ServerNotice PARAMS(( char *Msg )); +static void +Log_Message(int Level, const char *msg) +{ + if (!Is_Daemon) { + /* log to console */ + fprintf(stdout, "[%ld:%d %4ld] %s\n", (long)getpid(), Level, + (long)time(NULL) - NGIRCd_Start, msg); + fflush(stdout); + } +#ifdef SYSLOG + else { + syslog(Level, "%s", msg); + } +#endif +} + GLOBAL void Log_Init( bool Daemon_Mode ) @@ -248,25 +262,12 @@ va_dcl vsnprintf( msg, MAX_LOG_MSG_LEN, Format, ap ); va_end( ap ); - if (!Is_Daemon) { - /* log to console */ - fprintf(stdout, "[%d:%d %4ld] %s\n", (int)getpid( ), Level, - time(NULL) - NGIRCd_Start, msg); - fflush(stdout); - } -#ifdef SYSLOG - else - { - /* Syslog */ - syslog( Level, "%s", msg ); - } -#endif + Log_Message(Level, msg); - if( Level <= LOG_CRIT ) - { + if (Level <= LOG_CRIT) { /* log critical messages to stderr */ - fprintf( stderr, "%s\n", msg ); - fflush( stderr ); + fprintf(stderr, "%s\n", msg); + fflush(stderr); } if (snotice) { @@ -285,7 +286,7 @@ Log_Init_Resolver( void ) openlog( PACKAGE_NAME, LOG_CONS|LOG_PID, LOG_LOCAL5 ); #endif #ifdef DEBUG - Log_Resolver( LOG_DEBUG, "Resolver sub-process starting, PID %d.", getpid( )); + Log_Resolver(LOG_DEBUG, "Resolver sub-process starting, PID %ld.", (long)getpid()); #endif } /* Log_Init_Resolver */ @@ -294,7 +295,7 @@ GLOBAL void Log_Exit_Resolver( void ) { #ifdef DEBUG - Log_Resolver( LOG_DEBUG, "Resolver sub-process %d done.", getpid( )); + Log_Resolver(LOG_DEBUG, "Resolver sub-process %ld done.", (long)getpid()); #endif #ifdef SYSLOG closelog( ); @@ -335,15 +336,7 @@ va_dcl vsnprintf( msg, MAX_LOG_MSG_LEN, Format, ap ); va_end( ap ); - if (!Is_Daemon) { - /* Output to console */ - fprintf(stdout, "[%d:%d %4ld] %s\n", (int)getpid( ), Level, - time(NULL) - NGIRCd_Start, msg); - fflush(stdout); - } -#ifdef SYSLOG - else syslog( Level, "%s", msg ); -#endif + Log_Message(Level, msg); } /* Log_Resolver */ diff --git a/src/ngircd/messages.h b/src/ngircd/messages.h index 562f778..9e15b81 100644 --- a/src/ngircd/messages.h +++ b/src/ngircd/messages.h @@ -94,8 +94,9 @@ #define ERR_TOOMANYCHANNELS_MSG "405 %s %s :You have joined too many channels" #define ERR_WASNOSUCHNICK_MSG "406 %s %s :There was no such nickname" #define ERR_NOORIGIN_MSG "409 %s :No origin specified" -#define ERR_NORECIPIENT_MSG "411 %s :No receipient given (%s)" +#define ERR_NORECIPIENT_MSG "411 %s :No recipient given (%s)" #define ERR_NOTEXTTOSEND_MSG "412 %s :No text to send" +#define ERR_WILDTOPLEVEL "414 %s :Wildcard in toplevel domain" #define ERR_UNKNOWNCOMMAND_MSG "421 %s %s :Unknown command" #define ERR_NOMOTD_MSG "422 %s :MOTD file is missing" #define ERR_NONICKNAMEGIVEN_MSG "431 %s :No nickname given" diff --git a/src/ngircd/ngircd.c b/src/ngircd/ngircd.c index b564295..ad1168a 100644 --- a/src/ngircd/ngircd.c +++ b/src/ngircd/ngircd.c @@ -316,7 +316,7 @@ main( int argc, const char *argv[] ) #ifdef ZLIB strlcat( NGIRCd_ProtoID, "Z", sizeof NGIRCd_ProtoID ); #endif - Log( LOG_DEBUG, "Protocol and server ID is \"%s\".", NGIRCd_ProtoID ); + LogDebug("Protocol and server ID is \"%s\".", NGIRCd_ProtoID); /* Vordefinierte Channels anlegen */ Channel_InitPredefined( ); diff --git a/src/ngircd/parse.c b/src/ngircd/parse.c index ec856a0..6801997 100644 --- a/src/ngircd/parse.c +++ b/src/ngircd/parse.c @@ -180,7 +180,7 @@ Parse_Request( CONN_ID Idx, char *Request ) ptr = strchr( Request, ' ' ); if( ! ptr ) { - Log( LOG_DEBUG, "Connection %d: Parse error: prefix without command!?", Idx ); + LogDebug("Connection %d: Parse error: prefix without command!?", Idx); return Conn_WriteStr( Idx, "ERROR :Prefix without command!?" ); } *ptr = '\0'; diff --git a/src/ngircd/resolve.c b/src/ngircd/resolve.c index 999ef99..e7f73ad 100644 --- a/src/ngircd/resolve.c +++ b/src/ngircd/resolve.c @@ -14,8 +14,6 @@ #include "portab.h" -static char UNUSED id[] = "$Id: resolve.c,v 1.29 2008/02/26 22:04:17 fw Exp $"; - #include "imp.h" #include #include @@ -92,7 +90,7 @@ Resolve_Addr(RES_STAT * s, const ng_ipaddr_t *Addr, int identsock, pid = Resolver_fork(pipefd); if (pid > 0) { - Log(LOG_DEBUG, "Resolver for %s created (PID %d).", ng_ipaddr_tostr(Addr), pid); + LogDebug("Resolver for %s created (PID %d).", ng_ipaddr_tostr(Addr), pid); s->pid = pid; s->resolver_fd = pipefd[0]; diff --git a/src/testsuite/ngircd-test1.conf b/src/testsuite/ngircd-test1.conf index a12873f..51a57fb 100644 --- a/src/testsuite/ngircd-test1.conf +++ b/src/testsuite/ngircd-test1.conf @@ -22,7 +22,8 @@ PeerPassword = pwd2 [Channel] - Name = #InviteChannel +# This name should be accepted as '#InviteChannel' by ngircd. + Name = InviteChannel Modes = i [Channel] @@ -35,10 +36,17 @@ Name = #TopicChannel Modes = t Topic = the topic - + [Channel] Name = #SecretChannel Modes = s Topic = A secret Channel +[Channel] + Name = &LocalChannel + Topic = A local Channel + +[Channel] + Name = +ModelessChannel + Topic = A modeless Channel # -eof-