Updated to 5.0.8

This commit is contained in:
Dionysus 2021-01-08 18:15:08 -05:00
parent b351238d42
commit 88a904d7f7
Signed by: acidvegas
GPG Key ID: EF4B922DB85DC9DE
51 changed files with 2977 additions and 912 deletions

510
Config
View File

@ -104,49 +104,59 @@ fi
echo $CONF
$CONF || exit 1
cd "$UNREALCWD"
if [ "$QUICK" != "1" ] ; then
if [ ! -f $CONFDIR/tls/server.cert.pem -a ! -f $CONFDIR/ssl/server.cert.pem ]; then
export OPENSSLPATH
TEST=""
while [ -z "$TEST" ] ; do
if [ "$GENCERTIFICATE" = "1" ] ; then
TEST="Yes"
else
TEST="No"
fi
echo ""
echo "Do you want to generate an SSL certificate for the IRCd?"
echo "Only answer No if you already have one."
echo $n "[$TEST] -> $c"
read cc
if [ -z "$cc" ] ; then
cc=$TEST
fi
case "$cc" in
[Yy]*)
GENCERTIFICATE="1"
;;
[Nn]*)
GENCERTIFICATE=""
;;
*)
echo ""
echo "You must enter either Yes or No"
TEST=""
;;
esac
done
if [ "$GENCERTIFICATE" = 1 ]; then
make pem
echo "Certificate created successfully."
sleep 1
else
echo "Ok, not generating SSL certificate. Make sure that the certificate and key"
echo "are installed in conf/tls/server.crt.pem and conf/tls/server.key.pem prior to starting the IRCd."
fi
else
echo "SSL certificate already exists in configuration directory, no need to regenerate."
fi
if [ "$QUICK" != "1" ] ; then
if [ ! -f $CONFDIR/tls/server.cert.pem -a ! -f $CONFDIR/ssl/server.cert.pem ]; then
export OPENSSLPATH
TEST=""
while [ -z "$TEST" ] ; do
if [ "$GENCERTIFICATE" = "1" ] ; then
TEST="Yes"
else
TEST="No"
fi
echo ""
echo "UnrealIRCd requires an SSL certificate in order to work."
echo "Do you want to generate an SSL certificate for the IRCd?"
echo "Only answer No if you already have one."
echo $n "[$TEST] -> $c"
read cc
if [ -z "$cc" ] ; then
cc=$TEST
fi
case "$cc" in
[Yy]*)
GENCERTIFICATE="1"
;;
[Nn]*)
GENCERTIFICATE=""
;;
*)
echo ""
echo "You must enter either Yes or No"
TEST=""
;;
esac
done
if [ "$GENCERTIFICATE" = 1 ]; then
echo
echo "*******************************************************************************"
echo "Next you will be asked some questions in order to generate the SSL certificate."
echo "IMPORTANT: If you don't own a domain or don't know what to answer, then you can"
echo " simply press ENTER or use fictional names for each question!"
echo "*******************************************************************************"
echo "Press ENTER to continue"
read cc
make pem
echo "Certificate created successfully."
sleep 1
else
echo "Ok, not generating SSL certificate. Make sure that the certificate and key"
echo "are installed in conf/tls/server.cert.pem and conf/tls/server.key.pem prior to starting the IRCd."
fi
else
echo "SSL certificate already exists in configuration directory, no need to regenerate."
fi
fi
# Silently force a 'make clean' as otherwise part (or whole) of the
@ -158,89 +168,89 @@ make clean 1>/dev/null 2>&1
RUN_ADVANCED () {
TEST=""
while [ -z "$TEST" ] ; do
if [ "$SHOWLISTMODES" = "1" ] ; then
TEST="Yes"
else
TEST="No"
fi
echo ""
echo "Do you want to show the modes a channel has set in the /list output?"
echo $n "[$TEST] -> $c"
if [ "$SHOWLISTMODES" = "1" ] ; then
TEST="Yes"
else
TEST="No"
fi
echo ""
echo "Do you want to show the modes a channel has set in the /list output?"
echo $n "[$TEST] -> $c"
read cc
if [ -z "$cc" ] ; then
cc=$TEST
fi
case "$cc" in
if [ -z "$cc" ] ; then
cc=$TEST
fi
case "$cc" in
[Yy]*)
SHOWLISTMODES="1"
;;
SHOWLISTMODES="1"
;;
[Nn]*)
SHOWLISTMODES=""
;;
SHOWLISTMODES=""
;;
*)
echo ""
echo "You must enter either Yes or No"
TEST=""
;;
esac
echo ""
echo "You must enter either Yes or No"
TEST=""
;;
esac
done
TEST=""
while [ -z "$TEST" ] ; do
if [ "$NOOPEROVERRIDE" = "1" ] ; then
TEST="Yes"
else
TEST="No"
fi
echo ""
echo "Do you want to disable oper override?"
echo $n "[$TEST] -> $c"
if [ "$NOOPEROVERRIDE" = "1" ] ; then
TEST="Yes"
else
TEST="No"
fi
echo ""
echo "Do you want to disable oper override?"
echo $n "[$TEST] -> $c"
read cc
if [ -z "$cc" ] ; then
cc=$TEST
fi
case "$cc" in
if [ -z "$cc" ] ; then
cc=$TEST
fi
case "$cc" in
[Yy]*)
NOOPEROVERRIDE="1"
;;
NOOPEROVERRIDE="1"
;;
[Nn]*)
NOOPEROVERRIDE=""
;;
NOOPEROVERRIDE=""
;;
*)
echo ""
echo "You must enter either Yes or No"
TEST=""
;;
esac
echo ""
echo "You must enter either Yes or No"
TEST=""
;;
esac
done
TEST=""
while [ -z "$TEST" ] ; do
if [ "$OPEROVERRIDEVERIFY" = "1" ] ; then
TEST="Yes"
else
TEST="No"
fi
echo ""
echo "Do you want to require opers to /invite themselves into a +s or +p channel?"
echo $n "[$TEST] -> $c"
if [ "$OPEROVERRIDEVERIFY" = "1" ] ; then
TEST="Yes"
else
TEST="No"
fi
echo ""
echo "Do you want to require opers to /invite themselves into a +s or +p channel?"
echo $n "[$TEST] -> $c"
read cc
if [ -z "$cc" ] ; then
cc=$TEST
fi
case "$cc" in
if [ -z "$cc" ] ; then
cc=$TEST
fi
case "$cc" in
[Yy]*)
OPEROVERRIDEVERIFY="1"
;;
OPEROVERRIDEVERIFY="1"
;;
[Nn]*)
OPEROVERRIDEVERIFY=""
;;
OPEROVERRIDEVERIFY=""
;;
*)
echo ""
echo "You must enter either Yes or No"
TEST=""
;;
esac
echo ""
echo "You must enter either Yes or No"
TEST=""
;;
esac
done
}
@ -250,7 +260,7 @@ UNREALCWD="`pwd`"
BASEPATH="$HOME/unrealircd"
DEFPERM="0600"
SSLDIR=""
NICKNAMEHISTORYLENGTH="100"
NICKNAMEHISTORYLENGTH="2000"
MAXCONNECTIONS_REQUEST="auto"
REMOTEINC="1"
CURLDIR=""
@ -261,9 +271,9 @@ OPEROVERRIDEVERIFY=""
GENCERTIFICATE="1"
EXTRAPARA=""
if [ "`eval echo -n 'a'`" = "-n a" ] ; then
c="\c"
c="\c"
else
n="-n"
n="-n"
fi
@ -314,19 +324,19 @@ fi
clear
if [ -f "doc/Config.header" -a -z "$NOINTRO" ] ; then
more doc/Config.header
echo ""
echo $n "[Press Enter to continue]"
read cc
clear
fi
if [ -f "doc/Config.header" -a -z "$NOINTRO" ] ; then
more doc/Config.header
echo ""
echo $n "[Press Enter to continue]"
read cc
clear
fi
echo "We will now ask you a number of questions. You can just press ENTER to accept the defaults!"
echo ""
# This needs to be updated each release so auto-upgrading works for settings, modules, etc!!:
UNREALRELEASES="unrealircd-5.0.7-rc1 unrealircd-5.0.6 unrealircd-5.0.5.1 unrealircd-5.0.5 unrealircd-5.0.4 unrealircd-5.0.3.1 unrealircd-5.0.3 unrealircd-5.0.2 unrealircd-5.0.1 unrealircd-5.0.0 unrealircd-5.0.0-rc2 unrealircd-5.0.0-rc1"
UNREALRELEASES="unrealircd-5.0.8-rc1 unrealircd-5.0.7 unrealircd-5.0.7-rc1 unrealircd-5.0.6 unrealircd-5.0.5.1 unrealircd-5.0.5 unrealircd-5.0.4 unrealircd-5.0.3.1 unrealircd-5.0.3 unrealircd-5.0.2 unrealircd-5.0.1 unrealircd-5.0.0"
if [ -f "config.settings" ]; then
. ./config.settings
else
@ -405,9 +415,9 @@ echo " If this directory does not exist it will be created.)"
echo $n "[$TEST] -> $c"
read cc
if [ -z "$cc" ] ; then
BASEPATH=$TEST
BASEPATH=$TEST
else
BASEPATH=`eval echo $cc` # modified
BASEPATH=`eval echo $cc` # modified
fi
if [ "$BASEPATH" = "$UNREALCWD" ]; then
echo ""
@ -431,32 +441,28 @@ PRIVATELIBDIR="$BASEPATH/lib"
TEST=""
while [ -z "$TEST" ] ; do
TEST="$DEFPERM"
echo ""
echo "What should the default permissions for your configuration files be? (Set this to 0 to disable)"
echo "It is strongly recommended that you use 0600 to prevent unwanted reading of the file"
echo $n "[$TEST] -> $c"
TEST="$DEFPERM"
echo ""
echo "What should the default permissions for your configuration files be? (Set this to 0 to disable)"
echo "It is strongly recommended that you use 0600 to prevent unwanted reading of the file"
echo $n "[$TEST] -> $c"
read cc
if [ -z "$cc" ] ; then
DEFPERM=$TEST
break
fi
case "$cc" in
if [ -z "$cc" ] ; then
DEFPERM=$TEST
break
fi
case "$cc" in
[0-9]*)
DEFPERM="$cc"
;;
DEFPERM="$cc"
;;
*)
echo ""
echo "You must enter a number"
TEST=""
;;
esac
echo ""
echo "You must enter a number"
TEST=""
;;
esac
done
echo ""
echo "If you want, you can manually enter the path to OpenSSL/LibreSSL here."
echo "In most cases you can leave this blank and it will be detected automatically."
@ -475,43 +481,43 @@ fi
TEST="$SSLDIR"
echo $n "[$TEST] -> $c"
read cc
read cc
if [ -z "$cc" ] ; then
SSLDIR="$TEST"
SSLDIR="$TEST"
else
SSLDIR=`eval echo $cc` # modified
SSLDIR=`eval echo $cc` # modified
fi
TEST=""
while [ -z "$TEST" ] ; do
if [ "$REMOTEINC" = "1" ] ; then
TEST="Yes"
else
TEST="No"
fi
echo ""
echo "Do you want to enable remote includes?"
echo "This allows stuff like this in your configuration file:"
echo "include \"https://www.somesite.org/files/opers.conf\";"
echo $n "[$TEST] -> $c"
if [ "$REMOTEINC" = "1" ] ; then
TEST="Yes"
else
TEST="No"
fi
echo ""
echo "Do you want to enable remote includes?"
echo "This allows stuff like this in your configuration file:"
echo "include \"https://www.somesite.org/files/opers.conf\";"
echo $n "[$TEST] -> $c"
read cc
if [ -z "$cc" ] ; then
cc=$TEST
fi
case "$cc" in
if [ -z "$cc" ] ; then
cc=$TEST
fi
case "$cc" in
[Yy]*)
REMOTEINC="1"
;;
REMOTEINC="1"
;;
[Nn]*)
REMOTEINC=""
CURLDIR=""
;;
REMOTEINC=""
CURLDIR=""
;;
*)
echo ""
echo "You must enter either Yes or No"
TEST=""
;;
esac
echo ""
echo "You must enter either Yes or No"
TEST=""
;;
esac
done
if [ "$REMOTEINC" = "1" ] ; then
@ -589,108 +595,108 @@ if [ "$REMOTEINC" = "1" ] ; then
fi
fi
if [ "x$CURLDIR" = "x" ]; then
# Still empty?
TEST=""
while [ -z "$TEST" ] ; do
TEST="Yes"
echo ""
echo "Do you want me to automatically download and install curl for you?"
echo $n "[$TEST] -> $c"
read cc
if [ -z "$cc" ] ; then
cc=$TEST
fi
case "$cc" in
[Yy]*)
INSTALLCURL="1"
CURLDIR="$UNREALCWD/extras/curl"
;;
[Nn]*)
INSTALLCURL="0"
;;
*)
echo ""
echo "You must enter either Yes or No"
TEST=""
;;
esac
done
fi
if [ "x$CURLDIR" = "x" ]; then
# Still empty?
TEST=""
while [ -z "$TEST" ] ; do
TEST="Yes"
echo ""
echo "Do you want me to automatically download and install curl for you?"
echo $n "[$TEST] -> $c"
read cc
if [ -z "$cc" ] ; then
cc=$TEST
fi
case "$cc" in
[Yy]*)
INSTALLCURL="1"
CURLDIR="$UNREALCWD/extras/curl"
;;
[Nn]*)
INSTALLCURL="0"
;;
*)
echo ""
echo "You must enter either Yes or No"
TEST=""
;;
esac
done
fi
if [ "$INSTALLCURL" != "1" ]; then
TEST=""
while [ -z "$TEST" ] ; do
TEST="$CURLDIR"
echo ""
echo "Specify the directory you installed libcurl to"
echo $n "[$TEST] -> $c"
read cc
if [ -z "$cc" ] ; then
cc=$TEST
else
TEST=$cc
CURLDIR=`eval echo $cc` # modified
fi
done
fi
TEST=""
while [ -z "$TEST" ] ; do
TEST="$CURLDIR"
echo ""
echo "Specify the directory you installed libcurl to"
echo $n "[$TEST] -> $c"
read cc
if [ -z "$cc" ] ; then
cc=$TEST
else
TEST=$cc
CURLDIR=`eval echo $cc` # modified
fi
done
fi
fi
TEST=""
while [ -z "$TEST" ] ; do
if [ "$PREFIXAQ" = "1" ] ; then
TEST="Yes"
else
TEST="No"
fi
echo ""
echo "Do you want to enable prefixes for chanadmin and chanowner?"
echo "This will give +a the & prefix and ~ for +q (just like +o is @)"
echo "Supported by the major clients (mIRC, xchat, epic, eggdrop, Klient,"
echo "PJIRC, irssi, CGI:IRC, etc.)"
echo "This feature should be enabled/disabled network-wide."
echo $n "[$TEST] -> $c"
if [ "$PREFIXAQ" = "1" ] ; then
TEST="Yes"
else
TEST="No"
fi
echo ""
echo "Do you want to enable prefixes for chanadmin and chanowner?"
echo "This will give +a the & prefix and ~ for +q (just like +o is @)"
echo "Supported by the major clients (mIRC, xchat, epic, eggdrop, Klient,"
echo "PJIRC, irssi, CGI:IRC, etc.)"
echo "This feature should be enabled/disabled network-wide."
echo $n "[$TEST] -> $c"
read cc
if [ -z "$cc" ] ; then
cc=$TEST
fi
case "$cc" in
if [ -z "$cc" ] ; then
cc=$TEST
fi
case "$cc" in
[Yy]*)
PREFIXAQ="1"
;;
PREFIXAQ="1"
;;
[Nn]*)
PREFIXAQ=""
;;
PREFIXAQ=""
;;
*)
echo ""
echo "You must enter either Yes or No"
TEST=""
;;
esac
echo ""
echo "You must enter either Yes or No"
TEST=""
;;
esac
done
TEST=""
while [ -z "$TEST" ] ; do
TEST="$NICKNAMEHISTORYLENGTH"
echo ""
echo "How far back do you want to keep the nickname history?"
echo $n "[$TEST] -> $c"
TEST="$NICKNAMEHISTORYLENGTH"
echo ""
echo "How far back do you want to keep the nickname history?"
echo $n "[$TEST] -> $c"
read cc
if [ -z "$cc" ] ; then
NICKNAMEHISTORYLENGTH=$TEST
break
fi
case "$cc" in
if [ -z "$cc" ] ; then
NICKNAMEHISTORYLENGTH=$TEST
break
fi
case "$cc" in
[1-9]*)
NICKNAMEHISTORYLENGTH="$cc"
;;
NICKNAMEHISTORYLENGTH="$cc"
;;
*)
echo ""
echo "You must enter a number"
TEST=""
;;
esac
echo ""
echo "You must enter a number"
TEST=""
;;
esac
done
echo ""
@ -737,7 +743,7 @@ echo "Otherwise, see \`./configure --help' and write them here:"
echo $n "[$TEST] -> $c"
read EXTRAPARA
if [ -z "$EXTRAPARA" ]; then
EXTRAPARA="$TEST"
EXTRAPARA="$TEST"
fi
rm -f config.settings

View File

@ -164,54 +164,56 @@ depend:
done
install: all
$(INSTALL) -m 0700 -d @BINDIR@
$(INSTALL) -m 0700 src/ircd @BINDIR@/unrealircd
$(INSTALL) -m 0700 -d @DOCDIR@
$(INSTALL) -m 0600 doc/Authors doc/coding-guidelines doc/tao.of.irc @DOCDIR@
$(INSTALL) -m 0700 -d @CONFDIR@
$(INSTALL) -m 0600 doc/conf/*.conf @CONFDIR@
$(INSTALL) -m 0600 doc/conf/*.motd @CONFDIR@
$(INSTALL) -m 0600 doc/conf/modules.sources.list @CONFDIR@ ; \
$(INSTALL) -m 0700 unrealircd @SCRIPTDIR@
$(INSTALL) -m 0700 -d @MODULESDIR@
@rm -f @MODULESDIR@/*.so 1>/dev/null 2>&1
$(INSTALL) -m 0700 src/modules/*.so @MODULESDIR@
$(INSTALL) -m 0700 -d @MODULESDIR@/usermodes
@rm -f @MODULESDIR@/usermodes/*.so 1>/dev/null 2>&1
$(INSTALL) -m 0700 src/modules/usermodes/*.so @MODULESDIR@/usermodes
$(INSTALL) -m 0700 -d @MODULESDIR@/chanmodes
@rm -f @MODULESDIR@/chanmodes/*.so 1>/dev/null 2>&1
$(INSTALL) -m 0700 src/modules/chanmodes/*.so @MODULESDIR@/chanmodes
$(INSTALL) -m 0700 -d @MODULESDIR@/snomasks
@rm -f @MODULESDIR@/snomasks/*.so 1>/dev/null 2>&1
$(INSTALL) -m 0700 src/modules/snomasks/*.so @MODULESDIR@/snomasks
$(INSTALL) -m 0700 -d @MODULESDIR@/extbans
@rm -f @MODULESDIR@/extbans/*.so 1>/dev/null 2>&1
$(INSTALL) -m 0700 src/modules/extbans/*.so @MODULESDIR@/extbans
$(INSTALL) -m 0700 -d $(DESTDIR)@BINDIR@
$(INSTALL) -m 0700 src/ircd $(DESTDIR)@BINDIR@/unrealircd
$(INSTALL) -m 0700 -d $(DESTDIR)@DOCDIR@
$(INSTALL) -m 0600 doc/Authors doc/coding-guidelines doc/tao.of.irc $(DESTDIR)@DOCDIR@
$(INSTALL) -m 0700 -d $(DESTDIR)@CONFDIR@
$(INSTALL) -m 0600 doc/conf/*.conf $(DESTDIR)@CONFDIR@
$(INSTALL) -m 0600 doc/conf/*.motd $(DESTDIR)@CONFDIR@
$(INSTALL) -m 0600 doc/conf/modules.sources.list $(DESTDIR)@CONFDIR@ ; \
$(INSTALL) -m 0700 unrealircd $(DESTDIR)@SCRIPTDIR@
$(INSTALL) -m 0700 -d $(DESTDIR)@MODULESDIR@
@rm -f $(DESTDIR)@MODULESDIR@/*.so 1>/dev/null 2>&1
$(INSTALL) -m 0700 src/modules/*.so $(DESTDIR)@MODULESDIR@
$(INSTALL) -m 0700 -d $(DESTDIR)@MODULESDIR@/usermodes
@rm -f $(DESTDIR)@MODULESDIR@/usermodes/*.so 1>/dev/null 2>&1
$(INSTALL) -m 0700 src/modules/usermodes/*.so $(DESTDIR)@MODULESDIR@/usermodes
$(INSTALL) -m 0700 -d $(DESTDIR)@MODULESDIR@/chanmodes
@rm -f $(DESTDIR)@MODULESDIR@/chanmodes/*.so 1>/dev/null 2>&1
$(INSTALL) -m 0700 src/modules/chanmodes/*.so $(DESTDIR)@MODULESDIR@/chanmodes
$(INSTALL) -m 0700 -d $(DESTDIR)@MODULESDIR@/snomasks
@rm -f $(DESTDIR)@MODULESDIR@/snomasks/*.so 1>/dev/null 2>&1
$(INSTALL) -m 0700 src/modules/snomasks/*.so $(DESTDIR)@MODULESDIR@/snomasks
$(INSTALL) -m 0700 -d $(DESTDIR)@MODULESDIR@/extbans
@rm -f $(DESTDIR)@MODULESDIR@/extbans/*.so 1>/dev/null 2>&1
$(INSTALL) -m 0700 src/modules/extbans/*.so $(DESTDIR)@MODULESDIR@/extbans
@#If the conf/ssl directory exists then rename it here to conf/tls
@#and add a symlink for backwards compatibility (so that f.e. certbot
@#doesn't randomly fail after an upgrade to U5).
-@if [ -d "@CONFDIR@/ssl" ] ; then \
mv "@CONFDIR@/ssl" "@CONFDIR@/tls" ; \
ln -s "@CONFDIR@/tls" "@CONFDIR@/ssl" ; \
-@if [ -d "$(DESTDIR)@CONFDIR@/ssl" ] ; then \
mv "$(DESTDIR)@CONFDIR@/ssl" "$(DESTDIR)@CONFDIR@/tls" ; \
ln -s "$(DESTDIR)@CONFDIR@/tls" "$(DESTDIR)@CONFDIR@/ssl" ; \
fi
$(INSTALL) -m 0700 -d @CONFDIR@/tls
$(INSTALL) -m 0600 doc/conf/tls/curl-ca-bundle.crt @CONFDIR@/tls
$(INSTALL) -m 0700 -d $(DESTDIR)@CONFDIR@/tls
$(INSTALL) -m 0600 doc/conf/tls/curl-ca-bundle.crt $(DESTDIR)@CONFDIR@/tls
@# delete modules/cap directory, to avoid confusing with U4 to U5 upgrades:
rm -rf @MODULESDIR@/cap
$(INSTALL) -m 0700 -d @MODULESDIR@/third
@rm -f @MODULESDIR@/third/*.so 1>/dev/null 2>&1
rm -rf $(DESTDIR)@MODULESDIR@/cap
$(INSTALL) -m 0700 -d $(DESTDIR)@MODULESDIR@/third
@rm -f $(DESTDIR)@MODULESDIR@/third/*.so 1>/dev/null 2>&1
@#This step can fail with zero files, so we ignore exit status:
-$(INSTALL) -m 0700 src/modules/third/*.so @MODULESDIR@/third
$(INSTALL) -m 0700 -d @TMPDIR@
$(INSTALL) -m 0700 -d @CACHEDIR@
$(INSTALL) -m 0700 -d @PERMDATADIR@
$(INSTALL) -m 0700 -d @LOGDIR@
-@if [ ! -f "@CONFDIR@/tls/server.cert.pem" ] ; then \
$(INSTALL) -m 0600 server.req.pem @CONFDIR@/tls ; \
$(INSTALL) -m 0600 server.key.pem @CONFDIR@/tls ; \
$(INSTALL) -m 0600 server.cert.pem @CONFDIR@/tls ; \
-$(INSTALL) -m 0700 src/modules/third/*.so $(DESTDIR)@MODULESDIR@/third
$(INSTALL) -m 0700 -d $(DESTDIR)@TMPDIR@
$(INSTALL) -m 0700 -d $(DESTDIR)@CACHEDIR@
$(INSTALL) -m 0700 -d $(DESTDIR)@PERMDATADIR@
$(INSTALL) -m 0700 -d $(DESTDIR)@LOGDIR@
-@if [ ! -f "$(DESTDIR)@CONFDIR@/tls/server.cert.pem" ] ; then \
$(INSTALL) -m 0600 server.req.pem $(DESTDIR)@CONFDIR@/tls ; \
$(INSTALL) -m 0600 server.key.pem $(DESTDIR)@CONFDIR@/tls ; \
$(INSTALL) -m 0600 server.cert.pem $(DESTDIR)@CONFDIR@/tls ; \
fi
@rm -f $(DESTDIR)@SCRIPTDIR@/source
ln -s @BUILDDIR@ $(DESTDIR)@SCRIPTDIR@/source
@echo ''
@echo '* UnrealIRCd is now installed.'

View File

@ -269,6 +269,7 @@ DLL_FILES=SRC/MODULES/CLOAK.DLL \
SRC/MODULES/EXTBANS/MSGBYPASS.DLL \
SRC/MODULES/EXTBANS/TIMEDBAN.DLL \
SRC/MODULES/EXTBANS/PARTMSG.DLL \
SRC/MODULES/EXTBANS/SECURITYGROUP.DLL \
SRC/MODULES/ACCOUNT-NOTIFY.DLL \
SRC/MODULES/MESSAGE-TAGS.DLL \
SRC/MODULES/BATCH.DLL \
@ -1018,6 +1019,9 @@ src/modules/extbans/timedban.dll: src/modules/extbans/timedban.c $(INCLUDES)
src/modules/extbans/partmsg.dll: src/modules/extbans/partmsg.c $(INCLUDES)
$(CC) $(MODCFLAGS) /Fosrc/modules/extbans/ /Fesrc/modules/extbans/ src/modules/extbans/partmsg.c $(MODLFLAGS)
src/modules/extbans/securitygroup.dll: src/modules/extbans/securitygroup.c $(INCLUDES)
$(CC) $(MODCFLAGS) /Fosrc/modules/extbans/ /Fesrc/modules/extbans/ src/modules/extbans/securitygroup.c $(MODLFLAGS)
src/modules/account-notify.dll: src/modules/account-notify.c $(INCLUDES)
$(CC) $(MODCFLAGS) /Fosrc/modules/ /Fesrc/modules/ src/modules/account-notify.c $(MODLFLAGS)

21
SECURITY.md Normal file
View File

@ -0,0 +1,21 @@
# Security Policy
## Supported Versions
* The latest *stable* release of the 5.x branch
See [UnrealIRCd releases](https://www.unrealircd.org/docs/UnrealIRCd_releases) for information on older versions and End Of Life dates.
## Reporting a Vulnerability
Please report issues on the [bug tracker](https://bugs.unrealircd.org) and in the bug submit form **set the 'View Status' to 'private'**.
Do not report security issues on the forums or in a public IRC channel such as #unreal-support.
If you insist on e-mail then you can use syzop@unrealircd.org or security@unrealircd.org. Again, the bug tracker is preferred.
If you are *unsure* if something is a security issue, then report it at the bug tracker as a 'private' bug anyway. Better safe than sorry.
Do not ask around in public channels or forums.
You should get a response or at least an acknowledgement soon. If you don't hear back within 24 hours, then please try to contact us again.
## Full policy
See https://www.unrealircd.org/docs/Policy:_Handling_of_security_issues for full information.

View File

@ -272,3 +272,43 @@ else
AC_MSG_RESULT([no])
fi
])
AC_DEFUN([CHECK_ASN1_TIME_diff],
[
AC_MSG_CHECKING([for ASN1_TIME_diff in SSL library])
AC_LANG_PUSH(C)
SAVE_LIBS="$LIBS"
LIBS="$LIBS $CRYPTOLIB"
AC_TRY_LINK([#include <openssl/ssl.h>],
[int one, two; ASN1_TIME_diff(&one, &two, NULL, NULL);],
has_function=1,
has_function=0)
LIBS="$SAVE_LIBS"
AC_LANG_POP(C)
if test $has_function = 1; then
AC_MSG_RESULT([yes])
AC_DEFINE([HAS_ASN1_TIME_diff], [], [Define if ssl library has ASN1_TIME_diff])
else
AC_MSG_RESULT([no])
fi
])
AC_DEFUN([CHECK_X509_get0_notAfter],
[
AC_MSG_CHECKING([for X509_get0_notAfter in SSL library])
AC_LANG_PUSH(C)
SAVE_LIBS="$LIBS"
LIBS="$LIBS $CRYPTOLIB"
AC_TRY_LINK([#include <openssl/ssl.h>],
[X509_get0_notAfter(NULL);],
has_function=1,
has_function=0)
LIBS="$SAVE_LIBS"
AC_LANG_POP(C)
if test $has_function = 1; then
AC_MSG_RESULT([yes])
AC_DEFINE([HAS_X509_get0_notAfter], [], [Define if ssl library has X509_get0_notAfter])
else
AC_MSG_RESULT([no])
fi
])

114
configure vendored
View File

@ -1,6 +1,6 @@
#! /bin/sh
# Guess values for system-dependent variables and create Makefiles.
# Generated by GNU Autoconf 2.69 for unrealircd 5.0.7.
# Generated by GNU Autoconf 2.69 for unrealircd 5.0.8.
#
# Report bugs to <https://bugs.unrealircd.org/>.
#
@ -580,8 +580,8 @@ MAKEFLAGS=
# Identity of this package.
PACKAGE_NAME='unrealircd'
PACKAGE_TARNAME='unrealircd'
PACKAGE_VERSION='5.0.7'
PACKAGE_STRING='unrealircd 5.0.7'
PACKAGE_VERSION='5.0.8'
PACKAGE_STRING='unrealircd 5.0.8'
PACKAGE_BUGREPORT='https://bugs.unrealircd.org/'
PACKAGE_URL='https://unrealircd.org/'
@ -1325,7 +1325,7 @@ if test "$ac_init_help" = "long"; then
# Omit some internal or obsolete options to make the list less imposing.
# This message is too long to be a string in the A/UX 3.1 sh.
cat <<_ACEOF
\`configure' configures unrealircd 5.0.7 to adapt to many kinds of systems.
\`configure' configures unrealircd 5.0.8 to adapt to many kinds of systems.
Usage: $0 [OPTION]... [VAR=VALUE]...
@ -1391,7 +1391,7 @@ fi
if test -n "$ac_init_help"; then
case $ac_init_help in
short | recursive ) echo "Configuration of unrealircd 5.0.7:";;
short | recursive ) echo "Configuration of unrealircd 5.0.8:";;
esac
cat <<\_ACEOF
@ -1544,7 +1544,7 @@ fi
test -n "$ac_init_help" && exit $ac_status
if $ac_init_version; then
cat <<\_ACEOF
unrealircd configure 5.0.7
unrealircd configure 5.0.8
generated by GNU Autoconf 2.69
Copyright (C) 2012 Free Software Foundation, Inc.
@ -1913,7 +1913,7 @@ cat >config.log <<_ACEOF
This file contains any messages produced by compilers while
running configure, to aid debugging if configure makes a mistake.
It was created by unrealircd $as_me 5.0.7, which was
It was created by unrealircd $as_me 5.0.8, which was
generated by GNU Autoconf 2.69. Invocation command line was
$ $0 $@
@ -2321,7 +2321,7 @@ _ACEOF
# Minor version number (e.g.: Z in X.Y.Z)
UNREAL_VERSION_MINOR="7"
UNREAL_VERSION_MINOR="8"
cat >>confdefs.h <<_ACEOF
#define UNREAL_VERSION_MINOR $UNREAL_VERSION_MINOR
@ -6528,6 +6528,100 @@ else
$as_echo "no" >&6; }
fi
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for ASN1_TIME_diff in SSL library" >&5
$as_echo_n "checking for ASN1_TIME_diff in SSL library... " >&6; }
ac_ext=c
ac_cpp='$CPP $CPPFLAGS'
ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
ac_compiler_gnu=$ac_cv_c_compiler_gnu
SAVE_LIBS="$LIBS"
LIBS="$LIBS $CRYPTOLIB"
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
#include <openssl/ssl.h>
int
main ()
{
int one, two; ASN1_TIME_diff(&one, &two, NULL, NULL);
;
return 0;
}
_ACEOF
if ac_fn_c_try_link "$LINENO"; then :
has_function=1
else
has_function=0
fi
rm -f core conftest.err conftest.$ac_objext \
conftest$ac_exeext conftest.$ac_ext
LIBS="$SAVE_LIBS"
ac_ext=c
ac_cpp='$CPP $CPPFLAGS'
ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
ac_compiler_gnu=$ac_cv_c_compiler_gnu
if test $has_function = 1; then
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
$as_echo "yes" >&6; }
$as_echo "#define HAS_ASN1_TIME_diff /**/" >>confdefs.h
else
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
$as_echo "no" >&6; }
fi
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for X509_get0_notAfter in SSL library" >&5
$as_echo_n "checking for X509_get0_notAfter in SSL library... " >&6; }
ac_ext=c
ac_cpp='$CPP $CPPFLAGS'
ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
ac_compiler_gnu=$ac_cv_c_compiler_gnu
SAVE_LIBS="$LIBS"
LIBS="$LIBS $CRYPTOLIB"
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
#include <openssl/ssl.h>
int
main ()
{
X509_get0_notAfter(NULL);
;
return 0;
}
_ACEOF
if ac_fn_c_try_link "$LINENO"; then :
has_function=1
else
has_function=0
fi
rm -f core conftest.err conftest.$ac_objext \
conftest$ac_exeext conftest.$ac_ext
LIBS="$SAVE_LIBS"
ac_ext=c
ac_cpp='$CPP $CPPFLAGS'
ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
ac_compiler_gnu=$ac_cv_c_compiler_gnu
if test $has_function = 1; then
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
$as_echo "yes" >&6; }
$as_echo "#define HAS_X509_get0_notAfter /**/" >>confdefs.h
else
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
$as_echo "no" >&6; }
fi
# Check whether --enable-dynamic-linking was given.
if test "${enable_dynamic_linking+set}" = set; then :
enableval=$enable_dynamic_linking; enable_dynamic_linking=$enableval
@ -8398,7 +8492,7 @@ cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
# report actual input values of CONFIG_FILES etc. instead of their
# values after options handling.
ac_log="
This file was extended by unrealircd $as_me 5.0.7, which was
This file was extended by unrealircd $as_me 5.0.8, which was
generated by GNU Autoconf 2.69. Invocation command line was
CONFIG_FILES = $CONFIG_FILES
@ -8461,7 +8555,7 @@ _ACEOF
cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`"
ac_cs_version="\\
unrealircd config.status 5.0.7
unrealircd config.status 5.0.8
configured by $0, generated by GNU Autoconf 2.69,
with options \\"\$ac_cs_config\\"

View File

@ -7,7 +7,7 @@ dnl src/windows/unrealinst.iss
dnl doc/Config.header
dnl src/version.c.SH
AC_INIT([unrealircd], [5.0.7], [https://bugs.unrealircd.org/], [], [https://unrealircd.org/])
AC_INIT([unrealircd], [5.0.8], [https://bugs.unrealircd.org/], [], [https://unrealircd.org/])
AC_CONFIG_SRCDIR([src/ircd.c])
AC_CONFIG_HEADER([include/setup.h])
AC_CONFIG_AUX_DIR([autoconf])
@ -34,7 +34,7 @@ UNREAL_VERSION_MAJOR=["0"]
AC_DEFINE_UNQUOTED([UNREAL_VERSION_MAJOR], [$UNREAL_VERSION_MAJOR], [Major version number (e.g.: Y for X.Y.Z)])
# Minor version number (e.g.: Z in X.Y.Z)
UNREAL_VERSION_MINOR=["7"]
UNREAL_VERSION_MINOR=["8"]
AC_DEFINE_UNQUOTED([UNREAL_VERSION_MINOR], [$UNREAL_VERSION_MINOR], [Minor version number (e.g.: Z for X.Y.Z)])
# The version suffix such as a beta marker or release candidate
@ -504,6 +504,8 @@ CHECK_SSL
CHECK_SSL_CTX_SET1_CURVES_LIST
CHECK_SSL_CTX_SET_MIN_PROTO_VERSION
CHECK_SSL_CTX_SET_SECURITY_LEVEL
CHECK_ASN1_TIME_diff
CHECK_X509_get0_notAfter
AC_ARG_ENABLE(dynamic-linking, [AS_HELP_STRING([--disable-dynamic-linking], [Make the IRCd statically link with shared objects rather than dynamically (noone knows if disabling dynamic linking actually does anything or not)])],
[enable_dynamic_linking=$enableval], [enable_dynamic_linking="yes"])
AS_IF([test $enable_dynamic_linking = "yes"],

View File

@ -7,7 +7,7 @@
\___/|_| |_|_| \___|\__,_|_|\___/\_| \_| \____/\__,_|
Configuration Program
for UnrealIRCd 5.0.7
for UnrealIRCd 5.0.8
This program will help you to compile your IRC server, and ask you
questions regarding the compile-time settings of it during the process.

View File

@ -1,6 +1,72 @@
UnrealIRCd 5.0.7 Release Notes
UnrealIRCd 5.0.8 Release Notes
===============================
The main purpose of this release is to enhance the
[reputation](https://www.unrealircd.org/docs/Reputation_score)
functionality. There have also been some other changes and minor
bug fixes. For more information, see below.
Enhancements:
* Support for [security groups](https://www.unrealircd.org/docs/Security-group_block),
of which four groups always exist by default: known-users, unknown-users,
tls-users and tls-and-known-users.
* New extended ban ```~G:securitygroupname```. Typical usage would be
```MODE #chan +b ~G:unknown-users``` which will ban all users from the
channel that are not identified to services and have a reputation
score below 25 (by default). The exact settings can be tweaked in the
[security group block](https://www.unrealircd.org/docs/Security-group_block).
* The reputation command (IRCOp-only) has been extended to make it
easier to look for potential troublemakers:
* ```REPUTATION Nick``` shows reputation about the nick name
* ```REPUTATION IP``` shows reputation about the IP address
* ```REPUTATION #channel``` lists users in channel with their reputation score
* ```REPUTATION <NN``` lists users with reputation scores below value NN
* Only send the first 1000 matches on ```STATS gline``` or a
similar command. This to prevent the IRCOp from being flooded off.
This value can be changed via
[set::max-stats-matches](https://www.unrealircd.org/docs/Set_block#set::max-stats-matches)
* Warn when the SSL/TLS server certificate is expired or expires soon
(within 7 days).
* New option allow::options::reject-on-auth-failure if you want to
stop matching on a passworded allow block, see the
[allow password documentation](https://www.unrealircd.org/docs/Allow_block#password)
for more information. Note that most people won't use this.
Fixes:
* The ```WHO``` command searched on nick name even if it was told
to search on a specific account name via WHOX options.
* Some typos in the Config script and a warning
* Counting clients twice in some circumstances
Changes:
* Support for $(DESTDIR) in 'make install' if packaging for a distro
* Mention the ban reason in Q-line server notices
* Add self-test to module manager and improve the error message in case
the IRCd source directory does not exist.
* Print out a more helpful error if you run the unrealircd binary
rather than the unrealircd script with an argument like 'mkpasswd' etc.
* On *NIX create a symlink 'source' to the UnrealIRCd source
Module coders / Developers:
* The [Doxygen module API docs](https://www.unrealircd.org/api/5/index.html)
have been improved, in particular the
[Hook API](https://www.unrealircd.org/api/5/group__HookAPI.html)
is now 100% documented.
Reminder: UnrealIRCd 4 is no longer supported
----------------------------------------------
UnrealIRCd 4.x is [no longer supported](https://www.unrealircd.org/docs/UnrealIRCd_4_EOL).
Admins must upgrade to UnrealIRCd 5.
Upgrading from 4.x to 5.x?
Then check out the *UnrealIRCd 5* release notes [further down](#unrealircd-5).
Or, at the very least, check out
[Upgrading from 4.x](https://www.unrealircd.org/docs/Upgrading_from_4.x).
UnrealIRCd 5.0.7
-----------------
UnrealIRCd 5.0.7 consists mainly of fixes for the 5.x stable series,
with some minor enhancements.
@ -34,17 +100,6 @@ Module coders / Developers:
* No changes, only some small additions to the
[Doxygen module API docs](https://www.unrealircd.org/api/5/index.html)
Reminder: UnrealIRCd 4 is End Of Life
---------------------------------------
All support for the previous series, UnrealIRCd 4.x, will stop after
[December 31, 2020](https://www.unrealircd.org/docs/UnrealIRCd_4_EOL).
If you haven't upgraded yet, do so soon!
Upgrading from 4.x to 5.x?
Then check out the *UnrealIRCd 5* release notes [further down](#unrealircd-5). At the
very least, check out [Upgrading from 4.x](https://www.unrealircd.org/docs/Upgrading_from_4.x).
UnrealIRCd 5.0.6
-----------------

View File

@ -37,6 +37,11 @@ rem And we re-run the exact same command:
call extras\build-tests\windows\compilecmd\%SHORTNAME%.bat
if %ERRORLEVEL% NEQ 0 EXIT /B 1
rem Compile dependencies for unrealircd-tests -- this doesn't belong here though..
curl -fsS -o src\modules\third\fakereputation.c https://raw.githubusercontent.com/unrealircd/unrealircd-tests/master/serverconfig/unrealircd/modules/fakereputation.c
call extras\build-tests\windows\compilecmd\%SHORTNAME%.bat CUSTOMMODULE MODULEFILE=fakereputation
if %ERRORLEVEL% NEQ 0 EXIT /B 1
rem Convert c:\dev to c:\projects\unrealircd-5-libs
rem TODO: should use environment variable in innosetup script?
sed -i "s/c:\\dev\\unrealircd-5-libs/c:\\projects\\unrealircd-5-libs/gi" src\windows\unrealinst.iss

View File

@ -8,10 +8,11 @@ Here you should be able to find a lot of information on the data structures
and functions available to you when coding for UnrealIRCd.
## Wiki documentation ##
* Be sure to check the [Module API](https://www.unrealircd.org/docs/Dev:Module_API) article on the wiki, which currently provides a better overview of the module API.
* Be sure to check the [Module API](https://www.unrealircd.org/docs/Dev:Module_API) article on the wiki
as well, which provides a better *overview* of the module API
## Doxygen docs ##
* [Functions and structs ordered by purpose](modules.html) - **this contains most of the module API!**
* [The most common structs](group__CommonStructs.html) - like Client, User, Server, Channel, etc.
* [All structs](classes.html) - in a simple alphabetical index
* [Functions and structs ordered by purpose](modules.html) - this is work in progress and still needs expansion!
* [Browse by source file](dir_68267d1309a1af8e8297ef4c3efbcdba.html) - see all src/*.c files and their (documented) functions.

View File

@ -38,7 +38,7 @@ PROJECT_NAME = "UnrealIRCd"
# could be handy for archiving the generated documentation or if some version
# control system is used.
PROJECT_NUMBER = 5.0.7
PROJECT_NUMBER = 5.0.8
# Using the PROJECT_BRIEF tag one can provide an optional one line description
# for a project that appears at the top of each page and should give viewer a

View File

@ -90,6 +90,7 @@ extern MODVAR ConfigItem_alias *conf_alias;
extern MODVAR ConfigItem_include *conf_include;
extern MODVAR ConfigItem_help *conf_help;
extern MODVAR ConfigItem_offchans *conf_offchans;
extern MODVAR SecurityGroup *securitygroups;
extern void completed_connection(int, int, void *);
extern void clear_unknown();
extern EVENT(e_unload_module_delayed);
@ -163,7 +164,6 @@ extern MODVAR struct list_head global_server_list;
extern MODVAR struct list_head dead_list;
extern RealCommand *find_command(char *cmd, int flags);
extern RealCommand *find_command_simple(char *cmd);
extern Channel *find_channel(char *, Channel *);
extern Membership *find_membership_link(Membership *lp, Channel *ptr);
extern Member *find_member_link(Member *, Client *);
extern int remove_user_from_channel(Client *, Channel *);
@ -336,7 +336,7 @@ extern void del_queries(char *);
#define WATCH_HASH_TABLE_SIZE 32768
#define WHOWAS_HASH_TABLE_SIZE 32768
#define THROTTLING_HASH_TABLE_SIZE 8192
#define find_channel hash_find_channel
#define hash_find_channel find_channel
extern uint64_t siphash(const char *in, const char *k);
extern uint64_t siphash_raw(const char *in, size_t len, const char *k);
extern uint64_t siphash_nocase(const char *in, const char *k);
@ -359,7 +359,7 @@ extern Channel *hash_get_chan_bucket(uint64_t);
extern Client *hash_find_client(const char *, Client *);
extern Client *hash_find_id(const char *, Client *);
extern Client *hash_find_nickatserver(const char *, Client *);
extern Channel *hash_find_channel(char *name, Channel *channel);
extern Channel *find_channel(char *name, Channel *channel);
extern Client *hash_find_server(const char *, Client *);
extern struct MODVAR ThrottlingBucket *ThrottlingHash[THROTTLING_HASH_TABLE_SIZE];
@ -460,6 +460,7 @@ extern void count_memory(Client *cptr, char *nick);
extern void list_scache(Client *client);
extern char *oflagstr(long oflag);
extern int rehash(Client *client, int sig);
extern void s_die();
extern int match_simple(const char *mask, const char *name);
extern int match_esc(const char *mask, const char *name);
extern int add_listener(ConfigItem_listen *conf);
@ -549,10 +550,6 @@ extern void *safe_alloc(size_t size);
extern char *our_strdup(const char *str);
extern char *our_strldup(const char *str, size_t max);
extern MODFUNC char *tls_get_cipher(SSL *ssl);
extern TLSOptions *get_tls_options_for_client(Client *acptr);
extern int outdated_tls_client(Client *acptr);
extern char *outdated_tls_client_build_string(char *pattern, Client *acptr);
extern long config_checkval(char *value, unsigned short flags);
extern void config_status(FORMAT_STRING(const char *format), ...) __attribute__((format(printf,1,2)));
extern void init_random();
@ -701,7 +698,7 @@ extern MODVAR int (*find_shun)(Client *cptr);
extern MODVAR int (*find_spamfilter_user)(Client *client, int flags);
extern MODVAR TKL *(*find_qline)(Client *cptr, char *nick, int *ishold);
extern MODVAR TKL *(*find_tkline_match_zap)(Client *cptr);
extern MODVAR void (*tkl_stats)(Client *cptr, int type, char *para);
extern MODVAR void (*tkl_stats)(Client *cptr, int type, char *para, int *cnt);
extern MODVAR void (*tkl_sync)(Client *client);
extern MODVAR void (*cmd_tkl)(Client *client, MessageTag *recv_mtags, int parc, char *parv[]);
extern MODVAR int (*place_host_ban)(Client *client, BanAction action, char *reason, long duration);
@ -753,6 +750,25 @@ extern MODVAR void (*labeled_response_force_end)(void);
extern MODVAR void (*kick_user)(MessageTag *mtags, Channel *channel, Client *client, Client *victim, char *comment);
/* /Efuncs */
/* SSL/TLS functions */
extern int early_init_ssl();
extern int init_ssl();
extern int ssl_handshake(Client *); /* Handshake the accpeted con.*/
extern int ssl_client_handshake(Client *, ConfigItem_link *); /* and the initiated con.*/
extern int ircd_SSL_accept(Client *acptr, int fd);
extern int ircd_SSL_connect(Client *acptr, int fd);
extern int SSL_smart_shutdown(SSL *ssl);
extern void ircd_SSL_client_handshake(int, int, void *);
extern void SSL_set_nonblocking(SSL *s);
extern SSL_CTX *init_ctx(TLSOptions *tlsoptions, int server);
extern MODFUNC char *tls_get_cipher(SSL *ssl);
extern TLSOptions *get_tls_options_for_client(Client *acptr);
extern int outdated_tls_client(Client *acptr);
extern char *outdated_tls_client_build_string(char *pattern, Client *acptr);
extern int check_certificate_expiry_ctx(SSL_CTX *ctx, char **errstr);
extern EVENT(tls_check_expiry);
/* End of SSL/TLS functions */
extern void parse_message_tags_default_handler(Client *client, char **str, MessageTag **mtag_list);
extern char *mtags_to_string_default_handler(MessageTag *m, Client *client);
extern void *labeled_response_save_context_default_handler(void);
@ -793,6 +809,8 @@ extern char *cm_getparameter_ex(void **p, char mode);
extern void cm_putparameter_ex(void **p, char mode, char *str);
extern void cm_freeparameter_ex(void **p, char mode, char *str);
extern int file_exists(char *file);
extern time_t get_file_time(char *fname);
extern long get_file_size(char *fname);
extern void free_motd(MOTDFile *motd); /* s_serv.c */
extern void fix_timers(void);
extern char *chfl_to_sjoin_symbol(int s);
@ -974,3 +992,11 @@ extern int hide_idle_time(Client *client, Client *target);
extern void lost_server_link(Client *serv, FORMAT_STRING(const char *fmt), ...);
extern char *sendtype_to_cmd(SendType sendtype);
extern MODVAR MessageTagHandler *mtaghandlers;
extern int security_group_valid_name(char *name);
extern int security_group_exists(char *name);
extern SecurityGroup *add_security_group(char *name, int order);
extern SecurityGroup *find_security_group(char *name);
extern void free_security_group(SecurityGroup *s);
extern void set_security_group_defaults(void);
extern int user_allowed_by_security_group(Client *client, SecurityGroup *s);
extern int user_allowed_by_security_group_name(Client *client, char *secgroupname);

View File

@ -430,11 +430,62 @@ SINLINE void list_splice_tail_init(struct list_head *list,
pos != (head); \
pos = n, n = pos->prev)
/**
* list_for_each_entry - iterate over list of given type
* @pos: the type * to use as a loop cursor.
* @head: the head for your list.
* @member: the name of the list_struct within the struct.
/** Walk through client lists (with examples).
* @param pos The variable to use as a loop cursor
* @param head The head of your list
* @param member The name of the list_struct within the struct.
* @ingroup ListFunctions
* @section Examples
* @subsection client_list List all clients
* @code
* CMD_FUNC(cmd_listallclients)
* {
* Client *acptr;
* sendnotice(client, "List of all clients:");
* list_for_each_entry(acptr, &client_list, client_node)
* sendnotice(client, "Client %s", acptr->name);
* }
* @endcode
* @subsection lclient_list List all LOCAL clients
* @code
* CMD_FUNC(cmd_listalllocalclients)
* {
* Client *acptr;
* sendnotice(client, "List of all local clients:");
* list_for_each_entry(acptr, &lclient_list, lclient_node)
* sendnotice(client, "Client %s", acptr->name);
* }
* @endcode
* @subsection global_server_list List all servers
* @code
* CMD_FUNC(cmd_listallservers)
* {
* Client *acptr;
* sendnotice(client, "List of all servers:");
* list_for_each_entry(acptr, &global_server_list, client_node)
* sendnotice(client, "Server %s", acptr->name);
* }
* @endcode
* @subsection server_list List all LOCALLY connected servers
* @code
* CMD_FUNC(cmd_listallservers)
* {
* Client *acptr;
* sendnotice(client, "List of all LOCAL servers:");
* list_for_each_entry(acptr, &server_list, special_node)
* sendnotice(client, "Server %s", acptr->name);
* }
* @endcode
* @subsection oper_list List all LOCALLY connected IRCOps
* @code
* CMD_FUNC(cmd_listlocalircops)
* {
* Client *acptr;
* sendnotice(client, "List of all LOCAL IRCOps:");
* list_for_each_entry(acptr, &oper_list, special_node)
* sendnotice(client, "User %s", acptr->name);
* }
* @endcode
*/
#define list_for_each_entry(pos, head, member) \
for (pos = list_entry((head)->next, typeof(*pos), member); \
@ -514,12 +565,16 @@ SINLINE void list_splice_tail_init(struct list_head *list,
for (; &pos->member != (head); \
pos = list_entry(pos->member.next, typeof(*pos), member))
/**
* list_for_each_entry_safe - iterate over list of given type safe against removal of list entry
* @pos: the type * to use as a loop cursor.
* @n: another type * to use as temporary storage
* @head: the head for your list.
* @member: the name of the list_struct within the struct.
/** Walk through client lists - special 'safe' version.
* This is a special version, in case clients are removed from the list
* while the list is iterated. It is unlikely that you need to use this
* from modules, so use list_for_each_entry() instead.
* Examples are also in list_for_each_entry().
* @param pos The variable to use as a loop cursor
* @param n Variable to be used for temporary storage
* @param head The head of your list
* @param member The name of the list_struct within the struct.
* @ingroup ListFunctions
*/
#define list_for_each_entry_safe(pos, n, head, member) \
for (pos = list_entry((head)->next, typeof(*pos), member), \

File diff suppressed because it is too large Load Diff

View File

@ -28,6 +28,9 @@
/* Define if you have the <glob.h> header file. */
#undef GLOBH
/* Define if ssl library has ASN1_TIME_diff */
#undef HAS_ASN1_TIME_diff
/* Define if ssl library has SSL_CTX_set1_curves_list */
#undef HAS_SSL_CTX_SET1_CURVES_LIST
@ -37,6 +40,9 @@
/* Define if ssl library has SSL_CTX_set_security_level */
#undef HAS_SSL_CTX_SET_SECURITY_LEVEL
/* Define if ssl library has X509_get0_notAfter */
#undef HAS_X509_get0_notAfter
/* Define if you have crypt */
#undef HAVE_CRYPT

View File

@ -108,6 +108,7 @@ typedef struct ConfigItem_include ConfigItem_include;
typedef struct ConfigItem_blacklist_module ConfigItem_blacklist_module;
typedef struct ConfigItem_help ConfigItem_help;
typedef struct ConfigItem_offchans ConfigItem_offchans;
typedef struct SecurityGroup SecurityGroup;
typedef struct ListStruct ListStruct;
typedef struct ListStructPrio ListStructPrio;
@ -285,7 +286,7 @@ typedef enum ClientStatus {
#define SetUser(x) ((x)->status = CLIENT_STATUS_USER)
#define SetLog(x) ((x)->status = CLIENT_STATUS_LOG)
/* @} */
/** @} */
/** Used for checking certain properties of clients, such as IsSecure() and IsULine().
* @defgroup ClientFlags Client flags
@ -487,7 +488,7 @@ typedef enum ClientStatus {
#define ClearULine(x) do { (x)->flags &= ~CLIENT_FLAG_ULINE; } while(0)
#define ClearVirus(x) do { (x)->flags &= ~CLIENT_FLAG_VIRUS; } while(0)
#define ClearIdentLookupSent(x) do { (x)->flags &= ~CLIENT_FLAG_IDENTLOOKUPSENT; } while(0)
/* @} */
/** @} */
/* Others that access client structs: */
@ -498,6 +499,9 @@ typedef enum ClientStatus {
#define IsSynched(x) (x->serv->flags.synced)
#define IsServerSent(x) (x->serv && x->serv->flags.server_sent)
/* And more that access client stuff - but actually modularized */
#define GetReputation(client) (moddata_client_get(client, "reputation") ? atoi(moddata_client_get(client, "reputation")) : 0) /**< Get reputation value for a client */
/* PROTOCTL (Server protocol) stuff */
#ifndef DEBUGMODE
#define CHECKSERVERPROTO(x,y) (((x)->local->proto & y) == y)
@ -792,7 +796,8 @@ struct SWhois {
char *setby;
};
/** The command API - used by modules and the core.
/** The command API - used by modules and the core to add commands, overrides, etc.
* See also https://www.unrealircd.org/docs/Dev:Command_API for a higher level overview and example.
* @defgroup CommandAPI Command API
* @{
*/
@ -829,7 +834,7 @@ struct SWhois {
* E.g. parv[3] in the above example is out of bounds.
*/
#define CMD_FUNC(x) void (x) (Client *client, MessageTag *recv_mtags, int parc, char *parv[])
/* @} */
/** @} */
/** Command override function - used by all command override handlers.
* This is used in the code like <pre>CMD_OVERRIDE_FUNC(ovr_somecmd)</pre> as a function definition.
@ -1217,7 +1222,7 @@ struct Server {
} features;
};
/* @} */
/** @} */
struct MessageTag {
MessageTag *prev, *next;
@ -1379,6 +1384,7 @@ struct ConfigFlag_allow {
unsigned noident :1;
unsigned useip :1;
unsigned tls :1;
unsigned reject_on_auth_failure :1;
};
struct ConfigItem_allow {
@ -1715,6 +1721,16 @@ struct ConfigItem_offchans {
char *topic;
};
#define SECURITYGROUPLEN 48
struct SecurityGroup {
SecurityGroup *prev, *next;
int priority;
char name[SECURITYGROUPLEN+1];
int identified;
int reputation_score;
int webirc;
int tls;
};
#define HM_HOST 1
#define HM_IPV4 2
@ -2010,18 +2026,6 @@ extern MODVAR SSL_CTX *ctx;
extern MODVAR SSL_CTX *ctx_server;
extern MODVAR SSL_CTX *ctx_client;
extern SSL_METHOD *meth;
extern int early_init_ssl();
extern int init_ssl();
extern int ssl_handshake(Client *); /* Handshake the accpeted con.*/
extern int ssl_client_handshake(Client *, ConfigItem_link *); /* and the initiated con.*/
extern int ircd_SSL_accept(Client *acptr, int fd);
extern int ircd_SSL_connect(Client *acptr, int fd);
extern int SSL_smart_shutdown(SSL *ssl);
extern void ircd_SSL_client_handshake(int, int, void *);
extern void SSL_set_nonblocking(SSL *s);
extern SSL_CTX *init_ctx(TLSOptions *tlsoptions, int server);
#define TLS_PROTOCOL_TLSV1 0x0001
#define TLS_PROTOCOL_TLSV1_1 0x0002
#define TLS_PROTOCOL_TLSV1_2 0x0004

View File

@ -63,7 +63,7 @@
#define UNREAL_VERSION_MAJOR 0
/* Minor version number (e.g.: 1 for Unreal3.2.1) */
#define UNREAL_VERSION_MINOR 7
#define UNREAL_VERSION_MINOR 8
/* Version suffix such as a beta marker or release candidate marker. (e.g.:
-rcX for unrealircd-3.2.9-rcX) */

View File

@ -26,7 +26,9 @@
#include "unrealircd.h"
/** This is the extended channel mode API
/** This is the extended channel mode API,
* see also https://www.unrealircd.org/docs/Dev:Channel_Mode_API
* for more information.
* @defgroup ChannelModeAPI Channel mode API
* @{
*/

View File

@ -63,7 +63,7 @@ int (*find_shun)(Client *client);
int(*find_spamfilter_user)(Client *client, int flags);
TKL *(*find_qline)(Client *client, char *nick, int *ishold);
TKL *(*find_tkline_match_zap)(Client *client);
void (*tkl_stats)(Client *client, int type, char *para);
void (*tkl_stats)(Client *client, int type, char *para, int *cnt);
void (*tkl_sync)(Client *client);
void (*cmd_tkl)(Client *client, MessageTag *mtags, int parc, char *parv[]);
int (*place_host_ban)(Client *client, BanAction action, char *reason, long duration);

View File

@ -240,4 +240,5 @@ void SetupEvents(void)
EventAdd(NULL, "check_deadsockets", check_deadsockets, NULL, 1000, 0);
EventAdd(NULL, "handshake_timeout", handshake_timeout, NULL, 1000, 0);
EventAdd(NULL, "try_connections", try_connections, NULL, 2000, 0);
EventAdd(NULL, "tls_check_expiry", tls_check_expiry, NULL, (86400/2)*1000, 0);
}

View File

@ -25,7 +25,9 @@
*/
#include "unrealircd.h"
/** This is the message tags API (message-tags)
/** This is the message tags API (message-tags).
* For an overview of message tags in general (not the API)
* see https://www.unrealircd.org/docs/Message_tags
* @defgroup MessagetagAPI Message tag API
* @{
*/

View File

@ -28,7 +28,16 @@
long opermode = 0;
/** Lazy way to signal an SAJOIN MODE */
long sajoinmode = 0;
/** List of all channels on the server */
/** List of all channels on the server.
* @ingroup ListFunctions
* @section channels_example Example
* This code will list all channels on the network.
* @code
* sendnotice(client, "List of all channels:");
* for (channel = channels; channel; channel=channel->nextch)
* sendnotice(client, "Channel %s", channel->name);
* @endcode
*/
Channel *channels = NULL;
/* some buffers for rebuilding channel/nick lists with comma's */
@ -1144,7 +1153,7 @@ void set_channel_mlock(Client *client, Channel *channel, const char *newmlock, i
* @in modebuf_in Buffer pointing to mode characters (eg: +snk-l)
* @in parabuf_in Buffer pointing to all parameters (eg: key 123)
* @retval Returns 1 if we have valid data to return, 0 if at end of mode line.
* @section ex1 Example:
* @section parse_chanmode_example Example:
* @code
* ParseMode pm;
* int ret;

View File

@ -69,7 +69,8 @@ static int _conf_log (ConfigFile *conf, ConfigEntry *ce);
static int _conf_alias (ConfigFile *conf, ConfigEntry *ce);
static int _conf_help (ConfigFile *conf, ConfigEntry *ce);
static int _conf_offchans (ConfigFile *conf, ConfigEntry *ce);
static int _conf_sni (ConfigFile *conf, ConfigEntry *ce);
static int _conf_sni (ConfigFile *conf, ConfigEntry *ce);
static int _conf_security_group (ConfigFile *conf, ConfigEntry *ce);
/*
* Validation commands
@ -101,7 +102,8 @@ static int _test_log (ConfigFile *conf, ConfigEntry *ce);
static int _test_alias (ConfigFile *conf, ConfigEntry *ce);
static int _test_help (ConfigFile *conf, ConfigEntry *ce);
static int _test_offchans (ConfigFile *conf, ConfigEntry *ce);
static int _test_sni (ConfigFile *conf, ConfigEntry *ce);
static int _test_sni (ConfigFile *conf, ConfigEntry *ce);
static int _test_security_group (ConfigFile *conf, ConfigEntry *ce);
/* This MUST be alphabetized */
static ConfigCommand _ConfigCommands[] = {
@ -126,6 +128,7 @@ static ConfigCommand _ConfigCommands[] = {
{ "oper", _conf_oper, _test_oper },
{ "operclass", _conf_operclass, _test_operclass },
{ "require", _conf_require, _test_require },
{ "security-group", _conf_security_group, _test_security_group },
{ "set", _conf_set, _test_set },
{ "sni", _conf_sni, _test_sni },
{ "tld", _conf_tld, _test_tld },
@ -254,6 +257,7 @@ ConfigItem_include *conf_include = NULL;
ConfigItem_blacklist_module *conf_blacklist_module = NULL;
ConfigItem_help *conf_help = NULL;
ConfigItem_offchans *conf_offchans = NULL;
SecurityGroup *securitygroups = NULL;
MODVAR Configuration iConf;
MODVAR Configuration tempiConf;
@ -1902,6 +1906,7 @@ void postconf(void)
postconf_fixes();
do_weird_shun_stuff();
isupport_init(); /* for all the 005 values that changed.. */
tls_check_expiry(NULL);
}
int isanyserverlinked(void)
@ -2072,6 +2077,7 @@ int init_conf(char *rootconf, int rehash)
callbacks_switchover();
efunctions_switchover();
set_targmax_defaults();
set_security_group_defaults();
if (rehash)
{
Hook *h;
@ -5350,6 +5356,8 @@ int _conf_allow(ConfigFile *conf, ConfigEntry *ce)
allow->flags.useip = 1;
else if (!strcmp(cepp->ce_varname, "ssl") || !strcmp(cepp->ce_varname, "tls"))
allow->flags.tls = 1;
else if (!strcmp(cepp->ce_varname, "reject-on-auth-failure"))
allow->flags.reject_on_auth_failure = 1;
}
}
}
@ -5545,6 +5553,8 @@ int _test_allow(ConfigFile *conf, ConfigEntry *ce)
{}
else if (!strcmp(cepp->ce_varname, "ssl") || !strcmp(cepp->ce_varname, "tls"))
{}
else if (!strcmp(cepp->ce_varname, "reject-on-auth-failure"))
{}
else if (!strcmp(cepp->ce_varname, "sasl"))
{
config_error("%s:%d: The option allow::options::sasl no longer exists. "
@ -9317,7 +9327,7 @@ int _test_offchans(ConfigFile *conf, ConfigEntry *ce)
return 1;
}
config_warn("set::oficial-channels is deprecated. It often does not do what you want. "
config_warn("set::official-channels is deprecated. It often does not do what you want. "
"You're better of creating a channel, setting all modes, topic, etc. to your liking "
"and then making the channel permanent (MODE #channel +P). "
"The channel will then be stored in a database to preserve it between restarts.");
@ -10044,6 +10054,91 @@ int _test_deny(ConfigFile *conf, ConfigEntry *ce)
return errors;
}
int _test_security_group(ConfigFile *conf, ConfigEntry *ce)
{
int errors = 0;
ConfigEntry *cep;
if (!ce->ce_vardata)
{
config_error("%s:%i: security-group block needs a name, eg: security-group web-users {",
ce->ce_fileptr->cf_filename, ce->ce_varlinenum);
errors++;
} else {
if (!strcasecmp(ce->ce_vardata, "unknown-users"))
{
config_error("%s:%i: The 'unknown-users' group is a special group that is the "
"inverse of 'known-users', you cannot create or adjust it in the "
"config file, as it is created automatically by UnrealIRCd.",
ce->ce_fileptr->cf_filename, ce->ce_varlinenum);
errors++;
return errors;
}
if (!security_group_valid_name(ce->ce_vardata))
{
config_error("%s:%i: security-group block name '%s' contains invalid characters or is too long. "
"Only letters, numbers, underscore and hyphen are allowed.",
ce->ce_fileptr->cf_filename, ce->ce_varlinenum, ce->ce_vardata);
errors++;
}
}
for (cep = ce->ce_entries; cep; cep = cep->ce_next)
{
if (!strcmp(cep->ce_varname, "webirc"))
{
CheckNull(cep);
} else
if (!strcmp(cep->ce_varname, "identified"))
{
CheckNull(cep);
} else
if (!strcmp(cep->ce_varname, "reputation-score"))
{
int v;
CheckNull(cep);
v = atoi(cep->ce_vardata);
if ((v < 1) || (v > 10000))
{
config_error("%s:%i: security-group::reputation-score needs to be a value of 1-10000",
cep->ce_fileptr->cf_filename, cep->ce_varlinenum);
errors++;
}
} else
{
config_error_unknown(cep->ce_fileptr->cf_filename, cep->ce_varlinenum,
"security-group", cep->ce_varname);
errors++;
continue;
}
}
return errors;
}
int _conf_security_group(ConfigFile *conf, ConfigEntry *ce)
{
ConfigEntry *cep;
SecurityGroup *s = add_security_group(ce->ce_vardata, 1);
for (cep = ce->ce_entries; cep; cep = cep->ce_next)
{
if (!strcmp(cep->ce_varname, "webirc"))
s->webirc = config_checkval(cep->ce_vardata, CFG_YESNO);
else if (!strcmp(cep->ce_varname, "identified"))
s->identified = config_checkval(cep->ce_vardata, CFG_YESNO);
else if (!strcmp(cep->ce_varname, "reputation-score"))
s->reputation_score = atoi(cep->ce_vardata);
else if (!strcmp(cep->ce_varname, "priority"))
{
s->priority = atoi(cep->ce_vardata);
DelListItem(s, securitygroups);
AddListItemPrio(s, securitygroups, s->priority);
}
}
return 1;
}
#ifdef USE_LIBCURL
static void conf_download_complete(const char *url, const char *file, const char *errorbuf, int cached, void *inc_key)
{
@ -10641,6 +10736,7 @@ void link_generator(void)
" outgoing {\n"
" hostname %s;\n"
" port %d;\n"
" options { tls; autoconnect; }\n"
" }\n"
" password \"%s\" { spkifp; }\n"
" class servers;\n"

View File

@ -13,17 +13,6 @@ extern void StartUnrealAgain(void);
extern char *getosname(void);
time_t get_file_time(char *fname)
{
struct stat st;
if (stat(fname, &st) != 0)
return 0;
return (time_t)st.st_ctime;
}
char *find_best_coredump(void)
{
static char best_fname[512];
@ -560,17 +549,6 @@ int running_interactive(void)
#define REPORT_ASK 0
#define REPORT_AUTO 1
int getfilesize(char *fname)
{
struct stat st;
if (stat(fname, &st) != 0)
return -1;
return (int)st.st_size;
}
#define CRASH_REPORT_HOST "crash.unrealircd.org"
SSL_CTX *crashreport_init_ssl(void)
@ -614,7 +592,7 @@ int crashreport_send(char *fname)
int xfr = 0;
char *errstr = NULL;
filesize = getfilesize(fname);
filesize = get_file_size(fname);
if (filesize < 0)
return 0;

View File

@ -500,11 +500,21 @@ Client *hash_find_server(const char *server, Client *def)
return def;
}
/** Find a client, user (person), server or channel by name.
* If you are looking for "other find functions", then the alphabetical index of functions
* at 'f' is your best bet: https://www.unrealircd.org/api/5/globals_func_f.html#index_f
* @defgroup FindFunctions Find functions
* @{
*/
/** Find a client by name.
* This searches in the list of all types of clients, user/person, servers or an unregistered clients.
* If you know what type of client to search for, then use find_server() or find_person() instead!
* @param name The name to search for (eg: "nick" or "irc.example.net")
* @param requester The client that is searching for this name
* @note If 'requester' is a server or NULL, then we also check
* the ID table, otherwise not.
* @returns If the client is found then the Client is returned, otherwise NULL.
*/
Client *find_client(char *name, Client *requester)
{
@ -525,6 +535,7 @@ Client *find_client(char *name, Client *requester)
* @param requester The client searching for the name.
* @note If 'requester' is a server or NULL, then we also check
* the ID table, otherwise not.
* @returns If the server is found then the Client is returned, otherwise NULL.
*/
Client *find_server(char *name, Client *requester)
{
@ -539,13 +550,14 @@ Client *find_server(char *name, Client *requester)
return NULL;
}
/** Find a person.
/** Find a person (a user).
* @param name The name to search for (eg: "nick" or "001ABCDEFG")
* @param requester The client that is searching for this name
* @note If 'requester' is a server or NULL, then we also check
* the ID table, otherwise not.
* @returns If the user is found then the Client is returned, otherwise NULL.
*/
Client *find_person(char *name, Client *requester)
Client *find_person(char *name, Client *requester) /* TODO: this should have been called find_user() to be consistent */
{
Client *c2ptr;
@ -558,10 +570,12 @@ Client *find_person(char *name, Client *requester)
}
/*
* hash_find_channel
/** Find a channel by name.
* @param name The channel name to search for
* @param default_result If the channel is not found, this value is returned.
* @returns If the channel exists then the Channel is returned, otherwise default_result is returned.
*/
Channel *hash_find_channel(char *name, Channel *channel)
Channel *find_channel(char *name, Channel *default_result)
{
unsigned int hashv;
Channel *tmp;
@ -573,9 +587,11 @@ Channel *hash_find_channel(char *name, Channel *channel)
if (smycmp(name, tmp->chname) == 0)
return tmp;
}
return channel;
return default_result;
}
/** @} */
Channel *hash_get_chan_bucket(uint64_t hashv)
{
if (hashv > CHAN_HASH_TABLE_SIZE)
@ -963,18 +979,14 @@ EVENT(throttling_check_expire)
char *p = serveropts + strlen(serveropts);
Module *mi;
t = TStime();
if (!Hooks[17] && strchr(serveropts, 'm'))
if (!Hooks[HOOKTYPE_USERMSG] && strchr(serveropts, 'm'))
{ p = strchr(serveropts, 'm'); *p = '\0'; }
if (!Hooks[18] && strchr(serveropts, 'M'))
if (!Hooks[HOOKTYPE_CHANMSG] && strchr(serveropts, 'M'))
{ p = strchr(serveropts, 'M'); *p = '\0'; }
if (!Hooks[49] && !Hooks[51] && strchr(serveropts, 'R'))
{ p = strchr(serveropts, 'R'); *p = '\0'; }
if (Hooks[17] && !strchr(serveropts, 'm'))
if (Hooks[HOOKTYPE_USERMSG] && !strchr(serveropts, 'm'))
*p++ = 'm';
if (Hooks[18] && !strchr(serveropts, 'M'))
if (Hooks[HOOKTYPE_CHANMSG] && !strchr(serveropts, 'M'))
*p++ = 'M';
if ((Hooks[49] || Hooks[51]) && !strchr(serveropts, 'R'))
*p++ = 'R';
*p = '\0';
for (mi = Modules; mi; mi = mi->next)
if (!(mi->options & MOD_OPT_OFFICIAL))

View File

@ -96,7 +96,7 @@ void s_die()
#else
unload_all_modules();
unlink(conf_files ? conf_files->pid_file : IRCD_PIDFILE);
exit(-1);
exit(0);
#endif
}
@ -269,14 +269,7 @@ EVENT(garbage_collect)
loop.do_garbage_collect = 0;
}
/*
** try_connections
**
** Scan through configuration and try new connections.
** Returns the calendar time when the next call to this
** function should be made latest. (No harm done if this
** is called earlier or later...)
*/
/** Perform autoconnect to servers that are not linked yet. */
EVENT(try_connections)
{
ConfigItem_link *aconf;
@ -287,7 +280,7 @@ EVENT(try_connections)
for (aconf = conf_link; aconf; aconf = aconf->next)
{
/* We're only interested in autoconnect blocks that are valid (and ignore temporary link blocks) */
/* We're only interested in autoconnect blocks that are valid. Also, we ignore temporary link blocks. */
if (!(aconf->outgoing.options & CONNECT_AUTO) || !aconf->outgoing.hostname || (aconf->flag.temporary == 1))
continue;
@ -296,6 +289,7 @@ EVENT(try_connections)
/* Only do one connection attempt per <connfreq> seconds (for the same server) */
if ((aconf->hold > TStime()))
continue;
confrq = class->connfreq;
aconf->hold = TStime() + confrq;
@ -380,8 +374,7 @@ int match_tkls(Client *client)
return 0;
}
/** Time out connections that are still in handshake.
*/
/** Time out connections that are still in handshake. */
EVENT(handshake_timeout)
{
Client *client, *next;
@ -466,11 +459,7 @@ void check_ping(Client *client)
return;
}
/*
* Check registered connections for PING timeout.
* XXX: also does some other stuff still, need to sort this. --nenolod
* Perhaps it would be wise to ping servers as well mr nenolod, just an idea -- Syzop
*/
/** Check registered connections for ping timeout. Also, check for server bans. */
EVENT(check_pings)
{
Client *client, *next;
@ -493,6 +482,7 @@ EVENT(check_pings)
/* done */
}
/** Check for clients that are pending to be terminated */
EVENT(check_deadsockets)
{
Client *client, *next;
@ -550,18 +540,10 @@ static int bad_command(const char *argv0)
if (!argv0)
argv0 = "unrealircd";
(void)printf
("Usage: %s [-f <config>] [-F]\n"
"\n"
"UnrealIRCd\n"
" -f <config> Load configuration from <config> instead of the default\n"
" (%s).\n"
" -F Don't fork() when starting up. Use this when running\n"
" UnrealIRCd under gdb or when playing around with settings\n"
" on a non-production setup.\n"
"\n",
argv0, CONFIGFILE);
(void)printf("Server not started\n\n");
printf("ERROR: Incorrect command line argument encountered.\n"
"This is the unrealircd BINARY. End-users should NOT call this binary directly.\n"
"Please run the SCRIPT instead: %s/unrealircd\n", SCRIPTDIR);
printf("Server not started\n\n");
#else
if (!IsService) {
MessageBox(NULL,
@ -1098,7 +1080,7 @@ int InitUnrealIRCd(int argc, char *argv[])
bootopt |= BOOT_TTY;
break;
case 'v':
(void)printf("%s build %s\n", version, buildid);
(void)printf("%s\n", version);
#else
case 'v':
if (!IsService) {

View File

@ -810,7 +810,6 @@ void exit_client(Client *client, MessageTag *recv_mtags, char *comment)
exit_one_client(client, recv_mtags, comment);
free_message_tags(mtags_generated);
}
/** Initialize the (quite useless) IRC statistics */
@ -851,7 +850,7 @@ void verify_opercount(Client *orig, char *tag)
int valid_host(char *host)
{
char *p;
if (strlen(host) > HOSTLEN)
return 0; /* too long hosts are invalid too */
@ -1032,7 +1031,7 @@ int is_autojoin_chan(char *chname)
if (!strcasecmp(name, chname))
return 1;
}
if (AUTO_JOIN_CHANS)
{
strlcpy(buf, AUTO_JOIN_CHANS, sizeof(buf));
@ -1069,7 +1068,7 @@ int char_to_channelflag(char c)
int mixed_network(void)
{
Client *client;
list_for_each_entry(client, &server_list, special_node)
{
if (!IsServer(client) || IsULine(client))
@ -1083,7 +1082,7 @@ int mixed_network(void)
void unreal_delete_masks(ConfigItem_mask *m)
{
ConfigItem_mask *m_next;
for (; m; m = m_next)
{
m_next = m->next;
@ -1104,7 +1103,7 @@ static void unreal_add_mask(ConfigItem_mask **head, ConfigEntry *ce)
safe_strdup(m->mask, ce->ce_vardata);
else
safe_strdup(m->mask, ce->ce_varname);
add_ListItem((ListStruct *)m, (ListStruct **)head);
}
@ -1137,7 +1136,7 @@ int unreal_mask_match(Client *client, ConfigItem_mask *m)
return 1;
}
}
return 0;
}
@ -1191,7 +1190,7 @@ int swhois_add(Client *client, char *tag, int priority, char *swhois, Client *fr
safe_strdup(s->setby, tag);
s->priority = priority;
AddListItemPrio(s, client->user->swhois, s->priority);
sendto_server(skip, 0, PROTO_EXTSWHOIS, NULL, ":%s SWHOIS %s :%s",
from->id, client->id, swhois);
@ -1215,11 +1214,11 @@ int swhois_delete(Client *client, char *tag, char *swhois, Client *from, Client
{
SWhois *s, *s_next;
int ret = -1; /* default to 'not found' */
for (s = client->user->swhois; s; s = s_next)
{
s_next = s->next;
/* If ( same swhois or "*" ) AND same tag */
if ( ((!strcmp(s->line, swhois) || !strcmp(swhois, "*")) &&
!strcmp(s->setby, tag)))
@ -1234,7 +1233,7 @@ int swhois_delete(Client *client, char *tag, char *swhois, Client *from, Client
sendto_server(skip, PROTO_EXTSWHOIS, 0, NULL, ":%s SWHOIS %s - %s %d :%s",
from->id, client->id, tag, 0, swhois);
ret = 0;
}
}
@ -1893,6 +1892,41 @@ int filename_has_suffix(const char *fname, const char *suffix)
return 0;
}
/** Check if the specified file exists */
int file_exists(char *file)
{
FILE *fd;
fd = fopen(file, "r");
if (!fd)
return 0;
fclose(fd);
return 1;
}
/** Get the file creation time */
time_t get_file_time(char *fname)
{
struct stat st;
if (stat(fname, &st) != 0)
return 0;
return (time_t)st.st_ctime;
}
/** Get the size of a file */
long get_file_size(char *fname)
{
struct stat st;
if (stat(fname, &st) != 0)
return -1;
return (long)st.st_size;
}
/** Add a line to a MultiLine list */
void addmultiline(MultiLine **l, char *line)
{

View File

@ -1643,11 +1643,33 @@ void mm_parse_c_file(int argc, char *args[])
exit(0);
}
void mm_self_test(void)
{
char name[512];
snprintf(name, sizeof(name), "%s/src/modules/third", BUILDDIR);
if (file_exists(name))
return;
if (!file_exists(BUILDDIR))
{
fprintf(stderr, "ERROR: Directory %s does not exist.\n"
"The UnrealIRCd source is required for the module manager to work!\n",
BUILDDIR);
} else {
fprintf(stderr, "ERROR: Directory %s exists, but %s does not.\n"
"The UnrealIRCd source is required for the module manager to work.\n"
"It seems you only have a partial build directory??\n",
BUILDDIR, name);
}
exit(-1);
}
void modulemanager(int argc, char *args[])
{
if (!args[0])
mm_usage();
mm_self_test();
/* The following operations do not require reading
* of the repository list and are always available:
*/

View File

@ -34,7 +34,6 @@ Cmode_t EXTCMODE_SECUREONLY;
int secureonly_check_join(Client *client, Channel *channel, char *key, char *parv[]);
int secureonly_channel_sync (Channel *channel, int merge, int removetheirs, int nomode);
int secureonly_send_channel(Client *client, Channel *channel);
int secureonly_check_secure(Channel *channel);
int secureonly_check_sajoin(Client *target, Channel *channel, Client *requester);
int secureonly_specialcheck(Client *client, Channel *channel, char *parv[]);
@ -58,7 +57,6 @@ MOD_INIT()
HookAdd(modinfo->handle, HOOKTYPE_CAN_JOIN, 0, secureonly_check_join);
HookAdd(modinfo->handle, HOOKTYPE_CHANNEL_SYNCED, 0, secureonly_channel_sync);
HookAdd(modinfo->handle, HOOKTYPE_IS_CHANNEL_SECURE, 0, secureonly_check_secure);
HookAdd(modinfo->handle, HOOKTYPE_SEND_CHANNEL, 0, secureonly_send_channel);
HookAdd(modinfo->handle, HOOKTYPE_CAN_SAJOIN, 0, secureonly_check_sajoin);
@ -165,15 +163,6 @@ int secureonly_channel_sync(Channel *channel, int merge, int removetheirs, int n
return 0;
}
int secureonly_send_channel(Client *client, Channel *channel)
{
if (IsSecureOnly(channel))
if (!IsSecure(client))
return HOOK_DENY;
return HOOK_CONTINUE;
}
int secureonly_check_sajoin(Client *target, Channel *channel, Client *requester)
{
if (IsSecureOnly(channel) && !IsSecure(target))

View File

@ -67,8 +67,6 @@ UCounter *ucounter = NULL;
#define MSG_THROTTLE "THROTTLE"
#define GetReputation(client) (moddata_client_get(client, "reputation") ? atoi(moddata_client_get(client, "reputation")) : 0)
/* Forward declarations */
int ct_config_test(ConfigFile *cf, ConfigEntry *ce, int type, int *errs);
int ct_config_posttest(int *errs);

View File

@ -34,7 +34,7 @@ INCLUDES = ../../include/channel.h \
R_MODULES= \
join.so quiet.so nickchange.so inchannel.so realname.so \
account.so operclass.so certfp.so textban.so msgbypass.so \
timedban.so partmsg.so
timedban.so partmsg.so securitygroup.so
MODULES=$(R_MODULES)
MODULEFLAGS=@MODULEFLAGS@
@ -102,3 +102,7 @@ timedban.so: timedban.c $(INCLUDES)
partmsg.so: partmsg.c $(INCLUDES)
$(CC) $(CFLAGS) $(MODULEFLAGS) -DDYNAMIC_LINKING \
-o partmsg.so partmsg.c
securitygroup.so: securitygroup.c $(INCLUDES)
$(CC) $(CFLAGS) $(MODULEFLAGS) -DDYNAMIC_LINKING \
-o securitygroup.so securitygroup.c

View File

@ -0,0 +1,141 @@
/*
* Extended ban to ban based on security groups such as "unknown-users"
* (C) Copyright 2020 Bram Matthys (Syzop) and the UnrealIRCd team
*
* 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 1, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include "unrealircd.h"
ModuleHeader MOD_HEADER
= {
"extbans/securitygroup",
"4.2",
"ExtBan ~G - Ban based on security-group",
"UnrealIRCd Team",
"unrealircd-5",
};
/* Forward declarations */
char *extban_securitygroup_conv_param(char *para);
int extban_securitygroup_is_ok(Client *client, Channel *channel, char *para, int checkt, int what, int what2);
int extban_securitygroup_is_banned(Client *client, Channel *channel, char *banin, int type, char **msg, char **errmsg);
/** Called upon module init */
MOD_INIT()
{
ExtbanInfo req;
req.flag = 'G';
req.conv_param = extban_securitygroup_conv_param;
req.is_ok = extban_securitygroup_is_ok;
req.is_banned = extban_securitygroup_is_banned;
req.options = EXTBOPT_INVEX|EXTBOPT_TKL;
if (!ExtbanAdd(modinfo->handle, req))
{
config_error("could not register extended ban type ~G");
return MOD_FAILED;
}
MARK_AS_OFFICIAL_MODULE(modinfo);
return MOD_SUCCESS;
}
/** Called upon module load */
MOD_LOAD()
{
return MOD_SUCCESS;
}
/** Called upon unload */
MOD_UNLOAD()
{
return MOD_SUCCESS;
}
/* Helper function for extban_securitygroup_is_ok() and extban_securitygroup_conv_param()
* to do ban validation.
*/
int extban_securitygroup_generic(char *para, int strict)
{
char *mask;
mask = para+3;
/* ! at the start means negative match */
if (*mask == '!')
mask++;
/* Check if the rest of the security group name is valid */
if (strict)
{
if (!security_group_exists(mask))
return 0; /* security group does not exist */
} else {
if (!security_group_valid_name(mask))
return 0; /* invalid characters or too long */
}
if (!*mask)
return 0; /* don't allow "~G:" nor "~G:!" */
if (strlen(mask) > SECURITYGROUPLEN + 3)
mask[SECURITYGROUPLEN + 3] = '\0';
return 1;
}
int extban_securitygroup_is_ok(Client *client, Channel *channel, char *para, int checkt, int what, int what2)
{
if (MyUser(client) && (what == MODE_ADD) && (checkt == EXBCHK_PARAM))
{
char banbuf[SECURITYGROUPLEN+8];
strlcpy(banbuf, para, sizeof(banbuf));
if (!extban_securitygroup_generic(banbuf, 1))
{
SecurityGroup *s;
sendnotice(client, "ERROR: Unknown security-group '%s'. Syntax: +b ~G:securitygroup or +b ~G:!securitygroup", para+3);
sendnotice(client, "Available security groups:");
for (s = securitygroups; s; s = s->next)
sendnotice(client, "%s", s->name);
sendnotice(client, "unknown-users");
sendnotice(client, "End of security group list.");
return 0;
}
}
return 1;
}
/** Security group extban - conv_param */
char *extban_securitygroup_conv_param(char *para)
{
static char retbuf[SECURITYGROUPLEN + 8];
strlcpy(retbuf, para, sizeof(retbuf));
if (!extban_securitygroup_generic(retbuf, 0))
return NULL;
return retbuf;
}
/** Is the user banned by ~G:something ? */
int extban_securitygroup_is_banned(Client *client, Channel *channel, char *banin, int type, char **msg, char **errmsg)
{
char *ban = banin+3;
if (*ban == '!')
return !user_allowed_by_security_group_name(client, ban+1);
return user_allowed_by_security_group_name(client, ban);
}

View File

@ -1367,6 +1367,9 @@ int paracount_for_chanmode_from_server(Client *client, u_int what, char mode)
if (mode == '&')
return 0; /* & indicates bounce, it is not an actual mode character */
if (mode == 'F')
return (what == MODE_ADD) ? 1 : 0; /* Future compatibility */
/* If we end up here it means we have no idea if it is a parameter-eating or paramless
* channel mode. That's actually pretty bad. This shouldn't happen since CHANMODES=
* is sent since 2003 and the (often also required) EAUTH PROTOCTL is in there since 2010.

View File

@ -315,8 +315,8 @@ CMD_FUNC(cmd_nick_local)
{
client->local->since += 4; /* lag them up */
sendnumeric(client, ERR_ERRONEUSNICKNAME, nick, tklban->ptr.nameban->reason);
sendto_snomask(SNO_QLINE, "Forbidding Q-lined nick %s from %s.",
nick, get_client_name(cptr, FALSE));
sendto_snomask(SNO_QLINE, "Forbidding Q-lined nick %s from %s (%s)",
nick, get_client_name(cptr, FALSE), tklban->ptr.nameban->reason);
return; /* NICK message ignored */
}
/* fallthrough for ircops that have sufficient privileges */
@ -866,6 +866,12 @@ int _register_user(Client *client, char *nick, char *username, char *umode, char
/* Check G/Z lines before shuns -- kill before quite -- codemastr */
if (find_tkline_match(client, 0))
{
if (!IsDead(client) && client->local->class)
{
/* Fix client count bug, in case that it was a hold such as via authprompt */
client->local->class->clients--;
client->local->class = NULL;
}
ircstats.is_ref++;
return 0;
}
@ -892,7 +898,17 @@ int _register_user(Client *client, char *nick, char *username, char *umode, char
{
i = (*(h->func.intfunc))(client);
if (i == HOOK_DENY)
{
if (!IsDead(client) && client->local->class)
{
/* Fix client count bug, in case that
* the HOOK_DENY was only meant temporarily.
*/
client->local->class->clients--;
client->local->class = NULL;
}
return 0;
}
if (i == HOOK_ALLOW)
break;
}
@ -1316,12 +1332,9 @@ int AllowClient(Client *client, char *username)
for (aconf = conf_allow; aconf; aconf = aconf->next)
{
if (!aconf->hostname || !aconf->ip)
goto attach;
if (aconf->auth && !client->local->passwd && !moddata_client_get(client, "certfp"))
continue;
if (aconf->flags.tls && !IsSecure(client))
continue;
if (hp && hp->h_name)
{
hname = hp->h_name;
@ -1376,8 +1389,21 @@ int AllowClient(Client *client, char *username)
goto attach;
}
continue;
continue; /* No match */
attach:
/* Check authentication */
if (aconf->auth && !Auth_Check(client, aconf->auth, client->local->passwd))
{
/* Incorrect password/authentication - but was is it required? */
if (aconf->flags.reject_on_auth_failure)
{
exit_client(client, NULL, iConf.reject_message_unauthorized);
return 0;
} else {
continue; /* Continue (this is the default behavior) */
}
}
if (!aconf->flags.noident)
SetUseIdent(client);
if (!aconf->flags.useip && hp)
@ -1393,12 +1419,6 @@ int AllowClient(Client *client, char *username)
return 0;
}
if (aconf->auth && !Auth_Check(client, aconf->auth, client->local->passwd))
{
/* Always continue if password was wrong. */
continue;
}
if (!((aconf->class->clients + 1) > aconf->class->maxclients))
{
client->local->class = aconf->class;

View File

@ -343,9 +343,9 @@ CMD_FUNC(cmd_protoctl)
(long long)(TStime() - t));
snprintf(msg, sizeof(msg),
"Rejecting link %s: our clock is %lld seconds ahead. "
"Correct time is very important in IRC. Please "
"verify the clock on both %s (them) and %s (us), "
"fix it and then try linking again",
"Please verify the clock on both %s (them) and %s (us). "
"Correct time is very important for IRC servers, "
"see https://www.unrealircd.org/docs/FAQ#fix-your-clock",
get_client_name(client, TRUE),
(long long)(TStime() - t),
client->name, me.name);
@ -359,9 +359,9 @@ CMD_FUNC(cmd_protoctl)
(long long)(t - TStime()));
snprintf(msg, sizeof(msg),
"Rejecting link %s: our clock is %lld seconds behind. "
"Correct time is very important in IRC. Please "
"verify the clock on both %s (them) and %s (us), "
"fix it and then try linking again",
"Please verify the clock on both %s (them) and %s (us). "
"Correct time is very important for IRC servers, "
"see https://www.unrealircd.org/docs/FAQ#fix-your-clock",
get_client_name(client, TRUE),
(long long)(t - TStime()),
client->name, me.name);

View File

@ -682,6 +682,107 @@ int count_reputation_records(void)
return total;
}
void reputation_channel_query(Client *client, Channel *channel)
{
Member *m;
char buf[512];
char tbuf[256];
char **nicks;
int *scores;
int cnt = 0, i, j;
ReputationEntry *e;
sendtxtnumeric(client, "Users and reputation scores for %s:", channel->chname);
/* Step 1: build a list of nicks and their reputation */
nicks = safe_alloc((channel->users+1) * sizeof(char *));
scores = safe_alloc((channel->users+1) * sizeof(int));
for (m = channel->members; m; m = m->next)
{
nicks[cnt] = m->client->name;
if (m->client->ip)
{
e = find_reputation_entry(m->client->ip);
if (e)
scores[cnt] = e->score;
}
if (++cnt > channel->users)
{
sendto_ops("[BUG] reputation_channel_query() expected %d users but %d (or more) were present in %s",
channel->users, cnt, channel->chname);
#ifdef DEBUGMODE
abort();
#endif
break; /* safety net */
}
}
/* Step 2: lazy selection sort */
for (i = 0; i < cnt && nicks[i]; i++)
{
for (j = i+1; j < cnt && nicks[j]; j++)
{
if (scores[i] < scores[j])
{
char *nick_tmp;
int score_tmp;
nick_tmp = nicks[i];
score_tmp = scores[i];
nicks[i] = nicks[j];
scores[i] = scores[j];
nicks[j] = nick_tmp;
scores[j] = score_tmp;
}
}
}
/* Step 3: send the (ordered) list to the user */
*buf = '\0';
for (i = 0; i < cnt && nicks[i]; i++)
{
snprintf(tbuf, sizeof(tbuf), "%s\00314(%d)\003 ", nicks[i], scores[i]);
if ((strlen(tbuf)+strlen(buf) > 400) || !nicks[i+1])
{
sendtxtnumeric(client, "%s%s", buf, tbuf);
*buf = '\0';
} else {
strlcat(buf, tbuf, sizeof(buf));
}
}
sendtxtnumeric(client, "End of list.");
safe_free(nicks);
safe_free(scores);
}
void reputation_list_query(Client *client, int maxscore)
{
Client *target;
ReputationEntry *e;
sendtxtnumeric(client, "Users and reputation scores <%d:", maxscore);
list_for_each_entry(target, &client_list, client_node)
{
int score = 0;
if (!IsUser(target) || IsULine(target) || !target->ip)
continue;
e = find_reputation_entry(target->ip);
if (e)
score = e->score;
if (score >= maxscore)
continue;
sendtxtnumeric(client, "%s!%s@%s [%s] \017(score: %d)",
target->name,
target->user->username,
target->user->realhost,
target->ip,
score);
}
sendtxtnumeric(client, "End of list.");
}
CMD_FUNC(reputation_user_cmd)
{
ReputationEntry *e;
@ -709,13 +810,45 @@ CMD_FUNC(reputation_user_cmd)
}
sendnotice(client, "Current number of records (IP's): %d", count_reputation_records());
sendnotice(client, "-");
sendnotice(client, "For more specific information, use: /REPUTATION [nick|IP-address]");
sendnotice(client, "Available commands:");
sendnotice(client, "/REPUTATION [nick] Show reputation info about nick name");
sendnotice(client, "/REPUTATION [ip] Show reputation info about IP address");
sendnotice(client, "/REPUTATION [channel] List users in channel along with their reputation score");
sendnotice(client, "/REPUTATION <NN List users with reputation score below value NN");
return;
}
if (strchr(parv[1], '.') || strchr(parv[1], ':'))
{
ip = parv[1];
} else
if (parv[1][0] == '#')
{
Channel *channel = find_channel(parv[1], NULL);
if (!channel)
{
sendnumeric(client, ERR_NOSUCHCHANNEL, parv[1]);
return;
}
/* corner case: ircop without proper permissions and not in channel */
if (!ValidatePermissionsForPath("channel:see:names:invisible",client,NULL,NULL,NULL) && !get_access(client,channel))
{
sendnumeric(client, ERR_NOTONCHANNEL, channel->chname);
return;
}
reputation_channel_query(client, channel);
return;
} else
if (parv[1][0] == '<')
{
int max = atoi(parv[1] + 1);
if (max < 1)
{
sendnotice(client, "REPUTATION: Invalid search value specified. Use for example '/REPUTATION <5' to search on less-than-five");
return;
}
reputation_list_query(client, max);
return;
} else {
Client *target = find_person(parv[1], NULL);
if (!target)

View File

@ -27,8 +27,6 @@ ModuleHeader MOD_HEADER = {
"unrealircd-5",
};
#define GetReputation(client) (moddata_client_get(client, "reputation") ? atoi(moddata_client_get(client, "reputation")) : 0)
typedef struct RestrictedCommand RestrictedCommand;
struct RestrictedCommand {
RestrictedCommand *prev, *next;

View File

@ -462,22 +462,25 @@ int stats_denylinkall(Client *client, char *para)
int stats_gline(Client *client, char *para)
{
tkl_stats(client, TKL_GLOBAL|TKL_KILL, para);
tkl_stats(client, TKL_GLOBAL|TKL_ZAP, para);
int cnt = 0;
tkl_stats(client, TKL_GLOBAL|TKL_KILL, para, &cnt);
tkl_stats(client, TKL_GLOBAL|TKL_ZAP, para, &cnt);
return 0;
}
int stats_spamfilter(Client *client, char *para)
{
tkl_stats(client, TKL_SPAMF, para);
tkl_stats(client, TKL_GLOBAL|TKL_SPAMF, para);
int cnt = 0;
tkl_stats(client, TKL_SPAMF, para, &cnt);
tkl_stats(client, TKL_GLOBAL|TKL_SPAMF, para, &cnt);
return 0;
}
int stats_except(Client *client, char *para)
{
tkl_stats(client, TKL_EXCEPTION, para);
tkl_stats(client, TKL_EXCEPTION|TKL_GLOBAL, para);
int cnt = 0;
tkl_stats(client, TKL_EXCEPTION, para, &cnt);
tkl_stats(client, TKL_EXCEPTION|TKL_GLOBAL, para, &cnt);
return 0;
}
@ -564,8 +567,9 @@ int stats_port(Client *client, char *para)
int stats_bannick(Client *client, char *para)
{
tkl_stats(client, TKL_NAME, para);
tkl_stats(client, TKL_GLOBAL|TKL_NAME, para);
int cnt = 0;
tkl_stats(client, TKL_NAME, para, &cnt);
tkl_stats(client, TKL_GLOBAL|TKL_NAME, para, &cnt);
return 0;
}
@ -699,8 +703,9 @@ int stats_denylinkauto(Client *client, char *para)
int stats_kline(Client *client, char *para)
{
tkl_stats(client, TKL_KILL, NULL);
tkl_stats(client, TKL_ZAP, NULL);
int cnt = 0;
tkl_stats(client, TKL_KILL, NULL, &cnt);
tkl_stats(client, TKL_ZAP, NULL, &cnt);
return 0;
}
@ -720,7 +725,8 @@ int stats_banrealname(Client *client, char *para)
int stats_sqline(Client *client, char *para)
{
tkl_stats(client, TKL_NAME|TKL_GLOBAL, para);
int cnt = 0;
tkl_stats(client, TKL_NAME|TKL_GLOBAL, para, &cnt);
return 0;
}
@ -741,7 +747,8 @@ int stats_chanrestrict(Client *client, char *para)
int stats_shun(Client *client, char *para)
{
tkl_stats(client, TKL_GLOBAL|TKL_SHUN, para);
int cnt = 0;
tkl_stats(client, TKL_GLOBAL|TKL_SHUN, para, &cnt);
return 0;
}

View File

@ -234,8 +234,8 @@ int targetfloodprot_can_send_to_channel(Client *client, Channel *channel, Member
if (!MyUser(client))
return HOOK_CONTINUE;
/* Really, only IRCOps override */
if (IsOper(client) && ValidatePermissionsForPath("immune:target-flood",client,NULL,channel,NULL))
/* IRCOps and U-Lines override */
if (IsULine(client) || (IsOper(client) && ValidatePermissionsForPath("immune:target-flood",client,NULL,channel,NULL)))
return HOOK_CONTINUE;
what = sendtypetowhat(sendtype);
@ -280,8 +280,8 @@ int targetfloodprot_can_send_to_user(Client *client, Client *target, char **text
if (!MyUser(target))
return HOOK_CONTINUE;
/* Really, only IRCOps override */
if (IsOper(client) && ValidatePermissionsForPath("immune:target-flood",client,target,NULL,NULL))
/* IRCOps and U-Lines override */
if (IsULine(client) || (IsOper(client) && ValidatePermissionsForPath("immune:target-flood",client,target,NULL,NULL)))
return HOOK_CONTINUE;
what = sendtypetowhat(sendtype);

View File

@ -39,6 +39,8 @@ int tkl_config_test_ban(ConfigFile *, ConfigEntry *, int, int *);
int tkl_config_run_ban(ConfigFile *, ConfigEntry *, int);
int tkl_config_test_except(ConfigFile *, ConfigEntry *, int, int *);
int tkl_config_run_except(ConfigFile *, ConfigEntry *, int);
int tkl_config_test_set(ConfigFile *, ConfigEntry *, int, int *);
int tkl_config_run_set(ConfigFile *, ConfigEntry *, int);
CMD_FUNC(cmd_gline);
CMD_FUNC(cmd_shun);
CMD_FUNC(cmd_tempshun);
@ -76,7 +78,7 @@ int _find_shun(Client *client);
int _find_spamfilter_user(Client *client, int flags);
TKL *_find_qline(Client *client, char *nick, int *ishold);
TKL *_find_tkline_match_zap(Client *client);
void _tkl_stats(Client *client, int type, char *para);
void _tkl_stats(Client *client, int type, char *para, int *cnt);
void _tkl_sync(Client *client);
CMD_FUNC(_cmd_tkl);
int _place_host_ban(Client *client, BanAction action, char *reason, long duration);
@ -142,12 +144,15 @@ TKLTypeTable tkl_types[] = {
};
#define ALL_VALID_EXCEPTION_TYPES "kline, gline, zline, gzline, spamfilter, shun, qline, blacklist, connect-flood, unknown-data-flood, antirandom, antimixedutf8, ban-version"
int max_stats_matches = 1000;
MOD_TEST()
{
MARK_AS_OFFICIAL_MODULE(modinfo);
HookAdd(modinfo->handle, HOOKTYPE_CONFIGTEST, 0, tkl_config_test_spamfilter);
HookAdd(modinfo->handle, HOOKTYPE_CONFIGTEST, 0, tkl_config_test_ban);
HookAdd(modinfo->handle, HOOKTYPE_CONFIGTEST, 0, tkl_config_test_except);
HookAdd(modinfo->handle, HOOKTYPE_CONFIGTEST, 0, tkl_config_test_set);
EfunctionAdd(modinfo->handle, EFUNC_TKL_HASH, _tkl_hash);
EfunctionAdd(modinfo->handle, EFUNC_TKL_TYPETOCHAR, TO_INTFUNC(_tkl_typetochar));
EfunctionAdd(modinfo->handle, EFUNC_TKL_CHARTOTYPE, TO_INTFUNC(_tkl_chartotype));
@ -190,6 +195,7 @@ MOD_INIT()
HookAdd(modinfo->handle, HOOKTYPE_CONFIGRUN, 0, tkl_config_match_spamfilter);
HookAdd(modinfo->handle, HOOKTYPE_CONFIGRUN, 0, tkl_config_run_ban);
HookAdd(modinfo->handle, HOOKTYPE_CONFIGRUN, 0, tkl_config_run_except);
HookAdd(modinfo->handle, HOOKTYPE_CONFIGRUN, 0, tkl_config_run_set);
CommandAdd(modinfo->handle, "GLINE", cmd_gline, 3, CMD_OPER);
CommandAdd(modinfo->handle, "SHUN", cmd_shun, 3, CMD_OPER);
CommandAdd(modinfo->handle, "TEMPSHUN", cmd_tempshun, 2, CMD_OPER);
@ -902,6 +908,44 @@ int tkl_config_run_except(ConfigFile *cf, ConfigEntry *ce, int configtype)
return 1;
}
int tkl_config_test_set(ConfigFile *cf, ConfigEntry *ce, int configtype, int *errs)
{
int errors = 0;
/* We are only interested in set { } blocks */
if (configtype != CONFIG_SET)
return 0;
if (!strcmp(ce->ce_varname, "max-stats-matches"))
{
if (!ce->ce_vardata)
{
config_error("%s:%i: set::max-stats-matches: no value specified",
ce->ce_fileptr->cf_filename, ce->ce_varlinenum);
errors++;
}
// allow any other value, including 0 and negative.
*errs = errors;
return errors ? -1 : 1;
}
return 0;
}
int tkl_config_run_set(ConfigFile *cf, ConfigEntry *ce, int configtype)
{
/* We are only interested in set { } blocks */
if (configtype != CONFIG_SET)
return 0;
if (!strcmp(ce->ce_varname, "max-stats-matches"))
{
max_stats_matches = atoi(ce->ce_vardata);
return 1;
}
return 0;
}
/** Return unique spamfilter id for TKL */
char *spamfilter_id(TKL *tk)
{
@ -1269,7 +1313,7 @@ void cmd_tkl_line(Client *client, int parc, char *parv[], char *type)
mask++;
}
if (strchr(mask, '!'))
if ((*mask != '~') && strchr(mask, '!'))
{
sendnotice(client, "[error] Cannot have '!' in masks.");
return;
@ -1590,7 +1634,7 @@ CMD_FUNC(cmd_eline)
reason = parv[4];
}
if (strchr(mask, '!'))
if ((*mask != '~') && strchr(mask, '!'))
{
sendnotice(client, "[error] Cannot have '!' in masks.");
return;
@ -3298,7 +3342,7 @@ static void parse_stats_params(char *para, TKLFlag *flag)
/** Does this TKL entry match the search terms?
* This is a helper function for tkl_stats().
*/
void tkl_stats_matcher(Client *client, int type, char *para, TKLFlag *tklflags, TKL *tkl)
int tkl_stats_matcher(Client *client, int type, char *para, TKLFlag *tklflags, TKL *tkl)
{
/***** First, handle the selection ******/
@ -3306,66 +3350,66 @@ void tkl_stats_matcher(Client *client, int type, char *para, TKLFlag *tklflags,
{
if (tklflags->flags & BY_SETBY)
if (!match_simple(tklflags->set_by, tkl->set_by))
return;
return 0;
if (tklflags->flags & NOT_BY_SETBY)
if (match_simple(tklflags->set_by, tkl->set_by))
return;
return 0;
if (TKLIsServerBan(tkl))
{
if (tklflags->flags & BY_MASK)
{
if (!match_simple(tklflags->mask, make_user_host(tkl->ptr.serverban->usermask, tkl->ptr.serverban->hostmask)))
return;
return 0;
}
if (tklflags->flags & NOT_BY_MASK)
{
if (match_simple(tklflags->mask, make_user_host(tkl->ptr.serverban->usermask, tkl->ptr.serverban->hostmask)))
return;
return 0;
}
if (tklflags->flags & BY_REASON)
if (!match_simple(tklflags->reason, tkl->ptr.serverban->reason))
return;
return 0;
if (tklflags->flags & NOT_BY_REASON)
if (match_simple(tklflags->reason, tkl->ptr.serverban->reason))
return;
return 0;
} else
if (TKLIsNameBan(tkl))
{
if (tklflags->flags & BY_MASK)
{
if (!match_simple(tklflags->mask, tkl->ptr.nameban->name))
return;
return 0;
}
if (tklflags->flags & NOT_BY_MASK)
{
if (match_simple(tklflags->mask, tkl->ptr.nameban->name))
return;
return 0;
}
if (tklflags->flags & BY_REASON)
if (!match_simple(tklflags->reason, tkl->ptr.nameban->reason))
return;
return 0;
if (tklflags->flags & NOT_BY_REASON)
if (match_simple(tklflags->reason, tkl->ptr.nameban->reason))
return;
return 0;
} else
if (TKLIsBanException(tkl))
{
if (tklflags->flags & BY_MASK)
{
if (!match_simple(tklflags->mask, make_user_host(tkl->ptr.banexception->usermask, tkl->ptr.banexception->hostmask)))
return;
return 0;
}
if (tklflags->flags & NOT_BY_MASK)
{
if (match_simple(tklflags->mask, make_user_host(tkl->ptr.banexception->usermask, tkl->ptr.banexception->hostmask)))
return;
return 0;
}
if (tklflags->flags & BY_REASON)
if (!match_simple(tklflags->reason, tkl->ptr.banexception->reason))
return;
return 0;
if (tklflags->flags & NOT_BY_REASON)
if (match_simple(tklflags->reason, tkl->ptr.banexception->reason))
return;
return 0;
}
}
@ -3444,16 +3488,24 @@ void tkl_stats_matcher(Client *client, int type, char *para, TKLFlag *tklflags,
tkl->ptr.banexception->bantypes,
(tkl->expire_at != 0) ? (tkl->expire_at - TStime()) : 0,
(TStime() - tkl->set_at), tkl->set_by, tkl->ptr.banexception->reason);
} else
{
/* That's weird, unknown TKL type */
return 0;
}
return 1;
}
/* TKL Stats. This is used by /STATS gline and all the others */
void _tkl_stats(Client *client, int type, char *para)
void _tkl_stats(Client *client, int type, char *para, int *cnt)
{
TKL *tk;
TKLFlag tklflags;
int index, index2;
if ((max_stats_matches > 0) && (*cnt >= max_stats_matches))
return;
if (!BadPtr(para))
parse_stats_params(para, &tklflags);
@ -3467,7 +3519,16 @@ void _tkl_stats(Client *client, int type, char *para)
{
if (type && tk->type != type)
continue;
tkl_stats_matcher(client, type, para, &tklflags, tk);
if (tkl_stats_matcher(client, type, para, &tklflags, tk))
{
*cnt += 1;
if ((max_stats_matches > 0) && (*cnt >= max_stats_matches))
{
sendnumeric(client, ERR_TOOMANYMATCHES, "STATS", "too many matches (set::max-stats-matches)");
sendnotice(client, "Consider searching on something more specific, eg '/STATS gline +m *.nl'. See '/STATS' (without parameters) for help.");
return;
}
}
}
}
}
@ -3479,7 +3540,16 @@ void _tkl_stats(Client *client, int type, char *para)
{
if (type && tk->type != type)
continue;
tkl_stats_matcher(client, type, para, &tklflags, tk);
if (tkl_stats_matcher(client, type, para, &tklflags, tk))
{
*cnt += 1;
if ((max_stats_matches > 0) && (*cnt >= max_stats_matches))
{
sendnumeric(client, ERR_TOOMANYMATCHES, "STATS", "too many matches (set::max-stats-matches)");
sendnotice(client, "Consider searching on something more specific, eg '/STATS gline +m *.nl'. See '/STATS' (without parameters) for help.");
return;
}
}
}
}

View File

@ -351,45 +351,6 @@ CMD_FUNC(cmd_whox)
return;
}
/* '/who nick' */
if (((acptr = find_person(mask, NULL)) != NULL) &&
(!(fmt.matchsel & WMATCH_MODES)) &&
(!(fmt.matchsel & WMATCH_OPER) || IsOper(acptr)))
{
int isinvis = 0;
int i = 0;
Hook *h;
isinvis = IsInvisible(acptr);
for (lp = acptr->user->channel; lp; lp = lp->next)
{
member = IsMember(client, lp->channel);
if (isinvis && !member)
continue;
for (h = Hooks[HOOKTYPE_VISIBLE_IN_CHANNEL]; h; h = h->next)
{
i = (*(h->func.intfunc))(acptr,lp->channel);
if (i != 0)
break;
}
if (i != 0 && !(is_skochanop(client, lp->channel)) && !(is_skochanop(acptr, lp->channel) || has_voice(acptr,lp->channel)))
continue;
if (member || (!isinvis && PubChannel(lp->channel)))
break;
}
if (lp != NULL)
do_who(client, acptr, lp->channel, &fmt);
else
do_who(client, acptr, NULL, &fmt);
sendnumeric(client, RPL_ENDOFWHO, orig_mask);
return;
}
if (ValidatePermissionsForPath("channel:see:who:secret",client,NULL,NULL,NULL) ||
ValidatePermissionsForPath("channel:see:whois",client,NULL,NULL,NULL))
{
@ -561,9 +522,14 @@ static void who_common_channel(Client *client, Channel *channel,
static void who_global(Client *client, char *mask, int operspy, struct who_format *fmt)
{
Client *hunted = NULL;
Client *acptr;
int maxmatches = IsOper(client) ? INT_MAX : WHOLIMIT;
/* If searching for a nick explicitly, then include it later on in the result: */
if (mask && ((fmt->matchsel & WMATCH_NICK) || (fmt->matchsel == 0)))
hunted = find_person(mask, NULL);
/* Initialize the markers to zero */
list_for_each_entry(acptr, &client_list, client_node)
ClearMark(acptr);
@ -583,7 +549,7 @@ static void who_global(Client *client, char *mask, int operspy, struct who_forma
if (!IsUser(acptr))
continue;
if (IsInvisible(acptr) && !operspy && (client != acptr))
if (IsInvisible(acptr) && !operspy && (client != acptr) && (acptr != hunted))
continue;
if (IsMarked(acptr))

View File

@ -417,7 +417,10 @@ static void parse2(Client *cptr, Client **fromptr, MessageTag *mtags, char *ch)
/* If you're a user, and this command does not permit users or opers, deny */
if ((flags & CMD_USER) && !(cmptr->flags & CMD_USER) && !(cmptr->flags & CMD_OPER))
{
sendnumeric(cptr, ERR_NOTFORUSERS, cmptr->cmd);
if (cmptr->flags & CMD_UNREGISTERED)
sendnumeric(cptr, ERR_ALREADYREGISTRED); /* only for unregistered phase */
else
sendnumeric(cptr, ERR_NOTFORUSERS, cmptr->cmd); /* really never for users */
return;
}

View File

@ -164,11 +164,29 @@ void mark_data_to_send(Client *to)
}
}
/** Send data to clients, servers, channels, IRCOps, etc.
* There are a lot of send functions. The most commonly functions
* are: sendto_one() to send to an individual user,
* sendnumeric() to send a numeric to an individual user
* and sendto_channel() to send a message to a channel.
* @defgroup SendFunctions Send functions
* @{
*/
/** Send a message to a single client.
* This function is used quite a lot, after sendnumeric() it is the most-used send function.
* @param to The client to send to
* @param mtags Any message tags associated with this message (can be NULL)
* @param pattern The format string / pattern to use.
* @param ... Format string parameters.
* @section sendto_one_examples Examples
* @subsection sendto_one_mode_r Send "MODE -r"
* This will send the `:serv.er.name MODE yournick -r` message.
* Note that it will send only this message to illustrate the sendto_one() function.
* It does *not* set anyone actually -r.
* @code
* sendto_one(client, NULL, ":%s MODE %s :-r", me.name, client->name);
* @endcode
*/
void sendto_one(Client *to, MessageTag *mtags, FORMAT_STRING(const char *pattern), ...)
{
@ -180,8 +198,8 @@ void sendto_one(Client *to, MessageTag *mtags, FORMAT_STRING(const char *pattern
/** Send a message to a single client - va_list variant.
* This function is similar to sendto_one() except that it
* doesn't use varargs but a va_list instead.
* Generally this is NOT used outside send.c, so not by modules.
* doesn't use varargs but uses a va_list instead.
* Generally this function is NOT used outside send.c, so not by modules.
* @param to The client to send to
* @param mtags Any message tags associated with this message (can be NULL)
* @param pattern The format string / pattern to use.
@ -363,9 +381,9 @@ void sendbufto_one(Client *to, char *msg, unsigned int quick)
}
/** A single function to send data to a channel.
* Previously there were 6, now there is 1. This means there
* are likely some parameters that you will pass as NULL or 0
* but at least we can all use one single function.
* Previously there were 6 different functions to send channel data,
* now there is 1 single function. This also means that you most
* likely will pass NULL or 0 as some parameters.
* @param channel The channel to send to
* @param from The source of the message
* @param skip The client to skip (can be NULL).
@ -380,6 +398,36 @@ void sendbufto_one(Client *to, char *msg, unsigned int quick)
* @param mtags The message tags to attach to this message
* @param pattern The pattern (eg: ":%s PRIVMSG %s :%s")
* @param ... The parameters for the pattern.
* @note For all channel messages, it is important to attach the correct
* message tags (mtags) via a new_message() call, as can be seen
* in the example.
* @section sendto_channel_examples Examples
* @subsection sendto_channel_privmsg Send a PRIVMSG to a channel
* This command will send the message "Hello everyone!!!" to the channel when executed.
* @code
* CMD_FUNC(cmd_sayhello)
* {
* MessageTag *mtags = NULL;
* Channel *channel = NULL;
* if ((parc < 2) || BadPtr(parv[1]))
* {
* sendnumeric(client, ERR_NEEDMOREPARAMS, "SAYHELLO");
* return;
* }
* channel = find_channel(parv[1], NULL);
* if (!channel)
* {
* sendnumeric(client, ERR_NOSUCHCHANNEL, parv[1]);
* return;
* }
* new_message(client, recv_mtags, &mtags);
* sendto_channel(channel, client, client->direction, 0, 0,
* SEND_LOCAL|SEND_REMOTE, mtags,
* ":%s PRIVMSG %s :Hello everyone!!!",
* client->name, channel->name);
* free_message_tags(mtags);
* }
* @endcode
*/
void sendto_channel(Channel *channel, Client *from, Client *skip,
int prefix, long clicap, int sendflags,
@ -593,11 +641,15 @@ static int match_it(Client *one, char *mask, int what)
}
}
/*
* sendto_match_butone
*
* Send to all clients which match the mask in a way defined on 'what';
* either by user hostname or user servername.
/** Send to all clients which match the mask.
* This function is rarely used.
* @param one The client to skip
* @param from The sender
* @param mask The mask
* @param what One of MATCH_HOST or MATCH_SERVER
* @param mtags Message tags associated with the message
* @param pattern Format string
* @param ... Parameters to the format string
*/
void sendto_match_butone(Client *one, Client *from, char *mask, int what,
MessageTag *mtags, FORMAT_STRING(const char *pattern), ...)
@ -641,10 +693,9 @@ void sendto_match_butone(Client *one, Client *from, char *mask, int what,
}
}
/*
* sendto_ops
*
* Send to *local* ops only.
/** Send a message to all locally connected IRCOps
* @param pattern The format string / pattern to use.
* @param ... Format string parameters.
*/
void sendto_ops(FORMAT_STRING(const char *pattern), ...)
{
@ -664,10 +715,98 @@ void sendto_ops(FORMAT_STRING(const char *pattern), ...)
}
}
/*
* sendto_umode
*
* Send to specified umode
/* Hmm.. so local sending is called sendto_ops() and local+remote is sendto_ops_butone(),
* that is weird naming... (TODO fix some day in a new major series)
*/
/** Send a message to all IRCOps (local and remote), except one.
* @param one Skip sending the message to this client/direction
* @param from The sender (can not be NULL)
* @param pattern The format string / pattern to use.
* @param ... Format string parameters.
*/
void sendto_ops_butone(Client *one, Client *from, FORMAT_STRING(const char *pattern), ...)
{
va_list vl;
Client *acptr;
++current_serial;
list_for_each_entry(acptr, &client_list, client_node)
{
if (!SendWallops(acptr))
continue;
if (acptr->direction->local->serial == current_serial) /* sent message along it already ? */
continue;
if (acptr->direction == one)
continue; /* ...was the one I should skip */
acptr->direction->local->serial = current_serial;
va_start(vl, pattern);
vsendto_prefix_one(acptr->direction, from, NULL, pattern, vl);
va_end(vl);
}
}
/** This function does exactly the same as sendto_ops() in practice in 5.x.
* There used to be a difference between sendto_ops() and sendto_realops()
* with regards to user-settable snomasks, but this is no longer the case.
* TODO: remove this function in some future cleanup
*/
void sendto_realops(FORMAT_STRING(const char *pattern), ...)
{
va_list vl;
Client *acptr;
char nbuf[1024];
list_for_each_entry(acptr, &oper_list, special_node)
{
ircsnprintf(nbuf, sizeof(nbuf), ":%s NOTICE %s :*** ", me.name, acptr->name);
strlcat(nbuf, pattern, sizeof nbuf);
va_start(vl, pattern);
vsendto_one(acptr, NULL, nbuf, vl);
va_end(vl);
}
}
/** Send a message to all locally connected IRCOps and also log the error.
* @param pattern The format string / pattern to use.
* @param ... Format string parameters.
*/
void sendto_ops_and_log(FORMAT_STRING(const char *pattern), ...)
{
va_list vl;
char buf[1024];
va_start(vl, pattern);
ircvsnprintf(buf, sizeof(buf), pattern, vl);
va_end(vl);
ircd_log(LOG_ERROR, "%s", buf);
sendto_umode(UMODE_OPER, "%s", buf);
}
/** This function does exactly the same as sendto_ops_and_log()
* TODO: remove this function in some future cleanup
*/
void sendto_realops_and_log(FORMAT_STRING(const char *fmt), ...)
{
va_list vl;
static char buf[2048];
va_start(vl, fmt);
vsnprintf(buf, sizeof(buf), fmt, vl);
va_end(vl);
sendto_realops("%s", buf);
ircd_log(LOG_ERROR, "%s", buf);
}
/** Send a message to all locally connected users with specified user mode.
* @param umodes The umode that the recipient should have set (one of UMODE_)
* @param pattern The format string / pattern to use.
* @param ... Format string parameters.
*/
void sendto_umode(int umodes, FORMAT_STRING(const char *pattern), ...)
{
@ -687,10 +826,10 @@ void sendto_umode(int umodes, FORMAT_STRING(const char *pattern), ...)
}
}
/*
* sendto_umode_global
*
* Send to specified umode *GLOBALLY* (on all servers)
/** Send a message to all users with specified user mode (local & remote users).
* @param umodes The umode that the recipient should have set (one of UMODE_*)
* @param pattern The format string / pattern to use.
* @param ... Format string parameters.
*/
void sendto_umode_global(int umodes, FORMAT_STRING(const char *pattern), ...)
{
@ -734,10 +873,10 @@ void sendto_umode_global(int umodes, FORMAT_STRING(const char *pattern), ...)
}
}
/** Send to specified snomask - local / operonly.
* @param snomask Snomask to send to (can be a bitmask [AND])
* @param pattern printf-style pattern, followed by parameters.
* This function does not send snomasks to non-opers.
/** Send a message to all locally connected users with specified snomask.
* @param snomask The snomask that the recipient should have set (one of SNO_*)
* @param pattern The format string / pattern to use.
* @param ... Format string parameters.
*/
void sendto_snomask(int snomask, FORMAT_STRING(const char *pattern), ...)
{
@ -756,10 +895,10 @@ void sendto_snomask(int snomask, FORMAT_STRING(const char *pattern), ...)
}
}
/** Send to specified snomask - global / operonly.
* @param snomask Snomask to send to (can be a bitmask [AND])
* @param pattern printf-style pattern, followed by parameters
* This function does not send snomasks to non-opers.
/** Send a message to all users with specified snomask (local and remote users).
* @param snomask The snomask that the recipient should have set (one of SNO_*)
* @param pattern The format string / pattern to use.
* @param ... Format string parameters.
*/
void sendto_snomask_global(int snomask, FORMAT_STRING(const char *pattern), ...)
{
@ -788,10 +927,10 @@ void sendto_snomask_global(int snomask, FORMAT_STRING(const char *pattern), ...)
sendto_server(NULL, 0, 0, NULL, ":%s SENDSNO %s :%s", me.id, snobuf, nbuf);
}
/*
* send_cap_notify
*
* Send CAP DEL or CAP NEW to clients supporting this.
/** Send CAP DEL and CAP NEW notification to clients supporting it.
* This function is mostly meant to be used by the CAP and SASL modules.
* @param add Whether the CAP token is added (1) or removed (0)
* @param token The CAP token
*/
void send_cap_notify(int add, char *token)
{
@ -829,33 +968,6 @@ void send_cap_notify(int add, char *token)
}
}
/* ** sendto_ops_butone
** Send message to all operators.
** one - client not to send message to
** from- client which message is from *NEVER* NULL!!
*/
void sendto_ops_butone(Client *one, Client *from, FORMAT_STRING(const char *pattern), ...)
{
va_list vl;
Client *acptr;
++current_serial;
list_for_each_entry(acptr, &client_list, client_node)
{
if (!SendWallops(acptr))
continue;
if (acptr->direction->local->serial == current_serial) /* sent message along it already ? */
continue;
if (acptr->direction == one)
continue; /* ...was the one I should skip */
acptr->direction->local->serial = current_serial;
va_start(vl, pattern);
vsendto_prefix_one(acptr->direction, from, NULL, pattern, vl);
va_end(vl);
}
}
/* Prepare buffer based on format string and 'from' for LOCAL delivery.
* The prefix (:<something>) will be expanded to :nick!user@host if 'from'
* is a person, taking into account the rules for hidden/cloaked host.
@ -908,6 +1020,32 @@ static int vmakebuf_local_withprefix(char *buf, size_t buflen, Client *from, con
return len;
}
/** Send a message to a client, expand the sender prefix.
* This is similar to sendto_one() except that it will expand the source part :%s
* to :nick!user@host if needed, while with sendto_one() it will be :nick.
* @param to The client to send to
* @param mtags Any message tags associated with this message (can be NULL)
* @param pattern The format string / pattern to use.
* @param ... Format string parameters.
*/
void sendto_prefix_one(Client *to, Client *from, MessageTag *mtags, FORMAT_STRING(const char *pattern), ...)
{
va_list vl;
va_start(vl, pattern);
vsendto_prefix_one(to, from, mtags, pattern, vl);
va_end(vl);
}
/** Send a message to a single client, expand the sender prefix - va_list variant.
* This is similar to vsendto_one() except that it will expand the source part :%s
* to :nick!user@host if needed, while with sendto_one() it will be :nick.
* This function is also similar to sendto_prefix_one(), but this is the va_list
* variant.
* @param to The client to send to
* @param mtags Any message tags associated with this message (can be NULL)
* @param pattern The format string / pattern to use.
* @param ... Format string parameters.
*/
void vsendto_prefix_one(Client *to, Client *from, MessageTag *mtags, const char *pattern, va_list vl)
{
char *mtags_str = mtags ? mtags_to_string(mtags, to) : NULL;
@ -928,60 +1066,6 @@ void vsendto_prefix_one(Client *to, Client *from, MessageTag *mtags, const char
}
}
/*
* sendto_prefix_one
*
* to - destination client
* from - client which message is from
*
* NOTE: NEITHER OF THESE SHOULD *EVER* BE NULL!!
* -avalon
*/
void sendto_prefix_one(Client *to, Client *from, MessageTag *mtags, FORMAT_STRING(const char *pattern), ...)
{
va_list vl;
va_start(vl, pattern);
vsendto_prefix_one(to, from, mtags, pattern, vl);
va_end(vl);
}
/*
* sendto_realops
*
* Send to *local* ops only but NOT +s nonopers.
*/
void sendto_realops(FORMAT_STRING(const char *pattern), ...)
{
va_list vl;
Client *acptr;
char nbuf[1024];
list_for_each_entry(acptr, &oper_list, special_node)
{
ircsnprintf(nbuf, sizeof(nbuf), ":%s NOTICE %s :*** ", me.name, acptr->name);
strlcat(nbuf, pattern, sizeof nbuf);
va_start(vl, pattern);
vsendto_one(acptr, NULL, nbuf, vl);
va_end(vl);
}
}
/* Sends a message to all (local) opers AND logs to the ircdlog (as LOG_ERROR) */
void sendto_realops_and_log(FORMAT_STRING(const char *fmt), ...)
{
va_list vl;
static char buf[2048];
va_start(vl, fmt);
vsnprintf(buf, sizeof(buf), fmt, vl);
va_end(vl);
sendto_realops("%s", buf);
ircd_log(LOG_ERROR, "%s", buf);
}
void sendto_connectnotice(Client *newuser, int disconnect, char *comment)
{
Client *acptr;
@ -1102,6 +1186,11 @@ void sendto_one_nickcmd(Client *server, Client *client, char *umodes)
* has a % in their nick, which is a safe assumption since % is illegal.
*/
/** Send a server notice to a client.
* @param to The client to send to
* @param pattern The format string / pattern to use.
* @param ... Format string parameters.
*/
void sendnotice(Client *to, FORMAT_STRING(const char *pattern), ...)
{
static char realpattern[1024];
@ -1115,25 +1204,34 @@ void sendnotice(Client *to, FORMAT_STRING(const char *pattern), ...)
va_end(vl);
}
/** Send MultiLine list as a notice, one for each line */
/** Send MultiLine list as a notice, one for each line.
* @param client The client to send to
* @param m The MultiLine list.
*/
void sendnotice_multiline(Client *client, MultiLine *m)
{
for (; m; m = m->next)
sendnotice(client, "%s", m->line);
}
void sendtxtnumeric(Client *to, FORMAT_STRING(const char *pattern), ...)
{
static char realpattern[1024];
va_list vl;
ircsnprintf(realpattern, sizeof(realpattern), ":%s %d %s :%s", me.name, RPL_TEXT, to->name, pattern);
va_start(vl, pattern);
vsendto_one(to, NULL, realpattern, vl);
va_end(vl);
}
/** Send numeric to IRC client */
/** Send numeric message to a client.
* @param to The recipient
* @param numeric The numeric, one of RPL_* or ERR_*, see src/numeric.c
* @param ... The parameters for the numeric
* @note Be sure to provide the correct number and type of parameters that belong to the numeric. Check src/numeric.c when in doubt!
* @section sendnumeric_examples Examples
* @subsection sendnumeric_permission_denied Send "Permission Denied" numeric
* This numeric has no parameter, so is simple:
* @code
* sendnumeric(client, ERR_NOPRIVILEGES);
* @endcode
* @subsection sendnumeric_notenoughparameters Send "Not enough parameters" numeric
* This numeric requires 1 parameter: the name of the command.
* @code
* sendnumeric(client, ERR_NEEDMOREPARAMS, "SOMECOMMAND");
* @endcode
*/
void sendnumeric(Client *to, int numeric, ...)
{
va_list vl;
@ -1146,7 +1244,15 @@ void sendnumeric(Client *to, int numeric, ...)
va_end(vl);
}
/** Send numeric to IRC client */
/** Send numeric message to a client - format to user specific needs.
* This will ignore the numeric definition of src/numeric.c and always send ":me.name numeric clientname "
* followed by the pattern and format string you choose.
* @param to The recipient
* @param numeric The numeric, one of RPL_* or ERR_*, see src/numeric.c
* @param pattern The format string / pattern to use.
* @param ... Format string parameters.
* @note Don't forget to add a colon if you need it (eg `:%%s`), this is a common mistake.
*/
void sendnumericfmt(Client *to, int numeric, FORMAT_STRING(const char *pattern), ...)
{
va_list vl;
@ -1159,7 +1265,27 @@ void sendnumericfmt(Client *to, int numeric, FORMAT_STRING(const char *pattern),
va_end(vl);
}
/** Send raw data directly to socket, bypassing everything.
/** Send text numeric message to a client (RPL_TEXT).
* Because this generic output numeric is commonly used it got a special function for it.
* @param to The recipient
* @param numeric The numeric, one of RPL_* or ERR_*, see src/numeric.c
* @param pattern The format string / pattern to use.
* @param ... Format string parameters.
* @note Don't forget to add a colon if you need it (eg `:%%s`), this is a common mistake.
*/
void sendtxtnumeric(Client *to, FORMAT_STRING(const char *pattern), ...)
{
static char realpattern[1024];
va_list vl;
ircsnprintf(realpattern, sizeof(realpattern), ":%s %d %s :%s", me.name, RPL_TEXT, to->name, pattern);
va_start(vl, pattern);
vsendto_one(to, NULL, realpattern, vl);
va_end(vl);
}
/* Send raw data directly to socket, bypassing everything.
* Looks like an interesting function to call? NO! STOP!
* Don't use this function. It may only be used by the initial
* Z-Line check via the codepath to banned_client().
@ -1186,17 +1312,4 @@ void send_raw_direct(Client *user, FORMAT_STRING(FORMAT_STRING(const char *patte
(void)send(user->local->fd, sendbuf, sendlen, 0);
}
/** Send a message to all locally connected IRCOps and log the error.
*/
void sendto_ops_and_log(FORMAT_STRING(const char *pattern), ...)
{
va_list vl;
char buf[1024];
va_start(vl, pattern);
ircvsnprintf(buf, sizeof(buf), pattern, vl);
va_end(vl);
ircd_log(LOG_ERROR, "%s", buf);
sendto_umode(UMODE_OPER, "%s", buf);
}
/** @} */

View File

@ -32,7 +32,6 @@
/* for uname(), is POSIX so should be OK... */
#include <sys/utsname.h>
#endif
extern void s_die();
MODVAR int max_connection_count = 1, max_client_count = 1;
extern int do_garbage_collect;

View File

@ -724,17 +724,6 @@ void outofmemory(size_t bytes)
exit(7);
}
/** Check if the specified file exists */
int file_exists(char *file)
{
FILE *fd;
fd = fopen(file, "r");
if (!fd)
return 0;
fclose(fd);
return 1;
}
/** Returns a unique filename in the specified directory
* using the specified suffix. The returned value will
* be of the form <dir>/<random-hex>.<suffix>

104
src/tls.c
View File

@ -36,9 +36,10 @@ extern HWND hwIRCDWnd;
#define SAFE_SSL_ACCEPT 3
#define SAFE_SSL_CONNECT 4
/* Forward declarations */
static int fatal_ssl_error(int ssl_error, int where, int my_errno, Client *client);
extern int cipher_check(SSL_CTX *ctx, char **errstr);
extern int certificate_quality_check(SSL_CTX *ctx, char **errstr);
int cipher_check(SSL_CTX *ctx, char **errstr);
int certificate_quality_check(SSL_CTX *ctx, char **errstr);
/* The SSL structures */
SSL_CTX *ctx_server;
@ -1040,6 +1041,8 @@ int verify_certificate(SSL *ssl, char *hostname, char **errstr)
if (SSL_get_verify_result(ssl) != X509_V_OK)
{
// FIXME: there are actually about 25+ different possible errors,
// this is only the most common one:
strlcpy(buf, "Certificate is not issued by a trusted Certificate Authority", sizeof(buf));
if (errstr)
*errstr = buf;
@ -1333,3 +1336,100 @@ char *outdated_tls_client_build_string(char *pattern, Client *client)
buildvarstring(pattern, buf, sizeof(buf), name, value);
return buf;
}
int check_certificate_expiry_ctx(SSL_CTX *ctx, char **errstr)
{
#if !defined(HAS_ASN1_TIME_diff) || !defined(HAS_X509_get0_notAfter)
return 0;
#else
static char errbuf[512];
SSL *ssl;
X509 *cert;
const ASN1_TIME *cert_expiry_time;
int days_expiry = 0, seconds_expiry = 0;
long duration;
*errstr = NULL;
ssl = SSL_new(ctx);
if (!ssl)
return 0;
cert = SSL_get_certificate(ssl);
if (!cert)
{
SSL_free(ssl);
return 0;
}
/* get certificate time */
cert_expiry_time = X509_get0_notAfter(cert);
/* calculate difference */
ASN1_TIME_diff(&days_expiry, &seconds_expiry, cert_expiry_time, NULL);
duration = (days_expiry * 86400) + seconds_expiry;
/* certificate expiry? */
if ((days_expiry > 0) || (seconds_expiry > 0))
{
snprintf(errbuf, sizeof(errbuf), "certificate expired %s ago", pretty_time_val(duration));
SSL_free(ssl);
*errstr = errbuf;
return 1;
} else
/* or near-expiry? */
if (((days_expiry < 0) || (seconds_expiry < 0)) && (days_expiry > -7))
{
snprintf(errbuf, sizeof(errbuf), "certificate will expire in %s", pretty_time_val(0 - duration));
SSL_free(ssl);
*errstr = errbuf;
return 1;
}
/* All good */
SSL_free(ssl);
return 0;
#endif
}
void check_certificate_expiry_tlsoptions_and_warn(TLSOptions *tlsoptions)
{
SSL_CTX *ctx;
int ret;
char *errstr = NULL;
ctx = init_ctx(tlsoptions, 1);
if (!ctx)
return;
if (check_certificate_expiry_ctx(ctx, &errstr))
{
sendto_umode_global(UMODE_OPER, "Warning: TLS certificate '%s': %s", tlsoptions->certificate_file, errstr);
ircd_log(LOG_ERROR, "[warning] TLS certificate '%s': %s", tlsoptions->certificate_file, errstr);
}
SSL_CTX_free(ctx);
}
EVENT(tls_check_expiry)
{
ConfigItem_listen *listen;
ConfigItem_sni *sni;
ConfigItem_link *link;
/* set block */
check_certificate_expiry_tlsoptions_and_warn(iConf.tls_options);
for (listen = conf_listen; listen; listen = listen->next)
if (listen->tls_options)
check_certificate_expiry_tlsoptions_and_warn(listen->tls_options);
/* sni::tls-options.... */
for (sni = conf_sni; sni; sni = sni->next)
if (sni->tls_options)
check_certificate_expiry_tlsoptions_and_warn(sni->tls_options);
/* link::outgoing::tls-options.... */
for (link = conf_link; link; link = link->next)
if (link->tls_options)
check_certificate_expiry_tlsoptions_and_warn(link->tls_options);
}

View File

@ -726,3 +726,149 @@ int hide_idle_time(Client *client, Client *target)
return 0;
}
}
/** Check if the name of the security-group contains only valid characters.
* @param name The name of the group
* @returns 1 if name is valid, 0 if not (eg: illegal characters)
*/
int security_group_valid_name(char *name)
{
char *p;
if (strlen(name) > SECURITYGROUPLEN)
return 0; /* Too long */
for (p = name; *p; p++)
{
if (!isalnum(*p) && !strchr("_-", *p))
return 0; /* Character not allowed */
}
return 1;
}
/** Find a security-group.
* @param name The name of the security group
* @returns A SecurityGroup struct, or NULL if not found.
*/
SecurityGroup *find_security_group(char *name)
{
SecurityGroup *s;
for (s = securitygroups; s; s = s->next)
if (!strcasecmp(name, s->name))
return s;
return NULL;
}
/** Checks if a security-group exists.
* This function takes the 'unknown-users' magic group into account as well.
* @param name The name of the security group
* @returns 1 if it exists, 0 if not
*/
int security_group_exists(char *name)
{
if (!strcmp(name, "unknown-users") || find_security_group(name))
return 1;
return 0;
}
/** Add a new security-group and add it to the list, but search for existing one first.
* @param name The name of the security group
* @returns A SecurityGroup struct (already added to the 'securitygroups' linked list)
*/
SecurityGroup *add_security_group(char *name, int priority)
{
SecurityGroup *s = find_security_group(name);
/* Existing? */
if (s)
return s;
/* Otherwise, create a new entry */
s = safe_alloc(sizeof(SecurityGroup));
strlcpy(s->name, name, sizeof(s->name));
s->priority = priority;
AddListItemPrio(s, securitygroups, priority);
return s;
}
/** Free a SecurityGroup struct */
void free_security_group(SecurityGroup *s)
{
/* atm there is nothing else to free,
* but who knows this may change in the future
*/
safe_free(s);
}
/** Initialize the default security-group blocks */
void set_security_group_defaults(void)
{
SecurityGroup *s, *s_next;
/* First free all security groups */
for (s = securitygroups; s; s = s_next)
{
s_next = s->next;
free_security_group(s);
}
securitygroups = NULL;
/* Default group: known-users */
s = add_security_group("known-users", 100);
s->identified = 1;
s->reputation_score = 25;
s->webirc = 0;
/* Default group: tls-and-known-users */
s = add_security_group("tls-and-known-users", 200);
s->identified = 1;
s->reputation_score = 25;
s->webirc = 0;
s->tls = 1;
/* Default group: tls-users */
s = add_security_group("tls-users", 300);
s->tls = 1;
}
/** Returns 1 if the user is OK as far as the security-group is concerned.
* @param client The client to check
* @param s The security-group to check against
* @retval 1 if user is allowed by security-group, 0 if not.
*/
int user_allowed_by_security_group(Client *client, SecurityGroup *s)
{
if (s->identified && IsLoggedIn(client))
return 1;
if (s->webirc && moddata_client_get(client, "webirc"))
return 1;
if (s->reputation_score && (GetReputation(client) >= s->reputation_score))
return 1;
if (s->tls && (IsSecureConnect(client) || IsSecure(client)))
return 1;
return 0;
}
/** Returns 1 if the user is OK as far as the security-group is concerned - "by name" version.
* @param client The client to check
* @param secgroupname The name of the security-group to check against
* @retval 1 if user is allowed by security-group, 0 if not.
*/
int user_allowed_by_security_group_name(Client *client, char *secgroupname)
{
SecurityGroup *s;
/* Handle the magical 'unknown-users' case. */
if (!strcmp(secgroupname, "unknown-users"))
{
/* This is simply the inverse of 'known-users' */
s = find_security_group("known-users");
if (!s)
return 0; /* that's weird!? pretty impossible. */
return !user_allowed_by_security_group(client, s);
}
/* Find the group and evaluate it */
s = find_security_group(secgroupname);
if (!s)
return 0; /* security group not found: no match */
return user_allowed_by_security_group(client, s);
}

View File

@ -4,7 +4,7 @@ echo "Extracting src/version.c..."
#id=`grep '$Id: Changes,v' ../Changes`
#id=`echo $id |sed 's/.* Changes\,v \(.*\) .* Exp .*/\1/'`
id="5.0.7"
id="5.0.8"
echo "$id"
if test -r version.c

View File

@ -3,7 +3,7 @@
<assemblyIdentity
processorArchitecture="amd64"
name="UnrealIRCd.UnrealIRCd.5"
version="5.0.7.0"
version="5.0.8.0"
type="win32"
/>
<description>Internet Relay Chat Daemon</description>

View File

@ -6,7 +6,7 @@
[Setup]
AppName=UnrealIRCd 5
AppVerName=UnrealIRCd 5.0.7
AppVerName=UnrealIRCd 5.0.8
AppPublisher=UnrealIRCd Team
AppPublisherURL=https://www.unrealircd.org
AppSupportURL=https://www.unrealircd.org
@ -68,6 +68,7 @@ Source: "src\modules\chanmodes\*.dll"; DestDir: "{app}\modules\chanmodes"; Flags
Source: "src\modules\usermodes\*.dll"; DestDir: "{app}\modules\usermodes"; Flags: ignoreversion
Source: "src\modules\snomasks\*.dll"; DestDir: "{app}\modules\snomasks"; Flags: ignoreversion
Source: "src\modules\extbans\*.dll"; DestDir: "{app}\modules\extbans"; Flags: ignoreversion
Source: "src\modules\third\*.dll"; DestDir: "{app}\modules\third"; Flags: ignoreversion skipifsourcedoesntexist
Source: "c:\dev\unrealircd-5-libs\pcre2\bin\pcre*.dll"; DestDir: "{app}\bin"; Flags: ignoreversion
Source: "c:\dev\unrealircd-5-libs\argon2\vs2015\build\*.dll"; DestDir: "{app}\bin"; Flags: ignoreversion