{ "OSMSG_NEED_CHANNEL", "You must specify a channel for $b%s$b." },
{ "OSMSG_INVALID_IRCMASK", "$b%s$b is an invalid IRC hostmask." },
{ "OSMSG_ADDED_BAN", "I have banned $b%s$b from $b%s$b." },
+ { "OSMSG_NO_GLINE_CMD", "The GLINE command is not bound so you can only block with the default duration." },
+ { "OSMSG_BLOCK_TRUSTED", "$b%s$b is on a trusted ip. If you really want to G-line him, use the GLINE command." },
+ { "OSMSG_BLOCK_OPER" , "G-lining $b%s$b (*@%s) would also hit the IRC operator $b%s$b." },
{ "OSMSG_GLINE_ISSUED", "G-line issued for $b%s$b." },
{ "OSMSG_GLINE_REMOVED", "G-line removed for $b%s$b." },
{ "OSMSG_GLINE_FORCE_REMOVED", "Unknown/expired G-line removed for $b%s$b." },
time_t min_ts, max_ts;
unsigned int min_level, max_level, domain_depth, duration, min_clones, min_channels, max_channels;
unsigned char ip_mask_bits;
- unsigned int match_opers : 1, option_log : 1;
+ unsigned int match_opers : 1, match_trusted : 1, option_log : 1;
unsigned int chan_req_modes : 2, chan_no_modes : 2;
int authed : 2, info_space : 2;
} *discrim_t;
char *reason;
unsigned long duration = 0;
unsigned int offset = 2;
+ unsigned int nn;
+ struct svccmd *gline_cmd;
target = GetUserH(argv[1]);
if (!target) {
reply("MSG_SERVICE_IMMUNE", target->nick);
return 0;
}
+ if (dict_find(opserv_trusted_hosts, irc_ntoa(&target->ip), NULL)) {
+ reply("OSMSG_BLOCK_TRUSTED", target->nick);
+ return 0;
+ }
+
+ for(nn = 0; nn < curr_opers.used; nn++) {
+ if(memcmp(&curr_opers.list[nn]->ip, &target->ip, sizeof(irc_in_addr_t)) == 0) {
+ reply("OSMSG_BLOCK_OPER", target->nick, irc_ntoa(&target->ip), curr_opers.list[nn]->nick);
+ return 0;
+ }
+ }
+
if(argc > 2 && (duration = ParseInterval(argv[2]))) {
offset = 3;
}
+ if(duration && duration != opserv_conf.block_gline_duration) {
+ // We require more access when the duration is not the default block duration.
+ gline_cmd = dict_find(cmd->parent->commands, "gline", NULL);
+ if(!gline_cmd)
+ {
+ reply("OSMSG_NO_GLINE_CMD");
+ return 0;
+ }
+ if(!svccmd_can_invoke(user, cmd->parent->bot, gline_cmd, channel, SVCCMD_NOISY))
+ return 0;
+ }
reason = (argc > offset) ? unsplit_string(argv+offset, argc-offset, NULL) : NULL;
gline = opserv_block(target, user->handle_info->handle, reason, duration);
reply("OSMSG_GLINE_ISSUED", gline->target);
} else {
discrim->min_level = strtoul(cmp, NULL, 0);
}
- } else if ((irccasecmp(argv[i], "abuse") == 0)
- && (irccasecmp(argv[++i], "opers") == 0)) {
- discrim->match_opers = 1;
+ } else if (irccasecmp(argv[i], "abuse") == 0) {
+ const char *abuse_what = argv[++i];
+ if (irccasecmp(abuse_what, "opers") == 0) {
+ discrim->match_opers = 1;
+ } else if (irccasecmp(abuse_what, "trusted") == 0) {
+ discrim->match_trusted = 1;
+ }
} else if (irccasecmp(argv[i], "depth") == 0) {
discrim->domain_depth = strtoul(argv[++i], NULL, 0);
} else if (irccasecmp(argv[i], "clones") == 0) {
}
static int
-is_oper_victim(struct userNode *user, struct userNode *target, int match_opers)
+is_oper_victim(struct userNode *user, struct userNode *target, int match_opers, int check_ip)
+{
+ unsigned char is_victim;
+ unsigned int nn;
+
+ is_victim = !(IsService(target)
+ || (!match_opers && IsOper(target))
+ || (target->handle_info
+ && target->handle_info->opserv_level > user->handle_info->opserv_level));
+
+ // If we don't need an ip check or want to hit opers or the the "cheap" check already disqualified the target, we are done.
+ if (!check_ip || match_opers || !is_victim)
+ return is_victim;
+
+ for(nn = 0; nn < curr_opers.used; nn++) {
+ if(memcmp(&curr_opers.list[nn]->ip, &target->ip, sizeof(irc_in_addr_t)) == 0)
+ return 0;
+ }
+
+ return 1;
+}
+
+static int
+is_trust_victim(struct userNode *target, int match_trusted)
{
- return !(IsService(target)
- || (!match_opers && IsOper(target))
- || (target->handle_info
- && target->handle_info->opserv_level > user->handle_info->opserv_level));
+ return (match_trusted || !dict_find(opserv_trusted_hosts, irc_ntoa(&target->ip), NULL));
}
static int
{
struct discrim_and_source *das = extra;
- if (is_oper_victim(das->source, match, das->discrim->match_opers)) {
+ if (is_oper_victim(das->source, match, das->discrim->match_opers, 1) && is_trust_victim(match, das->discrim->match_trusted)) {
opserv_block(match, das->source->handle_info->handle, das->discrim->reason, das->discrim->duration);
}
{
struct discrim_and_source *das = extra;
- if (is_oper_victim(das->source, match, das->discrim->match_opers)) {
+ if (is_oper_victim(das->source, match, das->discrim->match_opers, 0) && is_trust_victim(match, das->discrim->match_trusted)) {
char *reason;
if (das->discrim->reason) {
reason = das->discrim->reason;
{
struct discrim_and_source *das = extra;
- if (is_oper_victim(das->source, match, das->discrim->match_opers)) {
+ if (is_oper_victim(das->source, match, das->discrim->match_opers, 1) && is_trust_victim(match, das->discrim->match_trusted)) {
char *reason, *mask;
int masksize;
if (das->discrim->reason) {
return 0;
}
+ if ((alert->reaction != REACT_NOTICE)
+ && !is_trust_victim(user, alert->discrim->match_trusted)) {
+ return 0;
+ }
+
/* The user matches the alert criteria, so trigger the reaction. */
if (alert->discrim->option_log)
log_module(OS_LOG, LOG_INFO, "Alert %s triggered by user %s!%s@%s (%s).", key, user->nick, user->ident, user->hostname, alert->discrim->reason);