]> jfr.im git - irc/unrealircd/unrealircd.git/commitdiff
* A new require sasl { } block which allows you to force users on the
authorBram Matthys <redacted>
Wed, 5 Sep 2018 09:34:48 +0000 (11:34 +0200)
committerBram Matthys <redacted>
Wed, 5 Sep 2018 09:34:48 +0000 (11:34 +0200)
  specified hostmask to use SASL. Any unauthenticated users matching
  the specified hostmask are are rejected.
  See https://www.unrealircd.org/docs/Require_sasl_block
Feature suggestion: https://bugs.unrealircd.org/view.php?id=5107

doc/RELEASE-NOTES
include/modules.h
include/struct.h
src/modules/m_nick.c
src/s_conf.c

index f1a1091570331d2c8dc7c0d29ccdd429aee924cd..2ea1c326d47e8f68fb16115e56d4a81d3e06b430 100644 (file)
@@ -10,8 +10,12 @@ Enhancements:
   This is especially useful if you only want to disable a few modules
   that are (normally) automatically loaded by conf/modules.default.conf.
   https://www.unrealircd.org/docs/Blacklist-module_directive
-* Next two new features have to do with SASL. More information on SASL
+* Next three new features have to do with SASL. More information on SASL
   in general can be found at https://www.unrealircd.org/docs/SASL
+* A new require sasl { } block which allows you to force users on the
+  specified hostmask to use SASL. Any unauthenticated users matching
+  the specified hostmask are are rejected.
+  See https://www.unrealircd.org/docs/Require_sasl_block
 * New "soft kline" and "soft gline". These will not be applied to users
   that are authenticated to services using SASL.
   These are just GLINE/KLINE's but prefixed with a percent sign:
index 8e611681062f12f2efcabc454b07f98b118ff82d..6d36afac9c79e399acc38974aa83c7f5e19ba4b9 100644 (file)
@@ -1090,6 +1090,7 @@ _UNREAL_ERROR(_hook_error_incompatible, "Incompatible hook function. Check argum
 #define CONFIG_ALLOW 6
 #define CONFIG_CLOAKKEYS 7
 #define CONFIG_SET_ANTI_FLOOD 8
+#define CONFIG_REQUIRE 9
 
 #define MOD_HEADER(name) Mod_Header
 #define MOD_TEST(name) DLLFUNC int Mod_Test(ModuleInfo *modinfo)
index cd17466c6eea51aa1823feee94e9ffeec2cbbd42..f1d6e46a69ed8e925d46194d01d6f537450262d6 100644 (file)
@@ -955,12 +955,13 @@ struct _configflag_tld
        unsigned        rulesptr  : 1;
 };
 
-#define CONF_BAN_NICK          1
-#define CONF_BAN_IP            2
-#define CONF_BAN_SERVER                3
-#define CONF_BAN_USER          4
-#define CONF_BAN_REALNAME      5
-#define CONF_BAN_VERSION        6
+#define CONF_BAN_NICK            1
+#define CONF_BAN_IP              2
+#define CONF_BAN_SERVER          3
+#define CONF_BAN_USER            4
+#define CONF_BAN_REALNAME        5
+#define CONF_BAN_VERSION         6
+#define CONF_BAN_UNAUTHENTICATED 7
 
 #define CONF_BAN_TYPE_CONF     0
 #define CONF_BAN_TYPE_AKILL    1
index eedb5d0446e11b7cdf7597b797416adeacd6310b..2ed5eac7318bf8e2f55508321fa2f543571cd884 100644 (file)
@@ -1327,9 +1327,7 @@ int _register_user(aClient *cptr, aClient *sptr, char *nick, char *username, cha
                else
                        u1 = NULL;
 
-               /*
-                * following block for the benefit of time-dependent K:-lines
-                */
+               /* Check ban user { } blocks (K-lines in conf) */
                if ((bconf = Find_ban(sptr, NULL, CONF_BAN_USER)))
                {
                        ircstp->is_ref++;
@@ -1341,6 +1339,7 @@ int _register_user(aClient *cptr, aClient *sptr, char *nick, char *username, cha
                            KLINE_ADDRESS);
                        return exit_client(cptr, cptr, cptr, "You are banned");
                }
+               /* Check ban realname { } blocks */
                if ((bconf = Find_ban(NULL, sptr->info, CONF_BAN_REALNAME)))
                {
                        ircstp->is_ref++;
@@ -1353,6 +1352,18 @@ int _register_user(aClient *cptr, aClient *sptr, char *nick, char *username, cha
                        return exit_client(cptr, sptr, &me,
                            "Your GECOS (real name) is banned from this server");
                }
+               /* Check require sasl { } blocks */
+               if (!IsLoggedIn(sptr) && (bconf = Find_ban(sptr, NULL, CONF_BAN_UNAUTHENTICATED)))
+               {
+                       ircstp->is_ref++;
+                       sendto_one(cptr,
+                           ":%s %d %s :*** You are not welcome on this server (%s)"
+                           " Email %s for more information.",
+                           me.name, ERR_YOUREBANNEDCREEP,
+                           cptr->name, bconf->reason ? bconf->reason : "",
+                           KLINE_ADDRESS);
+                       return exit_client(cptr, cptr, cptr, "You are banned");
+               }
                tkl_check_expire(NULL);
                /* Check G/Z lines before shuns -- kill before quite -- codemastr */
                if ((xx = find_tkline_match(sptr, 0)) < 0)
index 88db2ae73464803ad00d97ab18b3b6598292f6d9..5cf024756d4c032dd5e024898df34b105303fe2c 100644 (file)
@@ -92,6 +92,8 @@ static int    _conf_deny_dcc          (ConfigFile *conf, ConfigEntry *ce);
 static int     _conf_deny_link         (ConfigFile *conf, ConfigEntry *ce);
 static int     _conf_deny_channel      (ConfigFile *conf, ConfigEntry *ce);
 static int     _conf_deny_version      (ConfigFile *conf, ConfigEntry *ce);
+static int     _conf_require           (ConfigFile *conf, ConfigEntry *ce);
+static int     _conf_require_sasl      (ConfigFile *conf, ConfigEntry *ce);
 static int     _conf_allow_channel     (ConfigFile *conf, ConfigEntry *ce);
 static int     _conf_allow_dcc         (ConfigFile *conf, ConfigEntry *ce);
 static int     _conf_loadmodule        (ConfigFile *conf, ConfigEntry *ce);
@@ -122,6 +124,7 @@ static int  _test_except            (ConfigFile *conf, ConfigEntry *ce);
 static int     _test_vhost             (ConfigFile *conf, ConfigEntry *ce);
 static int     _test_link              (ConfigFile *conf, ConfigEntry *ce);
 static int     _test_ban               (ConfigFile *conf, ConfigEntry *ce);
+static int     _test_require           (ConfigFile *conf, ConfigEntry *ce);
 static int     _test_set               (ConfigFile *conf, ConfigEntry *ce);
 static int     _test_deny              (ConfigFile *conf, ConfigEntry *ce);
 static int     _test_allow_channel     (ConfigFile *conf, ConfigEntry *ce);
@@ -157,6 +160,7 @@ static ConfigCommand _ConfigCommands[] = {
        { "official-channels",          _conf_offchans,         _test_offchans  },
        { "oper",               _conf_oper,             _test_oper      },
        { "operclass",          _conf_operclass,        _test_operclass },
+       { "require",            _conf_require,          _test_require   },
        { "set",                _conf_set,              _test_set       },
        { "sni",                _conf_sni,              _test_sni       },
        { "spamfilter", _conf_spamfilter,       _test_spamfilter        },
@@ -7064,6 +7068,141 @@ int     _test_ban(ConfigFile *conf, ConfigEntry *ce)
        return errors;
 }
 
+int _conf_require(ConfigFile *conf, ConfigEntry *ce)
+{
+       ConfigEntry *cep;
+       ConfigItem_ban *ca;
+       Hook *h;
+
+       ca = MyMallocEx(sizeof(ConfigItem_ban));
+       if (!strcmp(ce->ce_vardata, "sasl"))
+       {
+               ca->flag.type = CONF_BAN_UNAUTHENTICATED;
+       }
+       else {
+               int value;
+               free(ca); /* ca isn't used, modules have their own list. */
+               for (h = Hooks[HOOKTYPE_CONFIGRUN]; h; h = h->next)
+               {
+                       value = (*(h->func.intfunc))(conf,ce,CONFIG_REQUIRE);
+                       if (value == 1)
+                               break;
+               }
+               return 0;
+       }
+       for (cep = ce->ce_entries; cep; cep = cep->ce_next)
+       {
+               if (!strcmp(cep->ce_varname, "mask"))
+               {
+                       ca->mask = strdup(cep->ce_vardata);
+               }
+               else if (!strcmp(cep->ce_varname, "reason"))
+                       ca->reason = strdup(cep->ce_vardata);
+               else if (!strcmp(cep->ce_varname, "action"))
+                       ca ->action = banact_stringtoval(cep->ce_vardata);
+       }
+       AddListItem(ca, conf_ban);
+       return 0;
+}
+
+int _test_require(ConfigFile *conf, ConfigEntry *ce)
+{
+       ConfigEntry *cep;
+       int errors = 0;
+       Hook *h;
+       char type = 0;
+       char has_mask = 0, has_action = 0, has_reason = 0;
+
+       if (!ce->ce_vardata)
+       {
+               config_error("%s:%i: require without type, did you mean 'require sasl'?",
+                       ce->ce_fileptr->cf_filename, ce->ce_varlinenum);
+               return 1;
+       }
+       if (!strcmp(ce->ce_vardata, "sasl"))
+       {}
+       else
+       {
+               int used = 0;
+               for (h = Hooks[HOOKTYPE_CONFIGTEST]; h; h = h->next)
+               {
+                       int value, errs = 0;
+                       if (h->owner && !(h->owner->flags & MODFLAG_TESTING)
+                           && !(h->owner->options & MOD_OPT_PERM))
+                               continue;
+                       value = (*(h->func.intfunc))(conf,ce,CONFIG_REQUIRE, &errs);
+                       if (value == 2)
+                               used = 1;
+                       if (value == 1)
+                       {
+                               used = 1;
+                               break;
+                       }
+                       if (value == -1)
+                       {
+                               used = 1;
+                               errors += errs;
+                               break;
+                       }
+                       if (value == -2)
+                       {
+                               used = 1;
+                               errors += errs;
+                       }
+               }
+               if (!used) {
+                       config_error("%s:%i: unknown require type '%s'",
+                               ce->ce_fileptr->cf_filename, ce->ce_varlinenum,
+                               ce->ce_vardata);
+                       return 1;
+               }
+               return errors;
+       }
+
+       for (cep = ce->ce_entries; cep; cep = cep->ce_next)
+       {
+               if (config_is_blankorempty(cep, "require"))
+               {
+                       errors++;
+                       continue;
+               }
+               if (!strcmp(cep->ce_varname, "mask"))
+               {
+                       if (has_mask)
+                       {
+                               config_warn_duplicate(cep->ce_fileptr->cf_filename,
+                                       cep->ce_varlinenum, "require::mask");
+                               continue;
+                       }
+                       has_mask = 1;
+               }
+               else if (!strcmp(cep->ce_varname, "reason"))
+               {
+                       if (has_reason)
+                       {
+                               config_warn_duplicate(cep->ce_fileptr->cf_filename,
+                                       cep->ce_varlinenum, "require::reason");
+                               continue;
+                       }
+                       has_reason = 1;
+               }
+       }
+
+       if (!has_mask)
+       {
+               config_error_missing(ce->ce_fileptr->cf_filename, ce->ce_varlinenum,
+                       "require::mask");
+               errors++;
+       }
+       if (!has_reason)
+       {
+               config_error_missing(ce->ce_fileptr->cf_filename, ce->ce_varlinenum,
+                       "require::reason");
+               errors++;
+       }
+       return errors;
+}
+
 #define CheckNull(x) if ((!(x)->ce_vardata) || (!(*((x)->ce_vardata)))) { config_error("%s:%i: missing parameter", (x)->ce_fileptr->cf_filename, (x)->ce_varlinenum); errors++; continue; }
 #define CheckNullAllowEmpty(x) if ((!(x)->ce_vardata)) { config_error("%s:%i: missing parameter", (x)->ce_fileptr->cf_filename, (x)->ce_varlinenum); errors++; continue; }
 #define CheckDuplicate(cep, name, display) if (settings.has_##name) { config_warn_duplicate((cep)->ce_fileptr->cf_filename, cep->ce_varlinenum, "set::" display); continue; } else settings.has_##name = 1