mirror of
git://git.acid.vegas/unrealircd.git
synced 2025-02-07 13:09:05 +00:00
Updated to 6.0.4
This commit is contained in:
parent
e3f051076e
commit
3d97a9500c
2
Config
2
Config
@ -375,7 +375,7 @@ echo "We will now ask you a number of questions. You can just press ENTER to acc
|
||||
echo ""
|
||||
|
||||
# This needs to be updated each release so auto-upgrading works for settings, modules, etc!!:
|
||||
UNREALRELEASES="unrealircd-6.0.2 unrealircd-6.0.1.1 unrealircd-6.0.1 unrealircd-6.0.0 unrealircd-6.0.0-rc2 unrealircd-6.0.0-rc1 unrealircd-6.0.0-beta4 unrealircd-6.0.0-beta3 unrealircd-6.0.0-beta2 unrealircd-6.0.0-beta1 unrealircd-5.2.3 unrealircd-5.2.2 unrealircd-5.2.1.1 unrealircd-5.2.1 unrealircd-5.2.1-rc1 unrealircd-5.2.0.2 unrealircd-5.2.0.1 unrealircd-5.2.0 unrealircd-5.2.0-rc1 unrealircd-5.0.9.1 unrealircd-5.0.9 unrealircd-5.0.9-rc1 unrealircd-5.0.8 unrealircd-5.0.8-rc1 unrealircd-5.0.7 unrealircd-5.0.7-rc1 unrealircd-5.0.6"
|
||||
UNREALRELEASES="unrealircd-6.0.4.1 unrealircd-6.0.4 unrealircd-6.0.4-rc2 unrealircd-6.0.4-rc1 unrealircd-6.0.3 unrealircd-6.0.2 unrealircd-6.0.1.1 unrealircd-6.0.1 unrealircd-6.0.0 unrealircd-6.0.0-rc2 unrealircd-6.0.0-rc1 unrealircd-6.0.0-beta4 unrealircd-6.0.0-beta3 unrealircd-6.0.0-beta2 unrealircd-6.0.0-beta1 unrealircd-5.2.3 unrealircd-5.2.2 unrealircd-5.2.1.1 unrealircd-5.2.1 unrealircd-5.2.1-rc1 unrealircd-5.2.0.2 unrealircd-5.2.0.1 unrealircd-5.2.0 unrealircd-5.2.0-rc1 unrealircd-5.0.9.1 unrealircd-5.0.9 unrealircd-5.0.9-rc1 unrealircd-5.0.8 unrealircd-5.0.8-rc1 unrealircd-5.0.7 unrealircd-5.0.7-rc1 unrealircd-5.0.6"
|
||||
if [ -f "config.settings" ]; then
|
||||
. ./config.settings
|
||||
else
|
||||
|
@ -178,7 +178,7 @@ EXP_OBJ_FILES=src/ircd_vars.obj src/channel.obj src/send.obj src/socket.obj \
|
||||
src/fdlist.obj src/dbuf.obj \
|
||||
src/hash.obj src/parse.obj \
|
||||
src/whowas.obj \
|
||||
src/misc.obj src/match.obj src/crule.obj \
|
||||
src/securitygroup.obj src/misc.obj src/match.obj src/crule.obj \
|
||||
src/debug.obj src/support.obj src/list.obj \
|
||||
src/serv.obj src/user.obj \
|
||||
src/version.obj src/ircsprintf.obj \
|
||||
@ -254,6 +254,7 @@ DLL_FILES=\
|
||||
src/modules/close.dll \
|
||||
src/modules/connect.dll \
|
||||
src/modules/connthrottle.dll \
|
||||
src/modules/creationtime.dll \
|
||||
src/modules/cycle.dll \
|
||||
src/modules/dccallow.dll \
|
||||
src/modules/dccdeny.dll \
|
||||
@ -278,6 +279,7 @@ DLL_FILES=\
|
||||
src/modules/geoip_base.dll \
|
||||
src/modules/geoip_classic.dll \
|
||||
src/modules/geoip_csv.dll \
|
||||
src/modules/geoip-tag.dll \
|
||||
src/modules/globops.dll \
|
||||
src/modules/help.dll \
|
||||
src/modules/hideserver.dll \
|
||||
@ -364,6 +366,7 @@ DLL_FILES=\
|
||||
src/modules/svsnline.dll \
|
||||
src/modules/svsnolag.dll \
|
||||
src/modules/svsnoop.dll \
|
||||
src/modules/svso.dll \
|
||||
src/modules/svspart.dll \
|
||||
src/modules/svssilence.dll \
|
||||
src/modules/svssno.dll \
|
||||
@ -379,6 +382,7 @@ DLL_FILES=\
|
||||
src/modules/trace.dll \
|
||||
src/modules/tsctl.dll \
|
||||
src/modules/typing-indicator.dll \
|
||||
src/modules/channel-context.dll \
|
||||
src/modules/umode2.dll \
|
||||
src/modules/unreal_server_compat.dll \
|
||||
src/modules/unsqline.dll \
|
||||
@ -502,6 +506,9 @@ src/conf_preprocessor.obj: src/conf_preprocessor.c $(INCLUDES)
|
||||
src/debug.obj: src/debug.c $(INCLUDES)
|
||||
$(CC) $(CFLAGS) src/debug.c
|
||||
|
||||
src/securitygroup.obj: src/securitygroup.c $(INCLUDES)
|
||||
$(CC) $(CFLAGS) src/securitygroup.c
|
||||
|
||||
src/misc.obj: src/misc.c $(INCLUDES) ./include/dbuf.h
|
||||
$(CC) $(CFLAGS) src/misc.c
|
||||
|
||||
@ -828,6 +835,9 @@ src/modules/connect.dll: src/modules/connect.c $(INCLUDES)
|
||||
src/modules/connthrottle.dll: src/modules/connthrottle.c $(INCLUDES)
|
||||
$(CC) $(MODCFLAGS) src/modules/connthrottle.c /Fesrc/modules/ /Fosrc/modules/ /Fdsrc/modules/connthrottle.pdb $(MODLFLAGS)
|
||||
|
||||
src/modules/creationtime.dll: src/modules/creationtime.c $(INCLUDES)
|
||||
$(CC) $(MODCFLAGS) src/modules/creationtime.c /Fesrc/modules/ /Fosrc/modules/ /Fdsrc/modules/creationtime.pdb $(MODLFLAGS)
|
||||
|
||||
src/modules/cycle.dll: src/modules/cycle.c $(INCLUDES)
|
||||
$(CC) $(MODCFLAGS) src/modules/cycle.c /Fesrc/modules/ /Fosrc/modules/ /Fdsrc/modules/cycle.pdb $(MODLFLAGS)
|
||||
|
||||
@ -900,6 +910,9 @@ src/modules/geoip_classic.dll: src/modules/geoip_classic.c $(INCLUDES)
|
||||
src/modules/geoip_csv.dll: src/modules/geoip_csv.c $(INCLUDES)
|
||||
$(CC) $(MODCFLAGS) src/modules/geoip_csv.c /Fesrc/modules/ /Fosrc/modules/ /Fdsrc/modules/geoip_csv.pdb $(MODLFLAGS)
|
||||
|
||||
src/modules/geoip-tag.dll: src/modules/geoip-tag.c $(INCLUDES)
|
||||
$(CC) $(MODCFLAGS) src/modules/geoip-tag.c /Fesrc/modules/ /Fosrc/modules/ /Fdsrc/modules/geoip-tag.pdb $(MODLFLAGS)
|
||||
|
||||
src/modules/geoip_maxmind.dll: src/modules/geoip_maxmind.c $(INCLUDES)
|
||||
$(CC) $(MODCFLAGS) src/modules/geoip_maxmind.c /Fesrc/modules/ /Fosrc/modules/ /Fdsrc/modules/geoip_maxmind.pdb $(MODLFLAGS)
|
||||
|
||||
@ -1161,6 +1174,9 @@ src/modules/svsnolag.dll: src/modules/svsnolag.c $(INCLUDES)
|
||||
src/modules/svsnoop.dll: src/modules/svsnoop.c $(INCLUDES)
|
||||
$(CC) $(MODCFLAGS) src/modules/svsnoop.c /Fesrc/modules/ /Fosrc/modules/ /Fdsrc/modules/svsnoop.pdb $(MODLFLAGS)
|
||||
|
||||
src/modules/svso.dll: src/modules/svso.c $(INCLUDES)
|
||||
$(CC) $(MODCFLAGS) src/modules/svso.c /Fesrc/modules/ /Fosrc/modules/ /Fdsrc/modules/svso.pdb $(MODLFLAGS)
|
||||
|
||||
src/modules/svspart.dll: src/modules/svspart.c $(INCLUDES)
|
||||
$(CC) $(MODCFLAGS) src/modules/svspart.c /Fesrc/modules/ /Fosrc/modules/ /Fdsrc/modules/svspart.pdb $(MODLFLAGS)
|
||||
|
||||
@ -1206,6 +1222,9 @@ src/modules/tsctl.dll: src/modules/tsctl.c $(INCLUDES)
|
||||
src/modules/typing-indicator.dll: src/modules/typing-indicator.c $(INCLUDES)
|
||||
$(CC) $(MODCFLAGS) src/modules/typing-indicator.c /Fesrc/modules/ /Fosrc/modules/ /Fdsrc/modules/typing-indicator.pdb $(MODLFLAGS)
|
||||
|
||||
src/modules/channel-context.dll: src/modules/channel-context.c $(INCLUDES)
|
||||
$(CC) $(MODCFLAGS) src/modules/channel-context.c /Fesrc/modules/ /Fosrc/modules/ /Fdsrc/modules/channel-context.pdb $(MODLFLAGS)
|
||||
|
||||
src/modules/umode2.dll: src/modules/umode2.c $(INCLUDES)
|
||||
$(CC) $(MODCFLAGS) src/modules/umode2.c /Fesrc/modules/ /Fosrc/modules/ /Fdsrc/modules/umode2.pdb $(MODLFLAGS)
|
||||
|
||||
|
15
README.md
15
README.md
@ -13,10 +13,17 @@ online documentation.
|
||||
* UnrealIRCd 6 is the *stable* series since December 2021. All new features go in there.
|
||||
* UnrealIRCd 5 is the *oldstable* series. It will receive bug fixes until
|
||||
July 1, 2022 plus another 12 months of security fixes.
|
||||
* For full details of release scheduling and EOL dates, see
|
||||
[UnrealIRCd releases](https://www.unrealircd.org/docs/UnrealIRCd_releases) on the wiki
|
||||
|
||||
## How to get started
|
||||
Please consult our excellent online documentation at https://www.unrealircd.org/docs/
|
||||
when setting up the IRCd!
|
||||
### Use the wiki!
|
||||
**IMPORTANT:** We recommend you follow our installation guide on the wiki instead of the
|
||||
steps in this README. The wiki has more detailed information and is more easy to navigate.
|
||||
* [Installing from source for *NIX](https://www.unrealircd.org/docs/Installing_from_source)
|
||||
* [Installating instructions for Windows](https://www.unrealircd.org/docs/Installing_(Windows))
|
||||
|
||||
Please consult the online documentation at https://www.unrealircd.org/docs/ when setting up the IRCd!
|
||||
|
||||
### Step 1: Installation
|
||||
#### Windows
|
||||
@ -36,11 +43,11 @@ Do the following steps under a separate account for running UnrealIRCd,
|
||||
* Now change to the directory where you installed UnrealIRCd, e.g. `cd /home/xxxx/unrealircd`
|
||||
|
||||
### Step 2: Configuration
|
||||
Configuration files are stored in the conf/ folder by default (eg: /home/xxxx/unrealircd/conf)
|
||||
Configuration files are stored in the `conf/` folder by default (eg: `/home/xxxx/unrealircd/conf`)
|
||||
|
||||
#### Create a configuration file
|
||||
If you are new, then you need to create your own configuration file:
|
||||
Copy conf/examples/example.conf to conf/ and call it unrealircd.conf.
|
||||
Copy `conf/examples/example.conf` to `conf/` and call it `unrealircd.conf`.
|
||||
Then open it in an editor and carefully modify it using the documentation and FAQ as a guide (see below).
|
||||
|
||||
### Step 3: Booting
|
||||
|
70
configure
vendored
70
configure
vendored
@ -1,6 +1,6 @@
|
||||
#! /bin/sh
|
||||
# Guess values for system-dependent variables and create Makefiles.
|
||||
# Generated by GNU Autoconf 2.69 for unrealircd 6.0.3.
|
||||
# Generated by GNU Autoconf 2.69 for unrealircd 6.0.4.2.
|
||||
#
|
||||
# Report bugs to <https://bugs.unrealircd.org/>.
|
||||
#
|
||||
@ -580,8 +580,8 @@ MAKEFLAGS=
|
||||
# Identity of this package.
|
||||
PACKAGE_NAME='unrealircd'
|
||||
PACKAGE_TARNAME='unrealircd'
|
||||
PACKAGE_VERSION='6.0.3'
|
||||
PACKAGE_STRING='unrealircd 6.0.3'
|
||||
PACKAGE_VERSION='6.0.4.2'
|
||||
PACKAGE_STRING='unrealircd 6.0.4.2'
|
||||
PACKAGE_BUGREPORT='https://bugs.unrealircd.org/'
|
||||
PACKAGE_URL='https://unrealircd.org/'
|
||||
|
||||
@ -1347,7 +1347,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 6.0.3 to adapt to many kinds of systems.
|
||||
\`configure' configures unrealircd 6.0.4.2 to adapt to many kinds of systems.
|
||||
|
||||
Usage: $0 [OPTION]... [VAR=VALUE]...
|
||||
|
||||
@ -1413,7 +1413,7 @@ fi
|
||||
|
||||
if test -n "$ac_init_help"; then
|
||||
case $ac_init_help in
|
||||
short | recursive ) echo "Configuration of unrealircd 6.0.3:";;
|
||||
short | recursive ) echo "Configuration of unrealircd 6.0.4.2:";;
|
||||
esac
|
||||
cat <<\_ACEOF
|
||||
|
||||
@ -1589,7 +1589,7 @@ fi
|
||||
test -n "$ac_init_help" && exit $ac_status
|
||||
if $ac_init_version; then
|
||||
cat <<\_ACEOF
|
||||
unrealircd configure 6.0.3
|
||||
unrealircd configure 6.0.4.2
|
||||
generated by GNU Autoconf 2.69
|
||||
|
||||
Copyright (C) 2012 Free Software Foundation, Inc.
|
||||
@ -1958,7 +1958,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 6.0.3, which was
|
||||
It was created by unrealircd $as_me 6.0.4.2, which was
|
||||
generated by GNU Autoconf 2.69. Invocation command line was
|
||||
|
||||
$ $0 $@
|
||||
@ -2366,7 +2366,7 @@ _ACEOF
|
||||
|
||||
|
||||
# Minor version number (e.g.: Z in X.Y.Z)
|
||||
UNREAL_VERSION_MINOR="3"
|
||||
UNREAL_VERSION_MINOR="4"
|
||||
|
||||
cat >>confdefs.h <<_ACEOF
|
||||
#define UNREAL_VERSION_MINOR $UNREAL_VERSION_MINOR
|
||||
@ -2376,7 +2376,7 @@ _ACEOF
|
||||
# The version suffix such as a beta marker or release candidate
|
||||
# marker. (e.g.: -rcX for unrealircd-3.2.9-rcX). This macro is a
|
||||
# string instead of an integer because it contains arbitrary data.
|
||||
UNREAL_VERSION_SUFFIX=""
|
||||
UNREAL_VERSION_SUFFIX=".2"
|
||||
|
||||
cat >>confdefs.h <<_ACEOF
|
||||
#define UNREAL_VERSION_SUFFIX "$UNREAL_VERSION_SUFFIX"
|
||||
@ -5638,6 +5638,54 @@ ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $
|
||||
ac_compiler_gnu=$ac_cv_c_compiler_gnu
|
||||
|
||||
|
||||
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
|
||||
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether C compiler accepts -Wformat-overflow" >&5
|
||||
$as_echo_n "checking whether C compiler accepts -Wformat-overflow... " >&6; }
|
||||
if ${ax_cv_check_cflags__Werror___Wformat_overflow+:} false; then :
|
||||
$as_echo_n "(cached) " >&6
|
||||
else
|
||||
|
||||
ax_check_save_flags=$CFLAGS
|
||||
CFLAGS="$CFLAGS -Werror -Wformat-overflow"
|
||||
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
|
||||
/* end confdefs.h. */
|
||||
|
||||
int
|
||||
main ()
|
||||
{
|
||||
|
||||
;
|
||||
return 0;
|
||||
}
|
||||
_ACEOF
|
||||
if ac_fn_c_try_compile "$LINENO"; then :
|
||||
ax_cv_check_cflags__Werror___Wformat_overflow=yes
|
||||
else
|
||||
ax_cv_check_cflags__Werror___Wformat_overflow=no
|
||||
fi
|
||||
rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
|
||||
CFLAGS=$ax_check_save_flags
|
||||
fi
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ax_cv_check_cflags__Werror___Wformat_overflow" >&5
|
||||
$as_echo "$ax_cv_check_cflags__Werror___Wformat_overflow" >&6; }
|
||||
if test x"$ax_cv_check_cflags__Werror___Wformat_overflow" = xyes; then :
|
||||
CFLAGS="$CFLAGS -Wno-format-overflow"
|
||||
else
|
||||
:
|
||||
fi
|
||||
|
||||
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
|
||||
|
||||
|
||||
ac_ext=c
|
||||
ac_cpp='$CPP $CPPFLAGS'
|
||||
ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
|
||||
@ -9414,7 +9462,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 6.0.3, which was
|
||||
This file was extended by unrealircd $as_me 6.0.4.2, which was
|
||||
generated by GNU Autoconf 2.69. Invocation command line was
|
||||
|
||||
CONFIG_FILES = $CONFIG_FILES
|
||||
@ -9477,7 +9525,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 6.0.3
|
||||
unrealircd config.status 6.0.4.2
|
||||
configured by $0, generated by GNU Autoconf 2.69,
|
||||
with options \\"\$ac_cs_config\\"
|
||||
|
||||
|
@ -7,7 +7,7 @@ dnl src/windows/unrealinst.iss
|
||||
dnl doc/Config.header
|
||||
dnl src/version.c.SH
|
||||
|
||||
AC_INIT([unrealircd], [6.0.3], [https://bugs.unrealircd.org/], [], [https://unrealircd.org/])
|
||||
AC_INIT([unrealircd], [6.0.4.2], [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,13 +34,13 @@ 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=["3"]
|
||||
UNREAL_VERSION_MINOR=["4"]
|
||||
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
|
||||
# marker. (e.g.: -rcX for unrealircd-3.2.9-rcX). This macro is a
|
||||
# string instead of an integer because it contains arbitrary data.
|
||||
UNREAL_VERSION_SUFFIX=[""]
|
||||
UNREAL_VERSION_SUFFIX=[".2"]
|
||||
AC_DEFINE_UNQUOTED([UNREAL_VERSION_SUFFIX], ["$UNREAL_VERSION_SUFFIX"], [Version suffix such as a beta marker or release candidate marker. (e.g.: -rcX for unrealircd-3.2.9-rcX)])
|
||||
|
||||
AC_PATH_PROG(RM,rm)
|
||||
@ -237,6 +237,8 @@ check_cc_flag([-Wformat-zero-length], [CFLAGS="$CFLAGS -Wno-format-zero-length"]
|
||||
|
||||
check_cc_flag([-Wformat-truncation], [CFLAGS="$CFLAGS -Wno-format-truncation"])
|
||||
|
||||
check_cc_flag([-Wformat-overflow], [CFLAGS="$CFLAGS -Wno-format-overflow"])
|
||||
|
||||
dnl While it can be useful to occasionally to compile with warnings about
|
||||
dnl unused variables and parameters, we often 'think ahead' when coding things
|
||||
dnl so they may be useless now but not later. Similarly, for variables, we
|
||||
|
@ -7,7 +7,7 @@
|
||||
\___/|_| |_|_| \___|\__,_|_|\___/\_| \_| \____/\__,_|
|
||||
|
||||
Configuration Program
|
||||
for UnrealIRCd 6.0.3
|
||||
for UnrealIRCd 6.0.4.2
|
||||
|
||||
This program will help you to compile your IRC server, and ask you
|
||||
questions regarding the compile-time settings of it during the process.
|
||||
|
@ -1,15 +1,183 @@
|
||||
UnrealIRCd 6.0.3
|
||||
=================
|
||||
UnrealIRCd 6.0.4.2
|
||||
===================
|
||||
Another small update to 6.0.4.x:
|
||||
|
||||
A number of serious issues were discovered in UnrealIRCd 6. Among these is
|
||||
an issue which will likely crash the IRCd sooner or later if you /REHASH
|
||||
with any active clients connected.
|
||||
We suggest everyone who is running UnrealIRCd 6 to upgrade to 6.0.3.
|
||||
* Fix crash when linking. This requires a certain sequence of events: first
|
||||
a server is linked in successfully, then we need to REHASH, and then a new
|
||||
link attempt has to come in with the same server name (for example because
|
||||
there is a network issue and the old link has not timed out yet).
|
||||
If all that happens, then an UnreaIRCd 6 server may crash, but not always.
|
||||
* Two IRCv3 specifications were ratified which we already supported as drafts:
|
||||
* Change CAP `draft/extended-monitor` to `extended-monitor`
|
||||
* Add message-tag `bot` next to existing (for now) `draft/bot`
|
||||
* Update Turkish translations
|
||||
|
||||
UnrealIRCd 6.0.4.1
|
||||
===================
|
||||
This is a small update to 6.0.4. It fixes the following issues that were
|
||||
present in all 6.0.x versions:
|
||||
|
||||
* Fix sporadic crash when linking a server (after successful authentication).
|
||||
This feels like a compiler bug. It affected only some people with GCC and
|
||||
only in some situations. When compiled with clang there was no problem.
|
||||
Hopefully we can work around it this way.
|
||||
* Make /INVITE bypass (nearly) all channel mode restrictions, as it used to
|
||||
be in UnrealIRCd 5.x. Both for invites by channel ops and for OperOverride.
|
||||
This also fixes a bug where an IRCOp with OperOverride could not bypass +l
|
||||
(limit) and other restrictions and would have to resort back to using
|
||||
MODE or SAMODE. Only +b and +i could be bypassed via INVITE OperOverride.
|
||||
|
||||
UnrealIRCd 6.0.4
|
||||
-----------------
|
||||
This release comes with lots of features and enhancements. In particular,
|
||||
security groups and mask items now allow you to write cleaner and more
|
||||
flexible configuration files. There are also JSON logging enhancements and
|
||||
several bug fixes. Thanks a lot to everyone who tested the release candidates!
|
||||
|
||||
If you are already running UnrealIRCd 6 then read below. Otherwise, jump
|
||||
straight to the [summary about UnrealIRCd 6](#Summary) to learn more
|
||||
about UnrealIRCd 6.
|
||||
|
||||
### Enhancements:
|
||||
* Show security groups in `WHOIS`
|
||||
* The [security-group block](https://www.unrealircd.org/docs/Security-group_block)
|
||||
has been expanded and the same functionality is now available in
|
||||
[mask items](https://www.unrealircd.org/docs/Mask_item) too:
|
||||
* This means the existing options like `identified`, `webirc`, `tls` and
|
||||
`reputation-score` can be used in `allow::mask` etc.
|
||||
* New options (in both security-group and mask) are:
|
||||
* `connect-time`: time a user is connected to IRC
|
||||
* `security-group`: to check another security group
|
||||
* `account`: services account name
|
||||
* `country`: country code, as found by GeoIP
|
||||
* `realname`: realname (gecos) of the user
|
||||
* `certfp`: certificate fingerprint
|
||||
* Every option also has an exclude- variant, eg. `exclude-country`.
|
||||
If a user matches any `exclude-` option then it is considered not a match.
|
||||
* The modules [connthrottle](https://www.unrealircd.org/docs/Connthrottle),
|
||||
[restrict-commands](https://www.unrealircd.org/docs/Set_block#set::restrict-commands)
|
||||
and [antirandom](https://www.unrealircd.org/docs/Set_block#set::antirandom)
|
||||
now use the new `except` sub-block which is a mask item. The old syntax
|
||||
(eg <code>set::antirandom::except-webirc</code>) is still accepted by UnrealIRCd
|
||||
and converted to the appropriate new setting behind the scenes
|
||||
(<code>set::antirandom::except::webirc</code>).
|
||||
* The modules [blacklist](https://www.unrealircd.org/docs/Blacklist_block)
|
||||
and [antimixedutf8](https://www.unrealircd.org/docs/Set_block#set::antimixedutf8)
|
||||
now also support the `except` block (a mask item).
|
||||
* Other than that the extended functionality is available in these blocks:
|
||||
`allow`, `oper`, `tld`, `vhost`, `deny channel`, `allow channel`.
|
||||
* Example of direct use in a ::mask item:
|
||||
```
|
||||
/* Spanish MOTD for Spanish speaking countries */
|
||||
tld {
|
||||
mask { country { ES; AR; BO; CL; CO; CR; DO; EC; SV; GT; HN; MX; NI; PA; PY; PE; PR; UY; VE; } }
|
||||
motd "motd.es.txt";
|
||||
rules "rules.es.txt";
|
||||
}
|
||||
```
|
||||
* Example of defining a security group and using it in a mask item later:
|
||||
```
|
||||
security-group irccloud {
|
||||
mask { ip1; ip2; ip3; ip4; }
|
||||
}
|
||||
allow {
|
||||
mask { security-group irccloud; }
|
||||
class clients;
|
||||
maxperip 128;
|
||||
}
|
||||
except ban {
|
||||
mask { security-group irccloud; }
|
||||
type { blacklist; connect-flood; handshake-data-flood; }
|
||||
}
|
||||
```
|
||||
* Because the mask item is so powerful now, the `password` in the
|
||||
[oper block](https://www.unrealircd.org/docs/Oper_block) is optional now.
|
||||
* We now support oper::auto-login, which means the user will become IRCOp
|
||||
automatically if they match the conditions on-connect. This can be used
|
||||
in combination with
|
||||
[certificate fingerprint](https://www.unrealircd.org/docs/Certificate_fingerprint)
|
||||
authentication for example:
|
||||
```
|
||||
security-group Syzop { certfp "1234etc."; }
|
||||
oper Syzop {
|
||||
auto-login yes;
|
||||
mask { security-group Syzop; }
|
||||
operclass netadmin-with-override;
|
||||
class opers;
|
||||
}
|
||||
except ban {
|
||||
mask { security-group Syzop; }
|
||||
type all;
|
||||
}
|
||||
```
|
||||
* For [JSON logging](https://www.unrealircd.org/docs/JSON_logging) a number
|
||||
of fields were added when a client is expanded:
|
||||
* `geoip`: with subitem `country_code` (eg. `NL`)
|
||||
* `tls`: with subitems `cipher` and `certfp`
|
||||
* Under subitem `users`:
|
||||
* `vhost`: if the visible host differs from the realhost then this is
|
||||
set (thus for both vhost and cloaked host)
|
||||
* `cloakedhost`: this is always set (except for eg. services users), even
|
||||
if the user is not cloaked so you can easily search on a cloaked host.
|
||||
* `idle_since`: last time the user has spoken (local clients only)
|
||||
* `channels`: list of channels (array), with a maximum of 384 chars.
|
||||
* The JSON logging now also strips ASCII below 32, so color- and
|
||||
control codes.
|
||||
* Support IRCv3 `+draft/channel-context`
|
||||
* Add `example.es.conf` (Spanish example configuration file)
|
||||
* The country of users is now communicated in the
|
||||
[message-tag](https://www.unrealircd.org/docs/Message_tags)
|
||||
`unrealircd.org/geoip` (only to IRCOps).
|
||||
* Add support for linking servers via UNIX domain sockets
|
||||
(`link::outgoing::file`).
|
||||
|
||||
### Fixes:
|
||||
* Crash in `except ban` with `~security-group:xyz`
|
||||
* Crash if hideserver module was loaded but `LINKS` was not blocked.
|
||||
* Crash on Windows when using the "Rehash" GUI option.
|
||||
* Infinite loop if one security-group referred to another.
|
||||
* Duplicate entries in the `+beI` lists of `+P` channels.
|
||||
* Regular users were able to -o a service bot (that has umode +S)
|
||||
* Module manager did not stop on compile error
|
||||
* [`set::modes-on-join`](https://www.unrealircd.org/docs/Set_block#set::modes-on-join)
|
||||
did not work with `+f` + timed bans properly, eg `[3t#b1]:10`
|
||||
* Several log messages were missing some information.
|
||||
* Reputation syncing across servers had a small glitch. Fix is mostly
|
||||
useful for servers that were not linked to the network for days or weeks.
|
||||
|
||||
### Changes:
|
||||
* Clarified that UnrealIRCd is licensed as "GPLv2 or later"
|
||||
* Fix use of variables in
|
||||
[`set::reject-message](https://www.unrealircd.org/docs/Set_block#set::reject-message)
|
||||
and in [`blacklist::reason](https://www.unrealircd.org/docs/Blacklist_block):
|
||||
previously short forms of variables were (unintentionally) expanded
|
||||
as well, such as `$serv` for `$server`. This is no longer supported, you need
|
||||
to use the correct full variable names.
|
||||
|
||||
### Developers and protocol:
|
||||
* The `creationtime` is now communicated of users. Until now this
|
||||
information was only known locally (the thing that was communicated
|
||||
that came close was "last nick change" but that is not the same).
|
||||
This is synced via (early) moddata across servers.
|
||||
Module coders can use `get_connected_time()`.
|
||||
* The `RPL_HOSTHIDDEN` is now sent from `userhost_changed()` so you
|
||||
don't explicitly send it yourself anymore.
|
||||
* The `SVSO` command is back, so services can make people IRCOp again.
|
||||
See `HELPOP SVSO` or [the commit](https://github.com/unrealircd/unrealircd/commit/50e5d91c798e7d07ca0c68d9fca302a6b6610786)
|
||||
for more information.
|
||||
* Due to last change the `HOOKTYPE_LOCAL_OPER` parameters were changed.
|
||||
* Module coders can enhance the
|
||||
[JSON logging](https://www.unrealircd.org/docs/JSON_logging)
|
||||
expansion items for clients and channels via new hooks like
|
||||
`HOOKTYPE_JSON_EXPAND_CLIENT`. This is used by the geoip and tls modules.
|
||||
|
||||
UnrealIRCd 6.0.3
|
||||
-----------------
|
||||
A number of serious issues were discovered in UnrealIRCd 6. Among these is
|
||||
an issue which will likely crash the IRCd sooner or later if you /REHASH
|
||||
with any active clients connected.
|
||||
We suggest everyone who is running UnrealIRCd 6 to upgrade to 6.0.3.
|
||||
|
||||
Fixes:
|
||||
* Crash in `WATCH` if the IRCd has been rehashed at least once. After doing
|
||||
a `REHASH` with active clients it will likely corrupt memory. It may take
|
||||
|
@ -74,11 +74,13 @@ loadmodule "setident";
|
||||
loadmodule "squit";
|
||||
loadmodule "stats";
|
||||
loadmodule "tkl";
|
||||
loadmodule "tline";
|
||||
loadmodule "trace";
|
||||
loadmodule "tsctl";
|
||||
loadmodule "unsqline";
|
||||
|
||||
// Server-2-Server Commands
|
||||
loadmodule "creationtime";
|
||||
loadmodule "eos";
|
||||
loadmodule "md";
|
||||
loadmodule "netinfo";
|
||||
@ -97,6 +99,7 @@ loadmodule "sendsno";
|
||||
loadmodule "sendumode";
|
||||
loadmodule "svsjoin";
|
||||
loadmodule "svskill";
|
||||
loadmodule "svslogin";
|
||||
loadmodule "svslusers";
|
||||
loadmodule "svsmode";
|
||||
loadmodule "svsmotd";
|
||||
@ -172,12 +175,13 @@ loadmodule "extbans/quiet"; /* +b ~quiet */
|
||||
loadmodule "extbans/textban"; /* +b ~text */
|
||||
loadmodule "extbans/timedban"; /* +b ~time */
|
||||
loadmodule "extbans/securitygroup"; /* +b ~security-group */
|
||||
|
||||
e
|
||||
// IRCv3 Extensions
|
||||
loadmodule "account-notify";
|
||||
loadmodule "account-tag";
|
||||
loadmodule "batch";
|
||||
loadmodule "bot-tag";
|
||||
loadmodule "channel-context";
|
||||
loadmodule "chathistory";
|
||||
loadmodule "clienttagdeny";
|
||||
loadmodule "echo-message";
|
||||
@ -200,6 +204,7 @@ loadmodule "blacklist";
|
||||
loadmodule "certfp";
|
||||
loadmodule "channeldb";
|
||||
loadmodule "charsys";
|
||||
loadmodule "connect-flood";
|
||||
loadmodule "connthrottle";
|
||||
#loadmodule "geoip_base";
|
||||
#loadmodule "geoip_classic";
|
||||
@ -209,6 +214,7 @@ loadmodule "history_backend_mem";
|
||||
loadmodule "ident_lookup";
|
||||
loadmodule "jointhrottle";
|
||||
loadmodule "json-log-tag";
|
||||
loadmodule "max-unknown-connections-per-ip";
|
||||
loadmodule "targetfloodprot";
|
||||
loadmodule "tkldb";
|
||||
loadmodule "tls_antidos";
|
||||
@ -220,4 +226,5 @@ loadmodule "restrict-commands";
|
||||
loadmodule "rmtkl";
|
||||
loadmodule "watch-backend";
|
||||
#loadmodule "webirc";
|
||||
#loadmodule "webserver";
|
||||
#loadmodule "websocket";
|
@ -1,4 +1,5 @@
|
||||
oper acidvegas {
|
||||
auto-login yes;
|
||||
mask localhost;
|
||||
password "REDACTED" { sslclientcertfp; }
|
||||
class clients;
|
||||
|
@ -1,4 +1,12 @@
|
||||
admin { ""; }
|
||||
@define $VOID "8,4 E N T E R T H E V O I D ";
|
||||
|
||||
admin {
|
||||
"4Administrator: Brandon Brown 14(aka MRCHATS) 6branbran89@supernets.org";
|
||||
" 4Moderator: Bristopher Manning 14(aka delorean) 6simpsonsfan95@supernets.org";
|
||||
" 4Sales: Branthony Bronson 14(aka pyrex) 6showercaphandgun@supernets.org";
|
||||
"";
|
||||
"Feel free to chat with us in #5000 for network help & support!";
|
||||
}
|
||||
|
||||
alias botserv { type services; }
|
||||
alias bs { target botserv; type services; }
|
||||
@ -60,7 +68,7 @@ blacklist dronebl {
|
||||
}
|
||||
action gzline;
|
||||
ban-time 30d;
|
||||
reason "8,4 E N T E R T H E V O I D ";
|
||||
reason "$VOID";
|
||||
}
|
||||
|
||||
blacklist efnetrbl {
|
||||
@ -71,7 +79,7 @@ blacklist efnetrbl {
|
||||
}
|
||||
action gzline;
|
||||
ban-time 30d;
|
||||
reason "8,4 E N T E R T H E V O I D ";
|
||||
reason "$VOID";
|
||||
}
|
||||
|
||||
blacklist torbl {
|
||||
@ -82,7 +90,7 @@ blacklist torbl {
|
||||
}
|
||||
action gzline;
|
||||
ban-time 30d;
|
||||
reason "8,4 E N T E R T H E V O I D ";
|
||||
reason "$VOID";
|
||||
}
|
||||
|
||||
set {
|
||||
@ -96,13 +104,13 @@ set {
|
||||
restrict-usermodes "ips";
|
||||
restrict-channelmodes "nLpPs";
|
||||
restrict-commands {
|
||||
channel-message { connect-delay 60; exempt-identified yes; exempt-reputation-score 100; }
|
||||
channel-notice { connect-delay 60; exempt-identified yes; exempt-reputation-score 100; }
|
||||
invite { connect-delay 300; exempt-identified yes; exempt-reputation-score 100; }
|
||||
join { connect-delay 15; exempt-identified yes; exempt-reputation-score 100; }
|
||||
list { connect-delay 30; exempt-identified yes; exempt-reputation-score 100; }
|
||||
private-message { connect-delay 300; exempt-identified yes; exempt-reputation-score 100; }
|
||||
private-notice { connect-delay 300; exempt-identified yes; exempt-reputation-score 100; }
|
||||
channel-message { connect-time 60; identified yes; reputation-score 100; }
|
||||
channel-notice { connect-time 60; identified yes; reputation-score 100; }
|
||||
invite { connect-time 300; identified yes; reputation-score 100; }
|
||||
join { connect-time 15; identified yes; reputation-score 100; }
|
||||
list { connect-time 30; identified yes; reputation-score 100; }
|
||||
private-message { connect-time 300; identified yes; reputation-score 100; }
|
||||
private-notice { connect-time 300; identified yes; reputation-score 100; }
|
||||
}
|
||||
auto-join "#superbowl";
|
||||
static-quit "EMO-QUIT";
|
||||
@ -145,14 +153,14 @@ set {
|
||||
ban-action gzline;
|
||||
ban-time 1h;
|
||||
}
|
||||
#target-flood {
|
||||
# channel-notice 15:5;
|
||||
# channel-privmsg 45:5;
|
||||
# channel-tagmsg 15:5;
|
||||
# private-notice 10:5;
|
||||
# private-privmsg 30:5;
|
||||
# private-tagmsg 10:5;
|
||||
#}
|
||||
target-flood {
|
||||
channel-notice 15:5;
|
||||
channel-privmsg 45:5;
|
||||
channel-tagmsg 15:5;
|
||||
private-notice 10:5;
|
||||
private-privmsg 30:5;
|
||||
private-tagmsg 10:5;
|
||||
}
|
||||
}
|
||||
known-users {
|
||||
away-flood 3:300;
|
||||
@ -185,29 +193,29 @@ set {
|
||||
modef-default-unsettime 5;
|
||||
spamfilter {
|
||||
ban-time 1d;
|
||||
ban-reason "8,4 E N T E R T H E V O I D ";
|
||||
ban-reason "$VOID";
|
||||
except "#anythinggoes";
|
||||
}
|
||||
max-targets-per-command { kick 1; part 1; privmsg 1; }
|
||||
hide-ban-reason yes;
|
||||
reject-message {
|
||||
gline "8,4 E N T E R T H E V O I D ";
|
||||
kline "8,4 E N T E R T H E V O I D ";
|
||||
password-mismatch "8,4 E N T E R T H E V O I D ";
|
||||
server-full "8,4 E N T E R T H E V O I D ";
|
||||
too-many-connections "8,4 E N T E R T H E V O I D ";
|
||||
unauthorized "8,4 E N T E R T H E V O I D ";
|
||||
gline "$VOID";
|
||||
kline "$VOID";
|
||||
password-mismatch "$VOID";
|
||||
server-full "$VOID";
|
||||
too-many-connections "$VOID";
|
||||
unauthorized "$VOID";
|
||||
}
|
||||
antimixedutf8 {
|
||||
score 8;
|
||||
ban-action block;
|
||||
ban-reason "8,4 E N T E R T H E V O I D ";
|
||||
ban-reason "$VOID";
|
||||
}
|
||||
connthrottle {
|
||||
known-users { minimum-reputation-score 100; sasl-bypass yes; }
|
||||
except { reputation-score 100; identified yes; webirc yes; }
|
||||
new-users { local-throttle 20:60; global-throttle 30:60; }
|
||||
disabled-when { reputation-gathering 1w; start-delay 3m; }
|
||||
reason "8,4 E N T E R T H E V O I D ";
|
||||
reason "$VOID";
|
||||
}
|
||||
history {
|
||||
channel {
|
||||
@ -244,8 +252,8 @@ set {
|
||||
hideserver {
|
||||
disable-map yes;
|
||||
disable-links yes;
|
||||
map-deny-message "8,4 E N T E R T H E V O I D ";
|
||||
links-deny-message "8,4 E N T E R T H E V O I D ";
|
||||
map-deny-message "$VOID";
|
||||
links-deny-message "$VOID";
|
||||
}
|
||||
|
||||
security-group known-users {
|
||||
|
@ -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 = 6.0.3
|
||||
PROJECT_NUMBER = 6.0.4.2
|
||||
|
||||
# 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
|
||||
|
@ -119,5 +119,5 @@ fi
|
||||
chmod +x unrealircd-upgrade-script.stage2
|
||||
./unrealircd-upgrade-script.stage2 $*
|
||||
SAVERET="$?"
|
||||
rm -f unrealircd-upgrade-script.stage2 unrealircd-upgrade-script.stage2
|
||||
rm -f unrealircd-upgrade-script.stage2 unrealircd-upgrade-script.stage2.asc
|
||||
exit $SAVERET
|
||||
|
@ -123,7 +123,7 @@
|
||||
* Common usage for this are: a trusted bot ran by an IRCOp, that you only
|
||||
* want to give "flood access" and nothing else, and other such things.
|
||||
*/
|
||||
#define FAKELAG_CONFIGURABLE
|
||||
//#undef FAKELAG_CONFIGURABLE
|
||||
|
||||
/* The default value for class::sendq */
|
||||
#define DEFAULT_SENDQ 3000000
|
||||
|
57
include/h.h
57
include/h.h
@ -111,7 +111,6 @@ extern MODVAR ConfigItem_deny_version *conf_deny_version;
|
||||
extern MODVAR ConfigItem_alias *conf_alias;
|
||||
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);
|
||||
@ -677,6 +676,7 @@ extern void unreal_setfilemodtime(const char *filename, time_t mtime);
|
||||
extern void DeleteTempModules(void);
|
||||
extern MODVAR Extban *extbaninfo;
|
||||
extern Extban *findmod_by_bantype(const char *str, const char **remainder);
|
||||
extern Extban *findmod_by_bantype_raw(const char *str, int ban_name_length);
|
||||
extern Extban *ExtbanAdd(Module *reserved, ExtbanInfo req);
|
||||
extern void ExtbanDel(Extban *);
|
||||
extern void extban_init(void);
|
||||
@ -749,7 +749,8 @@ extern MODVAR const char *(*tkl_type_string)(TKL *tk);
|
||||
extern MODVAR const char *(*tkl_type_config_string)(TKL *tk);
|
||||
extern MODVAR TKL *(*tkl_add_serverban)(int type, const char *usermask, const char *hostmask, const char *reason, const char *setby,
|
||||
time_t expire_at, time_t set_at, int soft, int flags);
|
||||
extern MODVAR TKL *(*tkl_add_banexception)(int type, const char *usermask, const char *hostmask, const char *reason, const char *set_by,
|
||||
extern MODVAR TKL *(*tkl_add_banexception)(int type, const char *usermask, const char *hostmask, SecurityGroup *match,
|
||||
const char *reason, const char *set_by,
|
||||
time_t expire_at, time_t set_at, int soft, const char *bantypes, int flags);
|
||||
extern MODVAR TKL *(*tkl_add_nameban)(int type, const char *name, int hold, const char *reason, const char *setby,
|
||||
time_t expire_at, time_t set_at, int flags);
|
||||
@ -779,10 +780,9 @@ extern MODVAR int (*match_spamfilter)(Client *client, const char *str_in, int ty
|
||||
extern MODVAR int (*match_spamfilter_mtags)(Client *client, MessageTag *mtags, const char *cmd);
|
||||
extern MODVAR int (*join_viruschan)(Client *client, TKL *tk, int type);
|
||||
extern MODVAR const char *(*StripColors)(const char *text);
|
||||
extern MODVAR const char *(*StripControlCodes)(const char *text);
|
||||
extern MODVAR void (*spamfilter_build_user_string)(char *buf, const char *nick, Client *acptr);
|
||||
extern MODVAR void (*send_protoctl_servers)(Client *client, int response);
|
||||
extern MODVAR int (*verify_link)(Client *client, ConfigItem_link **link_out);
|
||||
extern MODVAR ConfigItem_link *(*verify_link)(Client *client);
|
||||
extern MODVAR void (*send_server_message)(Client *client);
|
||||
extern MODVAR void (*broadcast_md_client)(ModDataInfo *mdi, Client *acptr, ModData *md);
|
||||
extern MODVAR void (*broadcast_md_channel)(ModDataInfo *mdi, Channel *channel, ModData *md);
|
||||
@ -834,6 +834,8 @@ extern MODVAR char *(*tkl_uhost)(TKL *tkl, char *buf, size_t buflen, int options
|
||||
extern MODVAR void (*do_unreal_log_remote_deliver)(LogLevel loglevel, const char *subsystem, const char *event_id, MultiLine *msg, const char *json_serialized);
|
||||
extern MODVAR char *(*get_chmodes_for_user)(Client *client, const char *flags);
|
||||
extern MODVAR WhoisConfigDetails (*whois_get_policy)(Client *client, Client *target, const char *name);
|
||||
extern MODVAR int (*make_oper)(Client *client, const char *operblock_name, const char *operclass, ConfigItem_class *clientclass, long modes, const char *snomask, const char *vhost);
|
||||
extern MODVAR int (*unreal_match_iplist)(Client *client, NameList *l);
|
||||
/* /Efuncs */
|
||||
|
||||
/* TLS functions */
|
||||
@ -859,6 +861,7 @@ extern MODVAR EVP_MD *sha1_function;
|
||||
extern MODVAR EVP_MD *md5_function;
|
||||
/* End of TLS functions */
|
||||
|
||||
/* Default handlers for efunctions */
|
||||
extern void parse_message_tags_default_handler(Client *client, char **str, MessageTag **mtag_list);
|
||||
extern const char *mtags_to_string_default_handler(MessageTag *m, Client *client);
|
||||
extern void *labeled_response_save_context_default_handler(void);
|
||||
@ -868,6 +871,8 @@ extern int add_silence_default_handler(Client *client, const char *mask, int sen
|
||||
extern int del_silence_default_handler(Client *client, const char *mask);
|
||||
extern int is_silenced_default_handler(Client *client, Client *acptr);
|
||||
extern void do_unreal_log_remote_deliver_default_handler(LogLevel loglevel, const char *subsystem, const char *event_id, MultiLine *msg, const char *json_serialized);
|
||||
extern int make_oper_default_handler(Client *client, const char *operblock_name, const char *operclass, ConfigItem_class *clientclass, long modes, const char *snomask, const char *vhost);
|
||||
/* End of default handlers for efunctions */
|
||||
|
||||
extern MODVAR MOTDFile opermotd, svsmotd, motd, botmotd, smotd, rules;
|
||||
extern MODVAR int max_connection_count;
|
||||
@ -925,10 +930,6 @@ extern void unreal_delete_match(Match *m);
|
||||
extern int unreal_match(Match *m, const char *str);
|
||||
extern int unreal_match_method_strtoval(const char *str);
|
||||
extern char *unreal_match_method_valtostr(int val);
|
||||
extern void unreal_delete_masks(ConfigItem_mask *m);
|
||||
extern void unreal_add_masks(ConfigItem_mask **head, ConfigEntry *ce);
|
||||
extern int unreal_mask_match(Client *acptr, ConfigItem_mask *m);
|
||||
extern int unreal_mask_match_string(const char *name, ConfigItem_mask *m);
|
||||
#ifdef _WIN32
|
||||
extern MODVAR BOOL IsService;
|
||||
#endif
|
||||
@ -946,7 +947,7 @@ extern void modulemanager(int argc, char *argv[]);
|
||||
extern int inet_pton4(const char *src, unsigned char *dst);
|
||||
extern int inet_pton6(const char *src, unsigned char *dst);
|
||||
extern int unreal_bind(int fd, const char *ip, int port, SocketType socket_type);
|
||||
extern int unreal_connect(int fd, const char *ip, int port, int ipv6);
|
||||
extern int unreal_connect(int fd, const char *ip, int port, SocketType socket_type);
|
||||
extern int is_valid_ip(const char *str);
|
||||
extern int ipv6_capable(void);
|
||||
extern int unix_sockets_capable(void);
|
||||
@ -1092,14 +1093,6 @@ extern int hide_idle_time(Client *client, Client *target);
|
||||
extern void lost_server_link(Client *serv, const char *tls_error_string);
|
||||
extern const char *sendtype_to_cmd(SendType sendtype);
|
||||
extern MODVAR MessageTagHandler *mtaghandlers;
|
||||
extern int security_group_valid_name(const char *name);
|
||||
extern int security_group_exists(const char *name);
|
||||
extern SecurityGroup *add_security_group(const char *name, int order);
|
||||
extern SecurityGroup *find_security_group(const 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, const char *secgroupname);
|
||||
#define nv_find_by_name(stru, name) do_nv_find_by_name(stru, name, ARRAY_SIZEOF((stru)))
|
||||
extern long do_nv_find_by_name(NameValue *table, const char *cmd, int numelements);
|
||||
#define nv_find_by_value(stru, value) do_nv_find_by_value(stru, value, ARRAY_SIZEOF((stru)))
|
||||
@ -1119,6 +1112,9 @@ extern void add_fmt_nvplist(NameValuePrioList **lst, int priority, const char *n
|
||||
extern void add_nvplist_numeric_fmt(NameValuePrioList **lst, int priority, const char *name, Client *to, int numeric, FORMAT_STRING(const char *pattern), ...) __attribute__((format(printf,6,7)));
|
||||
extern NameValuePrioList *find_nvplist(NameValuePrioList *list, const char *name);
|
||||
extern void free_nvplist(NameValuePrioList *lst);
|
||||
extern void unreal_add_name_values(NameValuePrioList **n, const char *name, ConfigEntry *ce);
|
||||
extern const char *namevalue(NameValuePrioList *n);
|
||||
extern const char *namevalue_nospaces(NameValuePrioList *n);
|
||||
extern const char *get_connect_extinfo(Client *client);
|
||||
extern char *unreal_strftime(const char *str);
|
||||
extern void strtolower(char *str);
|
||||
@ -1132,6 +1128,30 @@ extern void read_until(char **p, char *stopchars);
|
||||
extern int is_ip_valid(const char *ip);
|
||||
extern int is_file_readable(const char *file, const char *dir);
|
||||
json_t *json_string_unreal(const char *s);
|
||||
/* securitygroup.c start */
|
||||
extern MODVAR SecurityGroup *securitygroups;
|
||||
extern void unreal_delete_masks(ConfigItem_mask *m);
|
||||
extern void unreal_add_masks(ConfigItem_mask **head, ConfigEntry *ce);
|
||||
extern int unreal_mask_match(Client *acptr, ConfigItem_mask *m);
|
||||
extern int unreal_mask_match_string(const char *name, ConfigItem_mask *m);
|
||||
extern int test_match_item(ConfigFile *conf, ConfigEntry *cep, int *errors);
|
||||
extern int test_match_block(ConfigFile *conf, ConfigEntry *ce, int *errors_out);
|
||||
extern int test_match_block_too_broad(ConfigFile *conf, ConfigEntry *ce);
|
||||
extern int security_group_valid_name(const char *name);
|
||||
extern int security_group_exists(const char *name);
|
||||
extern SecurityGroup *add_security_group(const char *name, int order);
|
||||
extern SecurityGroup *find_security_group(const 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, const char *secgroupname);
|
||||
extern const char *get_security_groups(Client *client);
|
||||
extern int test_match_item(ConfigFile *conf, ConfigEntry *cep, int *errors);
|
||||
extern int conf_match_item(ConfigFile *conf, ConfigEntry *cep, SecurityGroup **block);
|
||||
extern int test_match_block(ConfigFile *conf, ConfigEntry *ce, int *errors_out);
|
||||
extern int conf_match_block(ConfigFile *conf, ConfigEntry *ce, SecurityGroup **block);
|
||||
extern int test_extended_list(Extban *extban, ConfigEntry *cep, int *errors);
|
||||
/* securitygroup.c end */
|
||||
/* src/unrealdb.c start */
|
||||
extern UnrealDB *unrealdb_open(const char *filename, UnrealDBMode mode, char *secret_block);
|
||||
extern int unrealdb_close(UnrealDB *c);
|
||||
@ -1249,3 +1269,6 @@ extern void add_proc_io_server(void);
|
||||
extern void procio_post_rehash(int failure);
|
||||
/* end of proc i/o */
|
||||
extern int minimum_msec_since_last_run(struct timeval *tv_old, long minimum);
|
||||
extern long get_connected_time(Client *client);
|
||||
extern const char *StripControlCodes(const char *text);
|
||||
extern const char *StripControlCodesEx(const char *text, char *output, size_t outputlen, int strip_flags);
|
||||
|
@ -27,10 +27,10 @@
|
||||
|
||||
char *gnulicense[] = {
|
||||
" \2UnrealIRCd License\2",
|
||||
"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 free software; you can redistribute it and/or",
|
||||
"modify it under the terms of the GNU General Public License",
|
||||
"as published by the Free Software Foundation; either version 2",
|
||||
"of the License, or (at your option) any later version.",
|
||||
"",
|
||||
"This program is distributed in the hope that it will be useful,",
|
||||
"but WITHOUT ANY WARRANTY; without even the implied warranty of",
|
||||
@ -39,10 +39,11 @@ char *gnulicense[] = {
|
||||
"",
|
||||
"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.",
|
||||
"Foundation, Inc., 51 Franklin Street, Fifth Floor,",
|
||||
"Boston, MA 02110-1301, USA.",
|
||||
"",
|
||||
"To see the UnrealIRCd License, please point your browser",
|
||||
"at http://www.gnu.org/copyleft/gpl.html or look in the",
|
||||
"file LICENSE in the UnrealIRCd dist",
|
||||
0
|
||||
"to https://www.gnu.org/licenses/old-licenses/gpl-2.0.html",
|
||||
"or look at the LICENSE file in the UnrealIRCd distribution.",
|
||||
NULL
|
||||
};
|
||||
|
@ -450,8 +450,11 @@ struct Extban {
|
||||
/** extbans module */
|
||||
Module *owner;
|
||||
|
||||
/* Set to 1 during rehash when module is unloading (which may be re-used, and then set to 0) */
|
||||
/** Set to 1 during rehash when module is unloading (which may be re-used, and then set to 0) */
|
||||
char unloaded;
|
||||
|
||||
/** Set to 1 when it is preregistered in MOD_TEST already */
|
||||
char preregistered;
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
@ -1097,8 +1100,8 @@ extern void SavePersistentLongX(ModuleInfo *modinfo, const char *varshortname, l
|
||||
#define HOOKTYPE_SEE_CHANNEL_IN_WHOIS 77
|
||||
/** See hooktype_join_data() */
|
||||
#define HOOKTYPE_JOIN_DATA 78
|
||||
/** See hooktype_oper_invite_ban() */
|
||||
#define HOOKTYPE_OPER_INVITE_BAN 79
|
||||
/** See hooktype_invite_bypass() */
|
||||
#define HOOKTYPE_INVITE_BYPASS 79
|
||||
/** See hooktype_view_topic_outside_channel() */
|
||||
#define HOOKTYPE_VIEW_TOPIC_OUTSIDE_CHANNEL 80
|
||||
/** See hooktype_chan_permit_nick_change() */
|
||||
@ -1159,6 +1162,15 @@ extern void SavePersistentLongX(ModuleInfo *modinfo, const char *varshortname, l
|
||||
#define HOOKTYPE_CAN_SET_TOPIC 110
|
||||
/** See hooktype_ip_change() */
|
||||
#define HOOKTYPE_IP_CHANGE 111
|
||||
/** See hooktype_json_expand_client() */
|
||||
#define HOOKTYPE_JSON_EXPAND_CLIENT 112
|
||||
/** See hooktype_json_expand_client() */
|
||||
#define HOOKTYPE_JSON_EXPAND_CLIENT_USER 113
|
||||
/** See hooktype_json_expand_client() */
|
||||
#define HOOKTYPE_JSON_EXPAND_CLIENT_SERVER 114
|
||||
/** See hooktype_json_expand_channel() */
|
||||
#define HOOKTYPE_JSON_EXPAND_CHANNEL 115
|
||||
|
||||
/* Adding a new hook here?
|
||||
* 1) Add the #define HOOKTYPE_.... with a new number
|
||||
* 2) Add a hook prototype (see below)
|
||||
@ -1683,9 +1695,10 @@ int hooktype_stats(Client *client, const char *str);
|
||||
* @param client The client
|
||||
* @param add 1 if the user becomes IRCOp, 0 if the user is no longer IRCOp
|
||||
* @param oper_block The name of the oper block used to oper up
|
||||
* @param operclass The name of the operclass
|
||||
* @return The return value is ignored (use return 0)
|
||||
*/
|
||||
int hooktype_local_oper(Client *client, int add, ConfigItem_oper *oper_block);
|
||||
int hooktype_local_oper(Client *client, int add, const char *oper_block, const char *operclass);
|
||||
|
||||
/** Called when a client sends a PASS command (function prototype for HOOKTYPE_LOCAL_PASS).
|
||||
* @param client The client
|
||||
@ -1858,14 +1871,16 @@ int hooktype_see_channel_in_whois(Client *client, Client *target, Channel *chann
|
||||
*/
|
||||
int hooktype_join_data(Client *who, Channel *channel);
|
||||
|
||||
/** Should the user be able to bypass bans? (function prototype for HOOKTYPE_OPER_INVITE_BAN).
|
||||
/** Should the user be able to bypass channel restrictions because they are invited? (function prototype for HOOKTYPE_INVITE_BYPASS).
|
||||
* @param client The client
|
||||
* @param channel The channel
|
||||
* @note The actual meaning of this hook is more complex, you are unlikely to use it, anyway.
|
||||
* @retval HOOK_DENY Deny the join if the user is also banned
|
||||
* @retval HOOK_DENY Don't allow the user to bypass channel restrictions when they are invited
|
||||
* @retval HOOK_CONTINUE Obey the normal rules
|
||||
* @note Usually you want a user to be able to bypass channel restrictions such as +l or +b when they are /INVITEd by another user
|
||||
* or have invited themselves (OperOverride). But, there may be special cases where you don't want this.
|
||||
* For example, this hook is used by +O to still not allow ircops to join +O channels even if they have OperOverride capability.
|
||||
*/
|
||||
int hooktype_oper_invite_ban(Client *client, Channel *channel);
|
||||
int hooktype_invite_bypass(Client *client, Channel *channel);
|
||||
|
||||
/** Should a user be able to view the topic when not in the channel? (function prototype for HOOKTYPE_VIEW_TOPIC_OUTSIDE_CHANNEL).
|
||||
* @param client The client requesting the topic
|
||||
@ -2145,6 +2160,46 @@ int hooktype_realname_change(Client *client, const char *oldinfo);
|
||||
*/
|
||||
int hooktype_ip_change(Client *client, const char *oldip);
|
||||
|
||||
/** Called when json_expand_client() is called.
|
||||
* Used for expanding information about 'client' in logging routines.
|
||||
* @param client The client that should be expanded
|
||||
* @param detail The amount of detail to provide (always 0 at the moment)
|
||||
* @param j The JSON object
|
||||
* @return The return value is ignored (use return 0)
|
||||
*/
|
||||
int hooktype_json_expand_client(Client *client, int detail, json_t *j);
|
||||
|
||||
/** Called when json_expand_client_user() is called.
|
||||
* Used for expanding information about 'client' in logging routines
|
||||
* when the client is a USER.
|
||||
* @param client The client that should be expanded
|
||||
* @param detail The amount of detail to provide (always 0 at the moment)
|
||||
* @param j The JSON object - root
|
||||
* @param child The JSON object - "user" child item
|
||||
* @return The return value is ignored (use return 0)
|
||||
*/
|
||||
int hooktype_json_expand_client_user(Client *client, int detail, json_t *j, json_t *child);
|
||||
|
||||
/** Called when json_expand_client_server() is called.
|
||||
* Used for expanding information about 'client' in logging routines
|
||||
* when the client is a SERVER.
|
||||
* @param client The client that should be expanded
|
||||
* @param detail The amount of detail to provide (always 0 at the moment)
|
||||
* @param j The JSON object - root
|
||||
* @param child The JSON object - "server" child item
|
||||
* @return The return value is ignored (use return 0)
|
||||
*/
|
||||
int hooktype_json_expand_client_server(Client *client, int detail, json_t *j, json_t *child);
|
||||
|
||||
/** Called when json_expand_channel() is called.
|
||||
* Used for expanding information about 'channel' in logging routines.
|
||||
* @param channel The channel that should be expanded
|
||||
* @param detail The amount of detail to provide (always 0 at the moment)
|
||||
* @param j The JSON object
|
||||
* @return The return value is ignored (use return 0)
|
||||
*/
|
||||
int hooktype_json_expand_channel(Channel *channel, int detail, json_t *j);
|
||||
|
||||
/** @} */
|
||||
|
||||
#ifdef GCC_TYPECHECKING
|
||||
@ -2223,7 +2278,7 @@ _UNREAL_ERROR(_hook_error_incompatible, "Incompatible hook function. Check argum
|
||||
((hooktype == HOOKTYPE_JOIN_DATA) && !ValidateHook(hooktype_join_data, func)) || \
|
||||
((hooktype == HOOKTYPE_PRE_KNOCK) && !ValidateHook(hooktype_pre_knock, func)) || \
|
||||
((hooktype == HOOKTYPE_PRE_INVITE) && !ValidateHook(hooktype_pre_invite, func)) || \
|
||||
((hooktype == HOOKTYPE_OPER_INVITE_BAN) && !ValidateHook(hooktype_oper_invite_ban, func)) || \
|
||||
((hooktype == HOOKTYPE_INVITE_BYPASS) && !ValidateHook(hooktype_invite_bypass, func)) || \
|
||||
((hooktype == HOOKTYPE_VIEW_TOPIC_OUTSIDE_CHANNEL) && !ValidateHook(hooktype_view_topic_outside_channel, func)) || \
|
||||
((hooktype == HOOKTYPE_CHAN_PERMIT_NICK_CHANGE) && !ValidateHook(hooktype_chan_permit_nick_change, func)) || \
|
||||
((hooktype == HOOKTYPE_IS_CHANNEL_SECURE) && !ValidateHook(hooktype_is_channel_secure, func)) || \
|
||||
@ -2259,7 +2314,11 @@ _UNREAL_ERROR(_hook_error_incompatible, "Incompatible hook function. Check argum
|
||||
((hooktype == HOOKTYPE_POST_REMOTE_NICKCHANGE) && !ValidateHook(hooktype_post_remote_nickchange, func)) || \
|
||||
((hooktype == HOOKTYPE_USERHOST_CHANGE) && !ValidateHook(hooktype_userhost_change, func)) || \
|
||||
((hooktype == HOOKTYPE_REALNAME_CHANGE) && !ValidateHook(hooktype_realname_change, func)) || \
|
||||
((hooktype == HOOKTYPE_IP_CHANGE) && !ValidateHook(hooktype_ip_change, func)) ) \
|
||||
((hooktype == HOOKTYPE_IP_CHANGE) && !ValidateHook(hooktype_ip_change, func)) || \
|
||||
((hooktype == HOOKTYPE_JSON_EXPAND_CLIENT) && !ValidateHook(hooktype_json_expand_client, func)) || \
|
||||
((hooktype == HOOKTYPE_JSON_EXPAND_CLIENT_USER) && !ValidateHook(hooktype_json_expand_client_user, func)) || \
|
||||
((hooktype == HOOKTYPE_JSON_EXPAND_CLIENT_SERVER) && !ValidateHook(hooktype_json_expand_client_server, func)) || \
|
||||
((hooktype == HOOKTYPE_JSON_EXPAND_CHANNEL) && !ValidateHook(hooktype_json_expand_channel, func)) ) \
|
||||
_hook_error_incompatible();
|
||||
#endif /* GCC_TYPECHECKING */
|
||||
|
||||
@ -2315,7 +2374,6 @@ enum EfunctionType {
|
||||
EFUNC_FIND_TKLINE_MATCH_ZAP_EX,
|
||||
EFUNC_SEND_LIST,
|
||||
EFUNC_STRIPCOLORS,
|
||||
EFUNC_STRIPCONTROLCODES,
|
||||
EFUNC_SPAMFILTER_BUILD_USER_STRING,
|
||||
EFUNC_SEND_PROTOCTL_SERVERS,
|
||||
EFUNC_VERIFY_LINK,
|
||||
@ -2384,6 +2442,8 @@ enum EfunctionType {
|
||||
EFUNC_DO_UNREAL_LOG_REMOTE_DELIVER,
|
||||
EFUNC_GET_CHMODES_FOR_USER,
|
||||
EFUNC_WHOIS_GET_POLICY,
|
||||
EFUNC_MAKE_OPER,
|
||||
EFUNC_UNREAL_MATCH_IPLIST,
|
||||
};
|
||||
|
||||
/* Module flags */
|
||||
|
@ -559,6 +559,7 @@ typedef enum ClientStatus {
|
||||
#define IsIPV6(x) ((x)->local->socket_type == SOCKET_TYPE_IPV6)
|
||||
#define IsUnixSocket(x) ((x)->local->socket_type == SOCKET_TYPE_UNIX)
|
||||
#define SetIPV6(x) do { (x)->local->socket_type = SOCKET_TYPE_IPV6; } while(0)
|
||||
#define SetUnixSocket(x) do { (x)->local->socket_type = SOCKET_TYPE_UNIX; } while(0)
|
||||
/** @} */
|
||||
|
||||
|
||||
@ -608,6 +609,7 @@ union ModData
|
||||
{
|
||||
int i;
|
||||
long l;
|
||||
long long ll;
|
||||
char *str;
|
||||
void *ptr;
|
||||
};
|
||||
@ -762,6 +764,8 @@ struct NameList {
|
||||
/** Delete an entry from a NameList - AND free it */
|
||||
#define del_name_list(list, str) _del_name_list(&list, str)
|
||||
|
||||
extern void unreal_add_names(NameList **n, ConfigEntry *ce);
|
||||
|
||||
/** @} */
|
||||
|
||||
typedef struct MultiLine MultiLine;
|
||||
@ -1102,6 +1106,7 @@ struct Spamfilter {
|
||||
struct BanException {
|
||||
char *usermask; /**< User mask */
|
||||
char *hostmask; /**< Host mask */
|
||||
SecurityGroup *match; /**< Security group (for config file items only) */
|
||||
unsigned short subtype; /**< See TKL_SUBTYPE_* */
|
||||
char *bantypes; /**< Exception types */
|
||||
char *reason; /**< Reason */
|
||||
@ -1557,7 +1562,7 @@ struct ConfigFlag_allow {
|
||||
struct ConfigItem_allow {
|
||||
ConfigItem_allow *prev, *next;
|
||||
ConfigFlag flag;
|
||||
ConfigItem_mask *mask;
|
||||
SecurityGroup *match;
|
||||
char *server;
|
||||
AuthConfig *auth;
|
||||
int maxperip; /**< Maximum connections permitted per IP address (locally) */
|
||||
@ -1624,12 +1629,13 @@ struct ConfigItem_oper {
|
||||
AuthConfig *auth;
|
||||
char *operclass;
|
||||
ConfigItem_class *class;
|
||||
ConfigItem_mask *mask;
|
||||
SecurityGroup *match;
|
||||
unsigned long modes, require_modes;
|
||||
char *vhost;
|
||||
int maxlogins;
|
||||
int server_notice_colors;
|
||||
int server_notice_show_event;
|
||||
int auto_login;
|
||||
};
|
||||
|
||||
/** The TLS options that are used in set::tls and otherblocks::tls-options.
|
||||
@ -1679,7 +1685,7 @@ struct ConfigItem_ulines {
|
||||
struct ConfigItem_tld {
|
||||
ConfigItem_tld *prev, *next;
|
||||
ConfigFlag_tld flag;
|
||||
ConfigItem_mask *mask;
|
||||
SecurityGroup *match;
|
||||
char *channel;
|
||||
char *motd_file, *rules_file, *smotd_file;
|
||||
char *botmotd_file, *opermotd_file;
|
||||
@ -1713,7 +1719,7 @@ struct ConfigItem_sni {
|
||||
struct ConfigItem_vhost {
|
||||
ConfigItem_vhost *prev, *next;
|
||||
ConfigFlag flag;
|
||||
ConfigItem_mask *mask;
|
||||
SecurityGroup *match;
|
||||
char *login, *virthost, *virtuser;
|
||||
SWhois *swhois;
|
||||
AuthConfig *auth;
|
||||
@ -1725,9 +1731,10 @@ struct ConfigItem_link {
|
||||
/* config options: */
|
||||
char *servername; /**< Name of the server ('link <servername> { }') */
|
||||
struct {
|
||||
ConfigItem_mask *mask; /**< incoming mask(s) to accept */
|
||||
SecurityGroup *match; /**< incoming mask(s) to accept */
|
||||
} incoming;
|
||||
struct {
|
||||
char *file; /**< UNIX domain socket to connect to */
|
||||
char *bind_ip; /**< Our IP to bind to when doing the connect */
|
||||
char *hostname; /**< Hostname or IP to connect to */
|
||||
int port; /**< Port to connect to */
|
||||
@ -1779,14 +1786,14 @@ struct ConfigItem_deny_channel {
|
||||
ConfigFlag flag;
|
||||
char *channel, *reason, *redirect, *class;
|
||||
unsigned char warn;
|
||||
ConfigItem_mask *mask;
|
||||
SecurityGroup *match;
|
||||
};
|
||||
|
||||
struct ConfigItem_allow_channel {
|
||||
ConfigItem_allow_channel *prev, *next;
|
||||
ConfigFlag flag;
|
||||
char *channel, *class;
|
||||
ConfigItem_mask *mask;
|
||||
SecurityGroup *match;
|
||||
};
|
||||
|
||||
struct ConfigItem_allow_dcc {
|
||||
@ -1859,11 +1866,28 @@ struct SecurityGroup {
|
||||
SecurityGroup *prev, *next;
|
||||
int priority;
|
||||
char name[SECURITYGROUPLEN+1];
|
||||
NameValuePrioList *printable_list;
|
||||
int printable_list_counter;
|
||||
/* Include */
|
||||
int identified;
|
||||
int reputation_score;
|
||||
long connect_time;
|
||||
int webirc;
|
||||
int tls;
|
||||
ConfigItem_mask *include_mask;
|
||||
NameList *ip;
|
||||
ConfigItem_mask *mask;
|
||||
NameList *security_group;
|
||||
NameValuePrioList *extended;
|
||||
/* Exclude */
|
||||
int exclude_identified;
|
||||
int exclude_reputation_score;
|
||||
long exclude_connect_time;
|
||||
int exclude_webirc;
|
||||
int exclude_tls;
|
||||
NameList *exclude_ip;
|
||||
ConfigItem_mask *exclude_mask;
|
||||
NameList *exclude_security_group;
|
||||
NameValuePrioList *exclude_extended;
|
||||
};
|
||||
|
||||
#define HM_HOST 1
|
||||
@ -2242,6 +2266,10 @@ typedef enum WhoisConfigDetails {
|
||||
WHOIS_CONFIG_DETAILS_FULL = 3,
|
||||
} WhoisConfigDetails;
|
||||
|
||||
/* Options for StripControlCodesEx() */
|
||||
#define UNRL_STRIP_LOW_ASCII 0x1 /**< Strip all ASCII < 32 (control codes) */
|
||||
#define UNRL_STRIP_KEEP_LF 0x2 /**< Do not strip LF (line feed, \n) */
|
||||
|
||||
#endif /* __struct_include__ */
|
||||
|
||||
#include "dynconf.h"
|
||||
|
@ -62,10 +62,10 @@
|
||||
#define UNREAL_VERSION_MAJOR 0
|
||||
|
||||
/* Minor version number (e.g.: 1 for Unreal3.2.1) */
|
||||
#define UNREAL_VERSION_MINOR 3
|
||||
#define UNREAL_VERSION_MINOR 4
|
||||
|
||||
/* Version suffix such as a beta marker or release candidate marker. (e.g.:
|
||||
-rcX for unrealircd-3.2.9-rcX) */
|
||||
#define UNREAL_VERSION_SUFFIX ""
|
||||
#define UNREAL_VERSION_SUFFIX ".2"
|
||||
|
||||
#endif
|
||||
|
@ -25,7 +25,7 @@ OBJS=ircd_vars.o dns.o auth.o channel.o crule.o dbuf.o \
|
||||
fdlist.o hash.o ircsprintf.o list.o \
|
||||
match.o modules.o parse.o mempool.o operclass.o \
|
||||
conf_preprocessor.o conf.o proc_io_server.o debug.o dispatch.o \
|
||||
misc.o serv.o aliases.o socket.o \
|
||||
securitygroup.o misc.o serv.o aliases.o socket.o \
|
||||
tls.o user.o scache.o send.o support.o \
|
||||
version.o whowas.o random.o api-usermode.o api-channelmode.o \
|
||||
api-moddata.o api-extban.o api-isupport.o api-command.o \
|
||||
|
@ -57,7 +57,8 @@ TKL *(*tkl_add_spamfilter)(int type, unsigned short target, unsigned short actio
|
||||
time_t expire_at, time_t set_at,
|
||||
time_t spamf_tkl_duration, const char *spamf_tkl_reason,
|
||||
int flags);
|
||||
TKL *(*tkl_add_banexception)(int type, const char *usermask, const char *hostmask, const char *reason, const char *set_by,
|
||||
TKL *(*tkl_add_banexception)(int type, const char *usermask, const char *hostmask, SecurityGroup *match,
|
||||
const char *reason, const char *set_by,
|
||||
time_t expire_at, time_t set_at, int soft, const char *bantypes, int flags);
|
||||
TKL *(*tkl_del_line)(TKL *tkl);
|
||||
void (*tkl_check_local_remove_shun)(TKL *tmp);
|
||||
@ -74,10 +75,9 @@ int (*match_spamfilter)(Client *client, const char *str_in, int type, const char
|
||||
int (*match_spamfilter_mtags)(Client *client, MessageTag *mtags, const char *cmd);
|
||||
int (*join_viruschan)(Client *client, TKL *tk, int type);
|
||||
const char *(*StripColors)(const char *text);
|
||||
const char *(*StripControlCodes)(const char *text);
|
||||
void (*spamfilter_build_user_string)(char *buf, const char *nick, Client *client);
|
||||
void (*send_protoctl_servers)(Client *client, int response);
|
||||
int (*verify_link)(Client *client, ConfigItem_link **link_out);
|
||||
ConfigItem_link *(*verify_link)(Client *client);
|
||||
void (*introduce_user)(Client *to, Client *client);
|
||||
void (*send_server_message)(Client *client);
|
||||
void (*broadcast_md_client)(ModDataInfo *mdi, Client *client, ModData *md);
|
||||
@ -135,6 +135,8 @@ int (*watch_check)(Client *client, int reply, int (*watch_notify)(Client *client
|
||||
void (*do_unreal_log_remote_deliver)(LogLevel loglevel, const char *subsystem, const char *event_id, MultiLine *msg, const char *json_serialized);
|
||||
char *(*get_chmodes_for_user)(Client *client, const char *flags);
|
||||
WhoisConfigDetails (*whois_get_policy)(Client *client, Client *target, const char *name);
|
||||
int (*make_oper)(Client *client, const char *operblock_name, const char *operclass, ConfigItem_class *clientclass, long modes, const char *snomask, const char *vhost);
|
||||
int (*unreal_match_iplist)(Client *client, NameList *l);
|
||||
|
||||
Efunction *EfunctionAddMain(Module *module, EfunctionType eftype, int (*func)(), void (*vfunc)(), void *(*pvfunc)(), char *(*stringfunc)(), const char *(*conststringfunc)())
|
||||
{
|
||||
@ -339,7 +341,6 @@ void efunctions_init(void)
|
||||
efunc_init_function(EFUNC_MATCH_SPAMFILTER_MTAGS, match_spamfilter_mtags, NULL);
|
||||
efunc_init_function(EFUNC_JOIN_VIRUSCHAN, join_viruschan, NULL);
|
||||
efunc_init_function(EFUNC_STRIPCOLORS, StripColors, NULL);
|
||||
efunc_init_function(EFUNC_STRIPCONTROLCODES, StripControlCodes, NULL);
|
||||
efunc_init_function(EFUNC_SPAMFILTER_BUILD_USER_STRING, spamfilter_build_user_string, NULL);
|
||||
efunc_init_function(EFUNC_SEND_PROTOCTL_SERVERS, send_protoctl_servers, NULL);
|
||||
efunc_init_function(EFUNC_VERIFY_LINK, verify_link, NULL);
|
||||
@ -406,4 +407,6 @@ void efunctions_init(void)
|
||||
efunc_init_function(EFUNC_DO_UNREAL_LOG_REMOTE_DELIVER, do_unreal_log_remote_deliver, do_unreal_log_remote_deliver_default_handler);
|
||||
efunc_init_function(EFUNC_GET_CHMODES_FOR_USER, get_chmodes_for_user, NULL);
|
||||
efunc_init_function(EFUNC_WHOIS_GET_POLICY, whois_get_policy, NULL);
|
||||
efunc_init_function(EFUNC_MAKE_OPER, make_oper, make_oper_default_handler);
|
||||
efunc_init_function(EFUNC_UNREAL_MATCH_IPLIST, unreal_match_iplist, NULL);
|
||||
}
|
||||
|
@ -38,9 +38,27 @@ void set_isupport_extban(void)
|
||||
ISupportSetFmt(NULL, "EXTBAN", "~,%s", extbanstr);
|
||||
}
|
||||
|
||||
Extban *findmod_by_bantype(const char *str, const char **remainder)
|
||||
Extban *findmod_by_bantype_raw(const char *str, int ban_name_length)
|
||||
{
|
||||
Extban *e;
|
||||
|
||||
for (e=extbans; e; e = e->next)
|
||||
{
|
||||
if ((ban_name_length == 1) && (e->letter == str[0]))
|
||||
return e;
|
||||
if (e->name)
|
||||
{
|
||||
int namelen = strlen(e->name);
|
||||
if ((namelen == ban_name_length) && !strncmp(e->name, str, namelen))
|
||||
return e;
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
Extban *findmod_by_bantype(const char *str, const char **remainder)
|
||||
{
|
||||
int ban_name_length;
|
||||
const char *p = strchr(str, ':');
|
||||
|
||||
@ -54,20 +72,7 @@ Extban *findmod_by_bantype(const char *str, const char **remainder)
|
||||
*remainder = p+1;
|
||||
|
||||
ban_name_length = p - str - 1;
|
||||
|
||||
for (e=extbans; e; e = e->next)
|
||||
{
|
||||
if ((ban_name_length == 1) && (e->letter == str[1]))
|
||||
return e;
|
||||
if (e->name)
|
||||
{
|
||||
int namelen = strlen(e->name);
|
||||
if ((namelen == ban_name_length) && !strncmp(e->name, str+1, namelen))
|
||||
return e;
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
return findmod_by_bantype_raw(str+1, ban_name_length);
|
||||
}
|
||||
|
||||
/* Check if this is a valid extended ban name */
|
||||
@ -121,6 +126,7 @@ static void extban_add_sorted(Extban *n)
|
||||
Extban *ExtbanAdd(Module *module, ExtbanInfo req)
|
||||
{
|
||||
Extban *e;
|
||||
ModuleObject *banobj;
|
||||
int existing = 0;
|
||||
|
||||
if (!req.name)
|
||||
@ -167,13 +173,34 @@ Extban *ExtbanAdd(Module *module, ExtbanInfo req)
|
||||
{
|
||||
if (e->letter == req.letter)
|
||||
{
|
||||
/* Extban already exists in our list, let's see... */
|
||||
if (e->unloaded)
|
||||
{
|
||||
e->unloaded = 0;
|
||||
existing = 1;
|
||||
break;
|
||||
} else {
|
||||
if (module)
|
||||
} else
|
||||
if ((module->flags == MODFLAG_TESTING) && e->preregistered)
|
||||
{
|
||||
/* We are in MOD_INIT (yeah confusing, isn't it?)
|
||||
* and the extban already exists and it was preregistered.
|
||||
* Then go ahead with really registering it.
|
||||
*/
|
||||
e->preregistered = 0;
|
||||
existing = 1;
|
||||
} else
|
||||
if (module->flags == MODFLAG_NONE)
|
||||
{
|
||||
/* Better don't touch it, as we may still fail at this stage
|
||||
* and if we would set .conv_param etc to this and the new module
|
||||
* gets unloaded because of a config typo then we would be screwed
|
||||
* (now we are not).
|
||||
* NOTE: this does mean that if you hot-load an extban module
|
||||
* then it may only be available for config stuff the 2nd rehash.
|
||||
*/
|
||||
return e;
|
||||
} else
|
||||
{
|
||||
module->errorcode = MODERR_EXISTS;
|
||||
return NULL;
|
||||
}
|
||||
@ -195,14 +222,16 @@ Extban *ExtbanAdd(Module *module, ExtbanInfo req)
|
||||
e->is_banned_events = req.is_banned_events;
|
||||
e->owner = module;
|
||||
e->options = req.options;
|
||||
if (module)
|
||||
{
|
||||
ModuleObject *banobj = safe_alloc(sizeof(ModuleObject));
|
||||
|
||||
if (module->flags == MODFLAG_NONE)
|
||||
e->preregistered = 1;
|
||||
|
||||
banobj = safe_alloc(sizeof(ModuleObject));
|
||||
banobj->object.extban = e;
|
||||
banobj->type = MOBJ_EXTBAN;
|
||||
AddListItem(banobj, module->objects);
|
||||
module->errorcode = MODERR_NOERROR;
|
||||
}
|
||||
|
||||
set_isupport_extban();
|
||||
return e;
|
||||
}
|
||||
@ -217,10 +246,27 @@ static void unload_extban_commit(Extban *e)
|
||||
|
||||
/* Then unload the extban */
|
||||
DelListItem(e, extbans);
|
||||
safe_free(e->name);
|
||||
safe_free(e);
|
||||
set_isupport_extban();
|
||||
}
|
||||
|
||||
/** Unload all unused extended bans after a REHASH */
|
||||
void unload_all_unused_extbans(void)
|
||||
{
|
||||
Extban *e, *e_next;
|
||||
|
||||
for (e=extbans; e; e = e_next)
|
||||
{
|
||||
e_next = e->next;
|
||||
if (e->letter && e->unloaded)
|
||||
{
|
||||
unload_extban_commit(e);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void ExtbanDel(Extban *e)
|
||||
{
|
||||
/* Always free the module object */
|
||||
|
@ -40,9 +40,6 @@ long sajoinmode = 0;
|
||||
*/
|
||||
Channel *channels = NULL;
|
||||
|
||||
/* A buffer for rebuilding channel/nick lists with comma's */
|
||||
static char buf[BUFSIZE];
|
||||
|
||||
static mp_pool_t *channel_pool = NULL;
|
||||
|
||||
/** This describes the letters, modes and options for core channel modes.
|
||||
|
408
src/conf.c
408
src/conf.c
@ -62,7 +62,7 @@ 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_security_group (ConfigFile *conf, ConfigEntry *ce);
|
||||
extern int _conf_security_group (ConfigFile *conf, ConfigEntry *ce);
|
||||
static int _conf_secret (ConfigFile *conf, ConfigEntry *ce);
|
||||
|
||||
/*
|
||||
@ -95,7 +95,7 @@ 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_security_group (ConfigFile *conf, ConfigEntry *ce);
|
||||
extern int _test_security_group (ConfigFile *conf, ConfigEntry *ce);
|
||||
static int _test_secret (ConfigFile *conf, ConfigEntry *ce);
|
||||
|
||||
/* This MUST be alphabetized */
|
||||
@ -185,6 +185,7 @@ ConfigEntry *config_find_entry(ConfigEntry *ce, const char *name);
|
||||
extern void add_entropy_configfile(struct stat *st, const char *buf);
|
||||
extern void unload_all_unused_umodes(void);
|
||||
extern void unload_all_unused_extcmodes(void);
|
||||
extern void unload_all_unused_extbans(void);
|
||||
extern void unload_all_unused_caps(void);
|
||||
extern void unload_all_unused_history_backends(void);
|
||||
int reloadable_perm_module_unloaded(void);
|
||||
@ -232,7 +233,6 @@ ConfigResource *config_resources = NULL;
|
||||
ConfigItem_blacklist_module *conf_blacklist_module = NULL;
|
||||
ConfigItem_help *conf_help = NULL;
|
||||
ConfigItem_offchans *conf_offchans = NULL;
|
||||
SecurityGroup *securitygroups = NULL;
|
||||
Secret *secrets = NULL;
|
||||
|
||||
MODVAR Configuration iConf;
|
||||
@ -577,6 +577,11 @@ long config_checkval(const char *orig, unsigned short flags)
|
||||
/** Free configuration setting for set::modes-on-join */
|
||||
void free_conf_channelmodes(struct ChMode *store)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i=0; i < 255; i++)
|
||||
safe_free(store->extparams[i]);
|
||||
|
||||
memset(store, 0, sizeof(struct ChMode));
|
||||
}
|
||||
|
||||
@ -2353,7 +2358,7 @@ void config_rehash()
|
||||
safe_free(oper_ptr->operclass);
|
||||
safe_free(oper_ptr->vhost);
|
||||
Auth_FreeAuthConfig(oper_ptr->auth);
|
||||
unreal_delete_masks(oper_ptr->mask);
|
||||
free_security_group(oper_ptr->match);
|
||||
DelListItem(oper_ptr, conf_oper);
|
||||
for (s = oper_ptr->swhois; s; s = s_next)
|
||||
{
|
||||
@ -2400,7 +2405,7 @@ void config_rehash()
|
||||
for (allow_ptr = conf_allow; allow_ptr; allow_ptr = (ConfigItem_allow *) next)
|
||||
{
|
||||
next = (ListStruct *)allow_ptr->next;
|
||||
unreal_delete_masks(allow_ptr->mask);
|
||||
free_security_group(allow_ptr->match);
|
||||
Auth_FreeAuthConfig(allow_ptr->auth);
|
||||
DelListItem(allow_ptr, conf_allow);
|
||||
safe_free(allow_ptr);
|
||||
@ -2437,6 +2442,8 @@ void config_rehash()
|
||||
free_motd(&tld_ptr->opermotd);
|
||||
free_motd(&tld_ptr->botmotd);
|
||||
|
||||
free_security_group(tld_ptr->match);
|
||||
|
||||
DelListItem(tld_ptr, conf_tld);
|
||||
safe_free(tld_ptr);
|
||||
}
|
||||
@ -2450,7 +2457,7 @@ void config_rehash()
|
||||
Auth_FreeAuthConfig(vhost_ptr->auth);
|
||||
safe_free(vhost_ptr->virthost);
|
||||
safe_free(vhost_ptr->virtuser);
|
||||
unreal_delete_masks(vhost_ptr->mask);
|
||||
free_security_group(vhost_ptr->match);
|
||||
for (s = vhost_ptr->swhois; s; s = s_next)
|
||||
{
|
||||
s_next = s->next;
|
||||
@ -2488,7 +2495,7 @@ void config_rehash()
|
||||
safe_free(deny_channel_ptr->reason);
|
||||
safe_free(deny_channel_ptr->class);
|
||||
DelListItem(deny_channel_ptr, conf_deny_channel);
|
||||
unreal_delete_masks(deny_channel_ptr->mask);
|
||||
free_security_group(deny_channel_ptr->match);
|
||||
safe_free(deny_channel_ptr);
|
||||
}
|
||||
|
||||
@ -2498,7 +2505,7 @@ void config_rehash()
|
||||
safe_free(allow_channel_ptr->channel);
|
||||
safe_free(allow_channel_ptr->class);
|
||||
DelListItem(allow_channel_ptr, conf_allow_channel);
|
||||
unreal_delete_masks(allow_channel_ptr->mask);
|
||||
free_security_group(allow_channel_ptr->match);
|
||||
safe_free(allow_channel_ptr);
|
||||
}
|
||||
|
||||
@ -3036,7 +3043,7 @@ ConfigItem_tld *find_tld(Client *client)
|
||||
|
||||
for (tld = conf_tld; tld; tld = tld->next)
|
||||
{
|
||||
if (unreal_mask_match(client, tld->mask))
|
||||
if (user_allowed_by_security_group(client, tld->match))
|
||||
{
|
||||
if ((tld->options & TLD_TLS) && !IsSecureConnect(client))
|
||||
continue;
|
||||
@ -3056,7 +3063,8 @@ ConfigItem_link *find_link(const char *servername, Client *client)
|
||||
|
||||
for (link = conf_link; link; link = link->next)
|
||||
{
|
||||
if (match_simple(link->servername, servername) && unreal_mask_match(client, link->incoming.mask))
|
||||
if (match_simple(link->servername, servername) &&
|
||||
user_allowed_by_security_group(client, link->incoming.match))
|
||||
{
|
||||
return link;
|
||||
}
|
||||
@ -3137,7 +3145,7 @@ ConfigItem_deny_channel *find_channel_allowed(Client *client, const char *name)
|
||||
{
|
||||
if (dchannel->class && strcmp(client->local->class->name, dchannel->class))
|
||||
continue;
|
||||
if (dchannel->mask && !unreal_mask_match(client, dchannel->mask))
|
||||
if (dchannel->match && !user_allowed_by_security_group(client, dchannel->match))
|
||||
continue;
|
||||
break; /* MATCH deny channel { } */
|
||||
}
|
||||
@ -3152,7 +3160,7 @@ ConfigItem_deny_channel *find_channel_allowed(Client *client, const char *name)
|
||||
{
|
||||
if (achannel->class && strcmp(client->local->class->name, achannel->class))
|
||||
continue;
|
||||
if (achannel->mask && !unreal_mask_match(client, achannel->mask))
|
||||
if (achannel->match && !user_allowed_by_security_group(client, achannel->match))
|
||||
continue;
|
||||
break; /* MATCH allow channel { } */
|
||||
}
|
||||
@ -3935,6 +3943,7 @@ int _conf_oper(ConfigFile *conf, ConfigEntry *ce)
|
||||
|
||||
oper = safe_alloc(sizeof(ConfigItem_oper));
|
||||
safe_strdup(oper->name, ce->value);
|
||||
oper->match = safe_alloc(sizeof(SecurityGroup));
|
||||
|
||||
/* Inherit some defaults: */
|
||||
oper->server_notice_colors = tempiConf.server_notice_colors;
|
||||
@ -3990,6 +3999,10 @@ int _conf_oper(ConfigFile *conf, ConfigEntry *ce)
|
||||
{
|
||||
oper->server_notice_show_event = config_checkval(cep->value, CFG_YESNO);
|
||||
}
|
||||
else if (!strcmp(cep->name, "auto-login"))
|
||||
{
|
||||
oper->auto_login = config_checkval(cep->value, CFG_YESNO);
|
||||
}
|
||||
else if (!strcmp(cep->name, "modes"))
|
||||
{
|
||||
oper->modes = set_usermode(cep->value);
|
||||
@ -4002,9 +4015,9 @@ int _conf_oper(ConfigFile *conf, ConfigEntry *ce)
|
||||
{
|
||||
oper->maxlogins = atoi(cep->value);
|
||||
}
|
||||
else if (!strcmp(cep->name, "mask"))
|
||||
else if (!strcmp(cep->name, "mask") || !strcmp(cep->name, "match"))
|
||||
{
|
||||
unreal_add_masks(&oper->mask, cep);
|
||||
conf_match_block(conf, cep, &oper->match);
|
||||
}
|
||||
else if (!strcmp(cep->name, "vhost"))
|
||||
{
|
||||
@ -4018,8 +4031,8 @@ int _conf_oper(ConfigFile *conf, ConfigEntry *ce)
|
||||
int _test_oper(ConfigFile *conf, ConfigEntry *ce)
|
||||
{
|
||||
char has_class = 0, has_password = 0, has_snomask = 0;
|
||||
char has_modes = 0, has_require_modes = 0, has_mask = 0, has_maxlogins = 0;
|
||||
char has_operclass = 0, has_vhost = 0;
|
||||
char has_modes = 0, has_require_modes = 0, has_mask = 0, has_match = 0, has_broad_match = 0;
|
||||
char has_maxlogins = 0, has_operclass = 0, has_vhost = 0, has_auto_login = 0;
|
||||
ConfigEntry *cep;
|
||||
int errors = 0;
|
||||
|
||||
@ -4125,6 +4138,10 @@ int _test_oper(ConfigFile *conf, ConfigEntry *ce)
|
||||
else if (!strcmp(cep->name, "server-notice-show-event"))
|
||||
{
|
||||
}
|
||||
else if (!strcmp(cep->name, "auto-login"))
|
||||
{
|
||||
has_auto_login = config_checkval(cep->value, CFG_YESNO);
|
||||
}
|
||||
/* oper::modes */
|
||||
else if (!strcmp(cep->name, "modes"))
|
||||
{
|
||||
@ -4187,7 +4204,22 @@ int _test_oper(ConfigFile *conf, ConfigEntry *ce)
|
||||
else if (!strcmp(cep->name, "mask"))
|
||||
{
|
||||
if (cep->value || cep->items)
|
||||
{
|
||||
has_mask = 1;
|
||||
test_match_block(conf, cep, &errors);
|
||||
if (test_match_block_too_broad(conf, cep))
|
||||
has_broad_match = 1;
|
||||
}
|
||||
}
|
||||
else if (!strcmp(cep->name, "match"))
|
||||
{
|
||||
if (cep->value || cep->items)
|
||||
{
|
||||
has_match = 1;
|
||||
test_match_block(conf, cep, &errors);
|
||||
if (test_match_block_too_broad(conf, cep))
|
||||
has_broad_match = 1;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -4207,7 +4239,22 @@ int _test_oper(ConfigFile *conf, ConfigEntry *ce)
|
||||
else if (!strcmp(cep->name, "mask"))
|
||||
{
|
||||
if (cep->value || cep->items)
|
||||
{
|
||||
has_mask = 1;
|
||||
test_match_block(conf, cep, &errors);
|
||||
if (test_match_block_too_broad(conf, cep))
|
||||
has_broad_match = 1;
|
||||
}
|
||||
}
|
||||
else if (!strcmp(cep->name, "match"))
|
||||
{
|
||||
if (cep->value || cep->items)
|
||||
{
|
||||
has_match = 1;
|
||||
test_match_block(conf, cep, &errors);
|
||||
if (test_match_block_too_broad(conf, cep))
|
||||
has_broad_match = 1;
|
||||
}
|
||||
}
|
||||
else if (!strcmp(cep->name, "password"))
|
||||
{
|
||||
@ -4230,16 +4277,39 @@ int _test_oper(ConfigFile *conf, ConfigEntry *ce)
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!has_password)
|
||||
|
||||
if (has_auto_login && has_broad_match)
|
||||
{
|
||||
config_error_missing(ce->file->filename, ce->line_number,
|
||||
"oper::password");
|
||||
config_error("%s:%i: your oper block for '%s' has auto-login but is completely unrestricted (mask *@*)!",
|
||||
ce->file->filename, ce->line_number, ce->value);
|
||||
errors++;
|
||||
} else
|
||||
if (!has_password && has_broad_match)
|
||||
{
|
||||
config_error("%s:%i: your oper block for '%s' has no password and is completely unrestricted (mask *@*)!",
|
||||
ce->file->filename, ce->line_number, ce->value);
|
||||
errors++;
|
||||
}
|
||||
if (!has_mask)
|
||||
|
||||
/* The rest should NOT be in an 'else'... */
|
||||
if (has_password && has_auto_login)
|
||||
{
|
||||
config_error("%s:%i: You have auto-login enabled for your oper block '%s' but you also have a password set. "
|
||||
"Remove the password if you want to use auto-login.",
|
||||
ce->file->filename, ce->line_number, ce->value);
|
||||
errors++;
|
||||
}
|
||||
if (!has_mask && !has_match)
|
||||
{
|
||||
config_error_missing(ce->file->filename, ce->line_number,
|
||||
"oper::mask");
|
||||
"oper::match");
|
||||
errors++;
|
||||
}
|
||||
if (has_mask && has_match)
|
||||
{
|
||||
config_error("%s:%d: You cannot have both ::mask and ::match. "
|
||||
"You should only use oper::match.",
|
||||
ce->file->filename, ce->line_number);
|
||||
errors++;
|
||||
}
|
||||
if (!has_class)
|
||||
@ -4590,8 +4660,8 @@ int _conf_tld(ConfigFile *conf, ConfigEntry *ce)
|
||||
|
||||
for (cep = ce->items; cep; cep = cep->next)
|
||||
{
|
||||
if (!strcmp(cep->name, "mask"))
|
||||
unreal_add_masks(&ca->mask, cep);
|
||||
if (!strcmp(cep->name, "match") || !strcmp(cep->name, "mask"))
|
||||
conf_match_block(conf, cep, &ca->match);
|
||||
else if (!strcmp(cep->name, "motd"))
|
||||
{
|
||||
safe_strdup(ca->motd_file, cep->value);
|
||||
@ -4640,12 +4710,12 @@ int _test_tld(ConfigFile *conf, ConfigEntry *ce)
|
||||
ConfigEntry *cep;
|
||||
int errors = 0;
|
||||
int fd = -1;
|
||||
char has_mask = 0, has_motd = 0, has_rules = 0, has_shortmotd = 0, has_channel = 0;
|
||||
char has_opermotd = 0, has_botmotd = 0, has_options = 0;
|
||||
char has_mask = 0, has_match = 0, has_motd = 0, has_rules = 0, has_shortmotd = 0;
|
||||
char has_channel = 0, has_opermotd = 0, has_botmotd = 0, has_options = 0;
|
||||
|
||||
for (cep = ce->items; cep; cep = cep->next)
|
||||
{
|
||||
if (!cep->value && strcmp(cep->name, "options"))
|
||||
if (!cep->value && strcmp(cep->name, "options") && strcmp(cep->name, "mask") && strcmp(cep->name, "match"))
|
||||
{
|
||||
config_error_empty(cep->file->filename, cep->line_number,
|
||||
"tld", cep->name);
|
||||
@ -4656,7 +4726,18 @@ int _test_tld(ConfigFile *conf, ConfigEntry *ce)
|
||||
if (!strcmp(cep->name, "mask"))
|
||||
{
|
||||
if (cep->value || cep->items)
|
||||
{
|
||||
has_mask = 1;
|
||||
test_match_block(conf, cep, &errors);
|
||||
}
|
||||
}
|
||||
else if (!strcmp(cep->name, "match"))
|
||||
{
|
||||
if (cep->value || cep->items)
|
||||
{
|
||||
has_match = 1;
|
||||
test_match_block(conf, cep, &errors);
|
||||
}
|
||||
}
|
||||
/* tld::motd */
|
||||
else if (!strcmp(cep->name, "motd"))
|
||||
@ -4806,10 +4887,17 @@ int _test_tld(ConfigFile *conf, ConfigEntry *ce)
|
||||
continue;
|
||||
}
|
||||
}
|
||||
if (!has_mask)
|
||||
if (!has_mask && !has_match)
|
||||
{
|
||||
config_error_missing(ce->file->filename, ce->line_number,
|
||||
"tld::mask");
|
||||
"tld::match");
|
||||
errors++;
|
||||
}
|
||||
if (has_mask && has_match)
|
||||
{
|
||||
config_error("%s:%d: You cannot have both ::mask and ::match. "
|
||||
"You should only use %s::match.",
|
||||
ce->file->filename, ce->line_number, ce->name);
|
||||
errors++;
|
||||
}
|
||||
if (!has_motd)
|
||||
@ -5342,12 +5430,13 @@ int _conf_allow(ConfigFile *conf, ConfigEntry *ce)
|
||||
}
|
||||
allow = safe_alloc(sizeof(ConfigItem_allow));
|
||||
allow->ipv6_clone_mask = tempiConf.default_ipv6_clone_mask;
|
||||
allow->match = safe_alloc(sizeof(SecurityGroup));
|
||||
|
||||
for (cep = ce->items; cep; cep = cep->next)
|
||||
{
|
||||
if (!strcmp(cep->name, "mask") || !strcmp(cep->name, "ip") || !strcmp(cep->name, "hostname"))
|
||||
if (!strcmp(cep->name, "match") || !strcmp(cep->name, "mask") || !strcmp(cep->name, "ip") || !strcmp(cep->name, "hostname"))
|
||||
{
|
||||
unreal_add_masks(&allow->mask, cep);
|
||||
conf_match_block(conf, cep, &allow->match);
|
||||
}
|
||||
else if (!strcmp(cep->name, "password"))
|
||||
allow->auth = AuthBlockToAuthConfig(cep);
|
||||
@ -5413,7 +5502,7 @@ int _test_allow(ConfigFile *conf, ConfigEntry *ce)
|
||||
ConfigEntry *cep, *cepp;
|
||||
int errors = 0;
|
||||
Hook *h;
|
||||
char has_ip = 0, has_hostname = 0, has_mask = 0;
|
||||
char has_ip = 0, has_hostname = 0, has_mask = 0, has_match = 0;
|
||||
char has_maxperip = 0, has_global_maxperip = 0, has_password = 0, has_class = 0;
|
||||
char has_redirectserver = 0, has_redirectport = 0, has_options = 0;
|
||||
int hostname_possible_silliness = 0;
|
||||
@ -5463,6 +5552,7 @@ int _test_allow(ConfigFile *conf, ConfigEntry *ce)
|
||||
for (cep = ce->items; cep; cep = cep->next)
|
||||
{
|
||||
if (strcmp(cep->name, "options") &&
|
||||
strcmp(cep->name, "match") &&
|
||||
strcmp(cep->name, "mask") &&
|
||||
config_is_blankorempty(cep, "allow"))
|
||||
{
|
||||
@ -5494,6 +5584,12 @@ int _test_allow(ConfigFile *conf, ConfigEntry *ce)
|
||||
else if (!strcmp(cep->name, "mask"))
|
||||
{
|
||||
has_mask = 1;
|
||||
test_match_block(conf, cep, &errors);
|
||||
}
|
||||
else if (!strcmp(cep->name, "match"))
|
||||
{
|
||||
has_match = 1;
|
||||
test_match_block(conf, cep, &errors);
|
||||
}
|
||||
else if (!strcmp(cep->name, "maxperip"))
|
||||
{
|
||||
@ -5641,27 +5737,33 @@ int _test_allow(ConfigFile *conf, ConfigEntry *ce)
|
||||
}
|
||||
}
|
||||
|
||||
if (has_mask && (has_ip || has_hostname))
|
||||
if ((has_mask || has_match) && (has_ip || has_hostname))
|
||||
{
|
||||
config_error("%s:%d: The allow block uses allow::mask, but you also have an allow::ip and allow::hostname.",
|
||||
config_error("%s:%d: The allow block uses allow::match, but you also have an allow::ip and allow::hostname.",
|
||||
ce->file->filename, ce->line_number);
|
||||
config_error("Please delete your allow::ip and allow::hostname entries and/or integrate them into allow::mask");
|
||||
config_error("Please delete your allow::ip and allow::hostname entries and/or integrate them into allow::match");
|
||||
} else
|
||||
if (has_ip)
|
||||
{
|
||||
config_warn("%s:%d: The allow block uses allow::mask nowadays. Rename your allow::ip item to allow::mask.",
|
||||
config_warn("%s:%d: The allow block uses allow::match nowadays. Rename your allow::ip item to allow::match.",
|
||||
ce->file->filename, ce->line_number);
|
||||
config_warn("See https://www.unrealircd.org/docs/FAQ#allow-mask for more information");
|
||||
} else
|
||||
if (has_hostname)
|
||||
{
|
||||
config_warn("%s:%d: The allow block uses allow::mask nowadays. Rename your allow::hostname item to allow::mask.",
|
||||
config_warn("%s:%d: The allow block uses allow::match nowadays. Rename your allow::hostname item to allow::match.",
|
||||
ce->file->filename, ce->line_number);
|
||||
config_warn("See https://www.unrealircd.org/docs/FAQ#allow-mask for more information");
|
||||
} else
|
||||
if (!has_mask)
|
||||
if (has_mask && has_match)
|
||||
{
|
||||
config_error("%s:%d: allow block needs an allow::mask",
|
||||
config_error("%s:%d: You cannot have both ::mask and ::match. You should only use allow::match.",
|
||||
ce->file->filename, ce->line_number);
|
||||
errors++;
|
||||
} else
|
||||
if (!has_match && !has_mask)
|
||||
{
|
||||
config_error("%s:%d: allow block needs an allow::match",
|
||||
ce->file->filename, ce->line_number);
|
||||
errors++;
|
||||
}
|
||||
@ -5702,15 +5804,15 @@ int _conf_allow_channel(ConfigFile *conf, ConfigEntry *ce)
|
||||
ConfigItem_allow_channel *allow = NULL;
|
||||
ConfigEntry *cep;
|
||||
char *class = NULL;
|
||||
ConfigEntry *mask = NULL;
|
||||
ConfigEntry *match = NULL;
|
||||
|
||||
/* First, search for ::class, if any */
|
||||
for (cep = ce->items; cep; cep = cep->next)
|
||||
{
|
||||
if (!strcmp(cep->name, "class"))
|
||||
class = cep->value;
|
||||
else if (!strcmp(cep->name, "mask"))
|
||||
mask = cep;
|
||||
else if (!strcmp(cep->name, "match") || !strcmp(cep->name, "mask"))
|
||||
match = cep;
|
||||
}
|
||||
|
||||
for (cep = ce->items; cep; cep = cep->next)
|
||||
@ -5722,8 +5824,8 @@ int _conf_allow_channel(ConfigFile *conf, ConfigEntry *ce)
|
||||
safe_strdup(allow->channel, cep->value);
|
||||
if (class)
|
||||
safe_strdup(allow->class, class);
|
||||
if (mask)
|
||||
unreal_add_masks(&allow->mask, mask);
|
||||
if (match)
|
||||
conf_match_block(conf, match, &allow->match);
|
||||
AddListItem(allow, conf_allow_channel);
|
||||
}
|
||||
}
|
||||
@ -5734,7 +5836,8 @@ int _test_allow_channel(ConfigFile *conf, ConfigEntry *ce)
|
||||
{
|
||||
ConfigEntry *cep;
|
||||
int errors = 0;
|
||||
char has_channel = 0, has_class = 0;
|
||||
char has_match = 0, has_mask = 0, has_channel = 0, has_class = 0;
|
||||
|
||||
for (cep = ce->items; cep; cep = cep->next)
|
||||
{
|
||||
if (config_is_blankorempty(cep, "allow channel"))
|
||||
@ -5758,8 +5861,15 @@ int _test_allow_channel(ConfigFile *conf, ConfigEntry *ce)
|
||||
}
|
||||
has_class = 1;
|
||||
}
|
||||
else if (!strcmp(cep->name, "match"))
|
||||
{
|
||||
has_match = 1;
|
||||
test_match_block(conf, cep, &errors);
|
||||
}
|
||||
else if (!strcmp(cep->name, "mask"))
|
||||
{
|
||||
has_mask = 1;
|
||||
test_match_block(conf, cep, &errors);
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -5768,6 +5878,13 @@ int _test_allow_channel(ConfigFile *conf, ConfigEntry *ce)
|
||||
errors++;
|
||||
}
|
||||
}
|
||||
if (has_mask && has_match)
|
||||
{
|
||||
config_error("%s:%d: You cannot have both ::mask and ::match. "
|
||||
"You should only use %s::match.",
|
||||
ce->file->filename, ce->line_number, ce->name);
|
||||
errors++;
|
||||
}
|
||||
if (!has_channel)
|
||||
{
|
||||
config_error_missing(ce->file->filename, ce->line_number,
|
||||
@ -5860,6 +5977,7 @@ int _conf_vhost(ConfigFile *conf, ConfigEntry *ce)
|
||||
ConfigItem_vhost *vhost;
|
||||
ConfigEntry *cep, *cepp;
|
||||
vhost = safe_alloc(sizeof(ConfigItem_vhost));
|
||||
vhost->match = safe_alloc(sizeof(SecurityGroup));
|
||||
|
||||
for (cep = ce->items; cep; cep = cep->next)
|
||||
{
|
||||
@ -5880,9 +5998,9 @@ int _conf_vhost(ConfigFile *conf, ConfigEntry *ce)
|
||||
safe_strdup(vhost->login, cep->value);
|
||||
else if (!strcmp(cep->name, "password"))
|
||||
vhost->auth = AuthBlockToAuthConfig(cep);
|
||||
else if (!strcmp(cep->name, "mask"))
|
||||
else if (!strcmp(cep->name, "match") || !strcmp(cep->name, "mask"))
|
||||
{
|
||||
unreal_add_masks(&vhost->mask, cep);
|
||||
conf_match_block(conf, cep, &vhost->match);
|
||||
}
|
||||
else if (!strcmp(cep->name, "swhois"))
|
||||
{
|
||||
@ -5914,7 +6032,7 @@ int _test_vhost(ConfigFile *conf, ConfigEntry *ce)
|
||||
{
|
||||
int errors = 0;
|
||||
ConfigEntry *cep;
|
||||
char has_vhost = 0, has_login = 0, has_password = 0, has_mask = 0;
|
||||
char has_vhost = 0, has_login = 0, has_password = 0, has_mask = 0, has_match = 0;
|
||||
|
||||
for (cep = ce->items; cep; cep = cep->next)
|
||||
{
|
||||
@ -6007,6 +6125,12 @@ int _test_vhost(ConfigFile *conf, ConfigEntry *ce)
|
||||
else if (!strcmp(cep->name, "mask"))
|
||||
{
|
||||
has_mask = 1;
|
||||
test_match_block(conf, cep, &errors);
|
||||
}
|
||||
else if (!strcmp(cep->name, "match"))
|
||||
{
|
||||
has_match = 1;
|
||||
test_match_block(conf, cep, &errors);
|
||||
}
|
||||
else if (!strcmp(cep->name, "swhois"))
|
||||
{
|
||||
@ -6038,10 +6162,17 @@ int _test_vhost(ConfigFile *conf, ConfigEntry *ce)
|
||||
"vhost::password");
|
||||
errors++;
|
||||
}
|
||||
if (!has_mask)
|
||||
if (!has_mask && !has_match)
|
||||
{
|
||||
config_error_missing(ce->file->filename, ce->line_number,
|
||||
"vhost::mask");
|
||||
"vhost::match");
|
||||
errors++;
|
||||
}
|
||||
if (has_mask && has_match)
|
||||
{
|
||||
config_error("%s:%d: You cannot have both ::mask and ::match. "
|
||||
"You should only use %s::match.",
|
||||
ce->file->filename, ce->line_number, ce->name);
|
||||
errors++;
|
||||
}
|
||||
return errors;
|
||||
@ -6172,9 +6303,9 @@ int _conf_link(ConfigFile *conf, ConfigEntry *ce)
|
||||
{
|
||||
for (cepp = cep->items; cepp; cepp = cepp->next)
|
||||
{
|
||||
if (!strcmp(cepp->name, "mask"))
|
||||
if (!strcmp(cepp->name, "match") || !strcmp(cepp->name, "mask"))
|
||||
{
|
||||
unreal_add_masks(&link->incoming.mask, cepp);
|
||||
conf_match_block(conf, cepp, &link->incoming.match);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -6184,6 +6315,8 @@ int _conf_link(ConfigFile *conf, ConfigEntry *ce)
|
||||
{
|
||||
if (!strcmp(cepp->name, "bind-ip"))
|
||||
safe_strdup(link->outgoing.bind_ip, cepp->value);
|
||||
else if (!strcmp(cepp->name, "file"))
|
||||
safe_strdup(link->outgoing.file, cepp->value);
|
||||
else if (!strcmp(cepp->name, "hostname"))
|
||||
safe_strdup(link->outgoing.hostname, cepp->value);
|
||||
else if (!strcmp(cepp->name, "port"))
|
||||
@ -6273,7 +6406,7 @@ int _test_link(ConfigFile *conf, ConfigEntry *ce)
|
||||
ConfigEntry *cep, *cepp, *ceppp;
|
||||
int errors = 0;
|
||||
|
||||
int has_incoming = 0, has_incoming_mask = 0, has_outgoing = 0;
|
||||
int has_incoming = 0, has_incoming_mask = 0, has_incoming_match = 0, has_outgoing = 0, has_outgoing_file = 0;
|
||||
int has_outgoing_bind_ip = 0, has_outgoing_hostname = 0, has_outgoing_port = 0;
|
||||
int has_outgoing_options = 0, has_hub = 0, has_leaf = 0, has_leaf_depth = 0;
|
||||
int has_password = 0, has_class = 0, has_options = 0;
|
||||
@ -6300,11 +6433,26 @@ int _test_link(ConfigFile *conf, ConfigEntry *ce)
|
||||
config_detect_duplicate(&has_incoming, cep, &errors);
|
||||
for (cepp = cep->items; cepp; cepp = cepp->next)
|
||||
{
|
||||
if (!strcmp(cepp->name, "match"))
|
||||
{
|
||||
if (cepp->value || cepp->items)
|
||||
{
|
||||
has_incoming_match = 1;
|
||||
test_match_block(conf, cepp, &errors);
|
||||
} else
|
||||
if (config_is_blankorempty(cepp, "link::incoming"))
|
||||
{
|
||||
errors++;
|
||||
continue;
|
||||
}
|
||||
} else
|
||||
if (!strcmp(cepp->name, "mask"))
|
||||
{
|
||||
if (cepp->value || cepp->items)
|
||||
{
|
||||
has_incoming_mask = 1;
|
||||
else
|
||||
test_match_block(conf, cepp, &errors);
|
||||
} else
|
||||
if (config_is_blankorempty(cepp, "link::incoming"))
|
||||
{
|
||||
errors++;
|
||||
@ -6328,6 +6476,15 @@ int _test_link(ConfigFile *conf, ConfigEntry *ce)
|
||||
config_detect_duplicate(&has_outgoing_bind_ip, cepp, &errors);
|
||||
// todo: ipv4 vs ipv6
|
||||
}
|
||||
else if (!strcmp(cepp->name, "file"))
|
||||
{
|
||||
if (config_is_blankorempty(cepp, "link::outgoing"))
|
||||
{
|
||||
errors++;
|
||||
continue;
|
||||
}
|
||||
config_detect_duplicate(&has_outgoing_file, cepp, &errors);
|
||||
}
|
||||
else if (!strcmp(cepp->name, "hostname"))
|
||||
{
|
||||
if (config_is_blankorempty(cepp, "link::outgoing"))
|
||||
@ -6491,16 +6648,25 @@ int _test_link(ConfigFile *conf, ConfigEntry *ce)
|
||||
if (has_incoming)
|
||||
{
|
||||
/* If we have an incoming sub-block then we need at least 'mask' and 'password' */
|
||||
if (!has_incoming_mask)
|
||||
if (!has_incoming_mask && !has_incoming_match)
|
||||
{
|
||||
config_error_missing(ce->file->filename, ce->line_number, "link::incoming::mask");
|
||||
config_error_missing(ce->file->filename, ce->line_number, "link::incoming::match");
|
||||
errors++;
|
||||
}
|
||||
if (has_incoming_mask && has_incoming_match)
|
||||
{
|
||||
config_error("%s:%d: You cannot have both link::incoming::mask and link::incoming::match. "
|
||||
"You should only use link::incoming::match.",
|
||||
ce->file->filename, ce->line_number);
|
||||
errors++;
|
||||
}
|
||||
}
|
||||
|
||||
if (has_outgoing)
|
||||
{
|
||||
/* If we have an outgoing sub-block then we need at least a hostname and port */
|
||||
/* If we have an outgoing sub-block then we need at least a hostname and port or a file */
|
||||
if (!has_outgoing_file)
|
||||
{
|
||||
if (!has_outgoing_hostname)
|
||||
{
|
||||
config_error_missing(ce->file->filename, ce->line_number, "link::outgoing::hostname");
|
||||
@ -6512,6 +6678,14 @@ int _test_link(ConfigFile *conf, ConfigEntry *ce)
|
||||
errors++;
|
||||
}
|
||||
}
|
||||
else if (has_outgoing_file && (has_outgoing_hostname || has_outgoing_port))
|
||||
{
|
||||
config_error("%s:%d: link block should either have a 'file' (for *NIX domain socket), "
|
||||
"OR have a 'hostname' and 'port' (for IPv4/IPv6). You cannot combine both in one link block.",
|
||||
ce->file->filename, ce->line_number);
|
||||
errors++;
|
||||
}
|
||||
}
|
||||
|
||||
/* The only other generic options that are required are 'class' and 'password' */
|
||||
if (!has_password)
|
||||
@ -8965,6 +9139,7 @@ int _test_set(ConfigFile *conf, ConfigEntry *ce)
|
||||
{
|
||||
/* keep this in sync with _test_allow() */
|
||||
int ipv6mask;
|
||||
CheckNull(cep);
|
||||
ipv6mask = atoi(cep->value);
|
||||
if (ipv6mask == 0)
|
||||
{
|
||||
@ -9818,9 +9993,9 @@ int _conf_deny_channel(ConfigFile *conf, ConfigEntry *ce)
|
||||
{
|
||||
safe_strdup(deny->class, cep->value);
|
||||
}
|
||||
else if (!strcmp(cep->name, "mask"))
|
||||
else if (!strcmp(cep->name, "match") || !strcmp(cep->name, "mask"))
|
||||
{
|
||||
unreal_add_masks(&deny->mask, cep);
|
||||
conf_match_block(conf, cep, &deny->match);
|
||||
}
|
||||
}
|
||||
AddListItem(deny, conf_deny_channel);
|
||||
@ -9894,6 +10069,7 @@ int _test_deny(ConfigFile *conf, ConfigEntry *ce)
|
||||
if (!strcmp(ce->value, "channel"))
|
||||
{
|
||||
char has_channel = 0, has_warn = 0, has_reason = 0, has_redirect = 0, has_class = 0;
|
||||
char has_mask = 0, has_match = 0;
|
||||
for (cep = ce->items; cep; cep = cep->next)
|
||||
{
|
||||
if (config_is_blankorempty(cep, "deny channel"))
|
||||
@ -9951,8 +10127,15 @@ int _test_deny(ConfigFile *conf, ConfigEntry *ce)
|
||||
}
|
||||
has_class = 1;
|
||||
}
|
||||
else if (!strcmp(cep->name, "match"))
|
||||
{
|
||||
has_match = 1;
|
||||
test_match_block(conf, cep, &errors);
|
||||
}
|
||||
else if (!strcmp(cep->name, "mask"))
|
||||
{
|
||||
has_mask = 1;
|
||||
test_match_block(conf, cep, &errors);
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -9973,6 +10156,13 @@ int _test_deny(ConfigFile *conf, ConfigEntry *ce)
|
||||
"deny channel::reason");
|
||||
errors++;
|
||||
}
|
||||
if (has_mask && has_match)
|
||||
{
|
||||
config_error("%s:%d: You cannot have both ::mask and ::match. "
|
||||
"You should only use %s %s::match.",
|
||||
ce->file->filename, ce->line_number, ce->name, ce->value);
|
||||
errors++;
|
||||
}
|
||||
}
|
||||
else if (!strcmp(ce->value, "link"))
|
||||
{
|
||||
@ -10177,104 +10367,6 @@ int _test_deny(ConfigFile *conf, ConfigEntry *ce)
|
||||
return errors;
|
||||
}
|
||||
|
||||
int _test_security_group(ConfigFile *conf, ConfigEntry *ce)
|
||||
{
|
||||
int errors = 0;
|
||||
ConfigEntry *cep;
|
||||
|
||||
if (!ce->value)
|
||||
{
|
||||
config_error("%s:%i: security-group block needs a name, eg: security-group web-users {",
|
||||
ce->file->filename, ce->line_number);
|
||||
errors++;
|
||||
} else {
|
||||
if (!strcasecmp(ce->value, "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->file->filename, ce->line_number);
|
||||
errors++;
|
||||
return errors;
|
||||
}
|
||||
if (!security_group_valid_name(ce->value))
|
||||
{
|
||||
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->file->filename, ce->line_number, ce->value);
|
||||
errors++;
|
||||
}
|
||||
}
|
||||
|
||||
for (cep = ce->items; cep; cep = cep->next)
|
||||
{
|
||||
if (!strcmp(cep->name, "webirc"))
|
||||
{
|
||||
CheckNull(cep);
|
||||
} else
|
||||
if (!strcmp(cep->name, "identified"))
|
||||
{
|
||||
CheckNull(cep);
|
||||
} else
|
||||
if (!strcmp(cep->name, "tls"))
|
||||
{
|
||||
CheckNull(cep);
|
||||
} else
|
||||
if (!strcmp(cep->name, "reputation-score"))
|
||||
{
|
||||
int v;
|
||||
CheckNull(cep);
|
||||
v = atoi(cep->value);
|
||||
if ((v < 1) || (v > 10000))
|
||||
{
|
||||
config_error("%s:%i: security-group::reputation-score needs to be a value of 1-10000",
|
||||
cep->file->filename, cep->line_number);
|
||||
errors++;
|
||||
}
|
||||
} else
|
||||
if (!strcmp(cep->name, "include-mask"))
|
||||
{
|
||||
} else
|
||||
{
|
||||
config_error_unknown(cep->file->filename, cep->line_number,
|
||||
"security-group", cep->name);
|
||||
errors++;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
return errors;
|
||||
}
|
||||
|
||||
int _conf_security_group(ConfigFile *conf, ConfigEntry *ce)
|
||||
{
|
||||
ConfigEntry *cep;
|
||||
SecurityGroup *s = add_security_group(ce->value, 1);
|
||||
|
||||
for (cep = ce->items; cep; cep = cep->next)
|
||||
{
|
||||
if (!strcmp(cep->name, "webirc"))
|
||||
s->webirc = config_checkval(cep->value, CFG_YESNO);
|
||||
else if (!strcmp(cep->name, "identified"))
|
||||
s->identified = config_checkval(cep->value, CFG_YESNO);
|
||||
else if (!strcmp(cep->name, "tls"))
|
||||
s->tls = config_checkval(cep->value, CFG_YESNO);
|
||||
else if (!strcmp(cep->name, "reputation-score"))
|
||||
s->reputation_score = atoi(cep->value);
|
||||
else if (!strcmp(cep->name, "priority"))
|
||||
{
|
||||
s->priority = atoi(cep->value);
|
||||
DelListItem(s, securitygroups);
|
||||
AddListItemPrio(s, securitygroups, s->priority);
|
||||
}
|
||||
else if (!strcmp(cep->name, "include-mask"))
|
||||
{
|
||||
unreal_add_masks(&s->include_mask, cep);
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
Secret *find_secret(const char *secret_name)
|
||||
{
|
||||
Secret *s;
|
||||
@ -10687,6 +10779,7 @@ int rehash_internal(Client *client)
|
||||
reread_motdsandrules();
|
||||
unload_all_unused_umodes();
|
||||
unload_all_unused_extcmodes();
|
||||
unload_all_unused_extbans();
|
||||
unload_all_unused_caps();
|
||||
unload_all_unused_history_backends();
|
||||
// unload_all_unused_moddata(); -- this will crash
|
||||
@ -10703,8 +10796,9 @@ int rehash_internal(Client *client)
|
||||
void link_cleanup(ConfigItem_link *link_ptr)
|
||||
{
|
||||
safe_free(link_ptr->servername);
|
||||
unreal_delete_masks(link_ptr->incoming.mask);
|
||||
free_security_group(link_ptr->incoming.match);
|
||||
Auth_FreeAuthConfig(link_ptr->auth);
|
||||
safe_free(link_ptr->outgoing.file);
|
||||
safe_free(link_ptr->outgoing.bind_ip);
|
||||
safe_free(link_ptr->outgoing.hostname);
|
||||
safe_free(link_ptr->hub);
|
||||
|
@ -1,6 +1,6 @@
|
||||
/* UnrealIRCd configuration preprocessor
|
||||
* (C) Copyright 2019 Bram Matthys ("Syzop") and the UnrealIRCd team
|
||||
* License: GPLv2
|
||||
* License: GPLv2 or later
|
||||
*
|
||||
* Technically this isn't a 100% true preprocessor, but to the end user
|
||||
* it will certainly look like it, hence the name.
|
||||
|
@ -1,6 +1,6 @@
|
||||
/* UnrealIRCd crash reporter code.
|
||||
* (C) Copyright 2015-2019 Bram Matthys ("Syzop") and the UnrealIRCd Team.
|
||||
* License: GPLv2
|
||||
* License: GPLv2 or later
|
||||
*/
|
||||
|
||||
#include "unrealircd.h"
|
||||
@ -306,7 +306,7 @@ int crash_report_asan_log(FILE *reportfd, char *coredump)
|
||||
stripcrlf(buf);
|
||||
fprintf(reportfd, " %s\n", buf);
|
||||
}
|
||||
n = pclose(fd);
|
||||
n = fclose(fd);
|
||||
fprintf(reportfd, "END OF ASAN LOG\n");
|
||||
|
||||
if (WEXITSTATUS(n) == 127)
|
||||
|
@ -57,7 +57,7 @@ EVENT(garbage_collect)
|
||||
if (loop.do_garbage_collect == 1) {
|
||||
loop.do_garbage_collect = 0;
|
||||
unreal_log(ULOG_INFO, "main", "GARBAGE_COLLECT_STARTED", NULL, "Cleaned up $count garbage blocks",
|
||||
(ii - freelinks));
|
||||
log_data_integer("count", (ii - freelinks)));
|
||||
}
|
||||
}
|
||||
if (loop.do_garbage_collect == 1)
|
||||
@ -83,7 +83,7 @@ int match_tkls(Client *client)
|
||||
{
|
||||
unreal_log(ULOG_INFO, "tkl", "BAN_REALNAME", client,
|
||||
"Banned client $client.details due to realname ban: $reason",
|
||||
bconf->reason ? bconf->reason : "no reason");
|
||||
log_data_string("reason", bconf->reason ? bconf->reason : "no reason"));
|
||||
|
||||
if (bconf->reason) {
|
||||
if (IsUser(client))
|
||||
|
@ -1,7 +1,7 @@
|
||||
/************************************************************************
|
||||
* UnrealIRCd - Unreal Internet Relay Chat Daemon - src/ircd_vars.c
|
||||
* (c) 2021- Bram Matthys and The UnrealIRCd team
|
||||
* License: GPLv2
|
||||
* License: GPLv2 or later
|
||||
*/
|
||||
#include "unrealircd.h"
|
||||
|
||||
|
59
src/log.c
59
src/log.c
@ -43,6 +43,26 @@ int log_sources_match(LogSource *logsource, LogLevel loglevel, const char *subsy
|
||||
void do_unreal_log_internal(LogLevel loglevel, const char *subsystem, const char *event_id, Client *client, int expand_msg, const char *msg, va_list vl);
|
||||
void log_blocks_switchover(void);
|
||||
|
||||
/** Calculate expansion of a JSON string thanks to double escaping.
|
||||
* orig => JSON => IRC
|
||||
* " => \" => \\"
|
||||
* \ => \\ => \\\\
|
||||
*/
|
||||
int json_dump_string_length(const char *s)
|
||||
{
|
||||
int len = 0;
|
||||
for (; *s; s++)
|
||||
{
|
||||
if (*s == '\\')
|
||||
len += 4;
|
||||
else if (*s == '"')
|
||||
len += 3;
|
||||
else
|
||||
len++;
|
||||
}
|
||||
return len;
|
||||
}
|
||||
|
||||
/** Convert a regular string value to a JSON string.
|
||||
* In UnrealIRCd, this must be used instead of json_string()
|
||||
* as we may use non-UTF8 sequences. Also, this takes care
|
||||
@ -53,13 +73,16 @@ void log_blocks_switchover(void);
|
||||
*/
|
||||
json_t *json_string_unreal(const char *s)
|
||||
{
|
||||
static char buf[8192];
|
||||
char buf1[512], buf2[512];
|
||||
char *verified_s;
|
||||
const char *stripped;
|
||||
|
||||
if (s == NULL)
|
||||
return json_null();
|
||||
|
||||
verified_s = unrl_utf8_make_valid(s, buf, sizeof(buf), 0);
|
||||
stripped = StripControlCodesEx(s, buf1, sizeof(buf1), UNRL_STRIP_LOW_ASCII|UNRL_STRIP_KEEP_LF);
|
||||
verified_s = unrl_utf8_make_valid(buf1, buf2, sizeof(buf2), 0);
|
||||
|
||||
return json_string(verified_s);
|
||||
}
|
||||
|
||||
@ -561,6 +584,9 @@ void json_expand_client(json_t *j, const char *key, Client *client, int detail)
|
||||
if (client->local && client->local->creationtime)
|
||||
json_object_set_new(child, "connected_since", json_timestamp(client->local->creationtime));
|
||||
|
||||
if (client->local && client->local->idle_since)
|
||||
json_object_set_new(child, "idle_since", json_timestamp(client->local->idle_since));
|
||||
|
||||
if (client->user)
|
||||
{
|
||||
char buf[512];
|
||||
@ -572,6 +598,10 @@ void json_expand_client(json_t *j, const char *key, Client *client, int detail)
|
||||
json_object_set_new(user, "username", json_string_unreal(client->user->username));
|
||||
if (!BadPtr(client->info))
|
||||
json_object_set_new(user, "realname", json_string_unreal(client->info));
|
||||
if (has_user_mode(client, 'x') && client->user->virthost && strcmp(client->user->virthost, client->user->realhost))
|
||||
json_object_set_new(user, "vhost", json_string_unreal(client->user->virthost));
|
||||
if (*client->user->cloakedhost)
|
||||
json_object_set_new(user, "cloakedhost", json_string_unreal(client->user->cloakedhost));
|
||||
if (client->uplink)
|
||||
json_object_set_new(user, "servername", json_string_unreal(client->uplink->name));
|
||||
if (IsLoggedIn(client))
|
||||
@ -592,6 +622,26 @@ void json_expand_client(json_t *j, const char *key, Client *client, int detail)
|
||||
str = get_operclass(client);
|
||||
if (str)
|
||||
json_object_set_new(user, "operclass", json_string_unreal(str));
|
||||
if (client->user->channel)
|
||||
{
|
||||
Membership *m;
|
||||
int cnt = 0;
|
||||
int len = 0;
|
||||
json_t *channels = json_array();
|
||||
json_object_set_new(user, "channels", channels);
|
||||
for (m = client->user->channel; m; m = m->next)
|
||||
{
|
||||
len += json_dump_string_length(m->channel->name);
|
||||
if (len > 384)
|
||||
{
|
||||
/* Truncated */
|
||||
json_array_append_new(channels, json_string_unreal("..."));
|
||||
break;
|
||||
}
|
||||
json_array_append_new(channels, json_string_unreal(m->channel->name));
|
||||
}
|
||||
}
|
||||
RunHook(HOOKTYPE_JSON_EXPAND_CLIENT_USER, client, detail, child, user);
|
||||
} else
|
||||
if (IsMe(client))
|
||||
{
|
||||
@ -645,7 +695,9 @@ void json_expand_client(json_t *j, const char *key, Client *client, int detail)
|
||||
}
|
||||
if (!BadPtr(client->server->features.nickchars))
|
||||
json_object_set_new(features, "nick_character_sets", json_string_unreal(client->server->features.nickchars));
|
||||
RunHook(HOOKTYPE_JSON_EXPAND_CLIENT_SERVER, client, detail, child, server);
|
||||
}
|
||||
RunHook(HOOKTYPE_JSON_EXPAND_CLIENT, client, detail, child);
|
||||
}
|
||||
|
||||
void json_expand_channel(json_t *j, const char *key, Channel *channel, int detail)
|
||||
@ -675,6 +727,7 @@ void json_expand_channel(json_t *j, const char *key, Channel *channel, int detai
|
||||
}
|
||||
|
||||
// Possibly later: If detail is set to 1 then expand more...
|
||||
RunHook(HOOKTYPE_JSON_EXPAND_CHANNEL, channel, detail, child);
|
||||
}
|
||||
|
||||
const char *timestamp_iso8601_now(void)
|
||||
@ -883,9 +936,11 @@ LogData *log_data_link_block(ConfigItem_link *link)
|
||||
safe_strdup(d->key, "link_block");
|
||||
d->value.object = j = json_object();
|
||||
json_object_set_new(j, "name", json_string_unreal(link->servername));
|
||||
json_object_set_new(j, "file", json_string_unreal(link->outgoing.file));
|
||||
json_object_set_new(j, "hostname", json_string_unreal(link->outgoing.hostname));
|
||||
json_object_set_new(j, "ip", json_string_unreal(link->connect_ip));
|
||||
json_object_set_new(j, "port", json_integer(link->outgoing.port));
|
||||
json_object_set_new(j, "class", json_string_unreal(link->class->name));
|
||||
|
||||
if (!link->outgoing.bind_ip && iConf.link_bindip)
|
||||
bind_ip = iConf.link_bindip;
|
||||
|
308
src/misc.c
308
src/misc.c
@ -916,145 +916,74 @@ int is_autojoin_chan(const char *chname)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/** Free all masks in the mask list */
|
||||
void unreal_delete_masks(ConfigItem_mask *m)
|
||||
{
|
||||
ConfigItem_mask *m_next;
|
||||
|
||||
for (; m; m = m_next)
|
||||
{
|
||||
m_next = m->next;
|
||||
|
||||
safe_free(m->mask);
|
||||
|
||||
safe_free(m);
|
||||
}
|
||||
}
|
||||
|
||||
/** Internal function to add one individual mask to the list */
|
||||
static void unreal_add_mask(ConfigItem_mask **head, ConfigEntry *ce)
|
||||
{
|
||||
ConfigItem_mask *m = safe_alloc(sizeof(ConfigItem_mask));
|
||||
|
||||
/* Since we allow both mask "xyz"; and mask { abc; def; };... */
|
||||
if (ce->value)
|
||||
safe_strdup(m->mask, ce->value);
|
||||
else
|
||||
safe_strdup(m->mask, ce->name);
|
||||
|
||||
add_ListItem((ListStruct *)m, (ListStruct **)head);
|
||||
}
|
||||
|
||||
/** Add mask entries from config */
|
||||
void unreal_add_masks(ConfigItem_mask **head, ConfigEntry *ce)
|
||||
/** Add name entries from config */
|
||||
void unreal_add_names(NameList **n, ConfigEntry *ce)
|
||||
{
|
||||
if (ce->items)
|
||||
{
|
||||
ConfigEntry *cep;
|
||||
for (cep = ce->items; cep; cep = cep->next)
|
||||
unreal_add_mask(head, cep);
|
||||
_add_name_list(n, cep->value ? cep->value : cep->name);
|
||||
} else
|
||||
if (ce->value)
|
||||
{
|
||||
unreal_add_mask(head, ce);
|
||||
_add_name_list(n, ce->value);
|
||||
}
|
||||
}
|
||||
|
||||
/** Check if a client matches any of the masks in the mask list.
|
||||
* The following rules apply:
|
||||
* - If you have only negating entries, like '!abc' and '!def', then
|
||||
* we assume an implicit * rule first, since that is clearly what
|
||||
* the user wants.
|
||||
* - If you have a mix, like '*.com', '!irc1*', '!irc2*' then the
|
||||
* implicit * is dropped and we assume you only want to match *.com,
|
||||
* with the exception of irc1*.com and irc2*.com.
|
||||
* - If you only have normal entries without ! then things are
|
||||
* as they always are.
|
||||
* @param client The client to run the mask match against
|
||||
* @param mask The mask entry from the config file
|
||||
* @returns 1 on match, 0 on non-match.
|
||||
*/
|
||||
int unreal_mask_match(Client *client, ConfigItem_mask *mask)
|
||||
/** Add name/value entries from config */
|
||||
void unreal_add_name_values(NameValuePrioList **n, const char *name, ConfigEntry *ce)
|
||||
{
|
||||
int retval = 1;
|
||||
ConfigItem_mask *m;
|
||||
|
||||
if (!mask)
|
||||
return 0; /* Empty mask block is no match */
|
||||
|
||||
/* First check normal matches (without ! prefix) */
|
||||
for (m = mask; m; m = m->next)
|
||||
if (ce->items)
|
||||
{
|
||||
if (m->mask[0] != '!')
|
||||
ConfigEntry *cep;
|
||||
for (cep = ce->items; cep; cep = cep->next)
|
||||
add_nvplist(n, 0, name, cep->value ? cep->value : cep->name);
|
||||
} else
|
||||
if (ce->value)
|
||||
{
|
||||
retval = 0; /* no implicit * */
|
||||
if (match_user(m->mask, client, MATCH_CHECK_REAL|MATCH_CHECK_EXTENDED))
|
||||
{
|
||||
retval = 1;
|
||||
break;
|
||||
add_nvplist(n, 0, name, ce->value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (retval)
|
||||
{
|
||||
/* We matched. Check for exceptions (with ! prefix) */
|
||||
for (m = mask; m; m = m->next)
|
||||
{
|
||||
if ((m->mask[0] == '!') && match_user(m->mask+1, client, MATCH_CHECK_REAL|MATCH_CHECK_EXTENDED))
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
/** Check if a string matches any of the masks in the mask list.
|
||||
* The following rules apply:
|
||||
* - If you have only negating entries, like '!abc' and '!def', then
|
||||
* we assume an implicit * rule first, since that is clearly what
|
||||
* the user wants.
|
||||
* - If you have a mix, like '*.com', '!irc1*', '!irc2*' then the
|
||||
* implicit * is dropped and we assume you only want to match *.com,
|
||||
* with the exception of irc1*.com and irc2*.com.
|
||||
* - If you only have normal entries without ! then things are
|
||||
* as they always are.
|
||||
* @param name The name to run the mask matching on
|
||||
* @param mask The mask entry from the config file
|
||||
* @returns 1 on match, 0 on non-match.
|
||||
*/
|
||||
int unreal_mask_match_string(const char *name, ConfigItem_mask *mask)
|
||||
/** Prints the name:value pair of a NameValuePrioList */
|
||||
const char *namevalue(NameValuePrioList *n)
|
||||
{
|
||||
int retval = 1;
|
||||
ConfigItem_mask *m;
|
||||
static char buf[512];
|
||||
|
||||
if (!mask)
|
||||
return 0; /* Empty mask block is no match */
|
||||
if (!n->name)
|
||||
return "";
|
||||
|
||||
/* First check normal matches (without ! prefix) */
|
||||
for (m = mask; m; m = m->next)
|
||||
{
|
||||
if (m->mask[0] != '!')
|
||||
{
|
||||
retval = 0; /* no implicit * */
|
||||
if (match_simple(m->mask, name))
|
||||
{
|
||||
retval = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!n->value)
|
||||
return n->name;
|
||||
|
||||
if (retval)
|
||||
{
|
||||
/* We matched. Check for exceptions (with ! prefix) */
|
||||
for (m = mask; m; m = m->next)
|
||||
{
|
||||
if ((m->mask[0] == '!') && match_simple(m->mask+1, name))
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
snprintf(buf, sizeof(buf), "%s:%s", n->name, n->value);
|
||||
return buf;
|
||||
}
|
||||
|
||||
return retval;
|
||||
/** Version of namevalue() but replaces spaces with underscores.
|
||||
* Used in for example numeric sending routines where a field
|
||||
* may not contain any spaces.
|
||||
*/
|
||||
const char *namevalue_nospaces(NameValuePrioList *n)
|
||||
{
|
||||
static char buf[512];
|
||||
char *p;
|
||||
|
||||
if (!n->name)
|
||||
return "";
|
||||
|
||||
if (!n->value)
|
||||
strlcpy(buf, n->name, sizeof(buf));
|
||||
|
||||
snprintf(buf, sizeof(buf), "%s:%s", n->name, n->value);
|
||||
|
||||
/* Replace spaces with underscores */
|
||||
for (p=buf; *p; p++)
|
||||
if (*p == ' ')
|
||||
*p = '_';
|
||||
|
||||
return buf;
|
||||
}
|
||||
|
||||
/** Our own strcasestr implementation because strcasestr is
|
||||
@ -1461,6 +1390,11 @@ void do_unreal_log_remote_deliver_default_handler(LogLevel loglevel, const char
|
||||
{
|
||||
}
|
||||
|
||||
int make_oper_default_handler(Client *client, const char *operblock_name, const char *operclass, ConfigItem_class *clientclass, long modes, const char *snomask, const char *vhost)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
/** my_timegm: mktime()-like function which will use GMT/UTC.
|
||||
* Strangely enough there is no standard function for this.
|
||||
* On some *NIX OS's timegm() may be available, sometimes only
|
||||
@ -2539,3 +2473,141 @@ int minimum_msec_since_last_run(struct timeval *tv_old, long minimum)
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/** Strip color, bold, underline, and reverse codes from a string.
|
||||
* @param text The input text
|
||||
* @param output The buffer for the output text
|
||||
* @param outputlen The length of the output buffer
|
||||
* @param strip_flags Zero or (a combination of) UNRL_STRIP_LOW_ASCII / UNRL_STRIP_KEEP_LF.
|
||||
* @returns The new string, which will be 'output', or in unusual cases (outputlen==0) will be NULL.
|
||||
*/
|
||||
const char *StripControlCodesEx(const char *text, char *output, size_t outputlen, int strip_flags)
|
||||
{
|
||||
int i = 0, len = strlen(text), save_len=0;
|
||||
char nc = 0, col = 0, rgb = 0;
|
||||
char *o = output;
|
||||
const char *save_text=NULL;
|
||||
|
||||
/* Handle special cases first.. */
|
||||
|
||||
if (outputlen == 0)
|
||||
return NULL;
|
||||
|
||||
if (outputlen == 1)
|
||||
{
|
||||
*output = '\0';
|
||||
return output;
|
||||
}
|
||||
|
||||
/* Reserve room for the NUL byte */
|
||||
outputlen--;
|
||||
|
||||
while (len > 0)
|
||||
{
|
||||
if ( col && ((isdigit(*text) && nc < 2) || (*text == ',' && nc < 3)))
|
||||
{
|
||||
nc++;
|
||||
if (*text == ',')
|
||||
nc = 0;
|
||||
}
|
||||
/* Syntax for RGB is ^DHHHHHH where H is a hex digit.
|
||||
* If < 6 hex digits are specified, the code is displayed
|
||||
* as text
|
||||
*/
|
||||
else if ((rgb && isxdigit(*text) && nc < 6) || (rgb && *text == ',' && nc < 7))
|
||||
{
|
||||
nc++;
|
||||
if (*text == ',')
|
||||
nc = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (col)
|
||||
col = 0;
|
||||
if (rgb)
|
||||
{
|
||||
if (nc != 6)
|
||||
{
|
||||
text = save_text+1;
|
||||
len = save_len-1;
|
||||
rgb = 0;
|
||||
continue;
|
||||
}
|
||||
rgb = 0;
|
||||
}
|
||||
switch (*text)
|
||||
{
|
||||
case 3:
|
||||
/* color */
|
||||
col = 1;
|
||||
nc = 0;
|
||||
break;
|
||||
case 4:
|
||||
/* RGB */
|
||||
save_text = text;
|
||||
save_len = len;
|
||||
rgb = 1;
|
||||
nc = 0;
|
||||
break;
|
||||
case 2:
|
||||
/* bold */
|
||||
break;
|
||||
case 31:
|
||||
/* underline */
|
||||
break;
|
||||
case 22:
|
||||
/* reverse */
|
||||
break;
|
||||
case 15:
|
||||
/* plain */
|
||||
break;
|
||||
case 29:
|
||||
/* italic */
|
||||
break;
|
||||
case 30:
|
||||
/* strikethrough */
|
||||
break;
|
||||
case 17:
|
||||
/* monospace */
|
||||
break;
|
||||
case 0xe2:
|
||||
if (!strncmp(text+1, "\x80\x8b", 2))
|
||||
{
|
||||
/* +2 means we skip 3 */
|
||||
text += 2;
|
||||
len -= 2;
|
||||
break;
|
||||
}
|
||||
/*fallthrough*/
|
||||
default:
|
||||
if ((*text >= ' ') ||
|
||||
!(strip_flags & UNRL_STRIP_LOW_ASCII) ||
|
||||
((strip_flags & UNRL_STRIP_KEEP_LF) && (*text == '\n'))
|
||||
)
|
||||
{
|
||||
*o++ = *text;
|
||||
outputlen--;
|
||||
if (outputlen == 0)
|
||||
{
|
||||
*o = '\0';
|
||||
return output;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
text++;
|
||||
len--;
|
||||
}
|
||||
|
||||
*o = '\0';
|
||||
return output;
|
||||
}
|
||||
|
||||
/* strip color, bold, underline, and reverse codes from a string */
|
||||
const char *StripControlCodes(const char *text)
|
||||
{
|
||||
static unsigned char new_str[4096];
|
||||
|
||||
return StripControlCodesEx(text, new_str, sizeof(new_str), 0);
|
||||
}
|
||||
|
@ -1,6 +1,6 @@
|
||||
/* UnrealIRCd module manager.
|
||||
* (C) Copyright 2019 Bram Matthys ("Syzop") and the UnrealIRCd Team.
|
||||
* License: GPLv2
|
||||
* License: GPLv2 or later
|
||||
* See https://www.unrealircd.org/docs/Module_manager for user documentation.
|
||||
*/
|
||||
|
||||
@ -1206,7 +1206,7 @@ int mm_compile(ManagedModule *m, char *tmpfile, int test)
|
||||
fprintf(stderr, "ERROR: Compile errors encountered while compiling module '%s'\n"
|
||||
"You are suggested to contact the author (%s) of this module:\n%s\n",
|
||||
m->name, m->author, m->troubleshooting);
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/** Actually download and install the module.
|
||||
@ -1222,7 +1222,7 @@ void mm_install_module(ManagedModule *m)
|
||||
basename = "mod.c";
|
||||
tmpfile = unreal_mktemp(TMPDIR, basename);
|
||||
|
||||
printf("ConfigResourceing %s from %s...\n", m->name, m->source);
|
||||
printf("Downloading %s from %s...\n", m->name, m->source);
|
||||
if (!mm_http_request(m->source, tmpfile, 1))
|
||||
{
|
||||
fprintf(stderr, "Repository %s seems to list a module file that cannot be retrieved (%s).\n", m->repo_url, m->source);
|
||||
@ -1655,21 +1655,23 @@ void mm_parse_c_file(int argc, char *args[])
|
||||
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);
|
||||
} else {
|
||||
snprintf(name, sizeof(name), "%s/src/modules/third/Makefile", BUILDDIR);
|
||||
if (!file_exists(name))
|
||||
{
|
||||
fprintf(stderr, "ERROR: Directory %s exists, but your UnrealIRCd is not compiled yet.\n"
|
||||
"You must compile your UnrealIRCd first (run './Config', then 'make install')\n",
|
||||
BUILDDIR);
|
||||
exit(-1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void modulemanager(int argc, char *args[])
|
||||
|
@ -39,7 +39,7 @@ MODULES= \
|
||||
sethost.so chghost.so chgident.so setname.so \
|
||||
setident.so sdesc.so svsmode.so swhois.so\
|
||||
svsmotd.so svsnline.so who_old.so whox.so mkpasswd.so \
|
||||
away.so svsnoop.so svsnick.so \
|
||||
away.so svsnoop.so svsnick.so svso.so \
|
||||
chgname.so kill.so \
|
||||
lag.so message.so oper.so pingpong.so \
|
||||
quit.so sendumode.so sqline.so \
|
||||
@ -71,12 +71,12 @@ MODULES= \
|
||||
message-tags.so batch.so \
|
||||
account-tag.so labeled-response.so link-security.so \
|
||||
message-ids.so plaintext-policy.so server-time.so sts.so \
|
||||
echo-message.so userip-tag.so userhost-tag.so \
|
||||
echo-message.so userip-tag.so userhost-tag.so geoip-tag.so \
|
||||
bot-tag.so reply-tag.so json-log-tag.so \
|
||||
typing-indicator.so \
|
||||
typing-indicator.so channel-context.so \
|
||||
ident_lookup.so history.so chathistory.so \
|
||||
targetfloodprot.so clienttagdeny.so watch-backend.so \
|
||||
monitor.so slog.so tls_cipher.so operinfo.so \
|
||||
monitor.so slog.so tls_cipher.so operinfo.so creationtime.so \
|
||||
unreal_server_compat.so \
|
||||
extended-monitor.so geoip_csv.so \
|
||||
geoip_base.so extjwt.so \
|
||||
|
@ -18,6 +18,8 @@
|
||||
* ban-action block;
|
||||
* ban-reason "Possible mixed character spam";
|
||||
* ban-time 4h; // For other types
|
||||
* except {
|
||||
* }
|
||||
* };
|
||||
* };
|
||||
*
|
||||
@ -56,6 +58,7 @@ struct {
|
||||
BanAction ban_action;
|
||||
char *ban_reason;
|
||||
long ban_time;
|
||||
SecurityGroup *except;
|
||||
} cfg;
|
||||
|
||||
static void free_config(void);
|
||||
@ -196,9 +199,12 @@ CMD_OVERRIDE_FUNC(override_msg)
|
||||
{
|
||||
int score, ret;
|
||||
|
||||
if (!MyUser(client) || (parc < 3) || BadPtr(parv[2]))
|
||||
if (!MyUser(client) || (parc < 3) || BadPtr(parv[2]) ||
|
||||
user_allowed_by_security_group(client, cfg.except))
|
||||
{
|
||||
/* Short circuit for: remote clients or insufficient parameters */
|
||||
/* Short circuit for: remote clients, insufficient parameters,
|
||||
* antimixedutf8::except.
|
||||
*/
|
||||
CallCommandOverride(ovr, client, recv_mtags, parc, parv);
|
||||
return;
|
||||
}
|
||||
@ -271,6 +277,7 @@ static void init_config(void)
|
||||
static void free_config(void)
|
||||
{
|
||||
safe_free(cfg.ban_reason);
|
||||
free_security_group(cfg.except);
|
||||
memset(&cfg, 0, sizeof(cfg)); /* needed! */
|
||||
}
|
||||
|
||||
@ -319,6 +326,10 @@ int antimixedutf8_config_test(ConfigFile *cf, ConfigEntry *ce, int type, int *er
|
||||
if (!strcmp(cep->name, "ban-time"))
|
||||
{
|
||||
} else
|
||||
if (!strcmp(cep->name, "except"))
|
||||
{
|
||||
test_match_block(cf, cep, &errors);
|
||||
} else
|
||||
{
|
||||
config_error("%s:%i: unknown directive set::antimixedutf8::%s",
|
||||
cep->file->filename, cep->line_number, cep->name);
|
||||
@ -357,6 +368,10 @@ int antimixedutf8_config_run(ConfigFile *cf, ConfigEntry *ce, int type)
|
||||
if (!strcmp(cep->name, "ban-time"))
|
||||
{
|
||||
cfg.ban_time = config_checkval(cep->value, CFG_TIME);
|
||||
} else
|
||||
if (!strcmp(cep->name, "except"))
|
||||
{
|
||||
conf_match_block(cf, cep, &cfg.except);
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
|
@ -25,7 +25,7 @@
|
||||
ModuleHeader MOD_HEADER
|
||||
= {
|
||||
"antirandom",
|
||||
"1.4",
|
||||
"1.5",
|
||||
"Detect and ban users with random names",
|
||||
"UnrealIRCd Team",
|
||||
"unrealircd-6",
|
||||
@ -504,8 +504,7 @@ struct {
|
||||
long ban_time;
|
||||
int convert_to_lowercase;
|
||||
int show_failedconnects;
|
||||
ConfigItem_mask *except_hosts;
|
||||
int except_webirc;
|
||||
SecurityGroup *except;
|
||||
} cfg;
|
||||
|
||||
/* Forward declarations */
|
||||
@ -542,7 +541,8 @@ MOD_INIT()
|
||||
|
||||
/* Some default values: */
|
||||
cfg.convert_to_lowercase = 1;
|
||||
cfg.except_webirc = 1;
|
||||
cfg.except = safe_alloc(sizeof(SecurityGroup));
|
||||
cfg.except->webirc = 1;
|
||||
|
||||
return MOD_SUCCESS;
|
||||
}
|
||||
@ -562,7 +562,7 @@ MOD_UNLOAD()
|
||||
static void free_config(void)
|
||||
{
|
||||
safe_free(cfg.ban_reason);
|
||||
unreal_delete_masks(cfg.except_hosts);
|
||||
free_security_group(cfg.except);
|
||||
memset(&cfg, 0, sizeof(cfg)); /* needed! */
|
||||
}
|
||||
|
||||
@ -580,6 +580,10 @@ int antirandom_config_test(ConfigFile *cf, ConfigEntry *ce, int type, int *errs)
|
||||
|
||||
for (cep = ce->items; cep; cep = cep->next)
|
||||
{
|
||||
if (!strcmp(cep->name, "except"))
|
||||
{
|
||||
test_match_block(cf, cep, &errors);
|
||||
} else
|
||||
if (!strcmp(cep->name, "except-hosts"))
|
||||
{
|
||||
} else
|
||||
@ -653,14 +657,20 @@ int antirandom_config_run(ConfigFile *cf, ConfigEntry *ce, int type)
|
||||
|
||||
for (cep = ce->items; cep; cep = cep->next)
|
||||
{
|
||||
if (!strcmp(cep->name, "except"))
|
||||
{
|
||||
conf_match_block(cf, cep, &cfg.except);
|
||||
} else
|
||||
if (!strcmp(cep->name, "except-hosts"))
|
||||
{
|
||||
/* backwards compatible with set::antirandom::except */
|
||||
for (cep2 = cep->items; cep2; cep2 = cep2->next)
|
||||
unreal_add_masks(&cfg.except_hosts, cep2);
|
||||
unreal_add_masks(&cfg.except->mask, cep2);
|
||||
} else
|
||||
if (!strcmp(cep->name, "except-webirc"))
|
||||
{
|
||||
cfg.except_webirc = config_checkval(cep->value, CFG_YESNO);
|
||||
/* backwards compatible with set::antirandom::except */
|
||||
cfg.except->webirc = config_checkval(cep->value, CFG_YESNO);
|
||||
} else
|
||||
if (!strcmp(cep->name, "threshold"))
|
||||
{
|
||||
@ -863,14 +873,14 @@ int antirandom_preconnect(Client *client)
|
||||
if (cfg.ban_action == BAN_ACT_WARN)
|
||||
{
|
||||
unreal_log(ULOG_INFO, "antirandom", "ANTIRANDOM_DENIED_USER", client,
|
||||
"[antirandom] would have denied access to user with score $score: $client:$client.info",
|
||||
"[antirandom] would have denied access to user with score $score: $client.details:$client.user.realname",
|
||||
log_data_integer("score", score));
|
||||
return HOOK_CONTINUE;
|
||||
}
|
||||
if (cfg.show_failedconnects)
|
||||
{
|
||||
unreal_log(ULOG_INFO, "antirandom", "ANTIRANDOM_DENIED_USER", client,
|
||||
"[antirandom] denied access to user with score $score: $client:$client.info",
|
||||
"[antirandom] denied access to user with score $score: $client.details:$client.user.realname",
|
||||
log_data_integer("score", score));
|
||||
}
|
||||
place_host_ban(client, cfg.ban_action, cfg.ban_reason, cfg.ban_time);
|
||||
@ -894,13 +904,8 @@ static void free_stuff(void)
|
||||
/** Is this user exempt from antirandom interventions? */
|
||||
static int is_exempt(Client *client)
|
||||
{
|
||||
/* WEBIRC gateway and exempt? */
|
||||
if (cfg.except_webirc)
|
||||
{
|
||||
const char *val = moddata_client_get(client, "webirc");
|
||||
if (val && (atoi(val)>0))
|
||||
if (user_allowed_by_security_group(client, cfg.except))
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (find_tkl_exception(TKL_ANTIRANDOM, client))
|
||||
return 1;
|
||||
@ -909,6 +914,5 @@ static int is_exempt(Client *client)
|
||||
if (IsSoftBanAction(cfg.ban_action) && IsLoggedIn(client))
|
||||
return 1;
|
||||
|
||||
/* On except host? */
|
||||
return unreal_mask_match(client, cfg.except_hosts);
|
||||
return 0;
|
||||
}
|
||||
|
@ -67,6 +67,7 @@ struct Blacklist {
|
||||
int action;
|
||||
long ban_time;
|
||||
char *reason;
|
||||
SecurityGroup *except;
|
||||
};
|
||||
|
||||
/* Blacklist user struct. In the c-ares DNS reply callback we need to pass
|
||||
@ -236,6 +237,8 @@ void delete_blacklist_block(Blacklist *e)
|
||||
|
||||
safe_free(e->name);
|
||||
safe_free(e->reason);
|
||||
free_security_group(e->except);
|
||||
|
||||
safe_free(e);
|
||||
}
|
||||
|
||||
@ -356,6 +359,10 @@ int blacklist_config_test(ConfigFile *cf, ConfigEntry *ce, int type, int *errs)
|
||||
}
|
||||
}
|
||||
} else
|
||||
if (!strcmp(cep->name, "except"))
|
||||
{
|
||||
test_match_block(cf, cep, &errors);
|
||||
} else
|
||||
if (!cep->value)
|
||||
{
|
||||
config_error_empty(cep->file->filename, cep->line_number,
|
||||
@ -388,8 +395,8 @@ int blacklist_config_test(ConfigFile *cf, ConfigEntry *ce, int type, int *errs)
|
||||
continue;
|
||||
}
|
||||
has_ban_time = 1;
|
||||
} else
|
||||
if (!strcmp(cep->name, "reason"))
|
||||
}
|
||||
else if (!strcmp(cep->name, "reason"))
|
||||
{
|
||||
if (has_reason)
|
||||
{
|
||||
@ -524,13 +531,17 @@ int blacklist_config_run(ConfigFile *cf, ConfigEntry *ce, int type)
|
||||
{
|
||||
d->action = banact_stringtoval(cep->value);
|
||||
}
|
||||
else if (!strcmp(cep->name, "ban-time"))
|
||||
{
|
||||
d->ban_time = config_checkval(cep->value, CFG_TIME);
|
||||
}
|
||||
else if (!strcmp(cep->name, "reason"))
|
||||
{
|
||||
safe_strdup(d->reason, cep->value);
|
||||
}
|
||||
else if (!strcmp(cep->name, "ban-time"))
|
||||
else if (!strcmp(cep->name, "except"))
|
||||
{
|
||||
d->ban_time = config_checkval(cep->value, CFG_TIME);
|
||||
conf_match_block(cf, cep, &d->except);
|
||||
}
|
||||
}
|
||||
|
||||
@ -587,6 +598,10 @@ int blacklist_start_check(Client *client)
|
||||
if (!BLUSER(client))
|
||||
break;
|
||||
|
||||
/* Check if user is exempt (then don't bother checking) */
|
||||
if (user_allowed_by_security_group(client, bl->except))
|
||||
continue;
|
||||
|
||||
/* Initiate blacklist requests */
|
||||
if (bl->backend_type == BLACKLIST_BACKEND_DNS)
|
||||
blacklist_dns_request(client, bl);
|
||||
|
@ -45,6 +45,12 @@ MOD_INIT()
|
||||
|
||||
MARK_AS_OFFICIAL_MODULE(modinfo);
|
||||
|
||||
memset(&mtag, 0, sizeof(mtag));
|
||||
mtag.name = "bot";
|
||||
mtag.is_ok = bottag_mtag_is_ok;
|
||||
mtag.flags = MTAG_HANDLER_FLAGS_NO_CAP_NEEDED;
|
||||
MessageTagHandlerAdd(modinfo->handle, &mtag);
|
||||
|
||||
memset(&mtag, 0, sizeof(mtag));
|
||||
mtag.name = "draft/bot";
|
||||
mtag.is_ok = bottag_mtag_is_ok;
|
||||
@ -82,7 +88,14 @@ void mtag_add_bottag(Client *client, MessageTag *recv_mtags, MessageTag **mtag_l
|
||||
|
||||
if (IsUser(client) && has_user_mode(client, 'B'))
|
||||
{
|
||||
MessageTag *m = safe_alloc(sizeof(MessageTag));
|
||||
MessageTag *m;
|
||||
|
||||
m = safe_alloc(sizeof(MessageTag));
|
||||
safe_strdup(m->name, "bot");
|
||||
m->value = NULL;
|
||||
AddListItem(m, *mtag_list);
|
||||
|
||||
m = safe_alloc(sizeof(MessageTag));
|
||||
safe_strdup(m->name, "draft/bot");
|
||||
m->value = NULL;
|
||||
AddListItem(m, *mtag_list);
|
||||
|
@ -6,7 +6,7 @@
|
||||
*
|
||||
* (C) Copyright 2014-2015 The UnrealIRCd team (Syzop, DBoyz, Nath and others)
|
||||
*
|
||||
* License: GPLv2
|
||||
* License: GPLv2 or later
|
||||
*/
|
||||
|
||||
#include "unrealircd.h"
|
||||
@ -27,6 +27,7 @@ void certfp_unserialize(const char *str, ModData *m);
|
||||
int certfp_handshake(Client *client);
|
||||
int certfp_connect(Client *client);
|
||||
int certfp_whois(Client *client, Client *target, NameValuePrioList **list);
|
||||
int certfp_log(Client *client, int detail, json_t *j);
|
||||
|
||||
ModDataInfo *certfp_md; /* Module Data structure which we acquire */
|
||||
|
||||
@ -51,6 +52,7 @@ MOD_INIT()
|
||||
HookAdd(modinfo->handle, HOOKTYPE_HANDSHAKE, 0, certfp_handshake);
|
||||
HookAdd(modinfo->handle, HOOKTYPE_SERVER_HANDSHAKE_OUT, 0, certfp_handshake);
|
||||
HookAdd(modinfo->handle, HOOKTYPE_WHOIS, 0, certfp_whois);
|
||||
HookAdd(modinfo->handle, HOOKTYPE_JSON_EXPAND_CLIENT, 0, certfp_log);
|
||||
|
||||
return MOD_SUCCESS;
|
||||
}
|
||||
@ -158,3 +160,24 @@ void certfp_unserialize(const char *str, ModData *m)
|
||||
{
|
||||
safe_strdup(m->str, str);
|
||||
}
|
||||
|
||||
int certfp_log(Client *client, int detail, json_t *j)
|
||||
{
|
||||
json_t *tls;
|
||||
const char *str;
|
||||
|
||||
str = moddata_client_get(client, "certfp");
|
||||
if (!str)
|
||||
return 0;
|
||||
|
||||
tls = json_object_get(j, "tls");
|
||||
if (!tls)
|
||||
{
|
||||
tls = json_object();
|
||||
json_object_set_new(j, "tls", tls);
|
||||
}
|
||||
|
||||
json_object_set_new(tls, "certfp", json_string_unreal(str));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -110,7 +110,7 @@ struct ChannelFloodProtection {
|
||||
/* Global variables */
|
||||
ModDataInfo *mdflood = NULL;
|
||||
Cmode_t EXTMODE_FLOODLIMIT = 0L;
|
||||
static int timedban_available = 0; /**< Set to 1 if extbans/timedban module is loaded. */
|
||||
static int timedban_available = 1; /**< Set to 1 if extbans/timedban module is loaded. Assumed 1 during config load due to set::modes-on-join race. */
|
||||
RemoveChannelModeTimer *removechannelmodetimer_list = NULL;
|
||||
char *floodprot_msghash_key = NULL;
|
||||
|
||||
|
@ -1,7 +1,7 @@
|
||||
/*
|
||||
* modules/chanmodes/history - Channel History
|
||||
* (C) Copyright 2009-2019 Bram Matthys (Syzop) and the UnrealIRCd team
|
||||
* License: GPLv2
|
||||
* License: GPLv2 or later
|
||||
*/
|
||||
#include "unrealircd.h"
|
||||
|
||||
|
@ -35,7 +35,7 @@ Cmode_t EXTCMODE_OPERONLY;
|
||||
int operonly_require_oper(Client *client, Channel *channel, char mode, const char *para, int checkt, int what);
|
||||
int operonly_can_join(Client *client, Channel *channel, const char *key, char **errmsg);
|
||||
int operonly_view_topic_outside_channel(Client *client, Channel *channel);
|
||||
int operonly_oper_invite_ban(Client *client, Channel *channel);
|
||||
int operonly_invite_bypass(Client *client, Channel *channel);
|
||||
|
||||
MOD_TEST()
|
||||
{
|
||||
@ -53,7 +53,7 @@ CmodeInfo req;
|
||||
CmodeAdd(modinfo->handle, req, &EXTCMODE_OPERONLY);
|
||||
|
||||
HookAdd(modinfo->handle, HOOKTYPE_CAN_JOIN, 0, operonly_can_join);
|
||||
HookAdd(modinfo->handle, HOOKTYPE_OPER_INVITE_BAN, 0, operonly_oper_invite_ban);
|
||||
HookAdd(modinfo->handle, HOOKTYPE_INVITE_BYPASS, 0, operonly_invite_bypass);
|
||||
HookAdd(modinfo->handle, HOOKTYPE_VIEW_TOPIC_OUTSIDE_CHANNEL, 0, operonly_view_topic_outside_channel);
|
||||
|
||||
|
||||
@ -81,10 +81,9 @@ int operonly_can_join(Client *client, Channel *channel, const char *key, char **
|
||||
return 0;
|
||||
}
|
||||
|
||||
int operonly_oper_invite_ban(Client *client, Channel *channel)
|
||||
int operonly_invite_bypass(Client *client, Channel *channel)
|
||||
{
|
||||
if ((channel->mode.mode & EXTCMODE_OPERONLY) &&
|
||||
!ValidatePermissionsForPath("channel:operonly:ban",client,NULL,NULL,NULL))
|
||||
if ((channel->mode.mode & EXTCMODE_OPERONLY) && !ValidatePermissionsForPath("channel:operonly:ban",client,NULL,NULL,NULL))
|
||||
return HOOK_DENY;
|
||||
|
||||
return HOOK_CONTINUE;
|
||||
|
95
src/modules/channel-context.c
Normal file
95
src/modules/channel-context.c
Normal file
@ -0,0 +1,95 @@
|
||||
/*
|
||||
* IRC - Internet Relay Chat, src/modules/channel-context.c
|
||||
* (C) 2022 Valware & The UnrealIRCd Team
|
||||
*
|
||||
* See file AUTHORS in IRC package for additional names of
|
||||
* the programmers.
|
||||
*
|
||||
* 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
|
||||
= {
|
||||
"channel-context",
|
||||
"1.0",
|
||||
"Channel Context (IRCv3)",
|
||||
"UnrealIRCd team",
|
||||
"unrealircd-6",
|
||||
};
|
||||
|
||||
int chancontext_mtag_is_ok(Client *client, const char *name, const char *value);
|
||||
void mtag_add_chancontext(Client *client, MessageTag *recv_mtags, MessageTag **mtag_list, const char *signature);
|
||||
|
||||
MOD_INIT()
|
||||
{
|
||||
MessageTagHandlerInfo mtag;
|
||||
|
||||
MARK_AS_OFFICIAL_MODULE(modinfo);
|
||||
|
||||
memset(&mtag, 0, sizeof(mtag));
|
||||
mtag.is_ok = chancontext_mtag_is_ok;
|
||||
mtag.flags = MTAG_HANDLER_FLAGS_NO_CAP_NEEDED;
|
||||
mtag.name = "+draft/channel-context";
|
||||
MessageTagHandlerAdd(modinfo->handle, &mtag);
|
||||
|
||||
HookAddVoid(modinfo->handle, HOOKTYPE_NEW_MESSAGE, 0, mtag_add_chancontext);
|
||||
|
||||
return MOD_SUCCESS;
|
||||
}
|
||||
|
||||
MOD_LOAD()
|
||||
{
|
||||
return MOD_SUCCESS;
|
||||
}
|
||||
|
||||
MOD_UNLOAD()
|
||||
{
|
||||
return MOD_SUCCESS;
|
||||
}
|
||||
|
||||
int chancontext_mtag_is_ok(Client *client, const char *name, const char *value)
|
||||
{
|
||||
if (BadPtr(value))
|
||||
return 0;
|
||||
|
||||
/* Validate a bit further, but only for local users.. */
|
||||
if (MyUser(client))
|
||||
{
|
||||
Channel *channel = find_channel(value);
|
||||
if (!channel)
|
||||
return 0;
|
||||
if (!IsMember(client, channel))
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
void mtag_add_chancontext(Client *client, MessageTag *recv_mtags, MessageTag **mtag_list, const char *signature)
|
||||
{
|
||||
MessageTag *m;
|
||||
|
||||
if (IsUser(client))
|
||||
{
|
||||
m = find_mtag(recv_mtags, "+draft/channel-context");
|
||||
if (m)
|
||||
{
|
||||
m = duplicate_mtag(m);
|
||||
AddListItem(m, *mtag_list);
|
||||
}
|
||||
}
|
||||
}
|
@ -1,7 +1,7 @@
|
||||
/*
|
||||
* Stores channel settings for +P channels in a .db file
|
||||
* (C) Copyright 2019 Syzop, Gottem and the UnrealIRCd team
|
||||
* License: GPLv2
|
||||
* License: GPLv2 or later
|
||||
*/
|
||||
|
||||
#include "unrealircd.h"
|
||||
@ -359,6 +359,14 @@ int write_channel_entry(UnrealDB *db, const char *tmpfname, Channel *channel)
|
||||
return 1;
|
||||
}
|
||||
|
||||
int ban_exists(Ban *lst, Ban *e)
|
||||
{
|
||||
for (; lst; lst = lst->next)
|
||||
if (!mycmp(lst->banstr, e->banstr))
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
#define R_SAFE(x) \
|
||||
do { \
|
||||
if (!(x)) { \
|
||||
@ -401,11 +409,19 @@ int read_listmode(UnrealDB *db, Ban **lst)
|
||||
}
|
||||
safe_strdup(e->banstr, str);
|
||||
|
||||
if (ban_exists(*lst, e))
|
||||
{
|
||||
/* Free again - duplicate item */
|
||||
safe_free(e->banstr);
|
||||
safe_free(e->who);
|
||||
safe_free(e);
|
||||
} else {
|
||||
/* Add to list */
|
||||
e->when = when;
|
||||
e->next = *lst;
|
||||
*lst = e;
|
||||
}
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
@ -1,6 +1,6 @@
|
||||
/* src/modules/chathistory.c - IRCv3 CHATHISTORY command.
|
||||
* (C) Copyright 2021 Bram Matthys (Syzop) and the UnrealIRCd team
|
||||
* License: GPLv2
|
||||
* License: GPLv2 or later
|
||||
*
|
||||
* This implements the "CHATHISTORY" command, the CAP and 005 token.
|
||||
* https://ircv3.net/specs/extensions/chathistory
|
||||
|
@ -231,6 +231,9 @@ void _userhost_changed(Client *client)
|
||||
if (HasCapabilityFast(client, CAP_CHGHOST))
|
||||
sendto_one(client, NULL, "%s", buf);
|
||||
|
||||
if (MyUser(client))
|
||||
sendnumeric(client, RPL_HOSTHIDDEN, GetHost(client));
|
||||
|
||||
/* A userhost change always generates the following network traffic:
|
||||
* server to server traffic, CAP "chghost" notifications, and
|
||||
* possibly PART+JOIN+MODE if force-rejoin had work to do.
|
||||
@ -338,7 +341,4 @@ CMD_FUNC(cmd_chghost)
|
||||
safe_strdup(target->user->virthost, parv[2]);
|
||||
|
||||
userhost_changed(target);
|
||||
|
||||
if (MyUser(target))
|
||||
sendnumeric(target, RPL_HOSTHIDDEN, parv[2]);
|
||||
}
|
||||
|
@ -106,10 +106,10 @@ CMD_FUNC(cmd_connect)
|
||||
return;
|
||||
}
|
||||
|
||||
if (!aconf->outgoing.hostname)
|
||||
if (!aconf->outgoing.hostname && !aconf->outgoing.file)
|
||||
{
|
||||
sendnotice(client,
|
||||
"*** Connect: Server %s is not configured to be an outgoing link (has a link block, but no link::outgoing::hostname)",
|
||||
"*** Connect: Server %s is not configured to be an outgoing link (has a link block, but no link::outgoing::hostname or link::outgoing::file)",
|
||||
parv[1]);
|
||||
return;
|
||||
}
|
||||
|
@ -1,7 +1,7 @@
|
||||
/*
|
||||
* connthrottle - Connection throttler
|
||||
* (C) Copyright 2004-2020 Bram Matthys (Syzop) and the UnrealIRCd team
|
||||
* License: GPLv2
|
||||
* License: GPLv2 or later
|
||||
* See https://www.unrealircd.org/docs/Connthrottle
|
||||
*/
|
||||
|
||||
@ -31,10 +31,8 @@ struct cfgstruct {
|
||||
/* set::connthrottle::known-users: */
|
||||
ThrottleSetting local;
|
||||
ThrottleSetting global;
|
||||
/* set::connthrottle::new-users: */
|
||||
int minimum_reputation_score;
|
||||
int sasl_bypass;
|
||||
int webirc_bypass;
|
||||
/* set::connthrottle::except: */
|
||||
SecurityGroup *except;
|
||||
/* set::connthrottle::disabled-when: */
|
||||
long reputation_gathering;
|
||||
int start_delay;
|
||||
@ -53,10 +51,8 @@ struct UCounter {
|
||||
ThrottleCounter local; /**< Local counter */
|
||||
ThrottleCounter global; /**< Global counter */
|
||||
int rejected_clients; /**< Number of rejected clients this minute */
|
||||
int allowed_score; /**< Number of allowed clients of type known-user */
|
||||
int allowed_sasl; /**< Number of allowed clients of type SASL */
|
||||
int allowed_webirc; /**< Number of allowed clients of type WEBIRC */
|
||||
int allowed_other; /**< Number of allowed clients of type other (new) */
|
||||
int allowed_except; /**< Number of allowed clients - on except list */
|
||||
int allowed_unknown_users; /**< Number of allowed clients - not on except list */
|
||||
char disabled; /**< Module disabled by oper? */
|
||||
int throttling_this_minute; /**< Did we do any throttling this minute? */
|
||||
int throttling_previous_minute; /**< Did we do any throttling previous minute? */
|
||||
@ -87,9 +83,10 @@ MOD_TEST()
|
||||
cfg.global.count = 30; cfg.global.period = 60;
|
||||
cfg.start_delay = 180; /* 3 minutes */
|
||||
safe_strdup(cfg.reason, "Throttled: Too many users trying to connect, please wait a while and try again");
|
||||
cfg.minimum_reputation_score = 24;
|
||||
cfg.sasl_bypass = 1;
|
||||
cfg.webirc_bypass = 0;
|
||||
cfg.except = safe_alloc(sizeof(SecurityGroup));
|
||||
cfg.except->reputation_score = 24;
|
||||
cfg.except->identified = 1;
|
||||
cfg.except->webirc = 0;
|
||||
|
||||
HookAdd(modinfo->handle, HOOKTYPE_CONFIGTEST, 0, ct_config_test);
|
||||
HookAdd(modinfo->handle, HOOKTYPE_CONFIGPOSTTEST, 0, ct_config_posttest);
|
||||
@ -120,6 +117,7 @@ MOD_UNLOAD()
|
||||
{
|
||||
SavePersistentPointer(modinfo, ucounter);
|
||||
safe_free(cfg.reason);
|
||||
free_security_group(cfg.except);
|
||||
return MOD_SUCCESS;
|
||||
}
|
||||
|
||||
@ -161,6 +159,10 @@ int ct_config_test(ConfigFile *cf, ConfigEntry *ce, int type, int *errs)
|
||||
|
||||
for (cep = ce->items; cep; cep = cep->next)
|
||||
{
|
||||
if (!strcmp(cep->name, "except"))
|
||||
{
|
||||
test_match_block(cf, cep, &errors);
|
||||
} else
|
||||
if (!strcmp(cep->name, "known-users"))
|
||||
{
|
||||
for (cepp = cep->items; cepp; cepp = cepp->next)
|
||||
@ -286,16 +288,20 @@ int ct_config_run(ConfigFile *cf, ConfigEntry *ce, int type)
|
||||
|
||||
for (cep = ce->items; cep; cep = cep->next)
|
||||
{
|
||||
if (!strcmp(cep->name, "except"))
|
||||
{
|
||||
conf_match_block(cf, cep, &cfg.except);
|
||||
} else
|
||||
if (!strcmp(cep->name, "known-users"))
|
||||
{
|
||||
for (cepp = cep->items; cepp; cepp = cepp->next)
|
||||
{
|
||||
if (!strcmp(cepp->name, "minimum-reputation-score"))
|
||||
cfg.minimum_reputation_score = atoi(cepp->value);
|
||||
cfg.except->reputation_score = atoi(cepp->value);
|
||||
else if (!strcmp(cepp->name, "sasl-bypass"))
|
||||
cfg.sasl_bypass = config_checkval(cepp->value, CFG_YESNO);
|
||||
cfg.except->identified = config_checkval(cepp->value, CFG_YESNO);
|
||||
else if (!strcmp(cepp->name, "webirc-bypass"))
|
||||
cfg.webirc_bypass = config_checkval(cepp->value, CFG_YESNO);
|
||||
cfg.except->webirc = config_checkval(cepp->value, CFG_YESNO);
|
||||
}
|
||||
} else
|
||||
if (!strcmp(cep->name, "new-users"))
|
||||
@ -360,23 +366,17 @@ EVENT(connthrottle_evt)
|
||||
unreal_log(ULOG_INFO, "connthrottle", "CONNTHROTLE_REPORT", NULL,
|
||||
"ConnThrottle] Stats for this server past 60 secs: "
|
||||
"Connections rejected: $num_rejected. "
|
||||
"Accepted: $num_accepted_known_users known user(s), "
|
||||
"$num_accepted_sasl SASL, "
|
||||
"$num_accepted_webirc WEBIRC and "
|
||||
"Accepted: $num_accepted_except except user(s) and "
|
||||
"$num_accepted_unknown_users new user(s).",
|
||||
log_data_integer("num_rejected", ucounter->rejected_clients),
|
||||
log_data_integer("num_accepted_known_users", ucounter->allowed_score),
|
||||
log_data_integer("num_accepted_sasl", ucounter->allowed_sasl),
|
||||
log_data_integer("num_accepted_webirc", ucounter->allowed_webirc),
|
||||
log_data_integer("num_accepted_unknown_users", ucounter->allowed_other));
|
||||
log_data_integer("num_accepted_except", ucounter->allowed_except),
|
||||
log_data_integer("num_accepted_unknown_users", ucounter->allowed_unknown_users));
|
||||
}
|
||||
|
||||
/* Reset stats for next message */
|
||||
ucounter->rejected_clients = 0;
|
||||
ucounter->allowed_score = 0;
|
||||
ucounter->allowed_sasl = 0;
|
||||
ucounter->allowed_webirc = 0;
|
||||
ucounter->allowed_other = 0;
|
||||
ucounter->allowed_except = 0;
|
||||
ucounter->allowed_unknown_users = 0;
|
||||
|
||||
ucounter->throttling_previous_minute = ucounter->throttling_this_minute;
|
||||
ucounter->throttling_this_minute = 0; /* reset */
|
||||
@ -399,24 +399,8 @@ int ct_pre_lconnect(Client *client)
|
||||
if (still_reputation_gathering())
|
||||
return HOOK_CONTINUE; /* still gathering reputation data */
|
||||
|
||||
if (cfg.sasl_bypass && IsLoggedIn(client))
|
||||
{
|
||||
/* Allowed in: user authenticated using SASL */
|
||||
return HOOK_CONTINUE;
|
||||
}
|
||||
|
||||
if (cfg.webirc_bypass && moddata_client_get(client, "webirc"))
|
||||
{
|
||||
/* Allowed in: user using WEBIRC */
|
||||
return HOOK_CONTINUE;
|
||||
}
|
||||
|
||||
score = GetReputation(client);
|
||||
if (score >= cfg.minimum_reputation_score)
|
||||
{
|
||||
/* Allowed in: IP has enough reputation ("known user") */
|
||||
return HOOK_CONTINUE;
|
||||
}
|
||||
if (user_allowed_by_security_group(client, cfg.except))
|
||||
return HOOK_CONTINUE; /* allowed: user is exempt (known user or otherwise) */
|
||||
|
||||
/* If we reach this then the user is NEW */
|
||||
|
||||
@ -486,30 +470,14 @@ int ct_lconnect(Client *client)
|
||||
if (still_reputation_gathering())
|
||||
return 0; /* still gathering reputation data */
|
||||
|
||||
if (cfg.sasl_bypass && IsLoggedIn(client))
|
||||
if (user_allowed_by_security_group(client, cfg.except))
|
||||
{
|
||||
/* Allowed in: user authenticated using SASL */
|
||||
ucounter->allowed_sasl++;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (cfg.webirc_bypass && moddata_client_get(client, "webirc"))
|
||||
{
|
||||
/* Allowed in: user using WEBIRC */
|
||||
ucounter->allowed_webirc++;
|
||||
return 0;
|
||||
}
|
||||
|
||||
score = GetReputation(client);
|
||||
if (score >= cfg.minimum_reputation_score)
|
||||
{
|
||||
/* Allowed in: IP has enough reputation ("known user") */
|
||||
ucounter->allowed_score++;
|
||||
return 0;
|
||||
ucounter->allowed_except++;
|
||||
return HOOK_CONTINUE; /* allowed: user is exempt (known user or otherwise) */
|
||||
}
|
||||
|
||||
/* Allowed NEW user */
|
||||
ucounter->allowed_other++;
|
||||
ucounter->allowed_unknown_users++;
|
||||
|
||||
bump_connect_counter(1);
|
||||
|
||||
@ -539,9 +507,8 @@ int ct_rconnect(Client *client)
|
||||
}
|
||||
#endif
|
||||
|
||||
score = GetReputation(client);
|
||||
if (score >= cfg.minimum_reputation_score)
|
||||
return 0; /* sufficient reputation: "known-user" */
|
||||
if (user_allowed_by_security_group(client, cfg.except))
|
||||
return 0; /* user is on except list (known user or otherwise) */
|
||||
|
||||
bump_connect_counter(0);
|
||||
|
||||
|
99
src/modules/creationtime.c
Normal file
99
src/modules/creationtime.c
Normal file
@ -0,0 +1,99 @@
|
||||
/*
|
||||
* Store creationtime in ModData
|
||||
* (C) Copyright 2022-.. Syzop and The UnrealIRCd Team
|
||||
* License: GPLv2 or later
|
||||
*/
|
||||
|
||||
#include "unrealircd.h"
|
||||
|
||||
ModuleHeader MOD_HEADER
|
||||
= {
|
||||
"creationtime",
|
||||
"6.0",
|
||||
"Store and retrieve creation time of clients",
|
||||
"UnrealIRCd Team",
|
||||
"unrealircd-6",
|
||||
};
|
||||
|
||||
/* Forward declarations */
|
||||
void creationtime_free(ModData *m);
|
||||
const char *creationtime_serialize(ModData *m);
|
||||
void creationtime_unserialize(const char *str, ModData *m);
|
||||
int creationtime_handshake(Client *client);
|
||||
int creationtime_welcome_user(Client *client, int numeric);
|
||||
int creationtime_whois(Client *client, Client *target);
|
||||
|
||||
ModDataInfo *creationtime_md; /* Module Data structure which we acquire */
|
||||
|
||||
#define SetCreationTime(x,y) do { moddata_client(x, creationtime_md).ll = y; } while(0)
|
||||
|
||||
MOD_INIT()
|
||||
{
|
||||
ModDataInfo mreq;
|
||||
|
||||
MARK_AS_OFFICIAL_MODULE(modinfo);
|
||||
|
||||
memset(&mreq, 0, sizeof(mreq));
|
||||
mreq.name = "creationtime";
|
||||
mreq.free = creationtime_free;
|
||||
mreq.serialize = creationtime_serialize;
|
||||
mreq.unserialize = creationtime_unserialize;
|
||||
mreq.sync = MODDATA_SYNC_EARLY;
|
||||
mreq.type = MODDATATYPE_CLIENT;
|
||||
creationtime_md = ModDataAdd(modinfo->handle, mreq);
|
||||
if (!creationtime_md)
|
||||
abort();
|
||||
|
||||
/* This event sets creationtime very early: on handshake in and out */
|
||||
HookAdd(modinfo->handle, HOOKTYPE_HANDSHAKE, 0, creationtime_handshake);
|
||||
HookAdd(modinfo->handle, HOOKTYPE_SERVER_HANDSHAKE_OUT, 0, creationtime_handshake);
|
||||
|
||||
/* And this event (re)sets it because that also happens in
|
||||
* welcome_user() in nick.c regarding #2174
|
||||
*/
|
||||
HookAdd(modinfo->handle, HOOKTYPE_WELCOME, 0, creationtime_welcome_user);
|
||||
|
||||
return MOD_SUCCESS;
|
||||
}
|
||||
|
||||
MOD_LOAD()
|
||||
{
|
||||
return MOD_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
MOD_UNLOAD()
|
||||
{
|
||||
return MOD_SUCCESS;
|
||||
}
|
||||
|
||||
int creationtime_handshake(Client *client)
|
||||
{
|
||||
SetCreationTime(client, client->local->creationtime);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int creationtime_welcome_user(Client *client, int numeric)
|
||||
{
|
||||
if (numeric == 0)
|
||||
SetCreationTime(client, client->local->creationtime);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void creationtime_free(ModData *m)
|
||||
{
|
||||
m->ll = 0;
|
||||
}
|
||||
|
||||
const char *creationtime_serialize(ModData *m)
|
||||
{
|
||||
static char buf[64];
|
||||
|
||||
snprintf(buf, sizeof(buf), "%lld", (long long)m->ll);
|
||||
return buf;
|
||||
}
|
||||
|
||||
void creationtime_unserialize(const char *str, ModData *m)
|
||||
{
|
||||
m->ll = atoll(str);
|
||||
}
|
@ -31,8 +31,7 @@ ModuleHeader MOD_HEADER
|
||||
const char *extban_account_conv_param(BanContext *b, Extban *extban);
|
||||
int extban_account_is_banned(BanContext *b);
|
||||
|
||||
/** Called upon module init */
|
||||
MOD_INIT()
|
||||
Extban *register_account_extban(ModuleInfo *modinfo)
|
||||
{
|
||||
ExtbanInfo req;
|
||||
|
||||
@ -44,14 +43,30 @@ MOD_INIT()
|
||||
req.is_banned = extban_account_is_banned;
|
||||
req.is_banned_events = BANCHK_ALL|BANCHK_TKL;
|
||||
req.options = EXTBOPT_INVEX|EXTBOPT_TKL;
|
||||
if (!ExtbanAdd(modinfo->handle, req))
|
||||
return ExtbanAdd(modinfo->handle, req);
|
||||
}
|
||||
|
||||
/** Called upon module test */
|
||||
MOD_TEST()
|
||||
{
|
||||
if (!register_account_extban(modinfo))
|
||||
{
|
||||
config_error("could not register extended ban type");
|
||||
return MOD_FAILED;
|
||||
}
|
||||
return MOD_SUCCESS;
|
||||
}
|
||||
|
||||
/** Called upon module init */
|
||||
MOD_INIT()
|
||||
{
|
||||
if (!register_account_extban(modinfo))
|
||||
{
|
||||
config_error("could not register extended ban type");
|
||||
return MOD_FAILED;
|
||||
}
|
||||
|
||||
MARK_AS_OFFICIAL_MODULE(modinfo);
|
||||
|
||||
return MOD_SUCCESS;
|
||||
}
|
||||
|
||||
@ -95,7 +110,7 @@ int extban_account_is_banned(BanContext *b)
|
||||
if (!strcmp(b->banstr, "*") && IsLoggedIn(b->client))
|
||||
return 1;
|
||||
|
||||
if (match_simple(b->banstr, b->client->user->account))
|
||||
if (b->client->user && match_simple(b->banstr, b->client->user->account))
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
|
@ -32,8 +32,7 @@ int extban_certfp_is_ok(BanContext *b);
|
||||
const char *extban_certfp_conv_param(BanContext *b, Extban *extban);
|
||||
int extban_certfp_is_banned(BanContext *b);
|
||||
|
||||
/* Called upon module init */
|
||||
MOD_INIT()
|
||||
Extban *register_certfp_extban(ModuleInfo *modinfo)
|
||||
{
|
||||
ExtbanInfo req;
|
||||
|
||||
@ -45,7 +44,25 @@ MOD_INIT()
|
||||
req.is_banned = extban_certfp_is_banned;
|
||||
req.is_banned_events = BANCHK_ALL|BANCHK_TKL;
|
||||
req.options = EXTBOPT_INVEX|EXTBOPT_TKL;
|
||||
if (!ExtbanAdd(modinfo->handle, req))
|
||||
return ExtbanAdd(modinfo->handle, req);
|
||||
}
|
||||
|
||||
/* Called upon module test */
|
||||
MOD_TEST()
|
||||
{
|
||||
if (!register_certfp_extban(modinfo))
|
||||
{
|
||||
config_error("could not register extended ban type");
|
||||
return MOD_FAILED;
|
||||
}
|
||||
|
||||
return MOD_SUCCESS;
|
||||
}
|
||||
|
||||
/* Called upon module init */
|
||||
MOD_INIT()
|
||||
{
|
||||
if (!register_certfp_extban(modinfo))
|
||||
{
|
||||
config_error("could not register extended ban type");
|
||||
return MOD_FAILED;
|
||||
|
@ -32,8 +32,7 @@ int extban_country_is_ok(BanContext *b);
|
||||
const char *extban_country_conv_param(BanContext *b, Extban *extban);
|
||||
int extban_country_is_banned(BanContext *b);
|
||||
|
||||
/* Called upon module init */
|
||||
MOD_INIT()
|
||||
Extban *register_country_extban(ModuleInfo *modinfo)
|
||||
{
|
||||
ExtbanInfo req;
|
||||
|
||||
@ -45,7 +44,25 @@ MOD_INIT()
|
||||
req.is_banned = extban_country_is_banned;
|
||||
req.is_banned_events = BANCHK_ALL|BANCHK_TKL;
|
||||
req.options = EXTBOPT_INVEX|EXTBOPT_TKL;
|
||||
if (!ExtbanAdd(modinfo->handle, req))
|
||||
return ExtbanAdd(modinfo->handle, req);
|
||||
}
|
||||
|
||||
/* Called upon module test */
|
||||
MOD_TEST()
|
||||
{
|
||||
if (!register_country_extban(modinfo))
|
||||
{
|
||||
config_error("could not register extended ban type");
|
||||
return MOD_FAILED;
|
||||
}
|
||||
|
||||
return MOD_SUCCESS;
|
||||
}
|
||||
|
||||
/* Called upon module init */
|
||||
MOD_INIT()
|
||||
{
|
||||
if (!register_country_extban(modinfo))
|
||||
{
|
||||
config_error("could not register extended ban type");
|
||||
return MOD_FAILED;
|
||||
|
@ -31,8 +31,7 @@ ModuleHeader MOD_HEADER
|
||||
const char *extban_realname_conv_param(BanContext *b, Extban *extban);
|
||||
int extban_realname_is_banned(BanContext *b);
|
||||
|
||||
/** Called upon module init */
|
||||
MOD_INIT()
|
||||
Extban *register_realname_extban(ModuleInfo *modinfo)
|
||||
{
|
||||
ExtbanInfo req;
|
||||
|
||||
@ -44,14 +43,30 @@ MOD_INIT()
|
||||
req.is_banned = extban_realname_is_banned;
|
||||
req.is_banned_events = BANCHK_ALL|BANCHK_TKL;
|
||||
req.options = EXTBOPT_INVEX|EXTBOPT_TKL;
|
||||
if (!ExtbanAdd(modinfo->handle, req))
|
||||
return ExtbanAdd(modinfo->handle, req);
|
||||
}
|
||||
|
||||
/** Called upon module test */
|
||||
MOD_TEST()
|
||||
{
|
||||
if (!register_realname_extban(modinfo))
|
||||
{
|
||||
config_error("could not register extended ban type");
|
||||
return MOD_FAILED;
|
||||
}
|
||||
return MOD_SUCCESS;
|
||||
}
|
||||
|
||||
/** Called upon module init */
|
||||
MOD_INIT()
|
||||
{
|
||||
if (!register_realname_extban(modinfo))
|
||||
{
|
||||
config_error("could not register extended ban type");
|
||||
return MOD_FAILED;
|
||||
}
|
||||
|
||||
MARK_AS_OFFICIAL_MODULE(modinfo);
|
||||
|
||||
return MOD_SUCCESS;
|
||||
}
|
||||
|
||||
|
@ -32,8 +32,7 @@ const char *extban_securitygroup_conv_param(BanContext *b, Extban *extban);
|
||||
int extban_securitygroup_is_ok(BanContext *b);
|
||||
int extban_securitygroup_is_banned(BanContext *b);
|
||||
|
||||
/** Called upon module init */
|
||||
MOD_INIT()
|
||||
Extban *register_securitygroup_extban(ModuleInfo *modinfo)
|
||||
{
|
||||
ExtbanInfo req;
|
||||
|
||||
@ -45,7 +44,25 @@ MOD_INIT()
|
||||
req.is_banned = extban_securitygroup_is_banned;
|
||||
req.is_banned_events = BANCHK_ALL|BANCHK_TKL;
|
||||
req.options = EXTBOPT_INVEX|EXTBOPT_TKL;
|
||||
if (!ExtbanAdd(modinfo->handle, req))
|
||||
return ExtbanAdd(modinfo->handle, req);
|
||||
}
|
||||
|
||||
/** Called upon module test */
|
||||
MOD_TEST()
|
||||
{
|
||||
if (!register_securitygroup_extban(modinfo))
|
||||
{
|
||||
config_error("could not register extended ban type ~G");
|
||||
return MOD_FAILED;
|
||||
}
|
||||
|
||||
return MOD_SUCCESS;
|
||||
}
|
||||
|
||||
/** Called upon module init */
|
||||
MOD_INIT()
|
||||
{
|
||||
if (!register_securitygroup_extban(modinfo))
|
||||
{
|
||||
config_error("could not register extended ban type ~G");
|
||||
return MOD_FAILED;
|
||||
|
@ -1,7 +1,7 @@
|
||||
/*
|
||||
* timedban - Timed bans that are automatically unset.
|
||||
* (C) Copyright 2009-2017 Bram Matthys (Syzop) and the UnrealIRCd team.
|
||||
* License: GPLv2
|
||||
* License: GPLv2 or later
|
||||
*
|
||||
* This module adds an extended ban ~t:time:mask
|
||||
* Where 'time' is the time in minutes after which the ban will be removed.
|
||||
|
@ -49,7 +49,7 @@ MOD_INIT()
|
||||
ModDataInfo mreq;
|
||||
|
||||
memset(&cap, 0, sizeof(cap));
|
||||
cap.name = "draft/extended-monitor";
|
||||
cap.name = "extended-monitor";
|
||||
c = ClientCapabilityAdd(modinfo->handle, &cap, &CAP_EXTENDED_MONITOR);
|
||||
if (!c)
|
||||
{
|
||||
|
108
src/modules/geoip-tag.c
Normal file
108
src/modules/geoip-tag.c
Normal file
@ -0,0 +1,108 @@
|
||||
/*
|
||||
* IRC - Internet Relay Chat, src/modules/geoip-tag.c
|
||||
* (C) 2022 westor, Syzop and The UnrealIRCd Team
|
||||
*
|
||||
* See file AUTHORS in IRC package for additional names of
|
||||
* the programmers.
|
||||
*
|
||||
* 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
|
||||
= {
|
||||
"geoip-tag",
|
||||
"6.0",
|
||||
"geoip message tag",
|
||||
"UnrealIRCd Team",
|
||||
"unrealircd-6",
|
||||
};
|
||||
|
||||
/* Forward declarations */
|
||||
int geoip_mtag_is_ok(Client *client, const char *name, const char *value);
|
||||
int geoip_mtag_should_send_to_client(Client *target);
|
||||
void mtag_add_geoip(Client *client, MessageTag *recv_mtags, MessageTag **mtag_list, const char *signature);
|
||||
|
||||
MOD_INIT()
|
||||
{
|
||||
MessageTagHandlerInfo mtag;
|
||||
|
||||
MARK_AS_OFFICIAL_MODULE(modinfo);
|
||||
|
||||
memset(&mtag, 0, sizeof(mtag));
|
||||
mtag.name = "unrealircd.org/geoip";
|
||||
mtag.is_ok = geoip_mtag_is_ok;
|
||||
mtag.should_send_to_client = geoip_mtag_should_send_to_client;
|
||||
mtag.flags = MTAG_HANDLER_FLAGS_NO_CAP_NEEDED;
|
||||
MessageTagHandlerAdd(modinfo->handle, &mtag);
|
||||
|
||||
HookAddVoid(modinfo->handle, HOOKTYPE_NEW_MESSAGE, 0, mtag_add_geoip);
|
||||
|
||||
return MOD_SUCCESS;
|
||||
}
|
||||
|
||||
MOD_LOAD()
|
||||
{
|
||||
return MOD_SUCCESS;
|
||||
}
|
||||
|
||||
MOD_UNLOAD()
|
||||
{
|
||||
return MOD_SUCCESS;
|
||||
}
|
||||
|
||||
/** This function verifies if the client sending
|
||||
* 'geoip-tag' is permitted to do so and uses a permitted
|
||||
* syntax.
|
||||
* We simply allow geoip-tag ONLY from servers and with any syntax.
|
||||
*/
|
||||
int geoip_mtag_is_ok(Client *client, const char *name, const char *value)
|
||||
{
|
||||
if (IsServer(client))
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void mtag_add_geoip(Client *client, MessageTag *recv_mtags, MessageTag **mtag_list, const char *signature)
|
||||
{
|
||||
MessageTag *m;
|
||||
|
||||
GeoIPResult *geoip;
|
||||
|
||||
if (IsUser(client) && ((geoip = geoip_client(client))))
|
||||
{
|
||||
MessageTag *m = find_mtag(recv_mtags, "unrealircd.org/geoip");
|
||||
if (m)
|
||||
{
|
||||
m = duplicate_mtag(m);
|
||||
} else {
|
||||
m = safe_alloc(sizeof(MessageTag));
|
||||
safe_strdup(m->name, "unrealircd.org/geoip");
|
||||
safe_strdup(m->value, geoip->country_code);
|
||||
}
|
||||
AddListItem(m, *mtag_list);
|
||||
}
|
||||
}
|
||||
|
||||
/** Outgoing filter for this message tag */
|
||||
int geoip_mtag_should_send_to_client(Client *target)
|
||||
{
|
||||
if (IsServer(target) || IsOper(target))
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
}
|
@ -2,7 +2,7 @@
|
||||
* GEOIP Base module, needed for all geoip functions
|
||||
* as this stores the geo information in ModData.
|
||||
* (C) Copyright 2021-.. Syzop and The UnrealIRCd Team
|
||||
* License: GPLv2
|
||||
* License: GPLv2 or later
|
||||
*/
|
||||
|
||||
#include "unrealircd.h"
|
||||
@ -28,6 +28,7 @@ int geoip_base_handshake(Client *client);
|
||||
int geoip_base_ip_change(Client *client, const char *oldip);
|
||||
int geoip_base_whois(Client *client, Client *target, NameValuePrioList **list);
|
||||
int geoip_connect_extinfo(Client *client, NameValuePrioList **list);
|
||||
int geoip_log(Client *client, int detail, json_t *j);
|
||||
int geoip_base_configtest(ConfigFile *cf, ConfigEntry *ce, int type, int *errs);
|
||||
int geoip_base_configrun(ConfigFile *cf, ConfigEntry *ce, int type);
|
||||
EVENT(geoip_base_set_existing_users_evt);
|
||||
@ -125,6 +126,7 @@ MOD_INIT()
|
||||
HookAdd(modinfo->handle, HOOKTYPE_CONNECT_EXTINFO, 1, geoip_connect_extinfo); /* (prio: near-first) */
|
||||
HookAdd(modinfo->handle, HOOKTYPE_PRE_LOCAL_CONNECT, 0,geoip_base_handshake); /* in case the IP changed in registration phase (WEBIRC, HTTP Forwarded) */
|
||||
HookAdd(modinfo->handle, HOOKTYPE_WHOIS, 0, geoip_base_whois);
|
||||
HookAdd(modinfo->handle, HOOKTYPE_JSON_EXPAND_CLIENT, 0, geoip_log);
|
||||
|
||||
CommandAdd(modinfo->handle, "GEOIP", cmd_geoip, MAXPARA, CMD_USER);
|
||||
|
||||
@ -206,7 +208,7 @@ void geoip_base_unserialize(const char *str, ModData *m)
|
||||
char *country_code = NULL;
|
||||
GeoIPResult *res;
|
||||
|
||||
if (m->ptr == NULL)
|
||||
if (m->ptr)
|
||||
{
|
||||
free_geoip_result((GeoIPResult *)m->ptr);
|
||||
m->ptr = NULL;
|
||||
@ -254,6 +256,21 @@ int geoip_connect_extinfo(Client *client, NameValuePrioList **list)
|
||||
return 0;
|
||||
}
|
||||
|
||||
int geoip_log(Client *client, int detail, json_t *j)
|
||||
{
|
||||
GeoIPResult *geo = GEOIPDATA(client);
|
||||
json_t *geoip;
|
||||
|
||||
if (!geo)
|
||||
return 0;
|
||||
|
||||
geoip = json_object();
|
||||
json_object_set_new(j, "geoip", geoip);
|
||||
json_object_set_new(geoip, "country_code", json_string_unreal(geo->country_code));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int geoip_base_whois(Client *client, Client *target, NameValuePrioList **list)
|
||||
{
|
||||
GeoIPResult *geo;
|
||||
|
@ -1,6 +1,6 @@
|
||||
/* GEOIP Classic module
|
||||
* (C) Copyright 2021 Bram Matthys and the UnrealIRCd team
|
||||
* License: GPLv2
|
||||
* License: GPLv2 or later
|
||||
*/
|
||||
|
||||
#include "unrealircd.h"
|
||||
|
@ -1,6 +1,6 @@
|
||||
/* GEOIP maxmind module
|
||||
* (C) Copyright 2021 Bram Matthys and the UnrealIRCd team
|
||||
* License: GPLv2
|
||||
* License: GPLv2 or later
|
||||
*/
|
||||
|
||||
#include "unrealircd.h"
|
||||
|
@ -459,7 +459,7 @@ CMD_OVERRIDE_FUNC(override_links)
|
||||
sendnumeric(client, RPL_LINKS, acptr->name, me.name,
|
||||
1, (acptr->info[0] ? acptr->info : "(Unknown Location)"));
|
||||
else
|
||||
sendnumeric(client, RPL_LINKS, acptr->name, acptr->uplink->name,
|
||||
sendnumeric(client, RPL_LINKS, acptr->name, acptr->uplink ? acptr->uplink->name : me.name,
|
||||
acptr->hopcount, (acptr->info[0] ? acptr->info : "(Unknown Location)"));
|
||||
}
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
/* src/modules/history_backend_mem.c - History Backend: memory
|
||||
* (C) Copyright 2019-2021 Bram Matthys (Syzop) and the UnrealIRCd team
|
||||
* License: GPLv2
|
||||
* License: GPLv2 or later
|
||||
*/
|
||||
#include "unrealircd.h"
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
/* src/modules/history_backend_null.c - History Backend: null / none
|
||||
* (C) Copyright 2019 Bram Matthys (Syzop) and the UnrealIRCd team
|
||||
* License: GPLv2
|
||||
* License: GPLv2 or later
|
||||
*/
|
||||
#include "unrealircd.h"
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
/* src/modules/ident_lookup.c - Ident lookups (RFC1413)
|
||||
* (C) Copyright 2019 Bram Matthys (Syzop) and the UnrealIRCd team
|
||||
* License: GPLv2
|
||||
* License: GPLv2 or later
|
||||
*/
|
||||
#include "unrealircd.h"
|
||||
|
||||
|
@ -62,10 +62,9 @@ MOD_UNLOAD()
|
||||
* ISON :nicklist
|
||||
*/
|
||||
|
||||
static char buf[BUFSIZE];
|
||||
|
||||
CMD_FUNC(cmd_ison)
|
||||
{
|
||||
char buf[BUFSIZE];
|
||||
char request[BUFSIZE];
|
||||
char namebuf[USERLEN + HOSTLEN + 4];
|
||||
Client *acptr;
|
||||
|
@ -94,37 +94,32 @@ MOD_UNLOAD()
|
||||
*/
|
||||
int _can_join(Client *client, Channel *channel, const char *key, char **errmsg)
|
||||
{
|
||||
Link *lp;
|
||||
Ban *banned;
|
||||
Hook *h;
|
||||
int i=0, j=0;
|
||||
|
||||
for (h = Hooks[HOOKTYPE_CAN_JOIN]; h; h = h->next)
|
||||
/* An /INVITE lets you bypass all restrictions */
|
||||
if (is_invited(client, channel))
|
||||
{
|
||||
i = (*(h->func.intfunc))(client,channel,key, errmsg);
|
||||
if (i != 0)
|
||||
return i;
|
||||
}
|
||||
|
||||
for (h = Hooks[HOOKTYPE_OPER_INVITE_BAN]; h; h = h->next)
|
||||
int j = 0;
|
||||
for (h = Hooks[HOOKTYPE_INVITE_BYPASS]; h; h = h->next)
|
||||
{
|
||||
j = (*(h->func.intfunc))(client,channel);
|
||||
if (j != 0)
|
||||
break;
|
||||
}
|
||||
|
||||
/* See if we can evade this ban */
|
||||
banned = is_banned(client, channel, BANCHK_JOIN, NULL, NULL);
|
||||
if (banned && j == HOOK_DENY)
|
||||
{
|
||||
*errmsg = STR_ERR_BANNEDFROMCHAN;
|
||||
return ERR_BANNEDFROMCHAN;
|
||||
/* Bypass is OK, unless a HOOKTYPE_INVITE_BYPASS hook returns HOOK_DENY */
|
||||
if (j != HOOK_DENY)
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (is_invited(client, channel))
|
||||
return 0; /* allowed to walk through all the other modes */
|
||||
for (h = Hooks[HOOKTYPE_CAN_JOIN]; h; h = h->next)
|
||||
{
|
||||
int i = (*(h->func.intfunc))(client,channel,key, errmsg);
|
||||
if (i != 0)
|
||||
return i;
|
||||
}
|
||||
|
||||
if (banned)
|
||||
/* See if we can evade this ban */
|
||||
if (is_banned(client, channel, BANCHK_JOIN, NULL, NULL))
|
||||
{
|
||||
*errmsg = STR_ERR_BANNEDFROMCHAN;
|
||||
return ERR_BANNEDFROMCHAN;
|
||||
@ -262,6 +257,7 @@ void _join_channel(Channel *channel, Client *client, MessageTag *recv_mtags, con
|
||||
MessageTag *mtags_mode = NULL;
|
||||
Cmode *cm;
|
||||
char modebuf[BUFSIZE], parabuf[BUFSIZE];
|
||||
int should_destroy = 0;
|
||||
|
||||
channel->mode.mode = MODES_ON_JOIN;
|
||||
|
||||
@ -281,6 +277,7 @@ void _join_channel(Channel *channel, Client *client, MessageTag *recv_mtags, con
|
||||
sendto_server(NULL, 0, 0, mtags_mode, ":%s MODE %s %s %s %lld",
|
||||
me.id, channel->name, modebuf, parabuf, (long long)channel->creationtime);
|
||||
sendto_one(client, mtags_mode, ":%s MODE %s %s %s", me.name, channel->name, modebuf, parabuf);
|
||||
RunHook(HOOKTYPE_LOCAL_CHANMODE, &me, channel, mtags_mode, modebuf, parabuf, 0, 0, &should_destroy);
|
||||
free_message_tags(mtags_mode);
|
||||
}
|
||||
|
||||
|
@ -21,7 +21,6 @@
|
||||
#include "unrealircd.h"
|
||||
|
||||
CMD_FUNC(cmd_kill);
|
||||
static char buf[BUFSIZE], buf2[BUFSIZE];
|
||||
|
||||
ModuleHeader MOD_HEADER
|
||||
= {
|
||||
@ -58,6 +57,7 @@ CMD_FUNC(cmd_kill)
|
||||
{
|
||||
char targetlist[BUFSIZE];
|
||||
char reason[BUFSIZE];
|
||||
char buf2[BUFSIZE];
|
||||
char *str;
|
||||
char *nick, *save = NULL;
|
||||
Client *target;
|
||||
|
@ -197,11 +197,15 @@ int lr_post_command(Client *from, MessageTag *mtags, const char *buf)
|
||||
int more_tags = currentcmd.firstbuf[0] == '@';
|
||||
currentcmd.client = NULL; /* prevent lr_packet from interfering */
|
||||
snprintf(packet, sizeof(packet)-3,
|
||||
"@label=%s%s%s\r\n",
|
||||
"@label=%s%s%s",
|
||||
currentcmd.label,
|
||||
more_tags ? ";" : " ",
|
||||
more_tags ? currentcmd.firstbuf+1 : currentcmd.firstbuf);
|
||||
sendbufto_one(from, packet, 0);
|
||||
/* Format the IRC message correctly here, so we can take the
|
||||
* quick path through sendbufto_one().
|
||||
*/
|
||||
strlcat(packet, "\r\n", sizeof(packet));
|
||||
sendbufto_one(from, packet, strlen(packet));
|
||||
goto done;
|
||||
}
|
||||
|
||||
|
@ -22,7 +22,6 @@
|
||||
|
||||
/* Forward declarations */
|
||||
const char *_StripColors(const char *text);
|
||||
const char *_StripControlCodes(const char *text);
|
||||
int ban_version(Client *client, const char *text);
|
||||
CMD_FUNC(cmd_private);
|
||||
CMD_FUNC(cmd_notice);
|
||||
@ -47,7 +46,6 @@ MOD_TEST()
|
||||
{
|
||||
MARK_AS_OFFICIAL_MODULE(modinfo);
|
||||
EfunctionAddConstString(modinfo->handle, EFUNC_STRIPCOLORS, _StripColors);
|
||||
EfunctionAddConstString(modinfo->handle, EFUNC_STRIPCONTROLCODES, _StripControlCodes);
|
||||
EfunctionAdd(modinfo->handle, EFUNC_CAN_SEND_TO_CHANNEL, _can_send_to_channel);
|
||||
return MOD_SUCCESS;
|
||||
}
|
||||
@ -526,8 +524,10 @@ CMD_FUNC(cmd_tagmsg)
|
||||
/* Taken from xchat by Peter Zelezny
|
||||
* changed very slightly by codemastr
|
||||
* RGB color stripping support added -- codemastr
|
||||
*
|
||||
* NOTE: if you change/update/enhance StripColors() then consider changing
|
||||
* the StripControlCodes() function as well (in misc.c) !!
|
||||
*/
|
||||
|
||||
const char *_StripColors(const char *text)
|
||||
{
|
||||
int i = 0, len = strlen(text), save_len=0;
|
||||
@ -595,103 +595,6 @@ const char *_StripColors(const char *text)
|
||||
return new_str;
|
||||
}
|
||||
|
||||
/* strip color, bold, underline, and reverse codes from a string */
|
||||
const char *_StripControlCodes(const char *text)
|
||||
{
|
||||
int i = 0, len = strlen(text), save_len=0;
|
||||
char nc = 0, col = 0, rgb = 0;
|
||||
const char *save_text=NULL;
|
||||
static unsigned char new_str[4096];
|
||||
while (len > 0)
|
||||
{
|
||||
if ( col && ((isdigit(*text) && nc < 2) || (*text == ',' && nc < 3)))
|
||||
{
|
||||
nc++;
|
||||
if (*text == ',')
|
||||
nc = 0;
|
||||
}
|
||||
/* Syntax for RGB is ^DHHHHHH where H is a hex digit.
|
||||
* If < 6 hex digits are specified, the code is displayed
|
||||
* as text
|
||||
*/
|
||||
else if ((rgb && isxdigit(*text) && nc < 6) || (rgb && *text == ',' && nc < 7))
|
||||
{
|
||||
nc++;
|
||||
if (*text == ',')
|
||||
nc = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (col)
|
||||
col = 0;
|
||||
if (rgb)
|
||||
{
|
||||
if (nc != 6)
|
||||
{
|
||||
text = save_text+1;
|
||||
len = save_len-1;
|
||||
rgb = 0;
|
||||
continue;
|
||||
}
|
||||
rgb = 0;
|
||||
}
|
||||
switch (*text)
|
||||
{
|
||||
case 3:
|
||||
/* color */
|
||||
col = 1;
|
||||
nc = 0;
|
||||
break;
|
||||
case 4:
|
||||
/* RGB */
|
||||
save_text = text;
|
||||
save_len = len;
|
||||
rgb = 1;
|
||||
nc = 0;
|
||||
break;
|
||||
case 2:
|
||||
/* bold */
|
||||
break;
|
||||
case 31:
|
||||
/* underline */
|
||||
break;
|
||||
case 22:
|
||||
/* reverse */
|
||||
break;
|
||||
case 15:
|
||||
/* plain */
|
||||
break;
|
||||
case 29:
|
||||
/* italic */
|
||||
break;
|
||||
case 30:
|
||||
/* strikethrough */
|
||||
break;
|
||||
case 17:
|
||||
/* monospace */
|
||||
break;
|
||||
case 0xe2:
|
||||
if (!strncmp(text+1, "\x80\x8b", 2))
|
||||
{
|
||||
/* +2 means we skip 3 */
|
||||
text += 2;
|
||||
len -= 2;
|
||||
break;
|
||||
}
|
||||
/*fallthrough*/
|
||||
default:
|
||||
new_str[i] = *text;
|
||||
i++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
text++;
|
||||
len--;
|
||||
}
|
||||
new_str[i] = 0;
|
||||
return new_str;
|
||||
}
|
||||
|
||||
/** Check ban version { } blocks, returns 1 if banned and 0 if not. */
|
||||
int ban_version(Client *client, const char *text)
|
||||
{
|
||||
|
@ -472,8 +472,8 @@ MultiLineMode *make_mode_str(Client *client, Channel *channel, Cmode_t oldem, in
|
||||
if (curr == MAXMULTILINEMODES)
|
||||
{
|
||||
/* Should be impossible.. */
|
||||
unreal_log(ULOG_ERROR, "mode", "MODE_MULTINE_EXCEEDED", client,
|
||||
"A mode string caused an avalanche effect of more than $max_multiline modes "
|
||||
unreal_log(ULOG_ERROR, "mode", "MODE_MULTILINE_EXCEEDED", client,
|
||||
"A mode string caused an avalanche effect of more than $max_multiline_modes modes "
|
||||
"in channel $channel. Caused by client $client. Expect a desync.",
|
||||
log_data_integer("max_multiline_modes", MAXMULTILINEMODES),
|
||||
log_data_channel("channel", channel));
|
||||
@ -807,6 +807,7 @@ void do_mode_char_member_mode_new(Channel *channel, Cmode *handler, const char *
|
||||
"[BUG] Client $target.details on channel $channel: "
|
||||
"found via find_membership_link() but NOT found via find_member_link(). "
|
||||
"This should never happen! Please report on https://bugs.unrealircd.org/",
|
||||
log_data_client("target", target),
|
||||
log_data_channel("channel", channel));
|
||||
return;
|
||||
}
|
||||
@ -816,6 +817,58 @@ void do_mode_char_member_mode_new(Channel *channel, Cmode *handler, const char *
|
||||
if ((what == MODE_DEL) && !strchr(member->member_modes, modechar))
|
||||
return; /* already unset */
|
||||
|
||||
/* HOOKTYPE_MODE_DEOP code */
|
||||
if (what == MODE_DEL)
|
||||
{
|
||||
int ret = EX_ALLOW;
|
||||
const char *badmode = NULL;
|
||||
Hook *h;
|
||||
const char *my_access;
|
||||
Membership *my_membership;
|
||||
|
||||
/* Set "my_access" to access flags of the requestor */
|
||||
if (IsUser(client) && (my_membership = find_membership_link(client->user->channel, channel)))
|
||||
my_access = my_membership->member_modes; /* client */
|
||||
else
|
||||
my_access = ""; /* server */
|
||||
|
||||
for (h = Hooks[HOOKTYPE_MODE_DEOP]; h; h = h->next)
|
||||
{
|
||||
int n = (*(h->func.intfunc))(client, target, channel, what, modechar, my_access, member->member_modes, &badmode);
|
||||
if (n == EX_DENY)
|
||||
{
|
||||
ret = n;
|
||||
} else
|
||||
if (n == EX_ALWAYS_DENY)
|
||||
{
|
||||
ret = n;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (ret == EX_ALWAYS_DENY)
|
||||
{
|
||||
if (MyUser(client) && badmode)
|
||||
sendto_one(client, NULL, "%s", badmode); /* send error message, if any */
|
||||
|
||||
if (MyUser(client))
|
||||
return; /* stop processing this mode */
|
||||
}
|
||||
|
||||
/* This probably should work but is completely untested (the operoverride stuff, I mean): */
|
||||
if (ret == EX_DENY)
|
||||
{
|
||||
if (!op_can_override("channel:override:mode:del",client,channel,handler))
|
||||
{
|
||||
if (badmode)
|
||||
sendto_one(client, NULL, "%s", badmode); /* send error message, if any */
|
||||
return; /* stop processing this mode */
|
||||
} else {
|
||||
opermode = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (what == MODE_ADD)
|
||||
{
|
||||
if (strchr(member->member_modes, modechar))
|
||||
@ -1306,8 +1359,6 @@ CMD_FUNC(_cmd_umode)
|
||||
|
||||
/* Notify */
|
||||
userhost_changed(client);
|
||||
if (MyUser(client))
|
||||
sendnumeric(client, RPL_HOSTHIDDEN, client->user->virthost);
|
||||
}
|
||||
|
||||
/* -x */
|
||||
@ -1321,8 +1372,6 @@ CMD_FUNC(_cmd_umode)
|
||||
|
||||
/* Notify */
|
||||
userhost_changed(client);
|
||||
if (MyUser(client))
|
||||
sendnumeric(client, RPL_HOSTHIDDEN, client->user->realhost);
|
||||
}
|
||||
/*
|
||||
* If I understand what this code is doing correctly...
|
||||
@ -1337,7 +1386,7 @@ CMD_FUNC(_cmd_umode)
|
||||
{
|
||||
list_del(&client->special_node);
|
||||
if (MyUser(client))
|
||||
RunHook(HOOKTYPE_LOCAL_OPER, client, 0, NULL);
|
||||
RunHook(HOOKTYPE_LOCAL_OPER, client, 0, NULL, NULL);
|
||||
remove_oper_privileges(client, 0);
|
||||
}
|
||||
|
||||
|
@ -68,8 +68,6 @@ MOD_UNLOAD()
|
||||
* 12 Feb 2000 - geesh, time for a rewrite -lucas
|
||||
************************************************************************/
|
||||
|
||||
static char buf[BUFSIZE];
|
||||
|
||||
/*
|
||||
** cmd_names
|
||||
** parv[1] = channel
|
||||
@ -88,6 +86,7 @@ CMD_FUNC(cmd_names)
|
||||
int idx, flag = 1, spos;
|
||||
const char *para = parv[1], *s;
|
||||
char nuhBuffer[NICKLEN+USERLEN+HOSTLEN+3];
|
||||
char buf[BUFSIZE];
|
||||
|
||||
if (parc < 2 || !MyConnect(client))
|
||||
{
|
||||
|
@ -46,7 +46,6 @@ ModuleHeader MOD_HEADER
|
||||
#define ASSUME_NICK_IN_FLIGHT
|
||||
|
||||
/* Variables */
|
||||
static char buf[BUFSIZE];
|
||||
static char spamfilter_user[NICKLEN + USERLEN + HOSTLEN + REALLEN + 64];
|
||||
|
||||
/* Forward declarations */
|
||||
@ -489,6 +488,7 @@ CMD_FUNC(cmd_uid)
|
||||
Client *acptr, *serv = NULL;
|
||||
Client *acptrs;
|
||||
char nick[NICKLEN + 1];
|
||||
char buf[BUFSIZE];
|
||||
long lastnick = 0;
|
||||
int differ = 1;
|
||||
const char *hostname, *username, *sstamp, *umodes, *virthost, *ip_raw, *realname;
|
||||
@ -758,10 +758,21 @@ CMD_FUNC(cmd_nick)
|
||||
}
|
||||
}
|
||||
|
||||
/** Welcome the user on IRC.
|
||||
* Send the RPL_WELCOME, LUSERS, MOTD, auto join channels, everything...
|
||||
*/
|
||||
void welcome_user(Client *client, TKL *viruschan_tkl)
|
||||
{
|
||||
int i;
|
||||
ConfigItem_tld *tlds;
|
||||
char buf[BUFSIZE];
|
||||
|
||||
/* Make creation time the real 'online since' time, excluding registration time.
|
||||
* Otherwise things like set::anti-spam-quit-messagetime 10s could mean
|
||||
* 1 second in practice (#2174).
|
||||
*/
|
||||
client->local->creationtime = TStime();
|
||||
client->local->idle_since = TStime();
|
||||
|
||||
RunHook(HOOKTYPE_WELCOME, client, 0);
|
||||
sendnumeric(client, RPL_WELCOME, NETWORK_NAME, client->name, client->user->username, client->user->realhost);
|
||||
@ -826,10 +837,11 @@ void welcome_user(Client *client, TKL *viruschan_tkl)
|
||||
sendto_serv_butone_nickcmd(client->direction, NULL, client, (*buf == '\0' ? "+" : buf));
|
||||
|
||||
broadcast_moddata_client(client);
|
||||
RunHook(HOOKTYPE_LOCAL_CONNECT, client);
|
||||
|
||||
if (buf[0] != '\0' && buf[1] != '\0')
|
||||
sendto_one(client, NULL, ":%s MODE %s :%s", client->name,
|
||||
client->name, buf);
|
||||
|
||||
if (client->user->snomask)
|
||||
sendnumeric(client, RPL_SNOMASK, client->user->snomask);
|
||||
|
||||
@ -839,12 +851,7 @@ void welcome_user(Client *client, TKL *viruschan_tkl)
|
||||
if (IsSecure(client) && (iConf.outdated_tls_policy_user == POLICY_WARN) && outdated_tls_client(client))
|
||||
sendnotice(client, "%s", outdated_tls_client_build_string(iConf.outdated_tls_policy_user_message, client));
|
||||
|
||||
/* Make creation time the real 'online since' time, excluding registration time.
|
||||
* Otherwise things like set::anti-spam-quit-messagetime 10s could mean
|
||||
* 1 second in practice (#2174).
|
||||
*/
|
||||
client->local->creationtime = TStime();
|
||||
client->local->idle_since = TStime();
|
||||
RunHook(HOOKTYPE_LOCAL_CONNECT, client);
|
||||
|
||||
/* Give the user a fresh start as far as fake-lag is concerned.
|
||||
* Otherwise the user could be lagged up already due to all the CAP stuff.
|
||||
@ -1261,7 +1268,7 @@ int AllowClient(Client *client)
|
||||
if (aconf->flags.tls && !IsSecure(client))
|
||||
continue;
|
||||
|
||||
if (!unreal_mask_match(client, aconf->mask))
|
||||
if (!user_allowed_by_security_group(client, aconf->match))
|
||||
continue;
|
||||
|
||||
/* Check authentication */
|
||||
|
@ -20,10 +20,6 @@
|
||||
|
||||
#include "unrealircd.h"
|
||||
|
||||
CMD_FUNC(cmd_oper);
|
||||
|
||||
|
||||
/* Place includes here */
|
||||
#define MSG_OPER "OPER" /* OPER */
|
||||
|
||||
ModuleHeader MOD_HEADER
|
||||
@ -35,27 +31,37 @@ ModuleHeader MOD_HEADER
|
||||
"unrealircd-6",
|
||||
};
|
||||
|
||||
/* This is called on module init, before Server Ready */
|
||||
MOD_INIT()
|
||||
/* Forward declarations */
|
||||
CMD_FUNC(cmd_oper);
|
||||
int _make_oper(Client *client, const char *operblock_name, const char *operclass, ConfigItem_class *clientclass, long modes, const char *snomask, const char *vhost);
|
||||
int oper_connect(Client *client);
|
||||
|
||||
MOD_TEST()
|
||||
{
|
||||
CommandAdd(modinfo->handle, MSG_OPER, cmd_oper, MAXPARA, CMD_USER);
|
||||
MARK_AS_OFFICIAL_MODULE(modinfo);
|
||||
EfunctionAdd(modinfo->handle, EFUNC_MAKE_OPER, _make_oper);
|
||||
return MOD_SUCCESS;
|
||||
}
|
||||
|
||||
MOD_INIT()
|
||||
{
|
||||
MARK_AS_OFFICIAL_MODULE(modinfo);
|
||||
CommandAdd(modinfo->handle, MSG_OPER, cmd_oper, MAXPARA, CMD_USER);
|
||||
HookAdd(modinfo->handle, HOOKTYPE_LOCAL_CONNECT, 0, oper_connect);
|
||||
return MOD_SUCCESS;
|
||||
}
|
||||
|
||||
/* Is first run when server is 100% ready */
|
||||
MOD_LOAD()
|
||||
{
|
||||
return MOD_SUCCESS;
|
||||
}
|
||||
|
||||
/* Called when module is unloaded */
|
||||
MOD_UNLOAD()
|
||||
{
|
||||
return MOD_SUCCESS;
|
||||
}
|
||||
|
||||
void set_oper_host(Client *client, char *host)
|
||||
void set_oper_host(Client *client, const char *host)
|
||||
{
|
||||
char uhost[HOSTLEN + USERLEN + 1];
|
||||
char *p;
|
||||
@ -70,8 +76,96 @@ void set_oper_host(Client *client, char *host)
|
||||
client->id, client->user->username);
|
||||
host = p;
|
||||
}
|
||||
iNAH_host(client, host);
|
||||
SetHidden(client);
|
||||
safe_strdup(client->user->virthost, host);
|
||||
if (MyConnect(client))
|
||||
sendto_server(NULL, 0, 0, NULL, ":%s SETHOST :%s", client->id, client->user->virthost);
|
||||
client->umodes |= UMODE_SETHOST|UMODE_HIDE;
|
||||
}
|
||||
|
||||
int _make_oper(Client *client, const char *operblock_name, const char *operclass, ConfigItem_class *clientclass, long modes, const char *snomask, const char *vhost)
|
||||
{
|
||||
long old_umodes = client->umodes & ALL_UMODES;
|
||||
|
||||
userhost_save_current(client);
|
||||
|
||||
/* Put in the right class (if any) */
|
||||
if (clientclass)
|
||||
{
|
||||
if (client->local->class)
|
||||
client->local->class->clients--;
|
||||
client->local->class = clientclass;
|
||||
client->local->class->clients++;
|
||||
}
|
||||
|
||||
/* set oper user modes */
|
||||
client->umodes |= UMODE_OPER;
|
||||
if (modes)
|
||||
client->umodes |= modes; /* oper::modes */
|
||||
else
|
||||
client->umodes |= OPER_MODES; /* set::modes-on-oper */
|
||||
|
||||
/* oper::vhost */
|
||||
if (vhost)
|
||||
{
|
||||
set_oper_host(client, vhost);
|
||||
} else
|
||||
if (IsHidden(client) && !client->user->virthost)
|
||||
{
|
||||
/* +x has just been set by modes-on-oper and no vhost. cloak the oper! */
|
||||
safe_strdup(client->user->virthost, client->user->cloakedhost);
|
||||
}
|
||||
|
||||
userhost_changed(client);
|
||||
|
||||
unreal_log(ULOG_INFO, "oper", "OPER_SUCCESS", client,
|
||||
"$client.details is now an IRC Operator [oper-block: $oper_block] [operclass: $operclass]",
|
||||
log_data_string("oper_block", operblock_name),
|
||||
log_data_string("operclass", operclass));
|
||||
|
||||
/* set oper snomasks */
|
||||
if (snomask)
|
||||
set_snomask(client, snomask); /* oper::snomask */
|
||||
else
|
||||
set_snomask(client, OPER_SNOMASK); /* set::snomask-on-oper */
|
||||
|
||||
send_umode_out(client, 1, old_umodes);
|
||||
if (client->user->snomask)
|
||||
sendnumeric(client, RPL_SNOMASK, client->user->snomask);
|
||||
|
||||
list_add(&client->special_node, &oper_list);
|
||||
|
||||
RunHook(HOOKTYPE_LOCAL_OPER, client, 1, operblock_name, operclass);
|
||||
|
||||
sendnumeric(client, RPL_YOUREOPER);
|
||||
|
||||
/* Update statistics */
|
||||
if (IsInvisible(client) && !(old_umodes & UMODE_INVISIBLE))
|
||||
irccounts.invisible++;
|
||||
if (IsOper(client) && !IsHideOper(client))
|
||||
irccounts.operators++;
|
||||
|
||||
if (SHOWOPERMOTD == 1)
|
||||
{
|
||||
const char *args[1] = { NULL };
|
||||
do_cmd(client, NULL, "OPERMOTD", 1, args);
|
||||
}
|
||||
|
||||
if (!BadPtr(OPER_AUTO_JOIN_CHANS) && strcmp(OPER_AUTO_JOIN_CHANS, "0"))
|
||||
{
|
||||
char *chans = strdup(OPER_AUTO_JOIN_CHANS);
|
||||
const char *args[3] = {
|
||||
client->name,
|
||||
chans,
|
||||
NULL
|
||||
};
|
||||
do_cmd(client, NULL, "JOIN", 3, args);
|
||||
safe_free(chans);
|
||||
/* Theoretically the oper may be killed on join. Would be fun, though */
|
||||
if (IsDead(client))
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
@ -83,7 +177,6 @@ CMD_FUNC(cmd_oper)
|
||||
{
|
||||
ConfigItem_oper *operblock;
|
||||
const char *operblock_name, *password;
|
||||
long old_umodes = client->umodes & ALL_UMODES;
|
||||
|
||||
if (!MyUser(client))
|
||||
return;
|
||||
@ -152,7 +245,7 @@ CMD_FUNC(cmd_oper)
|
||||
* more seriously, they are logged as errors instead of warnings.
|
||||
*/
|
||||
|
||||
if (!unreal_mask_match(client, operblock->mask))
|
||||
if (!user_allowed_by_security_group(client, operblock->match))
|
||||
{
|
||||
sendnumeric(client, ERR_NOOPERHOST);
|
||||
unreal_log(ULOG_ERROR, "oper", "OPER_FAILED", client,
|
||||
@ -164,7 +257,7 @@ CMD_FUNC(cmd_oper)
|
||||
return;
|
||||
}
|
||||
|
||||
if (!Auth_Check(client, operblock->auth, password))
|
||||
if (operblock->auth && !Auth_Check(client, operblock->auth, password))
|
||||
{
|
||||
sendnumeric(client, ERR_PASSWDMISMATCH);
|
||||
if (FAILOPER_WARN)
|
||||
@ -227,12 +320,6 @@ CMD_FUNC(cmd_oper)
|
||||
/* Store which oper block was used to become IRCOp (for maxlogins and whois) */
|
||||
safe_strdup(client->user->operlogin, operblock->name);
|
||||
|
||||
/* Put in the right class */
|
||||
if (client->local->class)
|
||||
client->local->class->clients--;
|
||||
client->local->class = operblock->class;
|
||||
client->local->class->clients++;
|
||||
|
||||
/* oper::swhois */
|
||||
if (operblock->swhois)
|
||||
{
|
||||
@ -241,67 +328,7 @@ CMD_FUNC(cmd_oper)
|
||||
swhois_add(client, "oper", -100, s->line, &me, NULL);
|
||||
}
|
||||
|
||||
/* set oper user modes */
|
||||
client->umodes |= UMODE_OPER;
|
||||
if (operblock->modes)
|
||||
client->umodes |= operblock->modes; /* oper::modes */
|
||||
else
|
||||
client->umodes |= OPER_MODES; /* set::modes-on-oper */
|
||||
|
||||
/* oper::vhost */
|
||||
if (operblock->vhost)
|
||||
{
|
||||
set_oper_host(client, operblock->vhost);
|
||||
} else
|
||||
if (IsHidden(client) && !client->user->virthost)
|
||||
{
|
||||
/* +x has just been set by modes-on-oper and no vhost. cloak the oper! */
|
||||
safe_strdup(client->user->virthost, client->user->cloakedhost);
|
||||
}
|
||||
|
||||
unreal_log(ULOG_INFO, "oper", "OPER_SUCCESS", client,
|
||||
"$client.details is now an IRC Operator [oper-block: $oper_block]",
|
||||
log_data_string("oper_block", parv[1]));
|
||||
|
||||
/* set oper snomasks */
|
||||
if (operblock->snomask)
|
||||
set_snomask(client, operblock->snomask); /* oper::snomask */
|
||||
else
|
||||
set_snomask(client, OPER_SNOMASK); /* set::snomask-on-oper */
|
||||
|
||||
send_umode_out(client, 1, old_umodes);
|
||||
if (client->user->snomask)
|
||||
sendnumeric(client, RPL_SNOMASK, client->user->snomask);
|
||||
|
||||
list_add(&client->special_node, &oper_list);
|
||||
|
||||
RunHook(HOOKTYPE_LOCAL_OPER, client, 1, operblock);
|
||||
|
||||
sendnumeric(client, RPL_YOUREOPER);
|
||||
|
||||
/* Update statistics */
|
||||
if (IsInvisible(client) && !(old_umodes & UMODE_INVISIBLE))
|
||||
irccounts.invisible++;
|
||||
if (IsOper(client) && !IsHideOper(client))
|
||||
irccounts.operators++;
|
||||
|
||||
if (SHOWOPERMOTD == 1)
|
||||
do_cmd(client, NULL, "OPERMOTD", parc, parv);
|
||||
|
||||
if (!BadPtr(OPER_AUTO_JOIN_CHANS) && strcmp(OPER_AUTO_JOIN_CHANS, "0"))
|
||||
{
|
||||
char *chans = strdup(OPER_AUTO_JOIN_CHANS);
|
||||
const char *args[3] = {
|
||||
client->name,
|
||||
chans,
|
||||
NULL
|
||||
};
|
||||
do_cmd(client, NULL, "JOIN", 3, args);
|
||||
safe_free(chans);
|
||||
/* Theoretically the oper may be killed on join. Would be fun, though */
|
||||
if (IsDead(client))
|
||||
return;
|
||||
}
|
||||
make_oper(client, operblock->name, operblock->operclass, operblock->class, operblock->modes, operblock->snomask, operblock->vhost);
|
||||
|
||||
/* set::plaintext-policy::oper 'warn' */
|
||||
if (!IsSecure(client) && !IsLocalhost(client) && (iConf.plaintext_policy_oper == POLICY_WARN))
|
||||
@ -323,3 +350,29 @@ CMD_FUNC(cmd_oper)
|
||||
log_data_string("warn_type", "OUTDATED_TLS_PROTOCOL_OR_CIPHER"));
|
||||
}
|
||||
}
|
||||
|
||||
int oper_connect(Client *client)
|
||||
{
|
||||
ConfigItem_oper *e;
|
||||
|
||||
if (IsOper(client))
|
||||
return 0;
|
||||
|
||||
for (e = conf_oper; e; e = e->next)
|
||||
{
|
||||
if (e->auto_login && user_allowed_by_security_group(client, e->match))
|
||||
{
|
||||
/* Ideally we would check all the criteria that cmd_oper does.
|
||||
* I'm taking a shortcut for now that is not ideal...
|
||||
*/
|
||||
const char *parx[3];
|
||||
parx[0] = NULL;
|
||||
parx[1] = e->name;
|
||||
parx[2] = NULL;
|
||||
do_cmd(client, NULL, "OPER", 3, parx);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -1,7 +1,7 @@
|
||||
/*
|
||||
* Store oper login in ModData, used by WHOIS and for auditting purposes.
|
||||
* (C) Copyright 2021-.. Syzop and The UnrealIRCd Team
|
||||
* License: GPLv2
|
||||
* License: GPLv2 or later
|
||||
*/
|
||||
|
||||
#include "unrealircd.h"
|
||||
@ -16,7 +16,7 @@ ModuleHeader MOD_HEADER
|
||||
};
|
||||
|
||||
/* Forward declarations */
|
||||
int operinfo_local_oper(Client *client, int up, ConfigItem_oper *oper_block);
|
||||
int operinfo_local_oper(Client *client, int up, const char *oper_block, const char *operclass);
|
||||
void operinfo_free(ModData *m);
|
||||
const char *operinfo_serialize(ModData *m);
|
||||
void operinfo_unserialize(const char *str, ModData *m);
|
||||
@ -68,12 +68,12 @@ MOD_UNLOAD()
|
||||
return MOD_SUCCESS;
|
||||
}
|
||||
|
||||
int operinfo_local_oper(Client *client, int up, ConfigItem_oper *oper_block)
|
||||
int operinfo_local_oper(Client *client, int up, const char *oper_block, const char *operclass)
|
||||
{
|
||||
if (up)
|
||||
{
|
||||
moddata_client_set(client, "operlogin", oper_block->name);
|
||||
moddata_client_set(client, "operclass", oper_block->operclass);
|
||||
moddata_client_set(client, "operlogin", oper_block);
|
||||
moddata_client_set(client, "operclass", operclass);
|
||||
} else {
|
||||
moddata_client_set(client, "operlogin", NULL);
|
||||
moddata_client_set(client, "operclass", NULL);
|
||||
|
@ -206,7 +206,7 @@ CMD_FUNC(cmd_protoctl)
|
||||
if ((aclient = hash_find_id(sid, NULL)) != NULL)
|
||||
{
|
||||
unreal_log(ULOG_ERROR, "link", "LINK_DENIED_SID_COLLISION", client,
|
||||
"Server link $client rejected. Server with SID $sid already exist via uplink $exiting_client.server.uplink.",
|
||||
"Server link $client rejected. Server with SID $sid already exist via uplink $existing_client.server.uplink.",
|
||||
log_data_string("sid", sid),
|
||||
log_data_client("existing_client", aclient));
|
||||
exit_client(client, NULL, "SID collision");
|
||||
@ -266,7 +266,7 @@ CMD_FUNC(cmd_protoctl)
|
||||
*/
|
||||
strlcpy(client->name, servername, sizeof(client->name));
|
||||
|
||||
if (!verify_link(client, &aconf))
|
||||
if (!(aconf = verify_link(client)))
|
||||
return;
|
||||
|
||||
/* note: software, protocol and flags may be NULL */
|
||||
|
@ -1,7 +1,7 @@
|
||||
/*
|
||||
* reputation - Provides a scoring system for "known users".
|
||||
* (C) Copyright 2015-2019 Bram Matthys (Syzop) and the UnrealIRCd team.
|
||||
* License: GPLv2
|
||||
* License: GPLv2 or later
|
||||
*
|
||||
* How this works is simple:
|
||||
* Every 5 minutes the IP address of all the connected users receive
|
||||
@ -918,6 +918,24 @@ static inline int is_reputation_expired(ReputationEntry *e)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/** If the reputation changed (due to server syncing) then update the
|
||||
* individual users reputation score as well.
|
||||
*/
|
||||
void reputation_changed_update_users(ReputationEntry *e)
|
||||
{
|
||||
Client *client;
|
||||
|
||||
list_for_each_entry(client, &client_list, client_node)
|
||||
{
|
||||
if (client->ip && !strcmp(e->ip, client->ip))
|
||||
{
|
||||
/* With some (possibly unneeded) care to only go forward */
|
||||
if (Reputation(client) < e->score)
|
||||
Reputation(client) = e->score;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
EVENT(delete_old_records)
|
||||
{
|
||||
int i;
|
||||
@ -1279,6 +1297,7 @@ CMD_FUNC(reputation_server_cmd)
|
||||
log_data_integer("score", e->score));
|
||||
#endif
|
||||
e->score = score;
|
||||
reputation_changed_update_users(e);
|
||||
}
|
||||
|
||||
/* If we don't have any entry for this IP, add it now. */
|
||||
@ -1296,6 +1315,7 @@ CMD_FUNC(reputation_server_cmd)
|
||||
e->score = score;
|
||||
e->last_seen = TStime();
|
||||
add_reputation_entry(e);
|
||||
reputation_changed_update_users(e);
|
||||
}
|
||||
|
||||
/* Propagate to the non-client direction (score may be updated) */
|
||||
|
@ -32,11 +32,7 @@ struct RestrictedCommand {
|
||||
RestrictedCommand *prev, *next;
|
||||
char *cmd;
|
||||
char *conftag;
|
||||
long connect_delay;
|
||||
int exempt_identified;
|
||||
int exempt_reputation_score;
|
||||
int exempt_webirc;
|
||||
int exempt_tls;
|
||||
SecurityGroup *except;
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
@ -103,6 +99,7 @@ MOD_UNLOAD()
|
||||
next = rcmd->next;
|
||||
safe_free(rcmd->conftag);
|
||||
safe_free(rcmd->cmd);
|
||||
free_security_group(rcmd->except);
|
||||
DelListItem(rcmd, RestrictedCommandList);
|
||||
safe_free(rcmd);
|
||||
}
|
||||
@ -170,6 +167,12 @@ int rcmd_configtest(ConfigFile *cf, ConfigEntry *ce, int type, int *errs)
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!strcmp(cep2->name, "except"))
|
||||
{
|
||||
test_match_block(cf, cep2, &errors);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!cep2->value)
|
||||
{
|
||||
config_error("%s:%i: blank set::restrict-commands::%s:%s without value", cep2->file->filename, cep2->line_number, cep->name, cep2->name);
|
||||
@ -249,7 +252,13 @@ int rcmd_configrun(ConfigFile *cf, ConfigEntry *ce, int type)
|
||||
config_warn("[restrict-commands] Command '%s' does not exist. Did you mistype? Or is the module providing it not loaded?", cmd);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (find_restrictions_bycmd(cmd))
|
||||
{
|
||||
config_warn("[restrict-commands] Multiple set::restrict-commands items for command '%s'. "
|
||||
"Only one config block will be effective.",
|
||||
cmd);
|
||||
continue;
|
||||
}
|
||||
if (!CommandOverrideAdd(ModInf.handle, cmd, 0, rcmd_override))
|
||||
{
|
||||
config_warn("[restrict-commands] Failed to add override for '%s' (NO RESTRICTIONS APPLY)", cmd);
|
||||
@ -260,38 +269,46 @@ int rcmd_configrun(ConfigFile *cf, ConfigEntry *ce, int type)
|
||||
rcmd = safe_alloc(sizeof(RestrictedCommand));
|
||||
safe_strdup(rcmd->cmd, cmd);
|
||||
safe_strdup(rcmd->conftag, conftag);
|
||||
rcmd->except = safe_alloc(sizeof(SecurityGroup));
|
||||
|
||||
for (cep2 = cep->items; cep2; cep2 = cep2->next)
|
||||
{
|
||||
if (!strcmp(cep2->name, "except"))
|
||||
{
|
||||
conf_match_block(cf, cep2, &rcmd->except);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!cep2->value)
|
||||
continue;
|
||||
|
||||
if (!strcmp(cep2->name, "connect-delay"))
|
||||
{
|
||||
rcmd->connect_delay = config_checkval(cep2->value, CFG_TIME);
|
||||
rcmd->except->connect_time = config_checkval(cep2->value, CFG_TIME);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!strcmp(cep2->name, "exempt-identified"))
|
||||
{
|
||||
rcmd->exempt_identified = config_checkval(cep2->value, CFG_YESNO);
|
||||
rcmd->except->identified = config_checkval(cep2->value, CFG_YESNO);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!strcmp(cep2->name, "exempt-webirc"))
|
||||
{
|
||||
rcmd->exempt_webirc = config_checkval(cep2->value, CFG_YESNO);
|
||||
rcmd->except->webirc = config_checkval(cep2->value, CFG_YESNO);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!strcmp(cep2->name, "exempt-tls"))
|
||||
{
|
||||
rcmd->exempt_tls = config_checkval(cep2->value, CFG_YESNO);
|
||||
rcmd->except->tls = config_checkval(cep2->value, CFG_YESNO);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!strcmp(cep2->name, "exempt-reputation-score"))
|
||||
{
|
||||
rcmd->exempt_reputation_score = atoi(cep2->value);
|
||||
rcmd->except->reputation_score = atoi(cep2->value);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
@ -305,15 +322,7 @@ int rcmd_canbypass(Client *client, RestrictedCommand *rcmd)
|
||||
{
|
||||
if (!client || !rcmd)
|
||||
return 1;
|
||||
if (rcmd->exempt_identified && IsLoggedIn(client))
|
||||
return 1;
|
||||
if (rcmd->exempt_webirc && moddata_client_get(client, "webirc"))
|
||||
return 1;
|
||||
if (rcmd->exempt_tls && IsSecureConnect(client))
|
||||
return 1;
|
||||
if (rcmd->exempt_reputation_score > 0 && (GetReputation(client) >= rcmd->exempt_reputation_score))
|
||||
return 1;
|
||||
if (rcmd->connect_delay && client->local && (TStime() - client->local->creationtime >= rcmd->connect_delay))
|
||||
if (user_allowed_by_security_group(client, rcmd->except))
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
@ -351,11 +360,11 @@ int rcmd_block_message(Client *client, const char *text, SendType sendtype, cons
|
||||
if (rcmd && !rcmd_canbypass(client, rcmd))
|
||||
{
|
||||
int notice = (sendtype == SEND_TYPE_NOTICE ? 1 : 0); // temporary hack FIXME !!!
|
||||
if (rcmd->connect_delay)
|
||||
if (rcmd->except->connect_time)
|
||||
{
|
||||
ircsnprintf(errbuf, sizeof(errbuf),
|
||||
"You cannot send %ss to %ss until you've been connected for %ld seconds or more",
|
||||
(notice ? "notice" : "message"), display, rcmd->connect_delay);
|
||||
(notice ? "notice" : "message"), display, rcmd->except->connect_time);
|
||||
} else {
|
||||
ircsnprintf(errbuf, sizeof(errbuf),
|
||||
"Sending of %ss to %ss been disabled by the network administrators",
|
||||
@ -382,11 +391,11 @@ CMD_OVERRIDE_FUNC(rcmd_override)
|
||||
rcmd = find_restrictions_bycmd(ovr->command->cmd);
|
||||
if (rcmd && !rcmd_canbypass(client, rcmd))
|
||||
{
|
||||
if (rcmd->connect_delay)
|
||||
if (rcmd->except->connect_time)
|
||||
{
|
||||
sendnumericfmt(client, ERR_UNKNOWNCOMMAND,
|
||||
"%s :You must be connected for at least %ld seconds before you can use this command",
|
||||
ovr->command->cmd, rcmd->connect_delay);
|
||||
ovr->command->cmd, rcmd->except->connect_time);
|
||||
} else {
|
||||
sendnumericfmt(client, ERR_UNKNOWNCOMMAND,
|
||||
"%s :This command is disabled by the network administrator",
|
||||
|
@ -167,6 +167,7 @@ CMD_FUNC(cmd_sapart)
|
||||
|
||||
log_sapart(client, target, request, comment);
|
||||
|
||||
/***
|
||||
if (comment)
|
||||
{
|
||||
snprintf(commentx, sizeof(commentx), "SAPart: %s", comment);
|
||||
@ -174,6 +175,7 @@ CMD_FUNC(cmd_sapart)
|
||||
} else {
|
||||
sendnotice(target, "*** You were forced to part %s", request);
|
||||
}
|
||||
***/
|
||||
|
||||
parv[0] = target->name; // nick
|
||||
parv[1] = request; // chan
|
||||
|
@ -45,7 +45,7 @@ EVENT(server_handshake_timeout);
|
||||
void send_channel_modes_sjoin3(Client *to, Channel *channel);
|
||||
CMD_FUNC(cmd_server);
|
||||
CMD_FUNC(cmd_sid);
|
||||
int _verify_link(Client *client, ConfigItem_link **link_out);
|
||||
ConfigItem_link *_verify_link(Client *client);
|
||||
void _send_protoctl_servers(Client *client, int response);
|
||||
void _send_server_message(Client *client);
|
||||
void _introduce_user(Client *to, Client *acptr);
|
||||
@ -59,7 +59,6 @@ void _connect_server(ConfigItem_link *aconf, Client *by, struct hostent *hp);
|
||||
static int connect_server_helper(ConfigItem_link *, Client *);
|
||||
|
||||
/* Global variables */
|
||||
static char buf[BUFSIZE];
|
||||
static cfgstruct cfg;
|
||||
static char *last_autoconnect_server = NULL;
|
||||
|
||||
@ -77,7 +76,7 @@ MOD_TEST()
|
||||
MARK_AS_OFFICIAL_MODULE(modinfo);
|
||||
EfunctionAddVoid(modinfo->handle, EFUNC_SEND_PROTOCTL_SERVERS, _send_protoctl_servers);
|
||||
EfunctionAddVoid(modinfo->handle, EFUNC_SEND_SERVER_MESSAGE, _send_server_message);
|
||||
EfunctionAdd(modinfo->handle, EFUNC_VERIFY_LINK, _verify_link);
|
||||
EfunctionAddPVoid(modinfo->handle, EFUNC_VERIFY_LINK, TO_PVOIDFUNC(_verify_link));
|
||||
EfunctionAddVoid(modinfo->handle, EFUNC_INTRODUCE_USER, _introduce_user);
|
||||
EfunctionAdd(modinfo->handle, EFUNC_CHECK_DENY_VERSION, _check_deny_version);
|
||||
EfunctionAddVoid(modinfo->handle, EFUNC_BROADCAST_SINFO, _broadcast_sinfo);
|
||||
@ -254,8 +253,13 @@ int server_needs_linking(ConfigItem_link *aconf)
|
||||
Client *client;
|
||||
ConfigItem_class *class;
|
||||
|
||||
/* 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))
|
||||
/* We're only interested in autoconnect blocks that also have
|
||||
* a valid link::outgoing configuration. We also ignore
|
||||
* temporary link blocks (not that they should exist...).
|
||||
*/
|
||||
if (!(aconf->outgoing.options & CONNECT_AUTO) ||
|
||||
(!aconf->outgoing.hostname && !aconf->outgoing.file) ||
|
||||
(aconf->flag.temporary == 1))
|
||||
return 0;
|
||||
|
||||
class = aconf->class;
|
||||
@ -635,12 +639,10 @@ void _send_server_message(Client *client)
|
||||
|
||||
/** Verify server link.
|
||||
* This does authentication and authorization checks.
|
||||
* @param cptr The client directly connected to us (cptr).
|
||||
* @param client The client which (originally) issued the server command (client).
|
||||
* @param link_out Pointer-to-pointer-to-link block. Will be set when auth OK. Caller may pass NULL if he doesn't care.
|
||||
* @returns This function returns 1 on successful authentication, 0 otherwise - in which case the client has been killed.
|
||||
* @param client The client which issued the command
|
||||
* @returns On successfull authentication, the link block is returned. On failure NULL is returned (client has been killed!).
|
||||
*/
|
||||
int _verify_link(Client *client, ConfigItem_link **link_out)
|
||||
ConfigItem_link *_verify_link(Client *client)
|
||||
{
|
||||
ConfigItem_link *link, *orig_link;
|
||||
Client *acptr = NULL, *ocptr = NULL;
|
||||
@ -652,15 +654,12 @@ int _verify_link(Client *client, ConfigItem_link **link_out)
|
||||
if (client->local->hostp && client->local->hostp->h_name)
|
||||
set_sockhost(client, client->local->hostp->h_name);
|
||||
|
||||
if (link_out)
|
||||
*link_out = NULL;
|
||||
|
||||
if (!client->local->passwd)
|
||||
{
|
||||
unreal_log(ULOG_ERROR, "link", "LINK_DENIED_NO_PASSWORD", client,
|
||||
"Link with server $client.details denied: No password provided. Protocol error.");
|
||||
exit_client(client, NULL, "Missing password");
|
||||
return 0;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (client->server && client->server->conf)
|
||||
@ -679,7 +678,7 @@ int _verify_link(Client *client, ConfigItem_link **link_out)
|
||||
log_data_link_block(client->server->conf));
|
||||
exit_client_fmt(client, NULL, "Servername (%s) does not match name in my link block (%s)",
|
||||
client->name, client->server->conf->servername);
|
||||
return 0;
|
||||
return NULL;
|
||||
}
|
||||
link = client->server->conf;
|
||||
goto skip_host_check;
|
||||
@ -695,16 +694,16 @@ int _verify_link(Client *client, ConfigItem_link **link_out)
|
||||
unreal_log(ULOG_ERROR, "link", "LINK_DENIED_UNKNOWN_SERVER", client,
|
||||
"Link with server $client.details denied: No link block named '$client'");
|
||||
exit_client(client, NULL, LINK_DEFAULT_ERROR_MSG);
|
||||
return 0;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (!link->incoming.mask)
|
||||
if (!link->incoming.match)
|
||||
{
|
||||
unreal_log(ULOG_ERROR, "link", "LINK_DENIED_NO_INCOMING", client,
|
||||
"Link with server $client.details denied: Link block exists, but there is no link::incoming::mask set.",
|
||||
"Link with server $client.details denied: Link block exists, but there is no link::incoming::match set.",
|
||||
log_data_link_block(link));
|
||||
exit_client(client, NULL, LINK_DEFAULT_ERROR_MSG);
|
||||
return 0;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
orig_link = link;
|
||||
@ -716,7 +715,7 @@ int _verify_link(Client *client, ConfigItem_link **link_out)
|
||||
"Link with server $client.details denied: Server is in link block but link::incoming::mask didn't match",
|
||||
log_data_link_block(orig_link));
|
||||
exit_client(client, NULL, LINK_DEFAULT_ERROR_MSG);
|
||||
return 0;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
skip_host_check:
|
||||
@ -767,7 +766,7 @@ skip_host_check:
|
||||
log_data_link_block(link));
|
||||
}
|
||||
exit_client(client, NULL, "Link denied (Authentication failed)");
|
||||
return 0;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Verify the TLS certificate (if requested) */
|
||||
@ -782,7 +781,7 @@ skip_host_check:
|
||||
log_data_string("certificate_failure_msg", "not using TLS"),
|
||||
log_data_link_block(link));
|
||||
exit_client(client, NULL, "Link denied (Not using TLS)");
|
||||
return 0;
|
||||
return NULL;
|
||||
}
|
||||
if (!verify_certificate(client->local->ssl, link->servername, &errstr))
|
||||
{
|
||||
@ -791,7 +790,7 @@ skip_host_check:
|
||||
log_data_string("certificate_failure_msg", errstr),
|
||||
log_data_link_block(link));
|
||||
exit_client(client, NULL, "Link denied (Certificate verification failed)");
|
||||
return 0;
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
@ -803,7 +802,7 @@ skip_host_check:
|
||||
log_data_string("ban_reason", bconf->reason),
|
||||
log_data_link_block(link));
|
||||
exit_client_fmt(client, NULL, "Banned server: %s", bconf->reason);
|
||||
return 0;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (link->class->clients + 1 > link->class->maxclients)
|
||||
@ -813,7 +812,7 @@ skip_host_check:
|
||||
"class '$link_block.class' is full",
|
||||
log_data_link_block(link));
|
||||
exit_client(client, NULL, "Full class");
|
||||
return 0;
|
||||
return NULL;
|
||||
}
|
||||
if (!IsLocalhost(client) && (iConf.plaintext_policy_server == POLICY_DENY) && !IsSecure(client))
|
||||
{
|
||||
@ -823,7 +822,7 @@ skip_host_check:
|
||||
"See https://www.unrealircd.org/docs/FAQ#server-requires-tls",
|
||||
log_data_link_block(link));
|
||||
exit_client(client, NULL, "Servers need to use TLS (set::plaintext-policy::server is 'deny')");
|
||||
return 0;
|
||||
return NULL;
|
||||
}
|
||||
if (IsSecure(client) && (iConf.outdated_tls_policy_server == POLICY_DENY) && outdated_tls_client(client))
|
||||
{
|
||||
@ -834,7 +833,7 @@ skip_host_check:
|
||||
log_data_link_block(link),
|
||||
log_data_string("tls_cipher", tls_get_cipher(client)));
|
||||
exit_client(client, NULL, "Server using outdates TLS protocol or cipher (set::outdated-tls-policy::server is 'deny')");
|
||||
return 0;
|
||||
return NULL;
|
||||
}
|
||||
/* This one is at the end, because it causes us to delink another server,
|
||||
* so we want to be (reasonably) sure that this one will succeed before
|
||||
@ -850,7 +849,7 @@ skip_host_check:
|
||||
log_data_string("me_name", me.name),
|
||||
log_data_link_block(link));
|
||||
exit_client(client, NULL, "Server Exists (server trying to link with same name as myself)");
|
||||
return 0;
|
||||
return NULL;
|
||||
} else {
|
||||
unreal_log(ULOG_ERROR, "link", "LINK_DROPPED_REINTRODUCED", client,
|
||||
"Link with server $client.details causes older link "
|
||||
@ -861,9 +860,7 @@ skip_host_check:
|
||||
}
|
||||
}
|
||||
|
||||
if (link_out)
|
||||
*link_out = link;
|
||||
return 1;
|
||||
return link;
|
||||
}
|
||||
|
||||
/** Server command. Only for locally connected servers!!.
|
||||
@ -935,7 +932,7 @@ CMD_FUNC(cmd_server)
|
||||
*/
|
||||
strlcpy(client->name, servername, sizeof(client->name));
|
||||
|
||||
if (!verify_link(client, &aconf))
|
||||
if (!(aconf = verify_link(client)))
|
||||
return; /* Rejected */
|
||||
|
||||
/* From this point the server is authenticated, so we can be more verbose
|
||||
@ -1200,6 +1197,7 @@ CMD_FUNC(cmd_sid)
|
||||
unreal_log(ULOG_ERROR, "link", "REMOTE_LINK_DENIED_SERVER_BAN", client,
|
||||
"Denied remote server $servername which was introduced by $client: "
|
||||
"Server is banned ($ban_reason)",
|
||||
log_data_string("servername", servername),
|
||||
log_data_string("ban_reason", bconf->reason));
|
||||
/* Before UnrealIRCd 6 this would SQUIT the server who introduced
|
||||
* this server. That seems a bit of an overreaction, so we now
|
||||
@ -1330,6 +1328,8 @@ CMD_FUNC(cmd_sid)
|
||||
|
||||
void _introduce_user(Client *to, Client *acptr)
|
||||
{
|
||||
char buf[512];
|
||||
|
||||
build_umode_string(acptr, 0, SEND_UMODES, buf);
|
||||
|
||||
sendto_one_nickcmd(to, NULL, acptr, buf);
|
||||
@ -1807,13 +1807,13 @@ void _connect_server(ConfigItem_link *aconf, Client *by, struct hostent *hp)
|
||||
{
|
||||
Client *client;
|
||||
|
||||
if (!aconf->outgoing.hostname)
|
||||
if (!aconf->outgoing.hostname && !aconf->outgoing.file)
|
||||
{
|
||||
/* Actually the caller should make sure that this doesn't happen,
|
||||
* so this error may never be triggered:
|
||||
*/
|
||||
unreal_log(ULOG_ERROR, "link", "LINK_ERROR_NO_OUTGOING", NULL,
|
||||
"Connect to $link_block failed: link block is for incoming only (no link::outgoing::hostname set)",
|
||||
"Connect to $link_block failed: link block is for incoming only (no link::outgoing::hostname or link::outgoing::file set)",
|
||||
log_data_link_block(aconf));
|
||||
return;
|
||||
}
|
||||
@ -1827,7 +1827,7 @@ void _connect_server(ConfigItem_link *aconf, Client *by, struct hostent *hp)
|
||||
* If we dont know the IP# for this host and itis a hostname and
|
||||
* not a ip# string, then try and find the appropriate host record.
|
||||
*/
|
||||
if (!aconf->connect_ip)
|
||||
if (!aconf->connect_ip && !aconf->outgoing.file)
|
||||
{
|
||||
if (is_valid_ip(aconf->outgoing.hostname))
|
||||
{
|
||||
@ -1861,7 +1861,7 @@ void _connect_server(ConfigItem_link *aconf, Client *by, struct hostent *hp)
|
||||
* Copy these in so we have something for error detection.
|
||||
*/
|
||||
strlcpy(client->name, aconf->servername, sizeof(client->name));
|
||||
strlcpy(client->local->sockhost, aconf->outgoing.hostname, HOSTLEN + 1);
|
||||
strlcpy(client->local->sockhost, aconf->outgoing.hostname ? aconf->outgoing.hostname : aconf->outgoing.file, HOSTLEN + 1);
|
||||
|
||||
if (!connect_server_helper(aconf, client))
|
||||
{
|
||||
@ -1884,7 +1884,7 @@ void _connect_server(ConfigItem_link *aconf, Client *by, struct hostent *hp)
|
||||
SetOutgoing(client);
|
||||
irccounts.unknown++;
|
||||
list_add(&client->lclient_node, &unknown_list);
|
||||
set_sockhost(client, aconf->outgoing.hostname);
|
||||
set_sockhost(client, aconf->outgoing.hostname ? aconf->outgoing.hostname : "127.0.0.1");
|
||||
add_client_to_list(client);
|
||||
|
||||
if (aconf->outgoing.options & CONNECT_TLS)
|
||||
@ -1896,7 +1896,9 @@ void _connect_server(ConfigItem_link *aconf, Client *by, struct hostent *hp)
|
||||
fd_setselect(client->local->fd, FD_SELECT_WRITE, completed_connection, client);
|
||||
|
||||
unreal_log(ULOG_INFO, "link", "LINK_CONNECTING", client,
|
||||
"Trying to activate link with server $client ($link_block.ip:$link_block.port)...",
|
||||
aconf->outgoing.file
|
||||
? "Trying to activate link with server $client ($link_block.file)..."
|
||||
: "Trying to activate link with server $client ($link_block.ip:$link_block.port)...",
|
||||
log_data_link_block(aconf));
|
||||
}
|
||||
|
||||
@ -1911,21 +1913,23 @@ static int connect_server_helper(ConfigItem_link *aconf, Client *client)
|
||||
char *bindip;
|
||||
char buf[BUFSIZE];
|
||||
|
||||
if (!aconf->connect_ip)
|
||||
if (!aconf->connect_ip && !aconf->outgoing.file)
|
||||
{
|
||||
unreal_log(ULOG_ERROR, "link", "LINK_ERROR_NOIP", client,
|
||||
"Connect to $client failed: no IP address to connect to",
|
||||
"Connect to $client failed: no IP address or file to connect to",
|
||||
log_data_link_block(aconf));
|
||||
return 0; /* handled upstream or shouldn't happen */
|
||||
}
|
||||
|
||||
if (strchr(aconf->connect_ip, ':'))
|
||||
if (aconf->outgoing.file)
|
||||
SetUnixSocket(client);
|
||||
else if (strchr(aconf->connect_ip, ':'))
|
||||
SetIPV6(client);
|
||||
|
||||
safe_strdup(client->ip, aconf->connect_ip);
|
||||
safe_strdup(client->ip, aconf->connect_ip ? aconf->connect_ip : "127.0.0.1");
|
||||
|
||||
snprintf(buf, sizeof buf, "Outgoing connection: %s", get_client_name(client, TRUE));
|
||||
client->local->fd = fd_socket(IsIPV6(client) ? AF_INET6 : AF_INET, SOCK_STREAM, 0, buf);
|
||||
client->local->fd = fd_socket(IsUnixSocket(client) ? AF_UNIX : (IsIPV6(client) ? AF_INET6 : AF_INET), SOCK_STREAM, 0, buf);
|
||||
if (client->local->fd < 0)
|
||||
{
|
||||
if (ERRNO == P_EMFILE)
|
||||
@ -1949,7 +1953,7 @@ static int connect_server_helper(ConfigItem_link *aconf, Client *client)
|
||||
return 0;
|
||||
}
|
||||
|
||||
set_sockhost(client, aconf->outgoing.hostname);
|
||||
set_sockhost(client, aconf->outgoing.hostname ? aconf->outgoing.hostname : "127.0.0.1");
|
||||
|
||||
if (!aconf->outgoing.bind_ip && iConf.link_bindip)
|
||||
bindip = iConf.link_bindip;
|
||||
@ -1971,10 +1975,14 @@ static int connect_server_helper(ConfigItem_link *aconf, Client *client)
|
||||
|
||||
set_sock_opts(client->local->fd, client, IsIPV6(client));
|
||||
|
||||
if (!unreal_connect(client->local->fd, client->ip, aconf->outgoing.port, IsIPV6(client)))
|
||||
if (!unreal_connect(client->local->fd,
|
||||
aconf->outgoing.file ? aconf->outgoing.file : client->ip,
|
||||
aconf->outgoing.port, client->local->socket_type))
|
||||
{
|
||||
unreal_log(ULOG_ERROR, "link", "LINK_ERROR_CONNECT", client,
|
||||
"Connect to $client ($link_block.ip:$link_block.port) failed: $socket_error",
|
||||
aconf->outgoing.file
|
||||
? "Connect to $client ($link_block.file) failed: $socket_error"
|
||||
: "Connect to $client ($link_block.ip:$link_block.port) failed: $socket_error",
|
||||
log_data_socket_error(client->local->fd),
|
||||
log_data_link_block(aconf));
|
||||
return 0;
|
||||
|
@ -143,7 +143,6 @@ CMD_FUNC(cmd_sethost)
|
||||
if (MyConnect(client))
|
||||
{
|
||||
sendto_one(client, NULL, ":%s MODE %s :+xt", client->name, client->name);
|
||||
sendnumeric(client, RPL_HOSTHIDDEN, vhost);
|
||||
sendnotice(client,
|
||||
"Your nick!user@host-mask is now (%s!%s@%s) - To disable it type /mode %s -x",
|
||||
client->name, client->user->username, vhost,
|
||||
|
@ -1,7 +1,7 @@
|
||||
/*
|
||||
* cmd_sinfo - Server information
|
||||
* (C) Copyright 2019 Bram Matthys (Syzop) and the UnrealIRCd team.
|
||||
* License: GPLv2
|
||||
* License: GPLv2 or later
|
||||
*/
|
||||
|
||||
#include "unrealircd.h"
|
||||
|
@ -487,14 +487,14 @@ int stats_except(Client *client, const char *para)
|
||||
int stats_allow(Client *client, const char *para)
|
||||
{
|
||||
ConfigItem_allow *allows;
|
||||
ConfigItem_mask *m;
|
||||
NameValuePrioList *m;
|
||||
|
||||
for (allows = conf_allow; allows; allows = allows->next)
|
||||
{
|
||||
for (m = allows->mask; m; m = m->next)
|
||||
for (m = allows->match->printable_list; m; m = m->next)
|
||||
{
|
||||
sendnumeric(client, RPL_STATSILINE,
|
||||
m->mask, "-",
|
||||
namevalue_nospaces(m), "-",
|
||||
allows->maxperip,
|
||||
allows->global_maxperip,
|
||||
allows->class->name,
|
||||
@ -521,14 +521,14 @@ int stats_command(Client *client, const char *para)
|
||||
int stats_oper(Client *client, const char *para)
|
||||
{
|
||||
ConfigItem_oper *o;
|
||||
ConfigItem_mask *m;
|
||||
NameValuePrioList *m;
|
||||
|
||||
for (o = conf_oper; o; o = o->next)
|
||||
{
|
||||
for (m = o->mask; m; m = m->next)
|
||||
for (m = o->match->printable_list; m; m = m->next)
|
||||
{
|
||||
sendnumeric(client, RPL_STATSOLINE,
|
||||
'O', m->mask, o->name,
|
||||
'O', namevalue_nospaces(m), o->name,
|
||||
o->operclass ? o->operclass: "",
|
||||
o->class->name ? o->class->name : "");
|
||||
}
|
||||
@ -668,15 +668,19 @@ int stats_uline(Client *client, const char *para)
|
||||
}
|
||||
int stats_vhost(Client *client, const char *para)
|
||||
{
|
||||
ConfigItem_mask *m;
|
||||
ConfigItem_vhost *vhosts;
|
||||
NameValuePrioList *m;
|
||||
|
||||
for (vhosts = conf_vhost; vhosts; vhosts = vhosts->next)
|
||||
{
|
||||
for (m = vhosts->mask; m; m = m->next)
|
||||
for (m = vhosts->match->printable_list; m; m = m->next)
|
||||
{
|
||||
sendtxtnumeric(client, "vhost %s%s%s %s %s", vhosts->virtuser ? vhosts->virtuser : "", vhosts->virtuser ? "@" : "",
|
||||
vhosts->virthost, vhosts->login, m->mask);
|
||||
sendtxtnumeric(client, "vhost %s%s%s %s %s",
|
||||
vhosts->virtuser ? vhosts->virtuser : "",
|
||||
vhosts->virtuser ? "@" : "",
|
||||
vhosts->virthost,
|
||||
vhosts->login,
|
||||
namevalue_nospaces(m));
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
@ -935,12 +939,16 @@ int stats_set(Client *client, const char *para)
|
||||
int stats_tld(Client *client, const char *para)
|
||||
{
|
||||
ConfigItem_tld *tld;
|
||||
ConfigItem_mask *m;
|
||||
NameValuePrioList *m;
|
||||
|
||||
for (tld = conf_tld; tld; tld = tld->next)
|
||||
{
|
||||
for (m = tld->mask; m; m = m->next)
|
||||
sendnumeric(client, RPL_STATSTLINE, m->mask, tld->motd_file, tld->rules_file ? tld->rules_file : "none");
|
||||
for (m = tld->match->printable_list; m; m = m->next)
|
||||
{
|
||||
sendnumeric(client, RPL_STATSTLINE, namevalue_nospaces(m),
|
||||
tld->motd_file,
|
||||
tld->rules_file ? tld->rules_file : "none");
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
@ -395,7 +395,7 @@ void do_svsmode(Client *client, MessageTag *recv_mtags, int parc, const char *pa
|
||||
* so remove all oper-only modes and snomasks.
|
||||
*/
|
||||
if (MyUser(client))
|
||||
RunHook(HOOKTYPE_LOCAL_OPER, client, 0, NULL);
|
||||
RunHook(HOOKTYPE_LOCAL_OPER, client, 0, NULL, NULL);
|
||||
remove_oper_privileges(target, 0);
|
||||
}
|
||||
goto setmodex;
|
||||
|
@ -82,7 +82,7 @@ CMD_FUNC(cmd_svsnoop)
|
||||
if (!list_empty(&acptr->special_node))
|
||||
list_del(&acptr->special_node);
|
||||
|
||||
RunHook(HOOKTYPE_LOCAL_OPER, client, 0, NULL);
|
||||
RunHook(HOOKTYPE_LOCAL_OPER, client, 0, NULL, NULL);
|
||||
remove_oper_privileges(acptr, 1);
|
||||
}
|
||||
}
|
||||
|
138
src/modules/svso.c
Normal file
138
src/modules/svso.c
Normal file
@ -0,0 +1,138 @@
|
||||
/* src/modules/svso.c - Grant IRCOp rights (for Services)
|
||||
* (C) Copyright 2022 Bram Matthys (Syzop) and the UnrealIRCd team
|
||||
* License: GPLv2 or later
|
||||
*/
|
||||
#include "unrealircd.h"
|
||||
|
||||
ModuleHeader MOD_HEADER
|
||||
= {
|
||||
"svso",
|
||||
"6.0.0",
|
||||
"Grant oper privileges via SVSO services command",
|
||||
"UnrealIRCd Team",
|
||||
"unrealircd-6",
|
||||
};
|
||||
|
||||
/* Forward declarations */
|
||||
CMD_FUNC(cmd_svso);
|
||||
|
||||
MOD_INIT()
|
||||
{
|
||||
MARK_AS_OFFICIAL_MODULE(modinfo);
|
||||
|
||||
CommandAdd(modinfo->handle, "SVSO", cmd_svso, MAXPARA, CMD_USER|CMD_SERVER);
|
||||
return MOD_SUCCESS;
|
||||
}
|
||||
|
||||
MOD_LOAD()
|
||||
{
|
||||
return MOD_SUCCESS;
|
||||
}
|
||||
|
||||
MOD_UNLOAD()
|
||||
{
|
||||
return MOD_SUCCESS;
|
||||
}
|
||||
|
||||
/* Syntax: SVSO <uid|nick> <oper account> <operclass> <class> <modes> <snomask> <vhost>
|
||||
* All these parameters need to be set, you cannot leave any of them out,
|
||||
* HOWEVER some can be set to "-" to skip setting them, this is true for:
|
||||
* <class>, <modes>, <snomask>, <vhost>
|
||||
*
|
||||
* In UnrealIRCd the <operclass> will be prefixed by "services:" if not already
|
||||
* present. It is up to you to include or omit it.
|
||||
*/
|
||||
CMD_FUNC(cmd_svso)
|
||||
{
|
||||
Client *acptr;
|
||||
char oper_account[64];
|
||||
const char *operclass;
|
||||
const char *clientclass;
|
||||
ConfigItem_class *clientclass_c;
|
||||
const char *modes;
|
||||
long modes_i = 0;
|
||||
const char *snomask;
|
||||
const char *vhost;
|
||||
|
||||
if (!IsULine(client))
|
||||
return;
|
||||
|
||||
if ((parc < 8) || BadPtr(parv[7]))
|
||||
{
|
||||
sendnumeric(client, ERR_NEEDMOREPARAMS, "SVSO");
|
||||
return;
|
||||
}
|
||||
|
||||
operclass = parv[3];
|
||||
clientclass = parv[4];
|
||||
modes = parv[5];
|
||||
snomask = parv[6];
|
||||
vhost = parv[7];
|
||||
|
||||
acptr = find_user(parv[1], NULL);
|
||||
if (!acptr)
|
||||
{
|
||||
sendnumeric(client, ERR_NOSUCHNICK, parv[1]);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!MyUser(acptr))
|
||||
{
|
||||
/* Forward it to the correct server, and we are done... */
|
||||
sendto_one(acptr, recv_mtags, ":%s SVSO %s %s %s %s %s %s %s",
|
||||
client->name, acptr->id, parv[2], parv[3], parv[4], parv[5], parv[6], parv[7]);
|
||||
return;
|
||||
}
|
||||
|
||||
/* CAVEAT ALERT !
|
||||
* Don't mix up 'client' and 'acptr' below...
|
||||
* 'client' is the server or services pseudouser that requests the change
|
||||
* 'acptr' is the person that will be made OPER
|
||||
*/
|
||||
|
||||
/* If we get here, we validate the request and then make the user oper. */
|
||||
if (!find_operclass(operclass))
|
||||
{
|
||||
sendnumeric(client, ERR_CANNOTDOCOMMAND, "SVSO", "Operclass does not exist");
|
||||
return;
|
||||
}
|
||||
|
||||
/* Set any items to NULL if they are skipped (on request) */
|
||||
if (!strcmp(clientclass, "-"))
|
||||
clientclass = NULL;
|
||||
if (!strcmp(modes, "-"))
|
||||
modes = NULL;
|
||||
if (!strcmp(snomask, "-"))
|
||||
snomask = NULL;
|
||||
if (!strcmp(vhost, "-"))
|
||||
vhost = NULL;
|
||||
|
||||
/* First, maybe the user is oper already? Then de-oper them.. */
|
||||
if (IsOper(acptr))
|
||||
{
|
||||
int was_hidden_oper = IsHideOper(acptr) ? 1 : 0;
|
||||
|
||||
list_del(&acptr->special_node);
|
||||
RunHook(HOOKTYPE_LOCAL_OPER, acptr, 0, NULL, NULL);
|
||||
remove_oper_privileges(acptr, 1);
|
||||
|
||||
if (!was_hidden_oper)
|
||||
irccounts.operators--;
|
||||
VERIFY_OPERCOUNT(acptr, "svso");
|
||||
|
||||
}
|
||||
|
||||
/* Prefix the oper block name with "services:" if it hasn't already */
|
||||
if (!strncmp(parv[2], "services:", 9))
|
||||
strlcpy(oper_account, parv[2], sizeof(oper_account));
|
||||
else
|
||||
snprintf(oper_account, sizeof(oper_account), "services:%s", parv[2]);
|
||||
|
||||
/* These needs to be looked up... */
|
||||
clientclass_c = find_class(clientclass); /* NULL is fine! */
|
||||
if (modes)
|
||||
modes_i = set_usermode(modes);
|
||||
|
||||
if (!make_oper(acptr, oper_account, operclass, clientclass_c, modes_i, snomask, vhost))
|
||||
sendnumeric(client, ERR_CANNOTDOCOMMAND, "SVSO", "Failed to make user oper");
|
||||
}
|
@ -1,6 +1,6 @@
|
||||
/* Target flood protection
|
||||
* (C)Copyright 2020 Bram Matthys and the UnrealIRCd team
|
||||
* License: GPLv2
|
||||
* License: GPLv2 or later
|
||||
*/
|
||||
|
||||
#include "unrealircd.h"
|
||||
|
@ -60,7 +60,8 @@ char *_tkl_type_config_string(TKL *tk);
|
||||
char *tkl_banexception_configname_to_chars(char *name);
|
||||
TKL *_tkl_add_serverban(int type, char *usermask, char *hostmask, char *reason, char *set_by,
|
||||
time_t expire_at, time_t set_at, int soft, int flags);
|
||||
TKL *_tkl_add_banexception(int type, char *usermask, char *hostmask, char *reason, char *set_by,
|
||||
TKL *_tkl_add_banexception(int type, char *usermask, char *hostmask, SecurityGroup *match,
|
||||
char *reason, char *set_by,
|
||||
time_t expire_at, time_t set_at, int soft, char *bantypes, int flags);
|
||||
TKL *_tkl_add_nameban(int type, char *name, int hold, char *reason, char *set_by,
|
||||
time_t expire_at, time_t set_at, int flags);
|
||||
@ -91,6 +92,7 @@ int check_mtag_spamfilters_present(void);
|
||||
int _join_viruschan(Client *client, TKL *tk, int type);
|
||||
void _spamfilter_build_user_string(char *buf, char *nick, Client *client);
|
||||
int _match_user(const char *rmask, Client *client, int options);
|
||||
int _unreal_match_iplist(Client *client, NameList *l);
|
||||
int _match_user_extended_server_ban(const char *banstr, Client *client);
|
||||
void ban_target_to_tkl_layer(BanTarget ban_target, BanAction action, Client *client, const char **tkl_username, const char **tkl_hostname);
|
||||
int _tkl_ip_hash(char *ip);
|
||||
@ -204,6 +206,7 @@ MOD_TEST()
|
||||
EfunctionAddVoid(modinfo->handle, EFUNC_SENDNOTICE_TKL_DEL, _sendnotice_tkl_del);
|
||||
EfunctionAdd(modinfo->handle, EFUNC_FIND_TKL_EXCEPTION, _find_tkl_exception);
|
||||
EfunctionAddString(modinfo->handle, EFUNC_TKL_UHOST, _tkl_uhost);
|
||||
EfunctionAdd(modinfo->handle, EFUNC_UNREAL_MATCH_IPLIST, _unreal_match_iplist);
|
||||
return MOD_SUCCESS;
|
||||
}
|
||||
|
||||
@ -678,7 +681,7 @@ int tkl_config_test_except(ConfigFile *cf, ConfigEntry *ce, int configtype, int
|
||||
{
|
||||
ConfigEntry *cep, *cepp;
|
||||
int errors = 0;
|
||||
int has_mask = 0;
|
||||
char has_mask = 0, has_match = 0;
|
||||
|
||||
/* We are only interested in except { } blocks */
|
||||
if (configtype != CONFIG_EXCEPT)
|
||||
@ -705,32 +708,18 @@ int tkl_config_test_except(ConfigFile *cf, ConfigEntry *ce, int configtype, int
|
||||
{
|
||||
if (!strcmp(cep->name, "mask"))
|
||||
{
|
||||
if (cep->items)
|
||||
if (cep->value || cep->items)
|
||||
{
|
||||
/* mask { *@1.1.1.1; *@2.2.2.2; *@3.3.3.3; }; */
|
||||
for (cepp = cep->items; cepp; cepp = cepp->next)
|
||||
{
|
||||
if (!cepp->name)
|
||||
{
|
||||
config_error_empty(cepp->file->filename,
|
||||
cepp->line_number, "except ban", "mask");
|
||||
errors++;
|
||||
continue;
|
||||
}
|
||||
has_mask = 1;
|
||||
test_match_block(cf, cep, &errors);
|
||||
}
|
||||
} else
|
||||
if (cep->value)
|
||||
if (!strcmp(cep->name, "match"))
|
||||
{
|
||||
/* mask *@1.1.1.1; */
|
||||
if (!cep->value)
|
||||
if (cep->value || cep->items)
|
||||
{
|
||||
config_error_empty(cep->file->filename,
|
||||
cep->line_number, "except ban", "mask");
|
||||
errors++;
|
||||
continue;
|
||||
}
|
||||
has_mask = 1;
|
||||
has_match = 1;
|
||||
test_match_block(cf, cep, &errors);
|
||||
}
|
||||
} else
|
||||
if (!strcmp(cep->name, "type"))
|
||||
@ -766,10 +755,17 @@ int tkl_config_test_except(ConfigFile *cf, ConfigEntry *ce, int configtype, int
|
||||
}
|
||||
}
|
||||
|
||||
if (!has_mask)
|
||||
if (!has_mask && !has_match)
|
||||
{
|
||||
config_error_missing(ce->file->filename, ce->line_number,
|
||||
"except ban::mask");
|
||||
"except ban::match");
|
||||
errors++;
|
||||
}
|
||||
if (has_mask && has_match)
|
||||
{
|
||||
config_error("%s:%d: You cannot have both ::mask and ::match. "
|
||||
"You should only use except::match.",
|
||||
ce->file->filename, ce->line_number);
|
||||
errors++;
|
||||
}
|
||||
|
||||
@ -777,60 +773,10 @@ int tkl_config_test_except(ConfigFile *cf, ConfigEntry *ce, int configtype, int
|
||||
return errors ? -1 : 1;
|
||||
}
|
||||
|
||||
void config_create_tkl_except(char *mask, char *bantypes)
|
||||
{
|
||||
char *usermask = NULL;
|
||||
char *hostmask = NULL;
|
||||
int soft = 0;
|
||||
char buf[256];
|
||||
char mask1buf[512];
|
||||
char mask2buf[512];
|
||||
char *p;
|
||||
|
||||
if (*mask == '%')
|
||||
{
|
||||
soft = 1;
|
||||
mask++;
|
||||
}
|
||||
strlcpy(buf, mask, sizeof(buf));
|
||||
if (is_extended_server_ban(buf))
|
||||
{
|
||||
char *err = NULL;
|
||||
if (!parse_extended_server_ban(buf, NULL, &err, 0, mask1buf, sizeof(mask1buf), mask2buf, sizeof(mask2buf)))
|
||||
{
|
||||
config_warn("Could not add extended server ban '%s': %s", buf, err);
|
||||
return;
|
||||
}
|
||||
usermask = mask1buf;
|
||||
hostmask = mask2buf;
|
||||
} else
|
||||
{
|
||||
p = strchr(buf, '@');
|
||||
if (!p)
|
||||
{
|
||||
usermask = "*";
|
||||
hostmask = buf;
|
||||
} else {
|
||||
*p++ = '\0';
|
||||
usermask = buf;
|
||||
hostmask = p;
|
||||
}
|
||||
}
|
||||
|
||||
if ((*usermask == ':') || (*hostmask == ':'))
|
||||
{
|
||||
config_error("Cannot add illegal ban '%s': for a given user@host - neither "
|
||||
"user nor host may start with a : character (semicolon)", mask);
|
||||
return;
|
||||
}
|
||||
|
||||
tkl_add_banexception(TKL_EXCEPTION, usermask, hostmask, "Added in configuration file",
|
||||
"-config-", 0, TStime(), soft, bantypes, TKL_FLAG_CONFIG);
|
||||
}
|
||||
|
||||
int tkl_config_run_except(ConfigFile *cf, ConfigEntry *ce, int configtype)
|
||||
{
|
||||
ConfigEntry *cep, *cepp;
|
||||
SecurityGroup *match = NULL;
|
||||
char bantypes[64];
|
||||
|
||||
/* We are only interested in except { } blocks */
|
||||
@ -867,6 +813,10 @@ int tkl_config_run_except(ConfigFile *cf, ConfigEntry *ce, int configtype)
|
||||
char *str = tkl_banexception_configname_to_chars(cep->value);
|
||||
strlcat(bantypes, str, sizeof(bantypes));
|
||||
}
|
||||
} else
|
||||
if (!strcmp(cep->name, "match") || !strcmp(cep->name, "mask"))
|
||||
{
|
||||
conf_match_block(cf, cep, &match);
|
||||
}
|
||||
}
|
||||
|
||||
@ -885,24 +835,8 @@ int tkl_config_run_except(ConfigFile *cf, ConfigEntry *ce, int configtype)
|
||||
abort(); /* someone can't code */
|
||||
}
|
||||
|
||||
/* Now walk through all mask entries */
|
||||
for (cep = ce->items; cep; cep = cep->next)
|
||||
{
|
||||
if (!strcmp(cep->name, "mask"))
|
||||
{
|
||||
if (cep->items)
|
||||
{
|
||||
/* mask { *@1.1.1.1; *@2.2.2.2; *@3.3.3.3; }; */
|
||||
for (cepp = cep->items; cepp; cepp = cepp->next)
|
||||
config_create_tkl_except(cepp->name, bantypes);
|
||||
} else
|
||||
if (cep->value)
|
||||
{
|
||||
/* mask *@1.1.1.1; */
|
||||
config_create_tkl_except(cep->value, bantypes);
|
||||
}
|
||||
}
|
||||
}
|
||||
tkl_add_banexception(TKL_EXCEPTION, "-", "-", match, "Added in configuration file",
|
||||
"-config-", 0, TStime(), 0, bantypes, TKL_FLAG_CONFIG);
|
||||
|
||||
return 1;
|
||||
}
|
||||
@ -2564,6 +2498,9 @@ TKL *_tkl_add_serverban(int type, char *usermask, char *hostmask, char *reason,
|
||||
* @param type TKL_EXCEPTION or TKLEXCEPT|TKL_GLOBAL.
|
||||
* @param usermask The user mask
|
||||
* @param hostmask The host mask
|
||||
* @param match A securitygroup used for matching (can be NULL,
|
||||
* if not NULL then this field is used as-is and not copied
|
||||
* so caller should not free!)
|
||||
* @param reason The reason for the ban
|
||||
* @param set_by Who (or what) set the ban
|
||||
* @param expire_at When will the ban expire (0 for permanent)
|
||||
@ -2577,7 +2514,8 @@ TKL *_tkl_add_serverban(int type, char *usermask, char *hostmask, char *reason,
|
||||
* Be sure not to call this function for spamfilters,
|
||||
* qlines or exempts, which have their own function!
|
||||
*/
|
||||
TKL *_tkl_add_banexception(int type, char *usermask, char *hostmask, char *reason, char *set_by,
|
||||
TKL *_tkl_add_banexception(int type, char *usermask, char *hostmask, SecurityGroup *match,
|
||||
char *reason, char *set_by,
|
||||
time_t expire_at, time_t set_at, int soft, char *bantypes, int flags)
|
||||
{
|
||||
TKL *tkl;
|
||||
@ -2585,7 +2523,6 @@ TKL *_tkl_add_banexception(int type, char *usermask, char *hostmask, char *reaso
|
||||
|
||||
if (!TKLIsBanExceptionType(type))
|
||||
abort();
|
||||
|
||||
tkl = safe_alloc(sizeof(TKL));
|
||||
/* First the common fields */
|
||||
tkl->type = type;
|
||||
@ -2597,6 +2534,7 @@ TKL *_tkl_add_banexception(int type, char *usermask, char *hostmask, char *reaso
|
||||
tkl->ptr.banexception = safe_alloc(sizeof(BanException));
|
||||
safe_strdup(tkl->ptr.banexception->usermask, usermask);
|
||||
safe_strdup(tkl->ptr.banexception->hostmask, hostmask);
|
||||
tkl->ptr.banexception->match = match;
|
||||
if (soft)
|
||||
tkl->ptr.banexception->subtype = TKL_SUBTYPE_SOFT;
|
||||
safe_strdup(tkl->ptr.banexception->bantypes, bantypes);
|
||||
@ -2702,6 +2640,8 @@ void _free_tkl(TKL *tkl)
|
||||
{
|
||||
safe_free(tkl->ptr.banexception->usermask);
|
||||
safe_free(tkl->ptr.banexception->hostmask);
|
||||
if (tkl->ptr.banexception->match)
|
||||
free_security_group(tkl->ptr.banexception->match);
|
||||
safe_free(tkl->ptr.banexception->bantypes);
|
||||
safe_free(tkl->ptr.banexception->reason);
|
||||
safe_free(tkl->ptr.banexception);
|
||||
@ -2770,7 +2710,7 @@ static void add_default_exempts(void)
|
||||
* Currently the list is: gline, kline, gzline, zline, shun, blacklist,
|
||||
* connect-flood, handshake-data-flood.
|
||||
*/
|
||||
tkl_add_banexception(TKL_EXCEPTION, "*", "127.0.0.0/8", "localhost is always exempt",
|
||||
tkl_add_banexception(TKL_EXCEPTION, "*", "127.0.0.0/8", NULL, "localhost is always exempt",
|
||||
"-default-", 0, TStime(), 0, "GkZzsbcd", TKL_FLAG_CONFIG);
|
||||
}
|
||||
|
||||
@ -2962,6 +2902,10 @@ static int find_tkl_exception_matcher(Client *client, int ban_type, TKL *except_
|
||||
if (!tkl_banexception_matches_type(except_tkl, ban_type))
|
||||
return 0;
|
||||
|
||||
/* For config file except ban { } we use security groups instead of simple user/host */
|
||||
if (except_tkl->ptr.banexception->match)
|
||||
return user_allowed_by_security_group(client, except_tkl->ptr.banexception->match);
|
||||
|
||||
tkl_uhost(except_tkl, uhost, sizeof(uhost), NO_SOFT_PREFIX);
|
||||
|
||||
if (match_user(uhost, client, MATCH_CHECK_REAL))
|
||||
@ -3565,12 +3509,26 @@ int tkl_stats_matcher(Client *client, int type, const char *para, TKLFlag *tklfl
|
||||
} else
|
||||
if (TKLIsBanException(tkl))
|
||||
{
|
||||
if (tkl->ptr.banexception->match)
|
||||
{
|
||||
/* Config-added: uses security groups */
|
||||
NameValuePrioList *m;
|
||||
for (m = tkl->ptr.banexception->match->printable_list; m; m = m->next)
|
||||
{
|
||||
sendnumeric(client, RPL_STATSEXCEPTTKL, namevalue_nospaces(m),
|
||||
tkl->ptr.banexception->bantypes,
|
||||
(tkl->expire_at != 0) ? (long long)(tkl->expire_at - TStime()) : 0,
|
||||
(long long)(TStime() - tkl->set_at), tkl->set_by, tkl->ptr.banexception->reason);
|
||||
}
|
||||
} else {
|
||||
/* IRC-added: uses simple user/host mask */
|
||||
char uhostbuf[BUFSIZE];
|
||||
char *uhost = tkl_uhost(tkl, uhostbuf, sizeof(uhostbuf), 0);
|
||||
sendnumeric(client, RPL_STATSEXCEPTTKL, uhost,
|
||||
tkl->ptr.banexception->bantypes,
|
||||
(tkl->expire_at != 0) ? (long long)(tkl->expire_at - TStime()) : 0,
|
||||
(long long)(TStime() - tkl->set_at), tkl->set_by, tkl->ptr.banexception->reason);
|
||||
}
|
||||
} else
|
||||
{
|
||||
/* That's weird, unknown TKL type */
|
||||
@ -3706,7 +3664,7 @@ void tkl_sync_send_entry(int add, Client *sender, Client *to, TKL *tkl)
|
||||
} else
|
||||
{
|
||||
unreal_log(ULOG_FATAL, "tkl", "BUG_TKL_SYNC_SEND_ENTRY", NULL,
|
||||
"[BUG] tkl_sync_send_entry() called for '%s' but unknown type: $tkl.type_string ($tkl_type_int)",
|
||||
"[BUG] tkl_sync_send_entry() called, but unknown type: $tkl.type_string ($tkl_type_int)",
|
||||
log_data_tkl("tkl", tkl),
|
||||
log_data_integer("tkl_type_int", typ));
|
||||
abort();
|
||||
@ -4072,7 +4030,7 @@ CMD_FUNC(cmd_tkl_add)
|
||||
{
|
||||
tkl_entry_exists = 1;
|
||||
} else {
|
||||
tkl = tkl_add_banexception(type, usermask, hostmask, reason,
|
||||
tkl = tkl_add_banexception(type, usermask, hostmask, NULL, reason,
|
||||
set_by, expire_at, set_at, softban, bantypes, 0);
|
||||
}
|
||||
} else
|
||||
@ -4123,7 +4081,7 @@ CMD_FUNC(cmd_tkl_add)
|
||||
{
|
||||
unreal_log(ULOG_WARNING, "tkl", "TKL_ADD_INVALID", client,
|
||||
"Invalid TKL entry from $client: "
|
||||
"Spamfilter '$spamfilter_string' has unkown match-type '$spamfilter_type'",
|
||||
"Spamfilter '$spamfilter_string' has unknown match-type '$spamfilter_type'",
|
||||
log_data_string("spamfilter_string", match_string),
|
||||
log_data_string("spamfilter_type", parv[10]));
|
||||
return;
|
||||
@ -4133,7 +4091,7 @@ CMD_FUNC(cmd_tkl_add)
|
||||
{
|
||||
unreal_log(ULOG_WARNING, "tkl", "TKL_ADD_INVALID", client,
|
||||
"Invalid TKL entry from $client: "
|
||||
"Spamfilter '$spamfilter_string' has unkown targets '$spamfilter_targets'",
|
||||
"Spamfilter '$spamfilter_string' has unknown targets '$spamfilter_targets'",
|
||||
log_data_string("spamfilter_string", match_string),
|
||||
log_data_string("spamfilter_targets", parv[3]));
|
||||
return;
|
||||
@ -4143,7 +4101,7 @@ CMD_FUNC(cmd_tkl_add)
|
||||
{
|
||||
unreal_log(ULOG_WARNING, "tkl", "TKL_ADD_INVALID", client,
|
||||
"Invalid TKL entry from $client: "
|
||||
"Spamfilter '$spamfilter_string' has unkown action '$spamfilter_action'",
|
||||
"Spamfilter '$spamfilter_string' has unknown action '$spamfilter_action'",
|
||||
log_data_string("spamfilter_string", match_string),
|
||||
log_data_string("spamfilter_action", parv[4]));
|
||||
return;
|
||||
@ -4312,7 +4270,7 @@ CMD_FUNC(cmd_tkl_del)
|
||||
{
|
||||
unreal_log(ULOG_WARNING, "tkl", "TKL_DEL_INVALID", client,
|
||||
"Invalid TKL deletion request from $client: "
|
||||
"Spamfilter '$spamfilter_string' has unkown targets '$spamfilter_targets'",
|
||||
"Spamfilter '$spamfilter_string' has unknown targets '$spamfilter_targets'",
|
||||
log_data_string("spamfilter_string", match_string),
|
||||
log_data_string("spamfilter_targets", parv[3]));
|
||||
return;
|
||||
@ -4322,7 +4280,7 @@ CMD_FUNC(cmd_tkl_del)
|
||||
{
|
||||
unreal_log(ULOG_WARNING, "tkl", "TKL_DEL_INVALID", client,
|
||||
"Invalid TKL deletion request from $client: "
|
||||
"Spamfilter '$spamfilter_string' has unkown action '$spamfilter_action'",
|
||||
"Spamfilter '$spamfilter_string' has unknown action '$spamfilter_action'",
|
||||
log_data_string("spamfilter_string", match_string),
|
||||
log_data_string("spamfilter_action", parv[4]));
|
||||
return;
|
||||
@ -5147,6 +5105,102 @@ int _match_user(const char *rmask, Client *client, int options)
|
||||
return 0; /* NOMATCH: nothing of the above matched */
|
||||
}
|
||||
|
||||
/** Returns 1 if the user is allowed by any of the security groups in the named list.
|
||||
* This is only used by security-group::security-group and
|
||||
* security-group::exclude-security-group.
|
||||
* @param client Client to check
|
||||
* @param l The NameList
|
||||
* @returns 1 if any of the security groups match, 0 if none of them matched.
|
||||
*/
|
||||
int _unreal_match_iplist(Client *client, NameList *l)
|
||||
{
|
||||
char client_ipv6 = 0;
|
||||
char clientip[IPSZ], maskip[IPSZ];
|
||||
|
||||
if (!client->ip)
|
||||
return 0; /* unusual, maybe services? */
|
||||
|
||||
if (strchr(client->ip, ':'))
|
||||
{
|
||||
client_ipv6 = 1;
|
||||
if (!inet_pton(AF_INET6, client->ip, clientip))
|
||||
return 0; /* unusual failure */
|
||||
} else {
|
||||
if (!inet_pton(AF_INET, client->ip, clientip))
|
||||
return 0; /* unusual failure */
|
||||
}
|
||||
|
||||
for (; l; l = l->next)
|
||||
{
|
||||
char mask[512], *p;
|
||||
int cidr = -1; /* CIDR length, -1 for no CIDR */
|
||||
|
||||
strlcpy(mask, l->name, sizeof(mask));
|
||||
p = strchr(mask, '/');
|
||||
if (p)
|
||||
{
|
||||
*p++ = '\0';
|
||||
cidr = atoi(p);
|
||||
if (cidr <= 0)
|
||||
return 0; /* NOMATCH: invalid CIDR */
|
||||
}
|
||||
|
||||
/* Three possible types: wildcard, ipv6, ipv4 */
|
||||
|
||||
if (strchr(mask, '*') || strchr(mask, '?'))
|
||||
{
|
||||
/* Wildcards */
|
||||
if (match_simple(mask, client->ip))
|
||||
return 1; /* MATCH by wildcard IP */
|
||||
}
|
||||
else if (strchr(mask, ':'))
|
||||
{
|
||||
/* IPv6 */
|
||||
if (!client_ipv6)
|
||||
continue; /* NOMATCH: client is IPv4 */
|
||||
if (!inet_pton(AF_INET6, mask, maskip))
|
||||
continue; /* NOMATCH: invalid IPv6 IP in mask */
|
||||
if (cidr < 0)
|
||||
{
|
||||
/* Try to match by exact IP */
|
||||
if (comp_with_mask(clientip, maskip, 128))
|
||||
return 1; /* MATCH by exact IP */
|
||||
} else
|
||||
if (cidr > 128)
|
||||
{
|
||||
continue; /* NOMATCH: invalid CIDR */
|
||||
} else
|
||||
if (comp_with_mask(clientip, maskip, cidr))
|
||||
{
|
||||
return 1; /* MATCH by CIDR */
|
||||
}
|
||||
} else
|
||||
{
|
||||
/* IPv4 */
|
||||
if (client_ipv6)
|
||||
continue; /* NOMATCH: client is IPv6 */
|
||||
if (!inet_pton(AF_INET, mask, maskip))
|
||||
continue; /* NOMATCH: invalid IPv6 IP in mask */
|
||||
if (cidr < 0)
|
||||
{
|
||||
/* Try to match by exact IP */
|
||||
if (comp_with_mask(clientip, maskip, 32))
|
||||
return 1; /* MATCH: by exact IP */
|
||||
} else
|
||||
if (cidr > 32)
|
||||
{
|
||||
continue; /* NOMATCH: invalid CIDR */
|
||||
} else
|
||||
if (comp_with_mask(clientip, maskip, cidr))
|
||||
{
|
||||
return 1; /* MATCH by CIDR */
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int _match_user_extended_server_ban(const char *banstr, Client *client)
|
||||
{
|
||||
const char *nextbanstr;
|
||||
|
@ -625,6 +625,7 @@ int read_tkldb(void)
|
||||
{
|
||||
tkl_add_banexception(tkl->type, tkl->ptr.banexception->usermask,
|
||||
tkl->ptr.banexception->hostmask,
|
||||
NULL,
|
||||
tkl->ptr.banexception->reason,
|
||||
tkl->set_by, tkl->expire_at,
|
||||
tkl->set_at, softban,
|
||||
|
@ -5,7 +5,7 @@
|
||||
*
|
||||
* (C) Copyright 2015- Bram Matthys and the UnrealIRCd team.
|
||||
*
|
||||
* License: GPLv2
|
||||
* License: GPLv2 or later
|
||||
*/
|
||||
|
||||
#include "unrealircd.h"
|
||||
|
@ -1,7 +1,7 @@
|
||||
/*
|
||||
* Store TLS cipher in ModData
|
||||
* (C) Copyright 2021-.. Syzop and The UnrealIRCd Team
|
||||
* License: GPLv2
|
||||
* License: GPLv2 or later
|
||||
*/
|
||||
|
||||
#include "unrealircd.h"
|
||||
@ -22,6 +22,7 @@ void tls_cipher_unserialize(const char *str, ModData *m);
|
||||
int tls_cipher_handshake(Client *client);
|
||||
int tls_cipher_connect(Client *client);
|
||||
int tls_cipher_whois(Client *client, Client *target);
|
||||
int log_tls_cipher(Client *client, int detail, json_t *j);
|
||||
|
||||
ModDataInfo *tls_cipher_md; /* Module Data structure which we acquire */
|
||||
|
||||
@ -45,6 +46,8 @@ ModDataInfo mreq;
|
||||
HookAdd(modinfo->handle, HOOKTYPE_HANDSHAKE, 0, tls_cipher_handshake);
|
||||
HookAdd(modinfo->handle, HOOKTYPE_SERVER_HANDSHAKE_OUT, 0, tls_cipher_handshake);
|
||||
|
||||
HookAdd(modinfo->handle, HOOKTYPE_JSON_EXPAND_CLIENT, 0, log_tls_cipher);
|
||||
|
||||
return MOD_SUCCESS;
|
||||
}
|
||||
|
||||
@ -89,3 +92,24 @@ void tls_cipher_unserialize(const char *str, ModData *m)
|
||||
{
|
||||
safe_strdup(m->str, str);
|
||||
}
|
||||
|
||||
int log_tls_cipher(Client *client, int detail, json_t *j)
|
||||
{
|
||||
json_t *tls;
|
||||
const char *str;
|
||||
|
||||
str = moddata_client_get(client, "tls_cipher");
|
||||
if (!str)
|
||||
return 0;
|
||||
|
||||
tls = json_object_get(j, "tls");
|
||||
if (!tls)
|
||||
{
|
||||
tls = json_object();
|
||||
json_object_set_new(j, "tls", tls);
|
||||
}
|
||||
|
||||
json_object_set_new(tls, "cipher", json_string_unreal(str));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -1,7 +1,7 @@
|
||||
/*
|
||||
* unreal_server_compat - Compatibility with pre-U6 servers
|
||||
* (C) Copyright 2016-2021 Bram Matthys (Syzop)
|
||||
* License: GPLv2
|
||||
* License: GPLv2 or later
|
||||
*
|
||||
* Currently the only purpose of this module is to rewrite MODE
|
||||
* and SJOIN lines to older servers so any bans/exempts/invex
|
||||
|
@ -89,7 +89,7 @@ CMD_FUNC(cmd_vhost)
|
||||
return;
|
||||
}
|
||||
|
||||
if (!unreal_mask_match(client, vhost->mask))
|
||||
if (!user_allowed_by_security_group(client, vhost->match))
|
||||
{
|
||||
unreal_log(ULOG_WARNING, "vhost", "VHOST_FAILED", client,
|
||||
"Failed VHOST attempt by $client.details [reason: $reason] [vhost-block: $vhost_block]",
|
||||
@ -157,7 +157,6 @@ CMD_FUNC(cmd_vhost)
|
||||
for (s = vhost->swhois; s; s = s->next)
|
||||
swhois_add(client, "vhost", -100, s->line, &me, NULL);
|
||||
}
|
||||
sendnumeric(client, RPL_HOSTHIDDEN, vhost->virthost);
|
||||
sendnotice(client, "*** Your vhost is now %s%s%s",
|
||||
vhost->virtuser ? vhost->virtuser : "",
|
||||
vhost->virtuser ? "@" : "",
|
||||
|
@ -85,7 +85,7 @@ MOD_INIT()
|
||||
}
|
||||
LoadPersistentPointer(modinfo, watchTable, watch_generic_free);
|
||||
if (watchTable == NULL)
|
||||
watchTable = safe_alloc(sizeof(Watch) * WATCH_HASH_TABLE_SIZE);
|
||||
watchTable = safe_alloc(sizeof(Watch *) * WATCH_HASH_TABLE_SIZE);
|
||||
|
||||
memset(&mreq, 0 , sizeof(mreq));
|
||||
mreq.type = MODDATATYPE_LOCAL_CLIENT;
|
||||
|
@ -119,8 +119,6 @@ static void show_watch_removed(Client *client, char *name)
|
||||
}
|
||||
}
|
||||
|
||||
static char buf[BUFSIZE];
|
||||
|
||||
#define WATCHES(client) (moddata_local_client(client, watchCounterMD).i)
|
||||
#define WATCH(client) (moddata_local_client(client, watchListMD).ptr)
|
||||
|
||||
@ -130,6 +128,7 @@ static char buf[BUFSIZE];
|
||||
CMD_FUNC(cmd_watch)
|
||||
{
|
||||
char request[BUFSIZE];
|
||||
char buf[BUFSIZE];
|
||||
Client *target;
|
||||
char *s, *user;
|
||||
char *p = NULL, *def = "l";
|
||||
|
@ -1,7 +1,7 @@
|
||||
/*
|
||||
* websocket - WebSocket support (RFC6455)
|
||||
* (C)Copyright 2016 Bram Matthys and the UnrealIRCd team
|
||||
* License: GPLv2
|
||||
* License: GPLv2 or later
|
||||
* This module was sponsored by Aberrant Software Inc.
|
||||
*/
|
||||
|
||||
|
@ -52,7 +52,6 @@ struct WhoisConfig {
|
||||
};
|
||||
|
||||
/* Global variables */
|
||||
static char buf[BUFSIZE];
|
||||
WhoisConfig *whoisconfig = NULL;
|
||||
|
||||
/* Forward declarations */
|
||||
@ -147,6 +146,8 @@ static void whois_config_setdefaults(void)
|
||||
|
||||
whois_config_add("reputation", WHOIS_CONFIG_USER_OPER, WHOIS_CONFIG_DETAILS_FULL);
|
||||
|
||||
whois_config_add("security-groups", WHOIS_CONFIG_USER_OPER, WHOIS_CONFIG_DETAILS_FULL);
|
||||
|
||||
whois_config_add("geo", WHOIS_CONFIG_USER_OPER, WHOIS_CONFIG_DETAILS_FULL);
|
||||
|
||||
whois_config_add("certfp", WHOIS_CONFIG_USER_EVERYONE, WHOIS_CONFIG_DETAILS_FULL);
|
||||
@ -294,6 +295,7 @@ CMD_FUNC(cmd_whois)
|
||||
char *p = NULL;
|
||||
int len, mlen;
|
||||
char querybuf[BUFSIZE];
|
||||
char buf[BUFSIZE];
|
||||
int ntargets = 0;
|
||||
int maxtargets = max_targets_for_command("WHOIS");
|
||||
|
||||
@ -561,6 +563,51 @@ CMD_FUNC(cmd_whois)
|
||||
}
|
||||
}
|
||||
|
||||
/* The following code deals with security-groups */
|
||||
policy = whois_get_policy(client, target, "security-groups");
|
||||
if ((policy > WHOIS_CONFIG_DETAILS_NONE) && !IsULine(target))
|
||||
{
|
||||
SecurityGroup *s;
|
||||
int security_groups_whois_lines = 0;
|
||||
|
||||
mlen = strlen(me.name) + strlen(client->name) + 10 + strlen(target->name) + strlen("is in security-groups: ");
|
||||
|
||||
if (user_allowed_by_security_group_name(target, "known-users"))
|
||||
strlcpy(buf, "known-users,", sizeof(buf));
|
||||
else
|
||||
strlcpy(buf, "unknown-users,", sizeof(buf));
|
||||
len = strlen(buf);
|
||||
|
||||
for (s = securitygroups; s; s = s->next)
|
||||
{
|
||||
if (len + strlen(s->name) > (size_t)BUFSIZE - 4 - mlen)
|
||||
{
|
||||
buf[len-1] = '\0';
|
||||
add_nvplist_numeric_fmt(&list, -15000-security_groups_whois_lines, "security-groups",
|
||||
target, RPL_WHOISSPECIAL,
|
||||
"%s :is in security-groups: %s", target->name, buf);
|
||||
security_groups_whois_lines++;
|
||||
*buf = '\0';
|
||||
len = 0;
|
||||
}
|
||||
if (strcmp(s->name, "known-users") && user_allowed_by_security_group(target, s))
|
||||
{
|
||||
strcpy(buf + len, s->name);
|
||||
len += strlen(buf+len);
|
||||
strcpy(buf + len, ",");
|
||||
len++;
|
||||
}
|
||||
}
|
||||
|
||||
if (*buf)
|
||||
{
|
||||
buf[len-1] = '\0';
|
||||
add_nvplist_numeric_fmt(&list, -15000-security_groups_whois_lines, "security-groups",
|
||||
client, RPL_WHOISSPECIAL,
|
||||
"%s :is in security-groups: %s", target->name, buf);
|
||||
security_groups_whois_lines++;
|
||||
}
|
||||
}
|
||||
if (MyUser(target) && IsShunned(target) && (whois_get_policy(client, target, "shunned") > WHOIS_CONFIG_DETAILS_NONE))
|
||||
{
|
||||
add_nvplist_numeric(&list, -20000, "shunned", client, RPL_WHOISSPECIAL,
|
||||
|
@ -3,7 +3,7 @@
|
||||
* was originally made for tircd and modified to work with u4.
|
||||
* - 2018 i <ircd@servx.org>
|
||||
* - 2019 Bram Matthys (Syzop) <syzop@vulnscan.org>
|
||||
* License: GPLv2
|
||||
* License: GPLv2 or later
|
||||
*/
|
||||
|
||||
#include "unrealircd.h"
|
||||
|
@ -1,6 +1,6 @@
|
||||
/** Oper classes code.
|
||||
* (C) Copyright 2015-present tmcarthur and the UnrealIRCd team
|
||||
* License: GPLv2
|
||||
* License: GPLv2 or later
|
||||
*/
|
||||
|
||||
#include "unrealircd.h"
|
||||
@ -282,6 +282,7 @@ OperPermission ValidatePermissionsForPathEx(OperClassACL *acl, OperClassACLPath
|
||||
OperPermission ValidatePermissionsForPath(const char *path, Client *client, Client *victim, Channel *channel, const void *extra)
|
||||
{
|
||||
ConfigItem_oper *ce_oper;
|
||||
const char *operclass;
|
||||
ConfigItem_operclass *ce_operClass;
|
||||
OperClass *oc = NULL;
|
||||
OperClassACLPath *operPath;
|
||||
@ -299,14 +300,17 @@ OperPermission ValidatePermissionsForPath(const char *path, Client *client, Clie
|
||||
ce_oper = find_oper(client->user->operlogin);
|
||||
if (!ce_oper)
|
||||
{
|
||||
operclass = moddata_client_get(client, "operclass");
|
||||
if (!operclass)
|
||||
return OPER_DENY;
|
||||
} else
|
||||
{
|
||||
operclass = ce_oper->operclass;
|
||||
}
|
||||
|
||||
ce_operClass = find_operclass(ce_oper->operclass);
|
||||
ce_operClass = find_operclass(operclass);
|
||||
if (!ce_operClass)
|
||||
{
|
||||
return OPER_DENY;
|
||||
}
|
||||
|
||||
oc = ce_operClass->classStruct;
|
||||
operPath = OperClass_parsePath(path);
|
||||
|
840
src/securitygroup.c
Normal file
840
src/securitygroup.c
Normal file
@ -0,0 +1,840 @@
|
||||
/*
|
||||
* Mask & security-group routines.
|
||||
* (C) Copyright 2015-.. 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 2
|
||||
* of the License, 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.
|
||||
*/
|
||||
|
||||
#include "unrealircd.h"
|
||||
|
||||
/* Global variables */
|
||||
SecurityGroup *securitygroups = NULL;
|
||||
|
||||
/** Free all masks in the mask list */
|
||||
void unreal_delete_masks(ConfigItem_mask *m)
|
||||
{
|
||||
ConfigItem_mask *m_next;
|
||||
|
||||
for (; m; m = m_next)
|
||||
{
|
||||
m_next = m->next;
|
||||
|
||||
safe_free(m->mask);
|
||||
|
||||
safe_free(m);
|
||||
}
|
||||
}
|
||||
|
||||
/** Internal function to add one individual mask to the list */
|
||||
static void unreal_add_mask(ConfigItem_mask **head, ConfigEntry *ce)
|
||||
{
|
||||
ConfigItem_mask *m = safe_alloc(sizeof(ConfigItem_mask));
|
||||
|
||||
/* Since we allow both mask "xyz"; and mask { abc; def; };... */
|
||||
if (ce->value)
|
||||
safe_strdup(m->mask, ce->value);
|
||||
else
|
||||
safe_strdup(m->mask, ce->name);
|
||||
|
||||
add_ListItem((ListStruct *)m, (ListStruct **)head);
|
||||
}
|
||||
|
||||
/** Add mask entries from config */
|
||||
void unreal_add_masks(ConfigItem_mask **head, ConfigEntry *ce)
|
||||
{
|
||||
if (ce->items)
|
||||
{
|
||||
ConfigEntry *cep;
|
||||
for (cep = ce->items; cep; cep = cep->next)
|
||||
unreal_add_mask(head, cep);
|
||||
} else
|
||||
{
|
||||
unreal_add_mask(head, ce);
|
||||
}
|
||||
}
|
||||
|
||||
/** Check if a client matches any of the masks in the mask list.
|
||||
* The following rules apply:
|
||||
* - If you have only negating entries, like '!abc' and '!def', then
|
||||
* we assume an implicit * rule first, since that is clearly what
|
||||
* the user wants.
|
||||
* - If you have a mix, like '*.com', '!irc1*', '!irc2*' then the
|
||||
* implicit * is dropped and we assume you only want to match *.com,
|
||||
* with the exception of irc1*.com and irc2*.com.
|
||||
* - If you only have normal entries without ! then things are
|
||||
* as they always are.
|
||||
* @param client The client to run the mask match against
|
||||
* @param mask The mask entry from the config file
|
||||
* @returns 1 on match, 0 on non-match.
|
||||
*/
|
||||
int unreal_mask_match(Client *client, ConfigItem_mask *mask)
|
||||
{
|
||||
int retval = 1;
|
||||
ConfigItem_mask *m;
|
||||
|
||||
if (!mask)
|
||||
return 0; /* Empty mask block is no match */
|
||||
|
||||
/* First check normal matches (without ! prefix) */
|
||||
for (m = mask; m; m = m->next)
|
||||
{
|
||||
if (m->mask[0] != '!')
|
||||
{
|
||||
retval = 0; /* no implicit * */
|
||||
if (match_user(m->mask, client, MATCH_CHECK_REAL|MATCH_CHECK_EXTENDED))
|
||||
{
|
||||
retval = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (retval)
|
||||
{
|
||||
/* We matched. Check for exceptions (with ! prefix) */
|
||||
for (m = mask; m; m = m->next)
|
||||
{
|
||||
if ((m->mask[0] == '!') && match_user(m->mask+1, client, MATCH_CHECK_REAL|MATCH_CHECK_EXTENDED))
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
/** Check if a string matches any of the masks in the mask list.
|
||||
* The following rules apply:
|
||||
* - If you have only negating entries, like '!abc' and '!def', then
|
||||
* we assume an implicit * rule first, since that is clearly what
|
||||
* the user wants.
|
||||
* - If you have a mix, like '*.com', '!irc1*', '!irc2*' then the
|
||||
* implicit * is dropped and we assume you only want to match *.com,
|
||||
* with the exception of irc1*.com and irc2*.com.
|
||||
* - If you only have normal entries without ! then things are
|
||||
* as they always are.
|
||||
* @param name The name to run the mask matching on
|
||||
* @param mask The mask entry from the config file
|
||||
* @returns 1 on match, 0 on non-match.
|
||||
*/
|
||||
int unreal_mask_match_string(const char *name, ConfigItem_mask *mask)
|
||||
{
|
||||
int retval = 1;
|
||||
ConfigItem_mask *m;
|
||||
|
||||
if (!mask)
|
||||
return 0; /* Empty mask block is no match */
|
||||
|
||||
/* First check normal matches (without ! prefix) */
|
||||
for (m = mask; m; m = m->next)
|
||||
{
|
||||
if (m->mask[0] != '!')
|
||||
{
|
||||
retval = 0; /* no implicit * */
|
||||
if (match_simple(m->mask, name))
|
||||
{
|
||||
retval = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (retval)
|
||||
{
|
||||
/* We matched. Check for exceptions (with ! prefix) */
|
||||
for (m = mask; m; m = m->next)
|
||||
{
|
||||
if ((m->mask[0] == '!') && match_simple(m->mask+1, name))
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
#define CheckNullX(x) if ((!(x)->value) || (!(*((x)->value)))) { config_error("%s:%i: missing parameter", (x)->file->filename, (x)->line_number); *errors = *errors + 1; return 0; }
|
||||
int test_match_item(ConfigFile *conf, ConfigEntry *cep, int *errors)
|
||||
{
|
||||
ConfigEntry *cepp;
|
||||
|
||||
if (!strcmp(cep->name, "webirc") || !strcmp(cep->name, "exclude-webirc"))
|
||||
{
|
||||
CheckNullX(cep);
|
||||
} else
|
||||
if (!strcmp(cep->name, "identified") || !strcmp(cep->name, "exclude-identified"))
|
||||
{
|
||||
CheckNullX(cep);
|
||||
} else
|
||||
if (!strcmp(cep->name, "tls") || !strcmp(cep->name, "exclude-tls"))
|
||||
{
|
||||
CheckNullX(cep);
|
||||
} else
|
||||
if (!strcmp(cep->name, "reputation-score") || !strcmp(cep->name, "exclude-reputation-score"))
|
||||
{
|
||||
const char *str = cep->value;
|
||||
int v;
|
||||
CheckNullX(cep);
|
||||
if (*str == '<')
|
||||
str++;
|
||||
v = atoi(str);
|
||||
if ((v < 1) || (v > 10000))
|
||||
{
|
||||
config_error("%s:%i: %s needs to be a value of 1-10000",
|
||||
cep->file->filename, cep->line_number, cep->name);
|
||||
*errors = *errors + 1;
|
||||
}
|
||||
} else
|
||||
if (!strcmp(cep->name, "connect-time") || !strcmp(cep->name, "exclude-connect-time"))
|
||||
{
|
||||
const char *str = cep->value;
|
||||
long v;
|
||||
CheckNullX(cep);
|
||||
if (*str == '<')
|
||||
str++;
|
||||
v = config_checkval(str, CFG_TIME);
|
||||
if (v < 1)
|
||||
{
|
||||
config_error("%s:%i: %s needs to be a time value (and more than 0 seconds)",
|
||||
cep->file->filename, cep->line_number, cep->name);
|
||||
*errors = *errors + 1;
|
||||
}
|
||||
} else
|
||||
if (!strcmp(cep->name, "mask") || !strcmp(cep->name, "include-mask") || !strcmp(cep->name, "exclude-mask"))
|
||||
{
|
||||
for (cepp = cep->items; cepp; cepp = cepp->next)
|
||||
{
|
||||
if (!strcmp(cepp->name, "mask"))
|
||||
continue;
|
||||
if (cepp->items || cepp->value)
|
||||
{
|
||||
config_error("%s:%i: security-group::mask should contain hostmasks only. "
|
||||
"Perhaps you meant to use it in security-group { %s ... } directly?",
|
||||
cepp->file->filename, cepp->line_number,
|
||||
cepp->name);
|
||||
*errors = *errors + 1;
|
||||
}
|
||||
}
|
||||
} else
|
||||
if (!strcmp(cep->name, "ip"))
|
||||
{
|
||||
} else
|
||||
if (!strcmp(cep->name, "security-group") || !strcmp(cep->name, "exclude-security-group"))
|
||||
{
|
||||
} else
|
||||
{
|
||||
/* Let's see if an extended server ban exists for this item... */
|
||||
Extban *extban;
|
||||
if (!strncmp(cep->name, "exclude-", 8))
|
||||
extban = findmod_by_bantype_raw(cep->name+8, strlen(cep->name+8));
|
||||
else
|
||||
extban = findmod_by_bantype_raw(cep->name, strlen(cep->name));
|
||||
if (extban && (extban->options & EXTBOPT_TKL) && (extban->is_banned_events & BANCHK_TKL))
|
||||
{
|
||||
test_extended_list(extban, cep, errors);
|
||||
return 1; /* Yup, handled */
|
||||
}
|
||||
return 0; /* Unhandled: unknown item for us */
|
||||
}
|
||||
return 1; /* Handled, but there could be errors */
|
||||
}
|
||||
|
||||
int test_match_block(ConfigFile *conf, ConfigEntry *ce, int *errors_out)
|
||||
{
|
||||
int errors = 0;
|
||||
ConfigEntry *cep;
|
||||
|
||||
/* (If there is only a ce->value, trust that it is OK) */
|
||||
|
||||
/* Test ce->items... */
|
||||
for (cep = ce->items; cep; cep = cep->next)
|
||||
{
|
||||
/* Only complain about things with values,
|
||||
* as valueless things like "10.0.0.0/8" are treated as a mask.
|
||||
*/
|
||||
if (!test_match_item(conf, cep, &errors) && cep->value)
|
||||
{
|
||||
config_error_unknown(cep->file->filename, cep->line_number,
|
||||
ce->name, cep->name);
|
||||
errors++;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
*errors_out = *errors_out + errors;
|
||||
return errors ? 0 : 1;
|
||||
}
|
||||
|
||||
#define tmbbw_is_wildcard(x) (!strcmp(x, "*") || !strcmp(x, "*@*"))
|
||||
int test_match_block_too_broad(ConfigFile *conf, ConfigEntry *ce)
|
||||
{
|
||||
ConfigEntry *cep, *cepp;
|
||||
|
||||
// match *;
|
||||
if (ce->value && tmbbw_is_wildcard(ce->value))
|
||||
return 1;
|
||||
|
||||
for (cep = ce->items; cep; cep = cep->next)
|
||||
{
|
||||
// match { *; }
|
||||
if (!cep->value && tmbbw_is_wildcard(cep->name))
|
||||
return 1;
|
||||
if (!strcmp(cep->name, "mask") || !strcmp(cep->name, "include-mask") || !strcmp(cep->name, "ip"))
|
||||
{
|
||||
// match { mask *; }
|
||||
if (cep->value && tmbbw_is_wildcard(cep->value))
|
||||
return 1;
|
||||
// match { mask { *; } }
|
||||
for (cepp = cep->items; cepp; cepp = cepp->next)
|
||||
if (tmbbw_is_wildcard(cepp->name))
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int _test_security_group(ConfigFile *conf, ConfigEntry *ce)
|
||||
{
|
||||
int errors = 0;
|
||||
ConfigEntry *cep;
|
||||
|
||||
/* First, check the name of the security group */
|
||||
if (!ce->value)
|
||||
{
|
||||
config_error("%s:%i: security-group block needs a name, eg: security-group web-users {",
|
||||
ce->file->filename, ce->line_number);
|
||||
errors++;
|
||||
} else {
|
||||
if (!strcasecmp(ce->value, "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->file->filename, ce->line_number);
|
||||
errors++;
|
||||
return errors;
|
||||
}
|
||||
if (!security_group_valid_name(ce->value))
|
||||
{
|
||||
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->file->filename, ce->line_number, ce->value);
|
||||
errors++;
|
||||
}
|
||||
}
|
||||
|
||||
for (cep = ce->items; cep; cep = cep->next)
|
||||
{
|
||||
if (!test_match_item(conf, cep, &errors))
|
||||
{
|
||||
config_error_unknown(cep->file->filename, cep->line_number,
|
||||
"security-group", cep->name);
|
||||
errors++;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
return errors;
|
||||
}
|
||||
|
||||
int conf_match_item(ConfigFile *conf, ConfigEntry *cep, SecurityGroup **block)
|
||||
{
|
||||
int errors = 0; /* unused */
|
||||
SecurityGroup *s = *block;
|
||||
|
||||
/* The following code is there so we don't create a security group
|
||||
* unless there is actually a valid config item for it encountered.
|
||||
* This so the security group '*s' can stay NULL if there are zero
|
||||
* items, so we don't waste any CPU if it is unused.
|
||||
*/
|
||||
if (*block == NULL)
|
||||
{
|
||||
/* Yeah we call a TEST routine from a CONFIG RUN routine ;). */
|
||||
if (!test_match_item(conf, cep, &errors))
|
||||
return 0; /* not for us */
|
||||
/* If we are still here then we must create the security group */
|
||||
*block = s = safe_alloc(sizeof(SecurityGroup));
|
||||
}
|
||||
|
||||
if (!strcmp(cep->name, "webirc"))
|
||||
s->webirc = config_checkval(cep->value, CFG_YESNO);
|
||||
else if (!strcmp(cep->name, "identified"))
|
||||
s->identified = config_checkval(cep->value, CFG_YESNO);
|
||||
else if (!strcmp(cep->name, "tls"))
|
||||
s->tls = config_checkval(cep->value, CFG_YESNO);
|
||||
else if (!strcmp(cep->name, "reputation-score"))
|
||||
{
|
||||
if (*cep->value == '<')
|
||||
s->reputation_score = 0 - atoi(cep->value+1);
|
||||
else
|
||||
s->reputation_score = atoi(cep->value);
|
||||
}
|
||||
else if (!strcmp(cep->name, "connect-time"))
|
||||
{
|
||||
if (*cep->value == '<')
|
||||
s->connect_time = 0 - config_checkval(cep->value+1, CFG_TIME);
|
||||
else
|
||||
s->connect_time = config_checkval(cep->value, CFG_TIME);
|
||||
}
|
||||
else if (!strcmp(cep->name, "mask") || !strcmp(cep->name, "include-mask"))
|
||||
{
|
||||
unreal_add_masks(&s->mask, cep);
|
||||
}
|
||||
else if (!strcmp(cep->name, "ip"))
|
||||
{
|
||||
unreal_add_names(&s->ip, cep);
|
||||
}
|
||||
else if (!strcmp(cep->name, "security-group"))
|
||||
{
|
||||
unreal_add_names(&s->security_group, cep);
|
||||
}
|
||||
else if (!strcmp(cep->name, "exclude-webirc"))
|
||||
s->exclude_webirc = config_checkval(cep->value, CFG_YESNO);
|
||||
else if (!strcmp(cep->name, "exclude-identified"))
|
||||
s->exclude_identified = config_checkval(cep->value, CFG_YESNO);
|
||||
else if (!strcmp(cep->name, "exclude-tls"))
|
||||
s->exclude_tls = config_checkval(cep->value, CFG_YESNO);
|
||||
else if (!strcmp(cep->name, "exclude-reputation-score"))
|
||||
{
|
||||
if (*cep->value == '<')
|
||||
s->exclude_reputation_score = 0 - atoi(cep->value+1);
|
||||
else
|
||||
s->exclude_reputation_score = atoi(cep->value);
|
||||
}
|
||||
else if (!strcmp(cep->name, "exclude-mask"))
|
||||
{
|
||||
unreal_add_masks(&s->exclude_mask, cep);
|
||||
}
|
||||
else if (!strcmp(cep->name, "exclude-security-group"))
|
||||
{
|
||||
unreal_add_names(&s->security_group, cep);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Let's see if an extended server ban exists for this item... this needs to be LAST! */
|
||||
Extban *extban;
|
||||
const char *name = cep->name;
|
||||
|
||||
if (!strncmp(cep->name, "exclude-", 8))
|
||||
{
|
||||
/* Extended (exclusive) ? */
|
||||
name = cep->name + 8;
|
||||
if (findmod_by_bantype_raw(name, strlen(name)))
|
||||
unreal_add_name_values(&s->exclude_extended, name, cep);
|
||||
else
|
||||
return 0; /* Unhandled */
|
||||
} else {
|
||||
/* Extended (inclusive) */
|
||||
if (findmod_by_bantype_raw(name, strlen(name)))
|
||||
unreal_add_name_values(&s->extended, name, cep);
|
||||
else
|
||||
return 0; /* Unhandled */
|
||||
}
|
||||
}
|
||||
|
||||
add_nvplist(&s->printable_list, s->printable_list_counter++, cep->name, cep->value);
|
||||
|
||||
return 1; /* Handled by us (guaranteed earlier) */
|
||||
}
|
||||
|
||||
int conf_match_block(ConfigFile *conf, ConfigEntry *ce, SecurityGroup **block)
|
||||
{
|
||||
ConfigEntry *cep;
|
||||
SecurityGroup *s = *block;
|
||||
|
||||
if (*block == NULL)
|
||||
*block = s = safe_alloc(sizeof(SecurityGroup));
|
||||
|
||||
/* Check for simple form: match *; / mask *; */
|
||||
if (ce->value)
|
||||
{
|
||||
unreal_add_masks(&s->mask, ce);
|
||||
add_nvplist(&s->printable_list, s->printable_list_counter++, "mask", ce->value);
|
||||
}
|
||||
|
||||
/* Check for long form: match { .... } / mask { .... } */
|
||||
for (cep = ce->items; cep; cep = cep->next)
|
||||
{
|
||||
if (!conf_match_item(conf, cep, &s) && !cep->value && !cep->items)
|
||||
{
|
||||
/* Valueless? Then it must be a mask like 10.0.0.0/8 */
|
||||
unreal_add_masks(&s->mask, cep);
|
||||
add_nvplist(&s->printable_list, s->printable_list_counter++, "mask", cep->name);
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
int _conf_security_group(ConfigFile *conf, ConfigEntry *ce)
|
||||
{
|
||||
ConfigEntry *cep;
|
||||
SecurityGroup *s = add_security_group(ce->value, 1);
|
||||
|
||||
for (cep = ce->items; cep; cep = cep->next)
|
||||
{
|
||||
if (!strcmp(cep->name, "priority"))
|
||||
{
|
||||
s->priority = atoi(cep->value);
|
||||
DelListItem(s, securitygroups);
|
||||
AddListItemPrio(s, securitygroups, s->priority);
|
||||
} else
|
||||
conf_match_item(conf, cep, &s);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
/** 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(const char *name)
|
||||
{
|
||||
const 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(const 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(const 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(const 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)
|
||||
{
|
||||
if (s == NULL)
|
||||
return;
|
||||
unreal_delete_masks(s->mask);
|
||||
unreal_delete_masks(s->exclude_mask);
|
||||
free_entire_name_list(s->security_group);
|
||||
free_entire_name_list(s->exclude_security_group);
|
||||
free_entire_name_list(s->ip);
|
||||
free_entire_name_list(s->exclude_ip);
|
||||
free_nvplist(s->extended);
|
||||
free_nvplist(s->exclude_extended);
|
||||
free_nvplist(s->printable_list);
|
||||
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: webirc */
|
||||
s = add_security_group("webirc-users", 50);
|
||||
s->webirc = 1;
|
||||
|
||||
/* 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;
|
||||
}
|
||||
|
||||
int user_matches_extended_list(Client *client, NameValuePrioList *e)
|
||||
{
|
||||
Extban *extban;
|
||||
BanContext b;
|
||||
|
||||
for (; e; e = e->next)
|
||||
{
|
||||
extban = findmod_by_bantype_raw(e->name, strlen(e->name));
|
||||
if (!extban ||
|
||||
!(extban->options & EXTBOPT_TKL) ||
|
||||
!(extban->is_banned_events & BANCHK_TKL))
|
||||
{
|
||||
continue; /* extban not found or of incorrect type */
|
||||
}
|
||||
|
||||
memset(&b, 0, sizeof(BanContext));
|
||||
b.client = client;
|
||||
b.banstr = e->value;
|
||||
b.ban_check_types = BANCHK_TKL;
|
||||
if (extban->is_banned(&b))
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int test_extended_list(Extban *extban, ConfigEntry *cep, int *errors)
|
||||
{
|
||||
BanContext b;
|
||||
|
||||
if (cep->value)
|
||||
{
|
||||
memset(&b, 0, sizeof(BanContext));
|
||||
b.banstr = cep->value;
|
||||
b.ban_check_types = BANCHK_TKL;
|
||||
b.what = MODE_ADD;
|
||||
if (!extban->conv_param(&b, extban))
|
||||
{
|
||||
config_error("%s:%i: %s has an invalid value",
|
||||
cep->file->filename, cep->line_number, cep->name);
|
||||
*errors = *errors + 1;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
for (cep = cep->items; cep; cep = cep->next)
|
||||
{
|
||||
memset(&b, 0, sizeof(BanContext));
|
||||
b.banstr = cep->name;
|
||||
b.ban_check_types = BANCHK_TKL;
|
||||
b.what = MODE_ADD;
|
||||
if (!extban->conv_param(&b, extban))
|
||||
{
|
||||
config_error("%s:%i: %s has an invalid value",
|
||||
cep->file->filename, cep->line_number, cep->name);
|
||||
*errors = *errors + 1;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/** Returns 1 if the user is allowed by any of the security groups in the named list.
|
||||
* This is only used by security-group::security-group and
|
||||
* security-group::exclude-security-group.
|
||||
* @param client Client to check
|
||||
* @param l The NameList
|
||||
* @returns 1 if any of the security groups match, 0 if none of them matched.
|
||||
*/
|
||||
int user_allowed_by_security_group_list(Client *client, NameList *l)
|
||||
{
|
||||
for (; l; l = l->next)
|
||||
if (user_allowed_by_security_group_name(client, l->name))
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/** 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)
|
||||
{
|
||||
static int recursion_security_group = 0;
|
||||
|
||||
/* Allow NULL securitygroup, makes it easier in the code elsewhere */
|
||||
if (!s)
|
||||
return 0;
|
||||
|
||||
if (recursion_security_group > 8)
|
||||
{
|
||||
unreal_log(ULOG_WARNING, "main", "SECURITY_GROUP_LOOP_DETECTED", client,
|
||||
"Loop detected while processing security-group '$security_group' -- "
|
||||
"are you perhaps referencing a security-group from a security-group?",
|
||||
log_data_string("security_group", s->name));
|
||||
return 0;
|
||||
}
|
||||
recursion_security_group++;
|
||||
|
||||
/* DO NOT USE 'return' IN CODE BELOW!!!!!!!!!
|
||||
* - use 'goto user_not_allowed' to reject
|
||||
* - use 'goto user_allowed' to accept
|
||||
*/
|
||||
|
||||
/* Process EXCLUSION criteria first... */
|
||||
if (s->exclude_identified && IsLoggedIn(client))
|
||||
goto user_not_allowed;
|
||||
if (s->exclude_webirc && moddata_client_get(client, "webirc"))
|
||||
goto user_not_allowed;
|
||||
if ((s->exclude_reputation_score > 0) && (GetReputation(client) >= s->exclude_reputation_score))
|
||||
goto user_not_allowed;
|
||||
if ((s->exclude_reputation_score < 0) && (GetReputation(client) < 0 - s->exclude_reputation_score))
|
||||
goto user_not_allowed;
|
||||
if (s->exclude_connect_time != 0)
|
||||
{
|
||||
long connect_time = get_connected_time(client);
|
||||
if ((s->exclude_connect_time > 0) && (connect_time >= s->exclude_connect_time))
|
||||
goto user_not_allowed;
|
||||
if ((s->exclude_connect_time < 0) && (connect_time < 0 - s->exclude_connect_time))
|
||||
goto user_not_allowed;
|
||||
}
|
||||
if (s->exclude_tls && (IsSecureConnect(client) || (MyConnect(client) && IsSecure(client))))
|
||||
goto user_not_allowed;
|
||||
if (s->exclude_mask && unreal_mask_match(client, s->exclude_mask))
|
||||
goto user_not_allowed;
|
||||
if (s->exclude_ip && unreal_match_iplist(client, s->exclude_ip))
|
||||
goto user_not_allowed;
|
||||
if (s->exclude_security_group && user_allowed_by_security_group_list(client, s->exclude_security_group))
|
||||
goto user_not_allowed;
|
||||
if (s->exclude_extended && user_matches_extended_list(client, s->exclude_extended))
|
||||
goto user_not_allowed;
|
||||
|
||||
/* Then process INCLUSION criteria... */
|
||||
if (s->identified && IsLoggedIn(client))
|
||||
goto user_allowed;
|
||||
if (s->webirc && moddata_client_get(client, "webirc"))
|
||||
goto user_allowed;
|
||||
if ((s->reputation_score > 0) && (GetReputation(client) >= s->reputation_score))
|
||||
goto user_allowed;
|
||||
if ((s->reputation_score < 0) && (GetReputation(client) < 0 - s->reputation_score))
|
||||
goto user_allowed;
|
||||
if (s->connect_time != 0)
|
||||
{
|
||||
long connect_time = get_connected_time(client);
|
||||
if ((s->connect_time > 0) && (connect_time >= s->connect_time))
|
||||
goto user_allowed;
|
||||
if ((s->connect_time < 0) && (connect_time < 0 - s->connect_time))
|
||||
goto user_allowed;
|
||||
}
|
||||
if (s->tls && (IsSecureConnect(client) || (MyConnect(client) && IsSecure(client))))
|
||||
goto user_allowed;
|
||||
if (s->mask && unreal_mask_match(client, s->mask))
|
||||
goto user_allowed;
|
||||
if (s->ip && unreal_match_iplist(client, s->ip))
|
||||
goto user_allowed;
|
||||
if (s->security_group && user_allowed_by_security_group_list(client, s->security_group))
|
||||
goto user_allowed;
|
||||
if (s->extended && user_matches_extended_list(client, s->extended))
|
||||
goto user_allowed;
|
||||
|
||||
user_not_allowed:
|
||||
recursion_security_group--;
|
||||
return 0;
|
||||
|
||||
user_allowed:
|
||||
recursion_security_group--;
|
||||
return 1;
|
||||
}
|
||||
|
||||
/** 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, const 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);
|
||||
}
|
||||
|
||||
/** Get comma separated list of matching security groups for 'client'.
|
||||
* This is usually only used for displaying purposes.
|
||||
* @returns string like "unknown-users,tls-users" from a static buffer.
|
||||
*/
|
||||
const char *get_security_groups(Client *client)
|
||||
{
|
||||
SecurityGroup *s;
|
||||
static char buf[512];
|
||||
|
||||
*buf = '\0';
|
||||
|
||||
/* We put known-users or unknown-users at the beginning.
|
||||
* The latter is special and doesn't actually exist
|
||||
* in the linked list, hence the special code here,
|
||||
* and again later in the for loop to skip it.
|
||||
*/
|
||||
if (user_allowed_by_security_group_name(client, "known-users"))
|
||||
strlcat(buf, "known-users,", sizeof(buf));
|
||||
else
|
||||
strlcat(buf, "unknown-users,", sizeof(buf));
|
||||
|
||||
for (s = securitygroups; s; s = s->next)
|
||||
{
|
||||
if (strcmp(s->name, "known-users") &&
|
||||
user_allowed_by_security_group(client, s))
|
||||
{
|
||||
strlcat(buf, s->name, sizeof(buf));
|
||||
strlcat(buf, ",", sizeof(buf));
|
||||
}
|
||||
}
|
||||
|
||||
if (*buf)
|
||||
buf[strlen(buf)-1] = '\0';
|
||||
return buf;
|
||||
}
|
@ -1208,7 +1208,9 @@ void lost_server_link(Client *client, const char *tls_error_string)
|
||||
if (client->server->conf)
|
||||
{
|
||||
unreal_log(ULOG_ERROR, "link", "LINK_ERROR_CONNECT", client,
|
||||
"Unable to link with server $client [$link_block.ip:$link_block.port]: $tls_error_string",
|
||||
client->server->conf->outgoing.file
|
||||
? "Unable to link with server $client [$link_block.file]: $tls_error_string"
|
||||
: "Unable to link with server $client [$link_block.ip:$link_block.port]: $tls_error_string",
|
||||
log_data_string("tls_error_string", tls_error_string),
|
||||
log_data_link_block(client->server->conf));
|
||||
} else {
|
||||
@ -1221,7 +1223,9 @@ void lost_server_link(Client *client, const char *tls_error_string)
|
||||
if (client->server->conf)
|
||||
{
|
||||
unreal_log(ULOG_ERROR, "link", "LINK_ERROR_CONNECT", client,
|
||||
"Unable to link with server $client [$link_block.ip:$link_block.port]: $socket_error",
|
||||
client->server->conf->outgoing.file
|
||||
? "Unable to link with server $client [$link_block.file]: $socket_error"
|
||||
: "Unable to link with server $client [$link_block.ip:$link_block.port]: $socket_error",
|
||||
log_data_socket_error(client->local->fd),
|
||||
log_data_link_block(client->server->conf));
|
||||
} else {
|
||||
|
15
src/socket.c
15
src/socket.c
@ -1300,11 +1300,11 @@ int deliver_it(Client *client, char *str, int len, int *want_read)
|
||||
}
|
||||
|
||||
/** Initiate an outgoing connection, the actual connect() call. */
|
||||
int unreal_connect(int fd, const char *ip, int port, int ipv6)
|
||||
int unreal_connect(int fd, const char *ip, int port, SocketType socket_type)
|
||||
{
|
||||
int n;
|
||||
|
||||
if (ipv6)
|
||||
if (socket_type == SOCKET_TYPE_IPV6)
|
||||
{
|
||||
struct sockaddr_in6 server;
|
||||
memset(&server, 0, sizeof(server));
|
||||
@ -1312,13 +1312,22 @@ int unreal_connect(int fd, const char *ip, int port, int ipv6)
|
||||
inet_pton(AF_INET6, ip, &server.sin6_addr);
|
||||
server.sin6_port = htons(port);
|
||||
n = connect(fd, (struct sockaddr *)&server, sizeof(server));
|
||||
} else {
|
||||
}
|
||||
else if (socket_type == SOCKET_TYPE_IPV4)
|
||||
{
|
||||
struct sockaddr_in server;
|
||||
memset(&server, 0, sizeof(server));
|
||||
server.sin_family = AF_INET;
|
||||
inet_pton(AF_INET, ip, &server.sin_addr);
|
||||
server.sin_port = htons(port);
|
||||
n = connect(fd, (struct sockaddr *)&server, sizeof(server));
|
||||
} else
|
||||
{
|
||||
struct sockaddr_un server;
|
||||
memset(&server, 0, sizeof(server));
|
||||
server.sun_family = AF_UNIX;
|
||||
strlcpy(server.sun_path, ip, sizeof(server.sun_path));
|
||||
n = connect(fd, (struct sockaddr *)&server, sizeof(server));
|
||||
}
|
||||
|
||||
#ifndef _WIN32
|
||||
|
@ -1269,7 +1269,7 @@ void buildvarstring(const char *inbuf, char *outbuf, size_t len, const char *nam
|
||||
/* find variable name in list */
|
||||
found = 0;
|
||||
for (cnt = 0; name[cnt]; cnt++)
|
||||
if (!strncasecmp(name[cnt], i, p - i))
|
||||
if (!strncasecmp(name[cnt], i, strlen(name[cnt])))
|
||||
{
|
||||
/* Found */
|
||||
found = 1;
|
||||
|
@ -354,7 +354,7 @@ SSL_CTX *init_ctx(TLSOptions *tlsoptions, int server)
|
||||
if (SSL_CTX_set_ciphersuites(ctx, tlsoptions->ciphersuites) == 0)
|
||||
{
|
||||
unreal_log(ULOG_ERROR, "config", "TLS_INVALID_CIPHERSUITES_LIST", NULL,
|
||||
"Failed to set TLS ciphersuites list '$tls_ciphers_list'\n$tls_error.all",
|
||||
"Failed to set TLS ciphersuites list '$tls_ciphersuites_list'\n$tls_error.all",
|
||||
log_data_string("tls_ciphersuites_list", tlsoptions->ciphersuites),
|
||||
log_data_tls_error());
|
||||
goto fail;
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user