#include "stdinc.h"
#include "send.h"
+#include "channel.h"
#include "client.h"
#include "common.h"
#include "config.h"
#include "ircd.h"
#include "match.h"
#include "s_conf.h"
+#include "s_newconf.h"
#include "msg.h"
#include "modules.h"
#include "hash.h"
#include "reject.h"
#include "hostmask.h"
+static int m_ban(struct Client *client_p, struct Client *source_p, int parc, const char *parv[]);
static int ms_ban(struct Client *client_p, struct Client *source_p, int parc, const char *parv[]);
struct Message ban_msgtab = {
"BAN", 0, 0, 0, MFLG_SLOW,
- {mg_unreg, mg_ignore, {ms_ban, 10}, {ms_ban, 10}, mg_ignore, mg_ignore}
+ {mg_unreg, {m_ban, 0}, {ms_ban, 9}, {ms_ban, 9}, mg_ignore, {m_ban, 0}}
};
mapi_clist_av1 ban_clist[] = { &ban_msgtab, NULL };
DECLARE_MODULE_AV1(ban, NULL, NULL, ban_clist, NULL, NULL, "$Revision: 1349 $");
+static int
+m_ban(struct Client *client_p, struct Client *source_p, int parc, const char *parv[])
+{
+ sendto_one_notice(source_p, ":The BAN command is not user-accessible.");
+ sendto_one_notice(source_p, ":To ban a user from a channel, see /QUOTE HELP CMODE");
+ if (IsOper(source_p))
+ sendto_one_notice(source_p, ":To ban a user from a server or from the network, see /QUOTE HELP KLINE");
+ return 0;
+}
+
/* ms_ban()
*
- * parv[1] - +/-
- * parv[2] - type
- * parv[3] - username mask or *
- * parv[4] - hostname mask
- * parv[5] - creation TS
- * parv[6] - duration (relative to creation)
- * parv[7] - lifetime (relative to creation)
- * parv[8] - oper or *
- * parv[9] - reason (possibly with |operreason)
+ * parv[1] - type
+ * parv[2] - username mask or *
+ * parv[3] - hostname mask
+ * parv[4] - creation TS
+ * parv[5] - duration (relative to creation)
+ * parv[6] - lifetime (relative to creation)
+ * parv[7] - oper or *
+ * parv[8] - reason (possibly with |operreason)
*/
static int
ms_ban(struct Client *client_p, struct Client *source_p, int parc, const char *parv[])
time_t created, hold, lifetime;
char *p;
int act;
+ int valid;
- if (strcmp(parv[1], "+") && strcmp(parv[1], "-"))
- {
- sendto_realops_snomask(SNO_GENERAL, L_NETWIDE,
- "Unknown BAN operation %s from %s",
- parv[1], source_p->name);
- return 0;
- }
- if (strlen(parv[2]) != 1)
+ if (strlen(parv[1]) != 1)
{
sendto_realops_snomask(SNO_GENERAL, L_NETWIDE,
"Unknown BAN type %s from %s",
- parv[2], source_p->name);
+ parv[1], source_p->name);
return 0;
}
- switch (parv[2][0])
+ switch (parv[1][0])
{
case 'K':
ntype = CONF_KILL;
stype = "K-Line";
break;
+ case 'X':
+ ntype = CONF_XLINE;
+ stype = "X-Line";
+ break;
+ case 'R':
+ ntype = IsChannelName(parv[3]) ? CONF_RESV_CHANNEL :
+ CONF_RESV_NICK;
+ stype = "RESV";
+ break;
default:
sendto_realops_snomask(SNO_GENERAL, L_NETWIDE,
"Unknown BAN type %s from %s",
- parv[2], source_p->name);
+ parv[1], source_p->name);
return 0;
}
- created = atol(parv[5]);
- hold = created + atoi(parv[6]);
- lifetime = created + atoi(parv[7]);
- if (!strcmp(parv[8], "*"))
+ created = atol(parv[4]);
+ hold = created + atoi(parv[5]);
+ lifetime = created + atoi(parv[6]);
+ if (!strcmp(parv[7], "*"))
oper = IsServer(source_p) ? source_p->name : get_oper_name(source_p);
else
- oper = parv[8];
- ptr = find_prop_ban(ntype, parv[3], parv[4]);
+ oper = parv[7];
+ ptr = find_prop_ban(ntype, parv[2], parv[3]);
if (ptr != NULL)
{
+ /* We already know about this ban mask. */
aconf = ptr->data;
- if (aconf->created >= created)
+ if (aconf->created > created ||
+ (aconf->created == created &&
+ aconf->lifetime >= lifetime))
{
if (IsPerson(source_p))
sendto_one_notice(source_p,
aconf->host);
return 0;
}
- act = !(aconf->status & CONF_ILLEGAL) || !strcmp(parv[1], "+");
+ /* act indicates if something happened (from the oper's
+ * point of view). This is the case if the ban was
+ * previously active (not deleted) or if the new ban
+ * is not a removal and not already expired.
+ */
+ act = !(aconf->status & CONF_ILLEGAL) || (hold != created &&
+ hold > rb_current_time());
if (lifetime > aconf->lifetime)
aconf->lifetime = lifetime;
/* already expired, hmm */
if (aconf->lifetime <= rb_current_time())
return 0;
+ /* Deactivate, it will be reactivated later if appropriate. */
deactivate_conf(aconf, ptr);
rb_free(aconf->user);
aconf->user = NULL;
}
else
{
+ /* New ban mask. */
aconf = make_conf();
aconf->status = CONF_ILLEGAL | ntype;
aconf->lifetime = lifetime;
rb_dlinkAddAlloc(aconf, &prop_bans);
- act = !strcmp(parv[1], "+");
+ act = hold != created && hold > rb_current_time();
}
aconf->flags &= ~CONF_FLAGS_MYOPER;
aconf->flags |= CONF_FLAGS_TEMPORARY;
- aconf->user = ntype == CONF_KILL ? rb_strdup(parv[3]) : NULL;
- aconf->host = rb_strdup(parv[4]);
+ aconf->user = ntype == CONF_KILL ? rb_strdup(parv[2]) : NULL;
+ aconf->host = rb_strdup(parv[3]);
aconf->info.oper = operhash_add(oper);
aconf->created = created;
aconf->hold = hold;
- p = strchr(parv[parc - 1], '|');
- if (p == NULL)
+ if (ntype != CONF_KILL || (p = strchr(parv[parc - 1], '|')) == NULL)
aconf->passwd = rb_strdup(parv[parc - 1]);
else
{
aconf->passwd = rb_strndup(parv[parc - 1], p - parv[parc - 1] + 1);
aconf->spasswd = rb_strdup(p + 1);
}
- if (!strcmp(parv[1], "+"))
+ /* The ban is fully filled in and in the prop_bans list
+ * but still deactivated. Now determine if it should be activated
+ * and send the server notices.
+ */
+ /* We only reject *@* and the like here.
+ * Otherwise malformed bans are fairly harmless and can be removed.
+ */
+ switch (ntype)
+ {
+ case CONF_KILL:
+ valid = valid_wild_card(aconf->user, aconf->host);
+ break;
+ case CONF_RESV_CHANNEL:
+ valid = 1;
+ break;
+ default:
+ valid = valid_wild_card_simple(aconf->host);
+ break;
+ }
+ if (act && hold != created && !valid)
+ {
+ sendto_realops_snomask(SNO_GENERAL, L_ALL,
+ "Ignoring global %d min. %s from %s%s%s for [%s%s%s]: too few non-wildcard characters",
+ (int)((hold - rb_current_time()) / 60),
+ stype,
+ IsServer(source_p) ? source_p->name : get_oper_name(source_p),
+ strcmp(parv[7], "*") ? " on behalf of " : "",
+ strcmp(parv[7], "*") ? parv[7] : "",
+ aconf->user ? aconf->user : "",
+ aconf->user ? "@" : "",
+ aconf->host);
+ if(IsPerson(source_p))
+ sendto_one_notice(source_p,
+ ":Your %s [%s%s%s] has too few non-wildcard characters",
+ stype,
+ aconf->user ? aconf->user : "",
+ aconf->user ? "@" : "",
+ aconf->host);
+ /* Propagate it, but do not apply it locally. */
+ }
+ else if (act && hold != created)
{
/* Keep the notices in sync with modules/m_kline.c etc. */
sendto_realops_snomask(SNO_GENERAL, L_ALL,
"%s added global %d min. %s%s%s for [%s%s%s] [%s]",
IsServer(source_p) ? source_p->name : get_oper_name(source_p),
- (hold - rb_current_time()) / 60,
+ (int)((hold - rb_current_time()) / 60),
stype,
- strcmp(parv[8], "*") ? " from " : "",
- strcmp(parv[8], "*") ? parv[8] : "",
+ strcmp(parv[7], "*") ? " from " : "",
+ strcmp(parv[7], "*") ? parv[7] : "",
aconf->user ? aconf->user : "",
aconf->user ? "@" : "",
aconf->host,
parv[parc - 1]);
- aconf->status &= ~CONF_ILLEGAL;
- ilog(L_KLINE, "%s %s %d %s %s %s", parv[2],
+ ilog(L_KLINE, "%s %s %d %s%s%s %s", parv[1],
IsServer(source_p) ? source_p->name : get_oper_name(source_p),
- (hold - rb_current_time()) / 60,
- aconf->user, aconf->host,
+ (int)((hold - rb_current_time()) / 60),
+ aconf->user ? aconf->user : "",
+ aconf->user ? " " : "",
+ aconf->host,
parv[parc - 1]);
+ aconf->status &= ~CONF_ILLEGAL;
}
else if (act)
{
aconf->user ? aconf->user : "",
aconf->user ? "@" : "",
aconf->host,
- strcmp(parv[8], "*") ? " on behalf of " : "",
- strcmp(parv[8], "*") ? parv[8] : "");
- ilog(L_KLINE, "U%s %s %s %s", parv[2],
+ strcmp(parv[7], "*") ? " on behalf of " : "",
+ strcmp(parv[7], "*") ? parv[7] : "");
+ ilog(L_KLINE, "U%s %s %s%s %s", parv[1],
IsServer(source_p) ? source_p->name : get_oper_name(source_p),
- aconf->user, aconf->host);
+ aconf->user ? aconf->user : "",
+ aconf->user ? " " : "",
+ aconf->host);
}
+ /* If CONF_ILLEGAL is still set at this point, remove entries from the
+ * reject cache (for klines and xlines).
+ * If CONF_ILLEGAL is not set, add the ban to the type-specific data
+ * structure and take action on matched clients/channels.
+ */
switch (ntype)
{
case CONF_KILL:
check_klines();
}
break;
+ case CONF_XLINE:
+ if (aconf->status & CONF_ILLEGAL)
+ remove_reject_mask(aconf->host, NULL);
+ else
+ {
+ rb_dlinkAddAlloc(aconf, &xline_conf_list);
+ check_xlines();
+ }
+ break;
+ case CONF_RESV_CHANNEL:
+ if (!(aconf->status & CONF_ILLEGAL))
+ {
+ add_to_resv_hash(aconf->host, aconf);
+ resv_chan_forcepart(aconf->host, aconf->passwd, hold - rb_current_time());
+ }
+ break;
+ case CONF_RESV_NICK:
+ if (!(aconf->status & CONF_ILLEGAL))
+ rb_dlinkAddAlloc(aconf, &resv_conf_list);
+ break;
}
- sendto_server(NULL, NULL, CAP_BAN|CAP_TS6, NOCAPS,
- ":%s BAN %s %s %s %s %s %s %s %s :%s",
+ sendto_server(client_p, NULL, CAP_BAN|CAP_TS6, NOCAPS,
+ ":%s BAN %s %s %s %s %s %s %s :%s",
source_p->id,
parv[1],
parv[2],
parv[5],
parv[6],
parv[7],
- parv[8],
parv[parc - 1]);
return 0;
}