#ifdef HAVE_ARPA_INET_H
#include <arpa/inet.h>
#endif
+#ifdef HAVE_REGEX_H
+#include <regex.h>
+#endif
#define OPSERV_CONF_NAME "services/opserv"
{ "OSMSG_CHANINFO_MANY_USERS", "%d users (\"/msg $S %s %s users\" for the list)" },
{ "OSMSG_CHANINFO_USER_COUNT", "Users (%d):" },
{ "OSMSG_CSEARCH_CHANNEL_INFO", "%s [%d users] %s %s" },
+ { "OSMSG_INVALID_REGEX", "Invalid regex: %s: %s (%d)" },
{ NULL, NULL }
};
typedef struct opservDiscrim {
struct chanNode *channel;
char *mask_nick, *mask_ident, *mask_host, *mask_info, *server, *ip_mask_str, *reason, *accountmask;
+ regex_t regex_nick, regex_ident, regex_host, regex_info;
+ unsigned int has_regex_nick : 1, has_regex_ident : 1, has_regex_host : 1, has_regex_info : 1;
unsigned long limit, ip_mask;
struct in_addr ip_addr;
unsigned int min_level, max_level, domain_depth, duration, min_clones, min_channels, max_channels;
unsigned int chan_req_modes : 2, chan_no_modes : 2;
int authed : 2, info_space : 2;
time_t min_ts, max_ts;
+ unsigned int use_regex : 1;
} *discrim_t;
struct discrim_and_source {
free(alert->owner);
free(alert->text_discrim);
free(alert->split_discrim);
+ if(alert->discrim->has_regex_nick)
+ regfree(&alert->discrim->regex_nick);
+ if(alert->discrim->has_regex_ident)
+ regfree(&alert->discrim->regex_ident);
+ if(alert->discrim->has_regex_host)
+ regfree(&alert->discrim->regex_host);
+ if(alert->discrim->has_regex_info)
+ regfree(&alert->discrim->regex_info);
free(alert->discrim->reason);
free(alert->discrim);
free(alert);
discrim->max_channels = INT_MAX;
discrim->authed = -1;
discrim->info_space = -1;
+ discrim->use_regex = 0;
dupmask = strdup(hostmask);
if (split_ircmask(dupmask, &discrim->mask_nick, &discrim->mask_ident, &discrim->mask_host)) {
if (discrim->mask_host && !discrim->mask_host[strspn(discrim->mask_host, "0123456789.?*")]) {
send_message(user, bot, "MSG_INVALID_BINARY", argv[i]);
goto fail;
}
+ } else if (irccasecmp(argv[i], "regex") == 0) {
+ i++;
+ if (true_string(argv[i])) {
+ discrim->use_regex = 1;
+ } else if (false_string(argv[i])) {
+ discrim->use_regex = 0;
+ } else {
+ send_message(user, opserv, "MSG_INVALID_BINARY", argv[i]);
+ goto fail;
+ }
} else if (irccasecmp(argv[i], "duration") == 0) {
discrim->duration = ParseInterval(argv[++i]);
} else if (irccasecmp(argv[i], "channel") == 0) {
if (discrim->mask_host && !discrim->mask_host[strspn(discrim->mask_host, "*.")]) {
discrim->mask_host = 0;
}
+
+ if(discrim->use_regex)
+ {
+ if(discrim->mask_nick)
+ {
+ int err = regcomp(&discrim->regex_nick, discrim->mask_nick, REG_EXTENDED|REG_ICASE|REG_NOSUB);
+ discrim->has_regex_nick = !err;
+ if(err)
+ {
+ char buff[256];
+ buff[regerror(err, &discrim->regex_nick, buff, sizeof(buff))] = 0;
+
+ send_message(user, opserv, "OSMSG_INVALID_REGEX", discrim->mask_nick, buff, err);
+ goto regfail;
+ }
+ }
+
+ if(discrim->mask_ident)
+ {
+ int err = regcomp(&discrim->regex_ident, discrim->mask_ident, REG_EXTENDED|REG_ICASE|REG_NOSUB);
+ discrim->has_regex_ident = !err;
+ if(err)
+ {
+ char buff[256];
+ buff[regerror(err, &discrim->regex_ident, buff, sizeof(buff))] = 0;
+
+ send_message(user, opserv, "OSMSG_INVALID_REGEX", discrim->mask_ident, buff, err);
+ goto regfail;
+ }
+ }
+
+ if(discrim->mask_host)
+ {
+ int err = regcomp(&discrim->regex_host, discrim->mask_host, REG_EXTENDED|REG_ICASE|REG_NOSUB);
+ discrim->has_regex_host = !err;
+ if(err)
+ {
+ char buff[256];
+ buff[regerror(err, &discrim->regex_host, buff, sizeof(buff))] = 0;
+
+ send_message(user, opserv, "OSMSG_INVALID_REGEX", discrim->mask_host, buff, err);
+ goto regfail;
+ }
+ }
+
+ if(discrim->mask_info)
+ {
+ int err = regcomp(&discrim->regex_info, discrim->mask_info, REG_EXTENDED|REG_ICASE|REG_NOSUB);
+ discrim->has_regex_info = !err;
+ if(err)
+ {
+ char buff[256];
+ buff[regerror(err, &discrim->regex_info, buff, sizeof(buff))] = 0;
+
+ send_message(user, opserv, "OSMSG_INVALID_REGEX", discrim->mask_info, buff, err);
+ goto regfail;
+ }
+ }
+ }
+
return discrim;
+
fail:
free(discrim);
return NULL;
+
+ regfail:
+ if(discrim->has_regex_nick)
+ regfree(&discrim->regex_nick);
+ if(discrim->has_regex_ident)
+ regfree(&discrim->regex_ident);
+ if(discrim->has_regex_host)
+ regfree(&discrim->regex_host);
+ if(discrim->has_regex_info)
+ regfree(&discrim->regex_info);
+
+ free(discrim);
+ return NULL;
}
static int
|| (discrim->authed == 1 && !user->handle_info)
|| (discrim->info_space == 0 && user->info[0] == ' ')
|| (discrim->info_space == 1 && user->info[0] != ' ')
- || (discrim->mask_nick && !match_ircglob(user->nick, discrim->mask_nick))
- || (discrim->mask_ident && !match_ircglob(user->ident, discrim->mask_ident))
- || (discrim->mask_host && !match_ircglob(user->hostname, discrim->mask_host))
- || (discrim->mask_info && !match_ircglob(user->info, discrim->mask_info))
|| (discrim->server && !match_ircglob(user->uplink->name, discrim->server))
|| (discrim->accountmask && (!user->handle_info || !match_ircglob(user->handle_info->handle, discrim->accountmask)))
|| (discrim->ip_mask && !MATCH_IPMASK(user->ip, discrim->ip_addr, discrim->ip_mask))) {
return 0;
}
+
+ if(discrim->use_regex)
+ {
+ if((discrim->has_regex_nick && regexec(&discrim->regex_nick, user->nick, 0, 0, 0))
+ || (discrim->has_regex_ident && regexec(&discrim->regex_ident, user->ident, 0, 0, 0))
+ || (discrim->has_regex_host && regexec(&discrim->regex_host, user->hostname, 0, 0, 0))
+ || (discrim->has_regex_info && regexec(&discrim->regex_info, user->info, 0, 0, 0))) {
+ return 0;
+ }
+ }
+ else
+ {
+ if ((discrim->mask_nick && !match_ircglob(user->nick, discrim->mask_nick))
+ || (discrim->mask_ident && !match_ircglob(user->ident, discrim->mask_ident))
+ || (discrim->mask_host && !match_ircglob(user->hostname, discrim->mask_host))
+ || (discrim->mask_info && !match_ircglob(user->info, discrim->mask_info))) {
+ return 0;
+ }
+ }
+
if (discrim->channel && !GetUserMode(discrim->channel, user)) return 0;
access = user->handle_info ? user->handle_info->opserv_level : 0;
if ((access < discrim->min_level)
if (das.discrim->channel)
UnlockChannel(das.discrim->channel);
free(das.discrim->reason);
+
+ if(das.discrim->has_regex_nick)
+ regfree(&das.discrim->regex_nick);
+ if(das.discrim->has_regex_ident)
+ regfree(&das.discrim->regex_ident);
+ if(das.discrim->has_regex_host)
+ regfree(&das.discrim->regex_host);
+ if(das.discrim->has_regex_info)
+ regfree(&das.discrim->regex_info);
+
free(das.discrim);
dict_delete(das.dict);
return 1;