diff options
41 files changed, 553 insertions, 261 deletions
diff --git a/.gitignore b/.gitignore index 19900414..e7ab7580 100644 --- a/.gitignore +++ b/.gitignore @@ -4,11 +4,13 @@ aclocal.m4 ansi2knr.1 ansi2knr.c ansi2knr.h +ar-lib autom4te.cache build-stamp-ngircd* config.log config.status configure +configure.ac configure.lineno cscope.out debian diff --git a/INSTALL b/INSTALL index 4e1cd2fb..b4459581 100644 --- a/INSTALL +++ b/INSTALL @@ -12,6 +12,14 @@ I. Upgrade Information ~~~~~~~~~~~~~~~~~~~~~~ +Differences to version 19.x + +- Starting with ngIRCd 20, users can "cloak" their hostname only when the + configuration variable "CloakHostModeX" (introduced in 19.2) is set. + Otherwise, only IRC opertators, other servers, and services are allowed to + set mode +x. This prevents regular users from changing their hostmask to + the name of the IRC server itself, which confused quite a few people ;-) + Differences to version 17 - Support for ZeroConf/Bonjour/Rendezvous service registration has been @@ -149,10 +157,14 @@ This step is therefore only interesting for developers. autogen.sh produces the Makefile.in's, which are necessary for the configure script itself, and some more files for make. To run autogen.sh you'll need -GNU autoconf and GNU automake (use recent versions! autoconf 2.53 and -automake 1.6.1 are known to work). - -Again: "end users" do not need this step! +GNU autoconf and GNU automake: at least autoconf 2.61 and automake 1.10 are +requird, newer is better. But don't use automake 1.12 or newer for creating +distribution archives: it will work but lack "de-ANSI-fucation" support in the +generated Makefile's! Stick with automake 1.11.x for this purpose ... +So automake 1.11.x and autoconf 2.67+ is recommended. + +Again: "end users" do not need this step and neither need GNU autoconf nor GNU +automake at all! 2): "./configure" diff --git a/Makefile.am b/Makefile.am index 58f202c9..f6a97ce6 100644 --- a/Makefile.am +++ b/Makefile.am @@ -1,6 +1,6 @@ # # ngIRCd -- The Next Generation IRC Daemon -# Copyright (c)2001-2011 Alexander Barton (alex@barton.de) and Contributors +# Copyright (c)2001-2012 Alexander Barton (alex@barton.de) and Contributors # # 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 @@ -13,24 +13,26 @@ AUTOMAKE_OPTIONS = gnu SUBDIRS = doc src man contrib +EXTRA_DIST = autogen.sh configure.ng .mailmap + clean-local: rm -f build-stamp* rm -rf ngircd.dest maintainer-clean-local: rm -rf autom4te.cache - rm -f Makefile.in Makefile aclocal.m4 configure - rm -f mkinstalldirs missing depcomp install-sh + rm -f Makefile.in Makefile aclocal.m4 configure configure.ac + rm -f ar-lib mkinstalldirs missing depcomp install-sh rm -f config.log debian testsuite: - make -C src/testsuite check + cd src/testsuite && make check lint: - make -C src/ngircd lint + cd src/ngircd && make lint srcdoc: - make -C doc srcdoc + cd doc && make srcdoc have-xcodebuild: @xcodebuild -project contrib/MacOSX/ngIRCd.xcodeproj -list \ diff --git a/autogen.sh b/autogen.sh index cca200b2..6c2a8dd1 100755 --- a/autogen.sh +++ b/autogen.sh @@ -16,6 +16,11 @@ # GNU autoconf. It tries to be smart in finding the correct/usable/available # installed versions of these tools on your system. # +# In addition, it enables or disables the "de-ANSI-fication" support of GNU +# automake, which is supported up to autoconf 1.11.x an has been removed +# in automake 1.12 -- make sure to use a version of automake supporting it +# when generating distribution archives! +# # The following strategy is used for each of aclocal, autoheader, automake, # and autoconf: first, "tool" (the regular name of the tool, e. g. "autoconf" # or "automake") is checked. If this fails, "tool<major><minor>" (for example @@ -129,7 +134,7 @@ fi # Try to detect the needed tools when no environment variable already # specifies one: -echo "Searching tools ..." +echo "Searching for required tools ..." [ -z "$ACLOCAL" ] && ACLOCAL=`Search aclocal 1` [ "$VERBOSE" = "1" ] && echo " - ACLOCAL=$ACLOCAL" [ -z "$AUTOHEADER" ] && AUTOHEADER=`Search autoheader 2` @@ -139,9 +144,8 @@ echo "Searching tools ..." [ -z "$AUTOCONF" ] && AUTOCONF=`Search autoconf 2` [ "$VERBOSE" = "1" ] && echo " - AUTOCONF=$AUTOCONF" -# Call ./configure when parameters have been passed to this script and -# GO isn't already defined. -[ -z "$GO" -a $# -gt 0 ] && GO=1 +[ $# -gt 0 ] && CONFIGURE_ARGS=" $@" || CONFIGURE_ARGS="" +[ -z "$GO" -a -n "$CONFIGURE_ARGS" ] && GO=1 # Verify that all tools have been found [ -z "$ACLOCAL" ] && Notfound aclocal @@ -149,10 +153,37 @@ echo "Searching tools ..." [ -z "$AUTOMAKE" ] && Notfound automake [ -z "$AUTOCONF" ] && Notfound autoconf +AM_VERSION=`$AUTOMAKE --version|head -n 1|egrep -o "([1-9]\.[0-9]+(\.[0-9]+)*)"` +ifs=$IFS; IFS="."; set $AM_VERSION; IFS=$ifs +AM_MAJOR="$1"; AM_MINOR="$2"; AM_PATCHLEVEL="$3" + +AM_MAKEFILES="src/ipaddr/Makefile.ng src/ngircd/Makefile.ng src/testsuite/Makefile.ng src/tool/Makefile.ng" + +if [ "$AM_MAJOR" -eq "1" -a "$AM_MINOR" -lt "12" ]; then + # automake < 1.12 => automatic de-ANSI-fication support available + echo "Enabling de-ANSI-fication support (automake $AM_VERSION) ..." + sed -e "s|^__ng_PROTOTYPES__|AM_C_PROTOTYPES|g" configure.ng >configure.ac + DEANSI_START="" + DEANSI_END="" +else + # automake >= 1.12 => no de-ANSI-fication support available + echo "Disabling de-ANSI-fication support (automake $AM_VERSION) ..." + sed -e "s|^__ng_PROTOTYPES__|AC_C_PROTOTYPES|g" configure.ng >configure.ac + DEANSI_START="#" + DEANSI_END=" # disabled by ./autogen.sh script" +fi +sed -e "s|^__ng_Makefile_am_template__|${DEANSI_START}AUTOMAKE_OPTIONS = ansi2knr${DEANSI_END}|g" \ + src/portab/Makefile.ng >src/portab/Makefile.am +for makefile_ng in $AM_MAKEFILES; do + makefile_am=`echo "$makefile_ng" | sed -e "s|\.ng\$|\.am|g"` + sed -e "s|^__ng_Makefile_am_template__|${DEANSI_START}AUTOMAKE_OPTIONS = ../portab/ansi2knr${DEANSI_END}|g" \ + $makefile_ng >$makefile_am +done + export ACLOCAL AUTOHEADER AUTOMAKE AUTOCONF # Generate files -echo "Generating files ..." +echo "Generating files using GNU $AUTOCONF and $AUTOMAKE ..." Run $ACLOCAL && \ Run $AUTOCONF && \ Run $AUTOHEADER && \ @@ -164,8 +195,7 @@ if [ $? -eq 0 -a -x ./configure ]; then NAME=`grep PACKAGE_STRING= configure | cut -d"'" -f2` if [ "$GO" = "1" ]; then [ -n "$PREFIX" ] && p=" --prefix=$PREFIX" || p="" - [ -n "$*" ] && a=" $*" || a="" - c="./configure${p}${a}" + c="./configure${p}${CONFIGURE_ARGS}" echo "Okay, autogen.sh for $NAME done." echo "Calling \"$c\" ..." $c diff --git a/configure.in b/configure.ng index cccda866..a3cab6ae 100644 --- a/configure.in +++ b/configure.ng @@ -9,11 +9,20 @@ # Please read the file COPYING, README and AUTHORS for more information. # -define(VERSION_ID,esyscmd(git describe|sed -e 's/rel-//g'|sed -e 's/-/~/'|tr -d \\n)) +define(VERSION_ID,esyscmd([ + V=`git describe 2>/dev/null | sed -e 's/rel-//g' | sed -e 's/-/~/'`; + [ -z "$V" -a -r configure ] \ + && V=`grep "PACKAGE_STRING=" configure | cut -d"'" -f2 | cut -d' ' -f2` + ( [ -n "$V" ] && echo "$V" || echo "??" ) | tr -d '\n'; +])) + +m4_ifdef([AM_SILENT_RULES], + [m4_define([ng_color_tests], [color-tests])], + [m4_define([ng_color_tests], [])]) # -- Initialisation -- -AC_PREREQ([2.67]) +AC_PREREQ([2.61]) AC_INIT([ngIRCd], VERSION_ID, [ngircd-ml@ngircd.barton.de], [ngircd], [http://ngircd.barton.de/]) @@ -21,7 +30,7 @@ AC_CONFIG_SRCDIR([src/ngircd/ngircd.c]) AC_CONFIG_HEADER([src/config.h]) AC_CANONICAL_HOST -AM_INIT_AUTOMAKE([1.11]) +AM_INIT_AUTOMAKE([-Wall 1.10 ]ng_color_tests) m4_ifdef([AM_SILENT_RULES], [AM_SILENT_RULES([yes])]) @@ -52,6 +61,8 @@ AC_PROG_CC_STDC # -- Helper programs -- +m4_ifdef([AM_PROG_AR], [AM_PROG_AR]) + AC_PROG_AWK AC_PROG_INSTALL AC_PROG_LN_S @@ -62,7 +73,7 @@ AC_PROG_RANLIB AC_C_CONST AC_C_INLINE -AM_C_PROTOTYPES +__ng_PROTOTYPES__ # -- Hard coded system and compiler dependencies/features/options ... -- @@ -701,4 +712,12 @@ echo $ECHO_N " libiconv support: $ECHO_C" echo +if ! grep "^AUTOMAKE_OPTIONS = ../portab/ansi2knr" src/ngircd/Makefile.am >/dev/null 2>&1; then + echo "WARNING:" + echo "This GNU automake generated build system does not support \"de-ANSI-fication\"," + echo "therefore don't use it to generate \"official\" distribution archives!" + echo "(Most probably you want to use GNU automake 1.11.x for this purpose ...)" + echo +fi + # -eof- diff --git a/contrib/MacOSX/config.h b/contrib/MacOSX/config.h index a25d8861..bf94d327 100644 --- a/contrib/MacOSX/config.h +++ b/contrib/MacOSX/config.h @@ -103,6 +103,8 @@ #define HAVE_GETNAMEINFO 1 /* Define to 1 if you have the `sigaction' function. */ #define HAVE_SIGACTION 1 +/* Define to 1 if you have the `setsid' function. */ +#define HAVE_SETSID 1 /* Define if socklen_t exists */ #define HAVE_socklen_t 1 diff --git a/doc/Makefile.am b/doc/Makefile.am index 00f2530c..cd51d7fe 100644 --- a/doc/Makefile.am +++ b/doc/Makefile.am @@ -19,6 +19,7 @@ SUFFIXES = .tmpl static_docs = \ Bopm.txt \ Capabilities.txt \ + Contributing.txt \ FAQ.txt \ GIT.txt \ HowToRelease.txt \ diff --git a/doc/Modes.txt b/doc/Modes.txt index c2c533f2..e3b754d6 100644 --- a/doc/Modes.txt +++ b/doc/Modes.txt @@ -68,7 +68,12 @@ channel of which he is a member. mode since description + q 20 User is channel owner can only be set by a service, other + owner and irc op. Can promote other users to q, a, o, h, v. + a 20 User is channel admin and can promote other users to v, h, o o 0.2.0 User is channel operator and can op/kick/... other members. + h 20 User is half op and can set channel modes imntvIbek and kick + voiced and normal users. v 0.2.0 User is "voiced" and can speak even if channel is moderated. diff --git a/doc/sample-ngircd.conf.tmpl b/doc/sample-ngircd.conf.tmpl index 57e65892..018855d5 100644 --- a/doc/sample-ngircd.conf.tmpl +++ b/doc/sample-ngircd.conf.tmpl @@ -165,6 +165,9 @@ # they are not(!) channel-operators? ;OperCanUseMode = no + # Should IRC Operators get AutoOp (+o) in persistent (+P) channels? + ;OperChanPAutoOp = yes + # Mask IRC Operator mode requests as if they were coming from the # server? (This is a compatibility hack for ircd-irc2 servers) ;OperServerMode = no diff --git a/man/ngircd.conf.5.tmpl b/man/ngircd.conf.5.tmpl index aff11a67..c03cf740 100644 --- a/man/ngircd.conf.5.tmpl +++ b/man/ngircd.conf.5.tmpl @@ -268,6 +268,10 @@ while connecting. Default: no. Should IRC Operators be allowed to use the MODE command even if they are not(!) channel-operators? Default: no. .TP +\fBOperChanPAutoOp\fR (boolean) +Should IRC Operators get AutoOp (+o) in persistent (+P) channels? +Default: yes. +.TP \fBOperServerMode\fR (boolean) If \fBOperCanUseMode\fR is enabled, this may lead the compatibility problems with Servers that run the ircd-irc2 Software. This Option "masks" mode diff --git a/src/ipaddr/.gitignore b/src/ipaddr/.gitignore new file mode 100644 index 00000000..08a6d725 --- /dev/null +++ b/src/ipaddr/.gitignore @@ -0,0 +1 @@ +Makefile.am diff --git a/src/ipaddr/Makefile.am b/src/ipaddr/Makefile.ng index 6ce299f2..ecfce295 100644 --- a/src/ipaddr/Makefile.am +++ b/src/ipaddr/Makefile.ng @@ -3,9 +3,11 @@ # (c) 2008 Florian Westphal <fw@strlen.de>, public domain. # -AUTOMAKE_OPTIONS = ../portab/ansi2knr +__ng_Makefile_am_template__ -INCLUDES = -I$(srcdir)/../portab +EXTRA_DIST = Makefile.ng + +AM_CPPFLAGS = -I$(srcdir)/../portab noinst_LIBRARIES = libngipaddr.a @@ -14,6 +16,6 @@ libngipaddr_a_SOURCES = ng_ipaddr.c noinst_HEADERS = ng_ipaddr.h maintainer-clean-local: - rm -f Makefile Makefile.in + rm -f Makefile Makefile.in Makefile.am # -eof- diff --git a/src/ngircd/.gitignore b/src/ngircd/.gitignore index c25ba5e3..d1148bfb 100644 --- a/src/ngircd/.gitignore +++ b/src/ngircd/.gitignore @@ -1,3 +1,4 @@ +Makefile.am check-help check-version ngircd diff --git a/src/ngircd/Makefile.am b/src/ngircd/Makefile.ng index c1fd4240..27b5c408 100644 --- a/src/ngircd/Makefile.am +++ b/src/ngircd/Makefile.ng @@ -1,6 +1,6 @@ # # ngIRCd -- The Next Generation IRC Daemon -# Copyright (c)2001-2012 Alexander Barton (alex@barton.de) +# Copyright (c)2001-2012 Alexander Barton (alex@barton.de) and Contributors # # 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 @@ -9,9 +9,11 @@ # Please read the file COPYING, README and AUTHORS for more information. # -AUTOMAKE_OPTIONS = ../portab/ansi2knr +__ng_Makefile_am_template__ -INCLUDES = -I$(srcdir)/../portab -I$(srcdir)/../tool -I$(srcdir)/../ipaddr +EXTRA_DIST = Makefile.ng + +AM_CPPFLAGS = -I$(srcdir)/../portab -I$(srcdir)/../tool -I$(srcdir)/../ipaddr LINTARGS = -weak -warnunixlib +unixlib -booltype BOOLEAN \ -varuse -retvalother -emptyret -unrecog @@ -105,7 +107,7 @@ clean-local: rm -f check-version check-help lint.out maintainer-clean-local: - rm -f Makefile Makefile.in + rm -f Makefile Makefile.in Makefile.am check-version: Makefile echo "#!/bin/sh" > check-version @@ -124,7 +126,7 @@ lint: for f in *.c; do \ echo "checking $$f ..."; \ splint $$f $(LINTARGS) -I$(srcdir) -I$(srcdir)/.. \ - $(INCLUDES) $(AM_CFLAGS) >lint.out 2>&1; \ + $(AM_CPPFLAGS) $(AM_CFLAGS) >lint.out 2>&1; \ grep "no warnings" lint.out > /dev/null 2>&1; \ if [ $$? -ne 0 ]; then \ waswarning=1; \ diff --git a/src/ngircd/channel.c b/src/ngircd/channel.c index f0a9525d..10b05405 100644 --- a/src/ngircd/channel.c +++ b/src/ngircd/channel.c @@ -299,6 +299,8 @@ Channel_Kick(CLIENT *Peer, CLIENT *Target, CLIENT *Origin, const char *Name, const char *Reason ) { CHANNEL *chan; + char *ptr, *target_modes; + bool can_kick = false; assert(Peer != NULL); assert(Target != NULL); @@ -319,14 +321,51 @@ Channel_Kick(CLIENT *Peer, CLIENT *Target, CLIENT *Origin, const char *Name, /* Check that user is on the specified channel */ if (!Channel_IsMemberOf(chan, Origin)) { IRC_WriteStrClient( Origin, ERR_NOTONCHANNEL_MSG, - Client_ID(Origin), Name); + Client_ID(Origin), Name); return; } + } + + if(Client_Type(Peer) == CLIENT_USER) { + /* Check if client has the rights to kick target */ + ptr = Channel_UserModes(chan, Peer); + target_modes = Channel_UserModes(chan, Target); + while(*ptr) { + /* Owner can kick everyone */ + if ( *ptr == 'q') { + can_kick = true; + break; + } + /* Admin can't kick owner */ + if ( *ptr == 'a' ) { + if (!strchr(target_modes, 'q')) { + can_kick = true; + break; + } + } + /* Op can't kick owner | admin */ + if ( *ptr == 'o' ) { + if (!strchr(target_modes, 'q') && + !strchr(target_modes, 'a')) { + can_kick = true; + break; + } + } + /* Half Op can't kick owner | admin | op */ + if ( *ptr == 'h' ) { + if (!strchr(target_modes, 'q') && + !strchr(target_modes, 'a') && + !strchr(target_modes, 'o')) { + can_kick = true; + break; + } + } + ptr++; + } - /* Check if user has operator status */ - if (!strchr(Channel_UserModes(chan, Origin), 'o')) { - IRC_WriteStrClient(Origin, ERR_CHANOPRIVSNEEDED_MSG, - Client_ID(Origin), Name); + if(!can_kick) { + IRC_WriteStrClient(Origin, ERR_CHANOPPRIVTOOLOW_MSG, + Client_ID(Origin), Name); return; } } @@ -812,9 +851,9 @@ Channel_SetMaxUsers(CHANNEL *Chan, unsigned long Count) static bool Can_Send_To_Channel(CHANNEL *Chan, CLIENT *From) { - bool is_member, has_voice, is_op; + bool is_member, has_voice, is_halfop, is_op, is_chanadmin, is_owner; - is_member = has_voice = is_op = false; + is_member = has_voice = is_halfop = is_op = is_chanadmin = is_owner = false; /* The server itself always can send messages :-) */ if (Client_ThisServer() == From) @@ -824,8 +863,14 @@ Can_Send_To_Channel(CHANNEL *Chan, CLIENT *From) is_member = true; if (strchr(Channel_UserModes(Chan, From), 'v')) has_voice = true; + if (strchr(Channel_UserModes(Chan, From), 'h')) + is_halfop = true; if (strchr(Channel_UserModes(Chan, From), 'o')) is_op = true; + if (strchr(Channel_UserModes(Chan, From), 'a')) + is_chanadmin = true; + if (strchr(Channel_UserModes(Chan, From), 'q')) + is_owner = true; } /* @@ -841,7 +886,7 @@ Can_Send_To_Channel(CHANNEL *Chan, CLIENT *From) && !Client_HasMode(From, 'o')) return false; - if (is_op || has_voice) + if (has_voice || is_halfop || is_op || is_chanadmin || is_owner) return true; if (strchr(Channel_Modes(Chan), 'm')) @@ -1196,64 +1241,6 @@ Channel_CheckKey(CHANNEL *Chan, CLIENT *Client, const char *Key) } /* Channel_CheckKey */ -/** - * Check wether a client is allowed to administer a channel or not. - * - * @param Chan The channel to test. - * @param Client The client from which the command has been received. - * @param Origin The originator of the command (or NULL). - * @param OnChannel Set to true if the originator is member of the channel. - * @param AdminOk Set to true if the client is allowed to do - * administrative tasks on this channel. - * @param UseServerMode Set to true if ngIRCd should emulate "server mode", - * that is send commands as if originating from a server - * and not the originator of the command. - */ -GLOBAL void -Channel_CheckAdminRights(CHANNEL *Chan, CLIENT *Client, CLIENT *Origin, - bool *OnChannel, bool *AdminOk, bool *UseServerMode) -{ - assert (Chan != NULL); - assert (Client != NULL); - assert (OnChannel != NULL); - assert (AdminOk != NULL); - assert (UseServerMode != NULL); - - /* Use the client as origin, if no origin has been given (no prefix?) */ - if (!Origin) - Origin = Client; - - *OnChannel = false; - *AdminOk = false; - *UseServerMode = false; - - if (Client_Type(Client) != CLIENT_USER - && Client_Type(Client) != CLIENT_SERVER - && Client_Type(Client) != CLIENT_SERVICE) - return; - - /* Allow channel administration if the client is a server or service */ - if (Client_Type(Client) != CLIENT_USER) { - *AdminOk = true; - return; - } - - *OnChannel = Channel_IsMemberOf(Chan, Origin); - - if (*OnChannel && strchr(Channel_UserModes(Chan, Origin), 'o')) { - /* User is a channel operator */ - *AdminOk = true; - } else if (Conf_OperCanMode) { - /* IRC operators are allowed to administer channels as well */ - if (Client_OperByMe(Origin)) { - *AdminOk = true; - if (Conf_OperServerMode) - *UseServerMode = true; - } - } -} /* Channel_CheckAdminRights */ - - static CL2CHAN * Get_First_Cl2Chan( CLIENT *Client, CHANNEL *Chan ) { diff --git a/src/ngircd/conf-ssl.h b/src/ngircd/conf-ssl.h index 3fab579c..428bcf45 100644 --- a/src/ngircd/conf-ssl.h +++ b/src/ngircd/conf-ssl.h @@ -39,13 +39,9 @@ struct ConnSSL_State { #endif }; -bool -ConnSSL_InitLibrary(void); -#else -static inline bool -ConnSSL_InitLibrary(void) -{ return true; } -#endif /* SSL_SUPPORT */ +#endif + +bool ConnSSL_InitLibrary(void); #endif /* conf_ssl_h */ diff --git a/src/ngircd/conf.c b/src/ngircd/conf.c index 5853926e..4ac37ad4 100644 --- a/src/ngircd/conf.c +++ b/src/ngircd/conf.c @@ -104,6 +104,8 @@ ConfSSL_Init(void) free(Conf_SSLOptions.DHFile); Conf_SSLOptions.DHFile = NULL; array_free_wipe(&Conf_SSLOptions.KeyFilePassword); + + array_free(&Conf_SSLOptions.ListenPorts); } /** @@ -370,6 +372,7 @@ Conf_Test( void ) printf(" MorePrivacy = %s\n", yesno_to_str(Conf_MorePrivacy)); printf(" NoticeAuth = %s\n", yesno_to_str(Conf_NoticeAuth)); printf(" OperCanUseMode = %s\n", yesno_to_str(Conf_OperCanMode)); + printf(" OperChanPAutoOp = %s\n", yesno_to_str(Conf_OperChanPAutoOp)); printf(" OperServerMode = %s\n", yesno_to_str(Conf_OperServerMode)); #ifdef PAM printf(" PAM = %s\n", yesno_to_str(Conf_PAM)); @@ -689,6 +692,7 @@ Set_Defaults(bool InitServers) PACKAGE_NAME, PACKAGE_VERSION); free(Conf_ListenAddress); Conf_ListenAddress = NULL; + array_free(&Conf_ListenPorts); array_free(&Conf_Motd); strlcpy(Conf_MotdFile, SYSCONFDIR, sizeof(Conf_MotdFile)); strlcat(Conf_MotdFile, MOTD_FILE, sizeof(Conf_MotdFile)); @@ -730,6 +734,7 @@ Set_Defaults(bool InitServers) Conf_MorePrivacy = false; Conf_NoticeAuth = false; Conf_OperCanMode = false; + Conf_OperChanPAutoOp = true; Conf_OperServerMode = false; #ifdef PAM Conf_PAM = true; @@ -1178,6 +1183,7 @@ CheckLegacyGlobalOption(int Line, char *Var, char *Arg) || strcasecmp(Var, "ConnectIPv4") == 0 || strcasecmp(Var, "ConnectIPv6") == 0 || strcasecmp(Var, "OperCanUseMode") == 0 + || strcasecmp(Var, "OperChanPAutoOp") == 0 || strcasecmp(Var, "OperServerMode") == 0 || strcasecmp(Var, "PredefChannelsOnly") == 0 || strcasecmp(Var, "SyslogFacility") == 0 @@ -1553,6 +1559,10 @@ Handle_OPTIONS(int Line, char *Var, char *Arg) Conf_OperCanMode = Check_ArgIsTrue(Arg); return; } + if (strcasecmp(Var, "OperChanPAutoOp") == 0) { + Conf_OperChanPAutoOp = Check_ArgIsTrue(Arg); + return; + } if (strcasecmp(Var, "OperServerMode") == 0) { Conf_OperServerMode = Check_ArgIsTrue(Arg); return; diff --git a/src/ngircd/conf.h b/src/ngircd/conf.h index 7a4e38aa..90d74d20 100644 --- a/src/ngircd/conf.h +++ b/src/ngircd/conf.h @@ -151,6 +151,9 @@ GLOBAL bool Conf_PredefChannelsOnly; /** Flag indicating if IRC operators are allowed to always use MODE (true) */ GLOBAL bool Conf_OperCanMode; +/** Flag indicating if IRC operators get AutoOp in persistent (+P) channels */ +GLOBAL bool Conf_OperChanPAutoOp; + /** * If true, mask channel MODE commands of IRC operators to the server. * Background: ircd2 will ignore channel MODE commands if an IRC operator diff --git a/src/ngircd/conn-ssl.c b/src/ngircd/conn-ssl.c index 8f7b70af..59729e04 100644 --- a/src/ngircd/conn-ssl.c +++ b/src/ngircd/conn-ssl.c @@ -156,7 +156,7 @@ Load_DH_params(void) bool ret = true; if (!Conf_SSLOptions.DHFile) { - Log(LOG_NOTICE, "Configuration option \"SSLDHFile\" not set!"); + Log(LOG_NOTICE, "Configuration option \"DHFile\" not set!"); return false; } fp = fopen(Conf_SSLOptions.DHFile, "r"); @@ -201,7 +201,7 @@ Load_DH_params(void) } if (need_dhgenerate) { Log(LOG_WARNING, - "SSLDHFile not set, generating %u bit DH parameters. This may take a while ...", + "DHFile not set, generating %u bit DH parameters. This may take a while ...", DH_BITS); err = gnutls_dh_params_generate2(tmp_dh_params, DH_BITS); if (err < 0) { @@ -241,6 +241,9 @@ void ConnSSL_Free(CONNECTION *c) bool ConnSSL_InitLibrary( void ) { + if (!array_bytes(&Conf_SSLOptions.ListenPorts)) + return true; + #ifdef HAVE_LIBSSL SSL_CTX *newctx; @@ -256,12 +259,14 @@ ConnSSL_InitLibrary( void ) * According to OpenSSL RAND_egd(3): "The automatic query of /var/run/egd-pool et al was added in OpenSSL 0.9.7"; * so it makes little sense to deal with PRNGD seeding ourselves. */ + array_free(&Conf_SSLOptions.ListenPorts); return false; } newctx = SSL_CTX_new(SSLv23_method()); if (!newctx) { LogOpenSSLError("SSL_CTX_new()", NULL); + array_free(&Conf_SSLOptions.ListenPorts); return false; } @@ -276,6 +281,7 @@ ConnSSL_InitLibrary( void ) return true; out: SSL_CTX_free(newctx); + array_free(&Conf_SSLOptions.ListenPorts); return false; #endif #ifdef HAVE_LIBGNUTLS @@ -287,10 +293,13 @@ out: err = gnutls_global_init(); if (err) { Log(LOG_ERR, "gnutls_global_init(): %s", gnutls_strerror(err)); + array_free(&Conf_SSLOptions.ListenPorts); return false; } - if (!ConnSSL_LoadServerKey_gnutls()) + if (!ConnSSL_LoadServerKey_gnutls()) { + array_free(&Conf_SSLOptions.ListenPorts); return false; + } Log(LOG_INFO, "gnutls %s initialized.", gnutls_check_version(NULL)); initialized = true; return true; @@ -313,7 +322,7 @@ ConnSSL_LoadServerKey_gnutls(void) cert_file = Conf_SSLOptions.CertFile ? Conf_SSLOptions.CertFile:Conf_SSLOptions.KeyFile; if (!cert_file) { - Log(LOG_NOTICE, "No SSL server key configured, SSL disabled."); + Log(LOG_ERR, "No SSL server key configured!"); return false; } @@ -344,7 +353,7 @@ ConnSSL_LoadServerKey_openssl(SSL_CTX *ctx) assert(ctx); if (!Conf_SSLOptions.KeyFile) { - Log(LOG_NOTICE, "No SSL server key configured, SSL disabled."); + Log(LOG_ERR, "No SSL server key configured!"); return false; } @@ -714,6 +723,13 @@ ConnSSL_GetCipherInfo(CONNECTION *c, char *buf, size_t len) #endif } +#else + +bool +ConnSSL_InitLibrary(void) +{ + return true; +} #endif /* SSL_SUPPORT */ /* -eof- */ diff --git a/src/ngircd/defines.h b/src/ngircd/defines.h index 82837599..ba7adf17 100644 --- a/src/ngircd/defines.h +++ b/src/ngircd/defines.h @@ -164,7 +164,7 @@ #define USERMODES "aBcCiorRswx" /** Supported channel modes. */ -#define CHANMODES "beiIklmMnoOPrRstvz" +#define CHANMODES "abehiIklmMnoOPqrRstvz" /** Away message for users connected to linked servers. */ #define DEFAULT_AWAY_MSG "Away" diff --git a/src/ngircd/irc-channel.c b/src/ngircd/irc-channel.c index d714b48f..4a157d67 100644 --- a/src/ngircd/irc-channel.c +++ b/src/ngircd/irc-channel.c @@ -167,8 +167,10 @@ join_set_channelmodes(CHANNEL *chan, CLIENT *target, const char *flags) } } - /* If channel persistent and client is ircop: make client chanop */ - if (strchr(Channel_Modes(chan), 'P') && strchr(Client_Modes(target), 'o')) + /* If the channel is persistent (+P) and client is an IRC op: + * make client chanop, if not disabled in configuration. */ + if (strchr(Channel_Modes(chan), 'P') && Conf_OperChanPAutoOp + && strchr(Client_Modes(target), 'o')) Channel_UserModeAdd(chan, target, 'o'); } /* join_set_channelmodes */ @@ -510,7 +512,7 @@ IRC_TOPIC( CLIENT *Client, REQUEST *Req ) CHANNEL *chan; CLIENT *from; char *topic; - bool onchannel, topicok, use_servermode, r; + bool r, is_oper; assert( Client != NULL ); assert( Req != NULL ); @@ -533,10 +535,9 @@ IRC_TOPIC( CLIENT *Client, REQUEST *Req ) return IRC_WriteStrClient(from, ERR_NOSUCHCHANNEL_MSG, Client_ID(from), Req->argv[0]); - Channel_CheckAdminRights(chan, Client, from, - &onchannel, &topicok, &use_servermode); - - if (!onchannel && !topicok) + /* Only IRC opers and channel members allowed */ + is_oper = Client_OperByMe(from); + if (!Channel_IsMemberOf(chan, from) && !is_oper) return IRC_WriteStrClient(from, ERR_NOTONCHANNEL_MSG, Client_ID(from), Req->argv[0]); @@ -565,8 +566,12 @@ IRC_TOPIC( CLIENT *Client, REQUEST *Req ) } if (strchr(Channel_Modes(chan), 't')) { - /* Topic Lock. Is the user a channel or IRC operator? */ - if (!topicok) + /* Topic Lock. Is the user a channel op or IRC operator? */ + if(!strchr(Channel_UserModes(chan, from), 'h') && + !strchr(Channel_UserModes(chan, from), 'o') && + !strchr(Channel_UserModes(chan, from), 'a') && + !strchr(Channel_UserModes(chan, from), 'q') && + !is_oper) return IRC_WriteStrClient(from, ERR_CHANOPRIVSNEEDED_MSG, Client_ID(from), Channel_Name(chan)); @@ -578,7 +583,7 @@ IRC_TOPIC( CLIENT *Client, REQUEST *Req ) Client_TypeText(from), Client_Mask(from), Channel_Name(chan), Req->argv[1][0] ? Req->argv[1] : "<none>"); - if (use_servermode) + if (Conf_OperServerMode) from = Client_ThisServer(); /* Update channel and forward new topic to other servers */ @@ -666,7 +671,8 @@ IRC_LIST( CLIENT *Client, REQUEST *Req ) if (MatchCaseInsensitive(pattern, Channel_Name(chan))) { /* Gotcha! */ if (!strchr(Channel_Modes(chan), 's') - || Channel_IsMemberOf(chan, from)) { + || Channel_IsMemberOf(chan, from) + || (!Conf_MorePrivacy && Client_OperByMe(Client))) { if (IRC_CheckListTooBig(from, count, MAX_RPL_LIST, "LIST")) diff --git a/src/ngircd/irc-info.c b/src/ngircd/irc-info.c index fc04773a..4909a96a 100644 --- a/src/ngircd/irc-info.c +++ b/src/ngircd/irc-info.c @@ -117,7 +117,7 @@ IRC_INFO(CLIENT * Client, REQUEST * Req) target = Client_Search(Req->argv[0]); else target = Client_ThisServer(); - + /* Make sure that the target is a server */ if (target && Client_Type(target) != CLIENT_SERVER) target = Client_Introducer(target); @@ -807,22 +807,48 @@ who_flags_status(const char *client_modes) } -static const char * -who_flags_qualifier(CLIENT *Client, const char *chan_user_modes) +/** + * Return channel user mode prefix(es). + * + * @param Client The client requesting the mode prefixes. + * @param chan_user_modes String with channel user modes. + * @param str String buffer to which the prefix(es) will be appended. + * @param len Size of "str" buffer. + * @return Pointer to "str". + */ +static char * +who_flags_qualifier(CLIENT *Client, const char *chan_user_modes, + char *str, size_t len) { assert(Client != NULL); if (Client_Cap(Client) & CLIENT_CAP_MULTI_PREFIX) { - if (strchr(chan_user_modes, 'o') && - strchr(chan_user_modes, 'v')) - return "@+"; + if (strchr(chan_user_modes, 'q')) + strlcat(str, "~", len); + if (strchr(chan_user_modes, 'a')) + strlcat(str, "&", len); + if (strchr(chan_user_modes, 'o')) + strlcat(str, "@", len); + if (strchr(chan_user_modes, 'h')) + strlcat(str, "%", len); + if (strchr(chan_user_modes, 'v')) + strlcat(str, "+", len); + + return str; } - if (strchr(chan_user_modes, 'o')) - return "@"; + if (strchr(chan_user_modes, 'q')) + strlcat(str, "~", len); + else if (strchr(chan_user_modes, 'a')) + strlcat(str, "&", len); + else if (strchr(chan_user_modes, 'o')) + strlcat(str, "@", len); + else if (strchr(chan_user_modes, 'h')) + strlcat(str, "%", len); else if (strchr(chan_user_modes, 'v')) - return "+"; - return ""; + strlcat(str, "+", len); + + return str; } @@ -840,8 +866,7 @@ IRC_WHO_Channel(CLIENT *Client, CHANNEL *Chan, bool OnlyOps) bool is_visible, is_member, is_ircop; CL2CHAN *cl2chan; const char *client_modes; - const char *chan_user_modes; - char flags[8]; + char flags[10]; CLIENT *c; int count = 0; @@ -872,9 +897,8 @@ IRC_WHO_Channel(CLIENT *Client, CHANNEL *Chan, bool OnlyOps) if (is_ircop) strlcat(flags, "*", sizeof(flags)); - chan_user_modes = Channel_UserModes(Chan, c); - strlcat(flags, who_flags_qualifier(c, chan_user_modes), - sizeof(flags)); + who_flags_qualifier(Client, Channel_UserModes(Chan, c), + flags, sizeof(flags)); if (!write_whoreply(Client, c, Channel_Name(Chan), flags)) @@ -1090,8 +1114,8 @@ IRC_WHOIS_SendReply(CLIENT *Client, CLIENT *from, CLIENT *c) if (str[strlen(str) - 1] != ':') strlcat(str, " ", sizeof(str)); - strlcat(str, who_flags_qualifier(c, Channel_UserModes(chan, c)), - sizeof(str)); + who_flags_qualifier(Client, Channel_UserModes(chan, c), + str, sizeof(str)); strlcat(str, Channel_Name(chan), sizeof(str)); if (strlen(str) > (LINE_LEN - CHANNEL_NAME_LEN - 4)) { @@ -1465,7 +1489,7 @@ IRC_Send_LUSERS(CLIENT *Client) Conn_CountMax(), Conn_CountAccepted())) return DISCONNECTED; #endif - + return CONNECTED; } /* IRC_Send_LUSERS */ @@ -1595,16 +1619,9 @@ IRC_Send_NAMES(CLIENT * Client, CHANNEL * Chan) if (is_member || is_visible) { if (str[strlen(str) - 1] != ':') strlcat(str, " ", sizeof(str)); - if (Client_Cap(Client) & CLIENT_CAP_MULTI_PREFIX && - strchr(Channel_UserModes(Chan, cl), 'o') && - strchr(Channel_UserModes(Chan, cl), 'v')) { - strlcat(str, "@+", sizeof(str)); - } else { - if (strchr(Channel_UserModes(Chan, cl), 'o')) - strlcat(str, "@", sizeof(str)); - else if (strchr(Channel_UserModes(Chan, cl), 'v')) - strlcat(str, "+", sizeof(str)); - } + + who_flags_qualifier(Client, Channel_UserModes(Chan, cl), + str, sizeof(str)); strlcat(str, Client_ID(cl), sizeof(str)); if (strlen(str) > (LINE_LEN - CLIENT_NICK_LEN - 4)) { diff --git a/src/ngircd/irc-login.c b/src/ngircd/irc-login.c index 74d8b9d1..99cd26f4 100644 --- a/src/ngircd/irc-login.c +++ b/src/ngircd/irc-login.c @@ -18,6 +18,7 @@ #include "imp.h" #include <assert.h> +#include <ctype.h> #include <stdlib.h> #include <string.h> #include <strings.h> @@ -422,11 +423,9 @@ IRC_USER(CLIENT * Client, REQUEST * Req) punctuation is allowed.*/ ptr = Req->argv[0]; while (*ptr) { - if ((*ptr < '0' || *ptr > '9') && - (*ptr < 'A' || *ptr > 'Z') && - (*ptr < 'a' || *ptr > 'z') && - (*ptr != '+') && (*ptr != '-') && - (*ptr != '.') && (*ptr != '_')) { + if (!isalnum(*ptr) && + *ptr != '+' && *ptr != '-' && + *ptr != '.' && *ptr != '_') { Conn_Close(Client_Conn(Client), NULL, "Invalid user name", true); return DISCONNECTED; diff --git a/src/ngircd/irc-mode.c b/src/ngircd/irc-mode.c index 71557201..90f638d8 100644 --- a/src/ngircd/irc-mode.c +++ b/src/ngircd/irc-mode.c @@ -278,9 +278,15 @@ Client_Mode( CLIENT *Client, REQUEST *Req, CLIENT *Origin, CLIENT *Target ) ok = IRC_WriteStrClient(Origin, ERR_RESTRICTED_MSG, Client_ID(Origin)); - else + else if (!set || Conf_CloakHostModeX[0] + || Client_Type(Client) == CLIENT_SERVER + || Client_OperByMe(Client)) { x[0] = 'x'; send_RPL_HOSTHIDDEN_MSG = true; + } else + ok = IRC_WriteStrClient(Origin, + ERR_NOPRIVILEGES_MSG, + Client_ID(Origin)); break; default: if (Client_Type(Client) != CLIENT_SERVER) { @@ -418,13 +424,16 @@ static bool 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 connected, set, skiponce, retval, onchannel, modeok, use_servermode; + argadd[CLIENT_PASS_LEN], *mode_ptr, *o_mode_ptr; + bool connected, set, skiponce, retval, use_servermode, + is_halfop, is_op, is_admin, is_owner, is_machine, is_oper; int mode_arg, arg_arg, mode_arg_count = 0; CLIENT *client; long l; size_t len; + is_halfop = is_op = is_admin = is_owner = is_machine = is_oper = false; + if (Channel_IsModeless(Channel)) return IRC_WriteStrClient(Client, ERR_NOCHANMODES_MSG, Client_ID(Client), Channel_Name(Channel)); @@ -433,10 +442,20 @@ Channel_Mode(CLIENT *Client, REQUEST *Req, CLIENT *Origin, CHANNEL *Channel) if (Req->argc <= 1) return Channel_Mode_Answer_Request(Origin, Channel); - Channel_CheckAdminRights(Channel, Client, Origin, - &onchannel, &modeok, &use_servermode); + /* Check if origin is oper and opers can use mode */ + use_servermode = Conf_OperServerMode; + if(Client_OperByMe(Client) && Conf_OperCanMode) { + is_oper = true; + } - if (!onchannel && !modeok) + /* Check if client is a server/service */ + if(Client_Type(Client) == CLIENT_SERVER || + Client_Type(Client) == CLIENT_SERVICE) { + is_machine = true; + } + + /* Check if client is member of channel or an oper or an server/service */ + if(!Channel_IsMemberOf(Channel, Client) && !is_oper && !is_machine) return IRC_WriteStrClient(Origin, ERR_NOTONCHANNEL_MSG, Client_ID(Origin), Channel_Name(Channel)); @@ -515,21 +534,44 @@ Channel_Mode(CLIENT *Client, REQUEST *Req, CLIENT *Origin, CHANNEL *Channel) if (arg_arg >= Req->argc) arg_arg = -1; + if(!is_machine) { + o_mode_ptr = Channel_UserModes(Channel, Client); + while( *o_mode_ptr ) { + if ( *o_mode_ptr == 'q') + is_owner = true; + if ( *o_mode_ptr == 'a') + is_admin = true; + if ( *o_mode_ptr == 'o') + is_op = true; + if ( *o_mode_ptr == 'h') + is_halfop = true; + o_mode_ptr++; + } + } + /* Validate modes */ x[0] = '\0'; argadd[0] = '\0'; client = NULL; switch (*mode_ptr) { /* --- Channel modes --- */ + case 'R': /* Registered users only */ + case 's': /* Secret channel */ + case 'z': /* Secure connections only */ + if(!is_oper && !is_machine && !is_owner && + !is_admin && !is_op) { + connected = IRC_WriteStrClient(Origin, + ERR_CHANOPRIVSNEEDED_MSG, + Client_ID(Origin), Channel_Name(Channel)); + goto chan_exit; + } case 'i': /* Invite only */ case 'M': /* Only identified nicks can write */ case 'm': /* Moderated */ case 'n': /* Only members can write */ - case 'R': /* Registered users only */ - case 's': /* Secret channel */ case 't': /* Topic locked */ - case 'z': /* Secure connections only */ - if (modeok) + if(is_oper || is_machine || is_owner || + is_admin || is_op || is_halfop) x[0] = *mode_ptr; else connected = IRC_WriteStrClient(Origin, @@ -540,7 +582,8 @@ Channel_Mode(CLIENT *Client, REQUEST *Req, CLIENT *Origin, CHANNEL *Channel) if (Mode_Limit_Reached(Client, mode_arg_count++)) goto chan_exit; if (!set) { - if (modeok) + if (is_oper || is_machine || is_owner || + is_admin || is_op || is_halfop) x[0] = *mode_ptr; else connected = IRC_WriteStrClient(Origin, @@ -550,7 +593,8 @@ Channel_Mode(CLIENT *Client, REQUEST *Req, CLIENT *Origin, CHANNEL *Channel) break; } if (arg_arg > mode_arg) { - if (modeok) { + if (is_oper || is_machine || is_owner || + is_admin || is_op || is_halfop) { Channel_ModeDel(Channel, 'k'); Channel_SetKey(Channel, Req->argv[arg_arg]); @@ -576,7 +620,8 @@ Channel_Mode(CLIENT *Client, REQUEST *Req, CLIENT *Origin, CHANNEL *Channel) if (Mode_Limit_Reached(Client, mode_arg_count++)) goto chan_exit; if (!set) { - if (modeok) + if (is_oper || is_machine || is_owner || + is_admin || is_op || is_halfop) x[0] = *mode_ptr; else connected = IRC_WriteStrClient(Origin, @@ -586,7 +631,8 @@ Channel_Mode(CLIENT *Client, REQUEST *Req, CLIENT *Origin, CHANNEL *Channel) break; } if (arg_arg > mode_arg) { - if (modeok) { + if (is_oper || is_machine || is_owner || + is_admin || is_op || is_halfop) { l = atol(Req->argv[arg_arg]); if (l > 0 && l < 0xFFFF) { Channel_ModeDel(Channel, 'l'); @@ -611,44 +657,47 @@ Channel_Mode(CLIENT *Client, REQUEST *Req, CLIENT *Origin, CHANNEL *Channel) } break; case 'O': /* IRC operators only */ - if (modeok) { + if (set) { /* Only IRC operators are allowed to * set the 'O' channel mode! */ - if (set && !(Client_OperByMe(Client) - || Client_Type(Client) == CLIENT_SERVER)) + if(is_oper || is_machine) + x[0] = 'O'; + else connected = IRC_WriteStrClient(Origin, ERR_NOPRIVILEGES_MSG, Client_ID(Origin)); - else - x[0] = 'O'; - } else + } else if(is_oper || is_machine || is_owner || + is_admin || is_op) + x[0] = 'O'; + else connected = IRC_WriteStrClient(Origin, - ERR_CHANOPRIVSNEEDED_MSG, - Client_ID(Origin), - Channel_Name(Channel)); - break; + ERR_CHANOPRIVSNEEDED_MSG, + Client_ID(Origin), + Channel_Name(Channel)); + break; case 'P': /* Persistent channel */ - if (modeok) { + if (set) { /* Only IRC operators are allowed to * set the 'P' channel mode! */ - if (set && !(Client_OperByMe(Client) - || Client_Type(Client) == CLIENT_SERVER)) + if(is_oper || is_machine) + x[0] = 'P'; + else connected = IRC_WriteStrClient(Origin, ERR_NOPRIVILEGES_MSG, Client_ID(Origin)); - else - x[0] = 'P'; - } else + } else if(is_oper || is_machine || is_owner || + is_admin || is_op) + x[0] = 'P'; + else connected = IRC_WriteStrClient(Origin, ERR_CHANOPRIVSNEEDED_MSG, Client_ID(Origin), Channel_Name(Channel)); break; /* --- Channel user modes --- */ - case 'a': - case 'h': - case 'q': - if (Client_Type(Client) != CLIENT_SERVER) { + case 'q': /* Owner */ + case 'a': /* Channel admin */ + if(!is_oper && !is_machine && !is_owner) { connected = IRC_WriteStrClient(Origin, ERR_CHANOPRIVSNEEDED_MSG, Client_ID(Origin), @@ -656,16 +705,34 @@ Channel_Mode(CLIENT *Client, REQUEST *Req, CLIENT *Origin, CHANNEL *Channel) goto chan_exit; } case 'o': /* Channel operator */ + if(!is_oper && !is_machine && !is_owner && + !is_admin && !is_op) { + connected = IRC_WriteStrClient(Origin, + ERR_CHANOPRIVSNEEDED_MSG, + Client_ID(Origin), + Channel_Name(Channel)); + goto chan_exit; + } + case 'h': /* Half Op */ + if(!is_oper && !is_machine && !is_owner && + !is_admin && !is_op) { + connected = IRC_WriteStrClient(Origin, + ERR_CHANOPRIVSNEEDED_MSG, + Client_ID(Origin), + Channel_Name(Channel)); + goto chan_exit; + } case 'v': /* Voice */ if (arg_arg > mode_arg) { - if (modeok) { + if (is_oper || is_machine || is_owner || + is_admin || is_op || is_halfop) { client = Client_Search(Req->argv[arg_arg]); if (client) x[0] = *mode_ptr; else - connected = IRC_WriteStrClient(Client, + connected = IRC_WriteStrClient(Origin, ERR_NOSUCHNICK_MSG, - Client_ID(Client), + Client_ID(Origin), Req->argv[arg_arg]); } else { connected = IRC_WriteStrClient(Origin, @@ -690,7 +757,8 @@ Channel_Mode(CLIENT *Client, REQUEST *Req, CLIENT *Origin, CHANNEL *Channel) goto chan_exit; if (arg_arg > mode_arg) { /* modify list */ - if (modeok) { + if (is_oper || is_machine || is_owner || + is_admin || is_op || is_halfop) { connected = set ? Add_To_List(*mode_ptr, Origin, Client, Channel, diff --git a/src/ngircd/irc-op.c b/src/ngircd/irc-op.c index 5e36b02b..08495475 100644 --- a/src/ngircd/irc-op.c +++ b/src/ngircd/irc-op.c @@ -166,8 +166,11 @@ IRC_INVITE(CLIENT *Client, REQUEST *Req) /* Is the channel "invite-only"? */ if (strchr(Channel_Modes(chan), 'i')) { - /* Yes. The user must be channel operator! */ - if (!strchr(Channel_UserModes(chan, from), 'o')) + /* Yes. The user must be channel owner/admin/operator/halfop! */ + if (!strchr(Channel_UserModes(chan, from), 'q') && + !strchr(Channel_UserModes(chan, from), 'a') && + !strchr(Channel_UserModes(chan, from), 'o') && + !strchr(Channel_UserModes(chan, from), 'h')) return IRC_WriteStrClient(from, ERR_CHANOPRIVSNEEDED_MSG, Client_ID(from), Channel_Name(chan)); remember = true; diff --git a/src/ngircd/irc-oper.c b/src/ngircd/irc-oper.c index 21577f00..237107f6 100644 --- a/src/ngircd/irc-oper.c +++ b/src/ngircd/irc-oper.c @@ -183,6 +183,8 @@ IRC_REHASH( CLIENT *Client, REQUEST *Req ) Log(LOG_NOTICE|LOG_snotice, "Got REHASH command from \"%s\" ...", Client_Mask(Client)); + IRC_WriteStrClient(Client, RPL_REHASHING_MSG, Client_ID(Client)); + raise(SIGHUP); return CONNECTED; diff --git a/src/ngircd/irc-server.c b/src/ngircd/irc-server.c index 8526a573..d605745c 100644 --- a/src/ngircd/irc-server.c +++ b/src/ngircd/irc-server.c @@ -54,7 +54,7 @@ IRC_SERVER( CLIENT *Client, REQUEST *Req ) CLIENT *from, *c; int i; CONN_ID con; - + assert( Client != NULL ); assert( Req != NULL ); @@ -88,7 +88,7 @@ IRC_SERVER( CLIENT *Client, REQUEST *Req ) Conn_Close( Client_Conn( Client ), NULL, "Bad password", true); return DISCONNECTED; } - + /* Is there a registered server with this ID? */ if( ! Client_CheckID( Client, Req->argv[0] )) return DISCONNECTED; @@ -203,10 +203,10 @@ GLOBAL bool IRC_NJOIN( CLIENT *Client, REQUEST *Req ) { char nick_in[COMMAND_LEN], nick_out[COMMAND_LEN], *channame, *ptr, modes[8]; - bool is_op, is_voiced; + bool is_owner, is_chanadmin, is_op, is_halfop, is_voiced; CHANNEL *chan; CLIENT *c; - + assert( Client != NULL ); assert( Req != NULL ); @@ -219,12 +219,16 @@ IRC_NJOIN( CLIENT *Client, REQUEST *Req ) ptr = strtok( nick_in, "," ); while( ptr ) { - is_op = is_voiced = false; - + is_owner = is_chanadmin = is_op = is_halfop = is_voiced = false; + /* cut off prefixes */ - while(( *ptr == '@' ) || ( *ptr == '+' )) + while(( *ptr == '~') || ( *ptr == '&' ) || ( *ptr == '@' ) || + ( *ptr == '%') || ( *ptr == '+' )) { + if( *ptr == '~' ) is_owner = true; + if( *ptr == '&' ) is_chanadmin = true; if( *ptr == '@' ) is_op = true; + if( *ptr == 'h' ) is_halfop = true; if( *ptr == '+' ) is_voiced = true; ptr++; } @@ -235,8 +239,11 @@ IRC_NJOIN( CLIENT *Client, REQUEST *Req ) Channel_Join( c, channame ); chan = Channel_Search( channame ); assert( chan != NULL ); - + + if( is_owner ) Channel_UserModeAdd( chan, c, 'q' ); + if( is_chanadmin ) Channel_UserModeAdd( chan, c, 'a' ); if( is_op ) Channel_UserModeAdd( chan, c, 'o' ); + if( is_halfop ) Channel_UserModeAdd( chan, c, 'h' ); if( is_voiced ) Channel_UserModeAdd( chan, c, 'v' ); /* announce to channel... */ @@ -251,12 +258,15 @@ IRC_NJOIN( CLIENT *Client, REQUEST *Req ) } if( nick_out[0] != '\0' ) strlcat( nick_out, ",", sizeof( nick_out )); + if( is_owner ) strlcat( nick_out, "~", sizeof( nick_out )); + if( is_chanadmin ) strlcat( nick_out, "&", sizeof( nick_out )); if( is_op ) strlcat( nick_out, "@", sizeof( nick_out )); + if( is_halfop ) strlcat( nick_out, "%", sizeof( nick_out )); if( is_voiced ) strlcat( nick_out, "+", sizeof( nick_out )); strlcat( nick_out, ptr, sizeof( nick_out )); } else Log( LOG_ERR, "Got NJOIN for unknown nick \"%s\" for channel \"%s\"!", ptr, channame ); - + /* search for next Nick */ ptr = strtok( NULL, "," ); } diff --git a/src/ngircd/messages.h b/src/ngircd/messages.h index 99d25828..35d621a6 100644 --- a/src/ngircd/messages.h +++ b/src/ngircd/messages.h @@ -21,7 +21,7 @@ #define RPL_YOURHOST_MSG "002 %s :Your host is %s, running version ngircd-%s (%s/%s/%s)" #define RPL_CREATED_MSG "003 %s :This server has been started %s" #define RPL_MYINFO_MSG "004 %s %s ngircd-%s %s %s" -#define RPL_ISUPPORT1_MSG "005 %s RFC2812 IRCD=ngIRCd CHARSET=UTF-8 CASEMAPPING=ascii PREFIX=(ov)@+ CHANTYPES=#&+ CHANMODES=beI,k,l,imMnOPRstz CHANLIMIT=#&+:%d :are supported on this server" +#define RPL_ISUPPORT1_MSG "005 %s RFC2812 IRCD=ngIRCd CHARSET=UTF-8 CASEMAPPING=ascii PREFIX=(qaohv)~&@%%+ CHANTYPES=#&+ CHANMODES=beI,k,l,imMnOPRstz CHANLIMIT=#&+:%d :are supported on this server" #define RPL_ISUPPORT2_MSG "005 %s CHANNELLEN=%d NICKLEN=%d TOPICLEN=%d AWAYLEN=%d KICKLEN=%d MODES=%d MAXLIST=beI:%d EXCEPTS=e INVEX=I PENALTY :are supported on this server" #define RPL_TRACELINK_MSG "200 %s Link %s-%s %s %s V%s %ld %d %d" @@ -93,6 +93,7 @@ #define RPL_ENDOFMOTD_MSG "376 %s :End of MOTD command" #define RPL_WHOISHOST_MSG "378 %s %s :is connecting from *@%s %s" #define RPL_YOUREOPER_MSG "381 %s :You are now an IRC Operator" +#define RPL_REHASHING_MSG "382 %s :Rehashing" #define RPL_YOURESERVICE_MSG "383 %s :You are service %s" #define RPL_TIME_MSG "391 %s %s :%s" #define RPL_HOSTHIDDEN_MSG "396 %s %s :is your displayed hostname now" @@ -125,7 +126,7 @@ #define ERR_NEEDMOREPARAMS_MSG "461 %s %s :Syntax error" #define ERR_ALREADYREGISTRED_MSG "462 %s :Connection already registered" #define ERR_PASSWDMISMATCH_MSG "464 %s :Invalid password" -#define ERR_CHANNELISFULL_MSG "471 %s %s :Cannot join channel (+l) -- Channel is too full, try later" +#define ERR_CHANNELISFULL_MSG "471 %s %s :Cannot join channel (+l) -- Channel is full, try later" #define ERR_SECURECHANNEL_MSG "471 %s %s :Cannot join channel (+z) -- SSL connections only" #define ERR_OPONLYCHANNEL_MSG "471 %s %s :Cannot join channel (+O) -- IRC opers only" #define ERR_REGONLYCHANNEL_MSG "471 %s %s :Cannot join channel (+R) -- Registered users only" @@ -137,6 +138,7 @@ #define ERR_LISTFULL_MSG "478 %s %s %s: Channel list is full (%d)" #define ERR_NOPRIVILEGES_MSG "481 %s :Permission denied" #define ERR_CHANOPRIVSNEEDED_MSG "482 %s %s :You are not channel operator" +#define ERR_CHANOPPRIVTOOLOW_MSG "482 %s %s :Your privileges are too low" #define ERR_CANTKILLSERVER_MSG "483 %s :You can't kill a server!" #define ERR_RESTRICTED_MSG "484 %s :Your connection is restricted" #define ERR_NICKREGISTER_MSG "484 %s :Cannot modify user mode (+R) -- Use IRC services" diff --git a/src/ngircd/ngircd.c b/src/ngircd/ngircd.c index bbfc6ce1..50d91ce8 100644 --- a/src/ngircd/ngircd.c +++ b/src/ngircd/ngircd.c @@ -669,7 +669,7 @@ NGIRCd_Init(bool NGIRCd_NoDaemon) /* SSL initialization */ if (!ConnSSL_InitLibrary()) Log(LOG_WARNING, - "Warning: Error during SSL initialization, continuing ..."); + "Error during SSL initialization, continuing without SSL ..."); /* Change root */ if (Conf_Chroot[0]) { diff --git a/src/ngircd/numeric.c b/src/ngircd/numeric.c index d59a1dc3..4bce60fb 100644 --- a/src/ngircd/numeric.c +++ b/src/ngircd/numeric.c @@ -67,10 +67,17 @@ Announce_Channel(CLIENT *Client, CHANNEL *Chan) * (if user is channel operator or has voice) */ if (str[strlen(str) - 1] != ':') strlcat(str, ",", sizeof(str)); - if (strchr(Channel_UserModes(Chan, cl), 'v')) - strlcat(str, "+", sizeof(str)); + if (strchr(Channel_UserModes(Chan, cl), 'q')) + strlcat(str, "~", sizeof(str)); + if (strchr(Channel_UserModes(Chan, cl), 'a')) + strlcat(str, "&", sizeof(str)); if (strchr(Channel_UserModes(Chan, cl), 'o')) strlcat(str, "@", sizeof(str)); + if (strchr(Channel_UserModes(Chan, cl), 'h')) + strlcat(str, "%", sizeof(str)); + if (strchr(Channel_UserModes(Chan, cl), 'v')) + strlcat(str, "+", sizeof(str)); + strlcat(str, Client_ID(cl), sizeof(str)); /* Send the data if the buffer is "full" */ diff --git a/src/portab/.gitignore b/src/portab/.gitignore index 839a69fd..9bac6ac1 100644 --- a/src/portab/.gitignore +++ b/src/portab/.gitignore @@ -1 +1,2 @@ +Makefile.am portabtest diff --git a/src/portab/Makefile.am b/src/portab/Makefile.am deleted file mode 100644 index a57ea495..00000000 --- a/src/portab/Makefile.am +++ /dev/null @@ -1,34 +0,0 @@ -# -# ngIRCd -- The Next Generation IRC Daemon -# Copyright (c)2001,2002 by Alexander Barton (alex@barton.de) -# -# Dieses Programm ist freie Software. Sie koennen es unter den Bedingungen -# der GNU General Public License (GPL), wie von der Free Software Foundation -# herausgegeben, weitergeben und/oder modifizieren, entweder unter Version 2 -# der Lizenz oder (wenn Sie es wuenschen) jeder spaeteren Version. -# Naehere Informationen entnehmen Sie bitter der Datei COPYING. Eine Liste -# der an ngIRCd beteiligten Autoren finden Sie in der Datei AUTHORS. -# - -AUTOMAKE_OPTIONS = ansi2knr - -noinst_LIBRARIES = libngportab.a - -libngportab_a_SOURCES = strdup.c strlcpy.c strtok_r.c vsnprintf.c waitpid.c - -check_PROGRAMS = portabtest - -portabtest_SOURCES = portabtest.c - -portabtest_LDFLAGS = -L. - -portabtest_LDADD = -lngportab - -noinst_HEADERS = imp.h exp.h portab.h splint.h - -maintainer-clean-local: - rm -f Makefile Makefile.in - -TESTS = portabtest - -# -eof- diff --git a/src/portab/Makefile.ng b/src/portab/Makefile.ng new file mode 100644 index 00000000..dac329fa --- /dev/null +++ b/src/portab/Makefile.ng @@ -0,0 +1,35 @@ +# +# ngIRCd -- The Next Generation IRC Daemon +# Copyright (c)2001-2012 Alexander Barton (alex@barton.de) and Contributors +# +# 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. +# + +__ng_Makefile_am_template__ + +EXTRA_DIST = Makefile.ng + +noinst_LIBRARIES = libngportab.a + +libngportab_a_SOURCES = strdup.c strlcpy.c strtok_r.c vsnprintf.c waitpid.c + +check_PROGRAMS = portabtest + +portabtest_SOURCES = portabtest.c + +portabtest_LDFLAGS = -L. + +portabtest_LDADD = -lngportab + +noinst_HEADERS = imp.h exp.h portab.h splint.h + +maintainer-clean-local: + rm -f Makefile Makefile.in Makefile.am + +TESTS = portabtest + +# -eof- diff --git a/src/testsuite/.gitignore b/src/testsuite/.gitignore index 5884a486..b33a08f4 100644 --- a/src/testsuite/.gitignore +++ b/src/testsuite/.gitignore @@ -1,3 +1,4 @@ +Makefile.am T-ngircd1 T-ngircd2 channel-test diff --git a/src/testsuite/Makefile.am b/src/testsuite/Makefile.ng index 9dc76a7d..b906091e 100644 --- a/src/testsuite/Makefile.am +++ b/src/testsuite/Makefile.ng @@ -1,21 +1,20 @@ # # ngIRCd -- The Next Generation IRC Daemon -# Copyright (c)2001-2011 Alexander Barton (alex@barton.de) and Contributors. +# Copyright (c)2001-2012 Alexander Barton (alex@barton.de) and Contributors # -# Dieses Programm ist freie Software. Sie koennen es unter den Bedingungen -# der GNU General Public License (GPL), wie von der Free Software Foundation -# herausgegeben, weitergeben und/oder modifizieren, entweder unter Version 2 -# der Lizenz oder (wenn Sie es wuenschen) jeder spaeteren Version. -# Naehere Informationen entnehmen Sie bitter der Datei COPYING. Eine Liste -# der an ngIRCd beteiligten Autoren finden Sie in der Datei AUTHORS. +# 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. # -AUTOMAKE_OPTIONS = ../portab/ansi2knr +__ng_Makefile_am_template__ -INCLUDES = -I$(srcdir)/../portab +AM_CPPFLAGS = -I$(srcdir)/../portab EXTRA_DIST = \ - README functions.inc getpid.sh \ + Makefile.ng README functions.inc getpid.sh \ start-server.sh stop-server.sh tests.sh stress-server.sh \ test-loop.sh wait-tests.sh \ channel-test.e connect-test.e check-idle.e invite-test.e \ @@ -32,7 +31,7 @@ clean-local: T-ngircd1 ngircd-test1.motd T-ngircd2 ngircd-test2.motd maintainer-clean-local: - rm -f Makefile Makefile.in + rm -f Makefile Makefile.in Makefile.am check_SCRIPTS = ngircd-TEST-Binary tests.sh diff --git a/src/testsuite/getpid.sh b/src/testsuite/getpid.sh index 19ced762..96ab4746 100755 --- a/src/testsuite/getpid.sh +++ b/src/testsuite/getpid.sh @@ -10,7 +10,7 @@ UNAME=`uname` if [ $UNAME = "FreeBSD" ]; then PS_FLAGS="-a"; PS_PIDCOL="1"; HEAD_FLAGS="-n 1" elif [ $UNAME = "A/UX" ]; then - PS_FLAGS="-ae"; PS_PIDCOL="1"; HEAD_FLAGS="-1" + PS_FLAGS="-af"; PS_PIDCOL="2"; HEAD_FLAGS="-1" elif [ $UNAME = "GNU" ]; then PS_FLAGS="-ax"; PS_PIDCOL="2"; HEAD_FLAGS="-n 1" elif [ $UNAME = "Linux" ]; then diff --git a/src/testsuite/mode-test.e b/src/testsuite/mode-test.e index 260cd03c..44b6e5df 100644 --- a/src/testsuite/mode-test.e +++ b/src/testsuite/mode-test.e @@ -31,6 +31,46 @@ expect { "@* MODE nick :-i" } +send "join #usermode\r" +expect { + timeout { exit 1 } + "@* JOIN :#usermode" +} +expect { + timeout { exit 1 } + "366" +} + +send "mode #usermode +v nick\r" +expect { + timeout { exit 1 } + "@* MODE #usermode +v nick\r" +} + +send "mode #usermode +h nick\r" +expect { + timeout { exit 1 } + "@* MODE #usermode +h nick\r" +} + +send "mode #usermode +a nick\r" +expect { + timeout { exit 1 } + "482 nick" +} + +send "mode #usermode +q nick\r" +expect { + timeout { exit 1 } + "482 nick" +} + +send "mode #usermode -vho nick nick nick\r" +expect { + timeout { exit 1 } + "@* MODE #usermode -vho nick nick nick" +} + send "oper TestOp 123\r" expect { timeout { exit 1 } @@ -47,6 +87,34 @@ expect { "221 nick +o" } +send "mode #usermode +a nick\r" +expect { + timeout { exit 1 } + "@* MODE #usermode +a nick" +} + +send "mode #usermode +q nick\r" +expect { + timeout { exit 1 } + "@* MODE #usermode +q nick" +} + +send "names #usermode\r" +expect { + timeout { exit 1 } + "353 nick = #usermode :~nick" +} +expect { + timeout { exit 1 } + "366 nick #usermode" +} + +send "part #usermode\r" +expect { + timeout { exit 1 } + "@* PART #usermode" +} + send "join #channel\r" expect { timeout { exit 1 } diff --git a/src/testsuite/stress-server.sh b/src/testsuite/stress-server.sh index 0f85958e..15d6df1f 100755 --- a/src/testsuite/stress-server.sh +++ b/src/testsuite/stress-server.sh @@ -1,7 +1,7 @@ #!/bin/sh # # ngIRCd Test Suite -# Copyright (c)2002-2004 by Alexander Barton (alex@barton.de) +# Copyright (c)2001-2012 Alexander Barton (alex@barton.de) and Contributors. # # 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 @@ -9,8 +9,6 @@ # (at your option) any later version. # Please read the file COPYING, README and AUTHORS for more information. # -# $Id: stress-server.sh,v 1.16 2005/12/30 22:13:21 alex Exp $ -# # detect source directory [ -z "$srcdir" ] && srcdir=`dirname $0` @@ -23,7 +21,8 @@ name=`basename $0` # create directories -mkdir -p logs tests +[ -d logs ] || mkdir logs +[ -d tests ] || mkdir tests # test for required external tools type expect > /dev/null 2>&1 diff --git a/src/testsuite/tests.sh b/src/testsuite/tests.sh index 2bd9ae40..dc184ffc 100755 --- a/src/testsuite/tests.sh +++ b/src/testsuite/tests.sh @@ -1,13 +1,21 @@ #!/bin/sh +# # ngIRCd Test Suite -# $Id: tests.sh,v 1.7 2004/09/06 22:04:06 alex Exp $ +# Copyright (c)2001-2012 Alexander Barton (alex@barton.de) and Contributors. +# +# 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. +# # detect source directory [ -z "$srcdir" ] && srcdir=`dirname $0` name=`basename $0` test=`echo ${name} | cut -d '.' -f 1` -mkdir -p logs +[ -d logs ] || mkdir logs if [ ! -r "$test" ]; then echo " ${name}: test \"$test\" not found!"; exit 77 diff --git a/src/tool/.gitignore b/src/tool/.gitignore new file mode 100644 index 00000000..08a6d725 --- /dev/null +++ b/src/tool/.gitignore @@ -0,0 +1 @@ +Makefile.am diff --git a/src/tool/Makefile.am b/src/tool/Makefile.ng index 8d6cda46..d88bdc94 100644 --- a/src/tool/Makefile.am +++ b/src/tool/Makefile.ng @@ -9,9 +9,11 @@ # Please read the file COPYING, README and AUTHORS for more information. # -AUTOMAKE_OPTIONS = ../portab/ansi2knr +__ng_Makefile_am_template__ -INCLUDES = -I$(srcdir)/../portab +EXTRA_DIST = Makefile.ng + +AM_CPPFLAGS = -I$(srcdir)/../portab noinst_LIBRARIES = libngtool.a @@ -20,6 +22,6 @@ libngtool_a_SOURCES = tool.c noinst_HEADERS = tool.h maintainer-clean-local: - rm -f Makefile Makefile.in + rm -f Makefile Makefile.in Makefile.am # -eof- |