/*
* Based on timedban.c. Created by k4be.
* (C) Copyright 2009-2017 Bram Matthys (Syzop) and the UnrealIRCd team.
* License: GPLv2
*
* This module adds an extended ban ~I:mask
* Ban prefixed with ~I will match only users that are not identified
* to services.
*
* Note that this extended ban is rather special in the sense that
* it permits (crazy) triple-extbans to be set, such as:
* +b ~I:~q:~c:#channel
* (=mute a user that is also on #channel, unless he's idenitifed to services)
*
* The triple-extbans / double-stacking requires special routines that
* are based on parts of the core and special recursion checks.
* If you are looking for inspiration of coding your own extended ban
* then look at another extended ban * module as this module is not a
* good starting point ;)
*/
#include "unrealircd.h"
/* Maximum length of a ban */
#define MAX_LENGTH 128
ModuleHeader MOD_HEADER(m_unauthban)
= {
"m_unauthban",
"$Id: v1.00 2018/11/05 k4be$",
"ExtBan ~I: bans that match only users that are not logged in",
"3.2-b8-1",
NULL
};
/* Forward declarations */
char *unauthban_extban_conv_param(char *para_in);
int unauthban_extban_is_ok(aClient* sptr, aChannel* chptr, char* para_in, int checkt, int what, int what2);
int unauthban_is_banned(aClient *sptr, aChannel *chptr, char *ban, int chktype);
void add_send_mode_param(aChannel *chptr, aClient *from, char what, char mode, char *param);
char *unauthban_chanmsg(aClient *, aClient *, aChannel *, char *, int);
MOD_TEST(m_unauthban)
{
return MOD_SUCCESS;
}
MOD_INIT(m_unauthban)
{
ExtbanInfo extban;
memset(&extban
, 0, sizeof(ExtbanInfo
));
extban.flag = 'I';
extban.options |= EXTBOPT_ACTMODIFIER; /* not really, but ours shouldn't be stacked from group 1 */
extban.options |= EXTBOPT_CHSVSMODE; /* so "SVSMODE -nick" will unset affected ~I extbans */
//extban.options |= EXTBOPT_INVEX; /* invex probably would be useless */
extban.conv_param = unauthban_extban_conv_param;
extban.is_ok = unauthban_extban_is_ok;
extban.is_banned = unauthban_is_banned;
if (!ExtbanAdd(modinfo->handle, extban))
{
config_error("m_unauthban: unable to register 'I' extban type!!");
return MOD_FAILED;
}
return MOD_SUCCESS;
}
MOD_LOAD(m_unauthban)
{
return MOD_SUCCESS;
}
MOD_UNLOAD(m_unauthban)
{
return MOD_SUCCESS;
}
/** Generic helper for our conv_param extban function.
* Mostly copied from clean_ban_mask()
*/
char *generic_clean_ban_mask(char *mask)
{
char *cp, *x;
char *user;
char *host;
Extban *p;
static char maskbuf[512];
/* Work on a copy */
strlcpy(maskbuf, mask, sizeof(maskbuf));
mask = maskbuf;
cp = index(mask, ' ');
if (cp)
*cp = '\0';
/* Strip any ':' at beginning since that would cause a desynch */
for (; (*mask && (*mask == ':')); mask++);
if (!*mask)
return NULL;
/* Forbid ASCII <= 32 in all bans */
for (x = mask; *x; x++)
if (*x <= ' ')
return NULL;
/* Extended ban? */
if ((*mask == '~') && mask[1] && (mask[2] == ':'))
{
p = findmod_by_bantype(mask[1]);
if (!p)
return NULL; /* reject unknown extban */
if (p->conv_param)
return p->conv_param(mask);
/* else, do some basic sanity checks and cut it off at 80 bytes */
if ((mask[1] != ':') || (mask[2] == '\0'))
return NULL; /* require a ":<char>" after extban type */
mask[80] = '\0';
return mask;
}
if ((*mask
== '~') && !strchr(mask
, '@'))
return NULL; /* not an extended ban and not a ~user@host ban either. */
if ((user = index((cp = mask), '!')))
*user++ = '\0';
if ((host = rindex(user ? user : cp, '@')))
{
*host++ = '\0';
if (!user)
return make_nick_user_host(NULL, trim_str(cp,USERLEN),
trim_str(host,HOSTLEN));
}
else if (!user && index(cp, '.'))
return make_nick_user_host(NULL, NULL, trim_str(cp,HOSTLEN));
return make_nick_user_host(trim_str(cp,NICKLEN), trim_str(user,USERLEN),
trim_str(host,HOSTLEN));
}
/** Convert ban to an acceptable format (or return NULL to fully reject it) */
char *unauthban_extban_conv_param(char *para_in)
{
static char retbuf[MAX_LENGTH+1];
char para[MAX_LENGTH+1];
char tmpmask[MAX_LENGTH+1];
char *newmask; /**< Cleaned matching method, such as 'n!u@h' */
static int unauthban_extban_conv_param_recursion = 0;
if (unauthban_extban_conv_param_recursion)
return NULL; /* reject: recursion detected! */
strlcpy(para, para_in+3, sizeof(para)); /* work on a copy (and truncate it) */
/* ~I:n!u@h for direct matching
* ~I:~x:.... when calling another bantype
*/
strlcpy(tmpmask, para, sizeof(tmpmask));
unauthban_extban_conv_param_recursion++;
//newmask = extban_conv_param_nuh_or_extban(tmpmask);
newmask = generic_clean_ban_mask(tmpmask);
unauthban_extban_conv_param_recursion--;
if (!newmask
|| (strlen(newmask
) <= 1))
return NULL;
snprintf(retbuf
, sizeof(retbuf
), "~I:%s", newmask
);
return retbuf;
}
int unauthban_extban_syntax(aClient *sptr, int checkt, char *reason)
{
if (MyClient(sptr) && (checkt == EXBCHK_PARAM))
{
sendnotice(sptr, "Error when setting unauth ban: %s", reason);
sendnotice(sptr, " Syntax: +b ~I:mask");
sendnotice(sptr, "Example: +b ~I:nick!user@host");
sendnotice(sptr, "Valid masks are: nick!user@host or another extban type such as ~c, ~S, ..");
}
return 0; /* FAIL: ban rejected */
}
/** Generic helper for sub-bans, used by our "is this ban ok?" function */
int generic_ban_is_ok(aClient *sptr, aChannel *chptr, char *mask, int checkt, int what, int what2)
{
if ((mask[0] == '~') && MyClient(sptr))
{
Extban *p;
/* This portion is copied from clean_ban_mask() */
if (mask[1] && (mask[2] == ':') &&
RESTRICT_EXTENDEDBANS && MyClient(sptr) &&
!ValidatePermissionsForPath("channel:extbans",sptr,NULL,NULL,NULL))
{
if (!strcmp(RESTRICT_EXTENDEDBANS
, "*"))
{
if (checkt == EXBCHK_ACCESS_ERR)
sendnotice(sptr, "Setting/removing of extended bans has been disabled");
return 0; /* REJECT */
}
if (strchr(RESTRICT_EXTENDEDBANS
, mask
[1]))
{
if (checkt == EXBCHK_ACCESS_ERR)
sendnotice(sptr, "Setting/removing of extended bantypes '%s' has been disabled", RESTRICT_EXTENDEDBANS);
return 0; /* REJECT */
}
}
/* End of portion */
/* This portion is inspired by m_mode */
p = findmod_by_bantype(mask[1]);
if (checkt == EXBCHK_ACCESS)
{
if (p && p->is_ok && !p->is_ok(sptr, chptr, mask, EXBCHK_ACCESS, what, what2) &&
!ValidatePermissionsForPath("override:extban",sptr,NULL,chptr,NULL))
{
return 0; /* REJECT */
}
} else
if (checkt == EXBCHK_ACCESS_ERR)
{
if (p && p->is_ok && !p->is_ok(sptr, chptr, mask, EXBCHK_ACCESS, what, what2) &&
!ValidatePermissionsForPath("override:extban",sptr,NULL,chptr,NULL))
{
p->is_ok(sptr, chptr, mask, EXBCHK_ACCESS_ERR, what, what2);
return 0; /* REJECT */
}
} else
if (checkt == EXBCHK_PARAM)
{
if (p && p->is_ok && !p->is_ok(sptr, chptr, mask, EXBCHK_PARAM, what, what2))
{
return 0; /* REJECT */
}
}
/* End of portion */
}
/* ACCEPT:
* - not an extban; OR
* - extban with NULL is_ok; OR
* - non-existing extban character (handled by conv_param?)
*/
return 1;
}
/** Validate ban ("is this ban ok?") */
int unauthban_extban_is_ok(aClient* sptr, aChannel* chptr, char* para_in, int checkt, int what, int what2)
{
char para[MAX_LENGTH+1];
char tmpmask[MAX_LENGTH+1];
char *newmask; /**< Cleaned matching method, such as 'n!u@h' */
static int unauthban_extban_is_ok_recursion = 0;
int res;
/* Always permit deletion */
if (what == MODE_DEL)
return 1;
if (unauthban_extban_is_ok_recursion)
return 0; /* Recursion detected (~I:~I:....) */
strlcpy(para, para_in+3, sizeof(para)); /* work on a copy (and truncate it) */
/* ~I:n!u@h for direct matching
* ~I:~x:.... when calling another bantype
*/
strlcpy(tmpmask, para, sizeof(tmpmask));
unauthban_extban_is_ok_recursion++;
//res = extban_is_ok_nuh_extban(sptr, chptr, tmpmask, checkt, what, what2);
res = generic_ban_is_ok(sptr, chptr, tmpmask, checkt, what, what2);
unauthban_extban_is_ok_recursion--;
if (res == 0)
{
/* This could be anything ranging from:
* invalid n!u@h syntax, unknown (sub)extbantype,
* disabled extban type in conf, too much recursion, etc.
*/
return unauthban_extban_syntax(sptr, checkt, "Invalid matcher");
}
return 1; /* OK */
}
/** Check if the user is currently banned */
int unauthban_is_banned(aClient *sptr, aChannel *chptr, char *ban, int chktype)
{
return 0; /* not for us */
if(IsLoggedIn(sptr)) return 0; // this is the magic
ban += 3; // skip extban prefix
return ban_check_mask(sptr, chptr, ban, chktype, 0); // if not logged in, process as normal ban
}
static char mbuf[512];
static char pbuf[512];
#if MODEBUFLEN > 512
#error "add_send_mode_param() is not made for MODEBUFLEN > 512"
#endif
void add_send_mode_param(aChannel *chptr, aClient *from, char what, char mode, char *param) {
static char *modes = NULL, lastwhat;
static short count = 0;
short send = 0;
if (!modes) modes = mbuf;
if (!mbuf[0]) {
modes = mbuf;
*modes++ = what;
*modes = 0;
lastwhat = what;
*pbuf = 0;
count = 0;
}
if (lastwhat != what) {
*modes++ = what;
*modes = 0;
lastwhat = what;
}
if (*pbuf)
*modes++ = mode;
*modes = 0;
count++;
}
else if (*pbuf)
send = 1;
if (count == MAXMODEPARAMS)
send = 1;
if (send) {
sendto_channel_butserv(chptr, &me, ":%s MODE %s %s %s", me.name, chptr->chname, mbuf, pbuf);
sendto_server(NULL, 0, 0, ":%s MODE %s %s %s 0", me.name, chptr->chname, mbuf, pbuf);
send = 0;
*pbuf = 0;
modes = mbuf;
*modes++ = what;
lastwhat = what;
if (count != MAXMODEPARAMS) {
strlcpy(pbuf, param, sizeof(pbuf));
*modes++ = mode;
count = 1;
}
else
count = 0;
*modes = 0;
}
}