X-Git-Url: https://jfr.im/git/irc/evilnet/x3.git/blobdiff_plain/ba4b4d51cca3e321dbb82384f00b9458e72e7639..5f233568c3ce77b13d813d475429a9ff50037f94:/src/opserv.c diff --git a/src/opserv.c b/src/opserv.c index 5718793..4480881 100644 --- a/src/opserv.c +++ b/src/opserv.c @@ -182,12 +182,14 @@ static const struct message_entry msgtab[] = { { "OSMSG_KICKALL_DONE", "I have cleared out %s." }, { "OSMSG_LEAVING", "Leaving $b%s$b." }, { "OSMSG_MARK_INVALID", "Sorry, marks must contain only letters, numbers, and dashes ('-')." }, + { "OSMSG_MARK_NOTMARKED", "Action not mark but mark supplied. (Did you mean marked?)" }, { "OSMSG_MODE_SET", "I have set the modes for $b%s$b." }, { "OSMSG_OP_DONE", "Opped the requested lusers." }, { "OSMSG_OPALL_DONE", "Opped everyone on $b%s$b." }, { "OSMSG_HOP_DONE", "Halfopped the requested lusers." }, { "OSMSG_HOPALL_DONE", "Halfopped everyone on $b%s$b." }, { "OMSG_BAD_SVSNICK", "$b%s$b is an invalid nickname." }, + { "OSMSG_BAD_SVSCMDTARGET", "$b%s$b is an invalid target for %s." }, { "OSMSG_WHOIS_IDENT", "%s (%s@%s) from %d.%d.%d.%d" }, { "OSMSG_WHOIS_NICK", "Nick : %s" }, @@ -217,7 +219,8 @@ static const struct message_entry msgtab[] = { { "OSMSG_WHOIS_HIDECHANS", "Channel list omitted for your sanity." }, { "OSMSG_WHOIS_VERSION", "Version : %s" }, { "OSMSG_WHOIS_SSLFP", "SSL f/print : %s" }, - { "OSMSG_WHOIS_MARK", "Mark : %s" }, + { "OSMSG_WHOIS_MARK", "Mark : %s" }, + { "OSMSG_WHOIS_MARKS", "Marks : %s" }, { "OSMSG_WHOIS_NO_NOTICE", "No_notices : %s" }, { "OSMSG_UNBAN_DONE", "Ban(s) removed from channel %s." }, { "OSMSG_CHANNEL_VOICED", "All users on %s voiced." }, @@ -571,7 +574,7 @@ struct discrim_and_source { unsigned int disp_limit; }; -static discrim_t opserv_discrim_create(struct userNode *user, struct userNode *bot, unsigned int argc, char *argv[], int allow_channel); +static discrim_t opserv_discrim_create(struct userNode *user, struct userNode *bot, unsigned int argc, char *argv[], int allow_channel, const char *action); static unsigned int opserv_discrim_search(discrim_t discrim, discrim_search_func dsf, void *data); static int gag_helper_func(struct userNode *match, void *extra); static int ungag_helper_func(struct userNode *match, void *extra); @@ -583,10 +586,13 @@ typedef enum { REACT_GLINE, REACT_TRACK, REACT_SHUN, + REACT_TEMPSHUN, REACT_SVSJOIN, REACT_SVSPART, REACT_VERSION, - REACT_MARK + REACT_MARK, + REACT_NOTICEUSER, + REACT_MSGUSER } opserv_alert_reaction; struct opserv_user_alert { @@ -1458,6 +1464,22 @@ opserv_svsjoin(struct userNode *target, UNUSED_ARG(char *src_handle), UNUSED_ARG return; /* channel is invite only */ } + if (!IsOper(target) && (channel->modes & MODE_OPERSONLY)) { + return; /* user is not oper and channel is opers only */ + } + + if (!IsAdmin(target) && (channel->modes & MODE_ADMINSONLY)) { + return; /* user is not admin and channel is admin only */ + } + + if (target->handle_info && (channel->modes & MODE_REGONLY)) { + return; /* user is not authed and channel is authed only users */ + } + + if (!IsSSL(target) && (channel->modes & MODE_SSLONLY)) { + return; /* user is not SSL and channel is SSL only */ + } + if (channel->limit > 0) { if (channel->members.used >= channel->limit) { return; /* channel is invite on */ @@ -1510,6 +1532,12 @@ opserv_shun(struct userNode *target, char *src_handle, char *reason, unsigned lo return shun_add(src_handle, mask, duration, reason, now, 1); } +static void +opserv_tempshun(struct userNode *target, char *src_handle, char *reason) +{ + irc_tempshun(opserv, target, 0, reason); +} + static MODCMD_FUNC(cmd_sblock) { struct userNode *target; @@ -1566,7 +1594,7 @@ static MODCMD_FUNC(cmd_shun) struct shun *shun; reason = unsplit_string(argv+3, argc-3, NULL); - if (!is_shun(argv[1]) && !IsChannelName(argv[1]) && (argv[1][0] != '&')) { + if (!is_shun(argv[1])) { reply("MSG_INVALID_SHUN", argv[1]); return 0; } @@ -1705,6 +1733,11 @@ static MODCMD_FUNC(cmd_svsjoin) return 0; } + if (IsLocal(target)) { + reply("OSMSG_BAD_SVSCMDTARGET", argv[1], "SVSJOIN"); + return 0; + } + if (!(channel = GetChannel(argv[2]))) { channel = AddChannel(argv[2], now, NULL, NULL, NULL); } @@ -1726,6 +1759,12 @@ static MODCMD_FUNC(cmd_svsnick) reply("MSG_NICK_UNKNOWN", argv[1]); return 0; } + + if (IsLocal(target)) { + reply("OSMSG_BAD_SVSCMDTARGET", argv[1], "SVSNICK"); + return 0; + } + if(!is_valid_nick(argv[2])) { reply("OMSG_BAD_SVSNICK", argv[2]); return 0; @@ -1951,6 +1990,11 @@ static MODCMD_FUNC(cmd_svspart) return 0; } + if (IsLocal(target)) { + reply("OSMSG_BAD_SVSCMDTARGET", argv[1], "SVSPART"); + return 0; + } + if (!GetUserMode(target_channel, target)) { reply("OSMSG_NOT_ON_CHANNEL", cmd->parent->bot->nick, target_channel->name); return 0; @@ -2174,6 +2218,28 @@ static MODCMD_FUNC(cmd_whois) if(target->mark) { reply("OSMSG_WHOIS_MARK", target->mark); } + if(target->marks) { + char markbuf[MAXLEN] = ""; + unsigned int ii = 0; + + string_list_sort(user->marks); + + for (ii=0; iimarks->used; ii++) + { + if (markbuf[0] && strlen(markbuf) + strlen(user->marks->list[ii]) + 4 > 70) { + reply("OSMSG_WHOIS_MARKS", markbuf); + memset(&markbuf, 0, MAXLEN); + } + + if (markbuf[0]) + strcat(markbuf, ", "); + strcat(markbuf, user->marks->list[ii]); + } + + if (markbuf[0]) + reply("OSMSG_WHOIS_MARKS", markbuf); + } + reply("OSMSG_WHOIS_NO_NOTICE", target->no_notice ? "YES":"NO"); if (target->modes) { @@ -2528,10 +2594,13 @@ static MODCMD_FUNC(cmd_stats_alerts) { case REACT_GLINE: reaction = "gline"; break; case REACT_TRACK: reaction = "track"; break; case REACT_SHUN: reaction = "shun"; break; + case REACT_TEMPSHUN: reaction = "tempshun"; break; case REACT_SVSJOIN: reaction = "svsjoin"; break; case REACT_SVSPART: reaction = "svspart"; break; case REACT_VERSION: reaction = "version"; break; case REACT_MARK: reaction = "mark"; break; + case REACT_NOTICEUSER: reaction = "noticeuser"; break; + case REACT_MSGUSER: reaction = "msguser"; break; default: reaction = ""; break; } reply("OSMSG_ALERT_IS", iter_key(it), reaction, alert->owner); @@ -2915,7 +2984,7 @@ opserv_channel_check(struct chanNode *newchan, UNUSED_ARG(void *extra)) } static void -opserv_channel_delete(struct chanNode *chan) +opserv_channel_delete(struct chanNode *chan, UNUSED_ARG(void *extra)) { timeq_del(0, opserv_part_channel, chan, TIMEQ_IGNORE_WHEN); } @@ -2955,7 +3024,9 @@ opserv_join_check(struct modeNode *mNode, UNUSED_ARG(void *extra)) if (IsService(user)) return 0; - dict_foreach(opserv_channel_alerts, alert_check_user, user); + /* Check for alerts, and stop if we find one that kills them. */ + if (dict_foreach(opserv_user_alerts, alert_check_user, user)) + return 1; if (opserv && channel->bad_channel) { opserv_debug("Found $b%s$b in bad-word channel $b%s$b; removing the user.", user->nick, channel->name); @@ -4751,7 +4822,7 @@ add_gag_helper(const char *key, void *data, UNUSED_ARG(void *extra)) } static struct opserv_user_alert * -opserv_add_user_alert(struct userNode *req, const char *name, opserv_alert_reaction reaction, const char *text_discrim, int last, int expire) +opserv_add_user_alert(struct userNode *req, const char *name, opserv_alert_reaction reaction, const char *text_discrim, int last, int expire, const char *action) { unsigned int wordc; char *wordv[MAXNUMPARAMS], *discrim_copy; @@ -4768,7 +4839,7 @@ opserv_add_user_alert(struct userNode *req, const char *name, opserv_alert_react alert->last = last; discrim_copy = strdup(text_discrim); /* save a copy of the discrim */ wordc = split_line(discrim_copy, false, ArrayLength(wordv), wordv); - alert->discrim = opserv_discrim_create(req, opserv, wordc, wordv, 0); + alert->discrim = opserv_discrim_create(req, opserv, wordc, wordv, 0, action); alert->expire = expire; /* Check for missing required criteria or broken records */ if (!alert->discrim || (reaction==REACT_SVSJOIN && !alert->discrim->chantarget) || @@ -4856,6 +4927,8 @@ add_user_alert(const char *key, void *data, UNUSED_ARG(void *extra)) reaction = REACT_TRACK; else if (!irccasecmp(react, "shun")) reaction = REACT_SHUN; + else if (!irccasecmp(react, "tempshun")) + reaction = REACT_TEMPSHUN; else if (!irccasecmp(react, "svsjoin")) reaction = REACT_SVSJOIN; else if (!irccasecmp(react, "svspart")) @@ -4864,11 +4937,15 @@ add_user_alert(const char *key, void *data, UNUSED_ARG(void *extra)) reaction = REACT_VERSION; else if (!irccasecmp(react, "mark")) reaction = REACT_MARK; + else if (!irccasecmp(react, "noticeuser")) + reaction = REACT_NOTICEUSER; + else if (!irccasecmp(react, "msguser")) + reaction = REACT_MSGUSER; else { log_module(OS_LOG, LOG_ERROR, "Invalid reaction %s for alert %s.", react, key); return 0; } - alert = opserv_add_user_alert(opserv, key, reaction, discrim, last, expire); + alert = opserv_add_user_alert(opserv, key, reaction, discrim, last, expire, react); if (!alert) { log_module(OS_LOG, LOG_ERROR, "Unable to create alert %s from database.", key); return 0; @@ -5147,10 +5224,13 @@ opserv_saxdb_write(struct saxdb_context *ctx) case REACT_GLINE: reaction = "gline"; break; case REACT_TRACK: reaction = "track"; break; case REACT_SHUN: reaction = "shun"; break; + case REACT_TEMPSHUN: reaction = "tempshun"; break; case REACT_SVSJOIN: reaction = "svsjoin"; break; case REACT_SVSPART: reaction = "svspart"; break; case REACT_VERSION: reaction = "version"; break; case REACT_MARK: reaction = "mark"; break; + case REACT_NOTICEUSER: reaction = "noticeuser"; break; + case REACT_MSGUSER: reaction = "msguser"; break; default: reaction = NULL; log_module(OS_LOG, LOG_ERROR, "Invalid reaction type %d for alert %s (while writing database).", alert->reaction, iter_key(it)); @@ -5252,7 +5332,7 @@ static MODCMD_FUNC(cmd_settime) } static discrim_t -opserv_discrim_create(struct userNode *user, struct userNode *bot, unsigned int argc, char *argv[], int allow_channel) +opserv_discrim_create(struct userNode *user, struct userNode *bot, unsigned int argc, char *argv[], int allow_channel, const char *action) { unsigned int i, j; discrim_t discrim; @@ -5360,6 +5440,10 @@ opserv_discrim_create(struct userNode *user, struct userNode *bot, unsigned int goto fail; } } else if (irccasecmp(argv[i], "mark") == 0) { + if (irccasecmp(action, "mark")) { + send_message(user, bot, "OSMSG_MARK_NOTMARKED"); + goto fail; + } if(!is_valid_mark(argv[i+1])) { send_message(user, bot, "OSMSG_MARK_INVALID"); goto fail; @@ -5647,6 +5731,20 @@ discrim_match(discrim_t discrim, struct userNode *user) { unsigned int level, i; char *scmp=NULL, *dcmp=NULL; + int markmatched = 0; + + if (discrim->mask_mark) + { + unsigned int ii = 0; + + if (user->mark && match_ircglob(user->mark, discrim->mask_mark)) + markmatched = 1; + + if (user->marks) + for (ii=0; iimarks->used; ii++) + if (match_ircglob(user->marks->list[ii], discrim->mask_mark)) + markmatched = 1; + } if ((user->timestamp < discrim->min_ts) || (user->timestamp > discrim->max_ts) @@ -5657,7 +5755,7 @@ discrim_match(discrim_t discrim, struct userNode *user) || (discrim->info_space == 0 && user->info[0] == ' ') || (discrim->info_space == 1 && user->info[0] != ' ') || (discrim->server && !match_ircglob(user->uplink->name, discrim->server)) - || (discrim->mask_mark && (!user->mark || !match_ircglob(user->mark, discrim->mask_mark))) + || (discrim->mask_mark && !markmatched) || (discrim->accountmask && (!user->handle_info || !match_ircglob(user->handle_info->handle, discrim->accountmask))) || (discrim->ip_mask_bits && !irc_check_mask(&user->ip, &discrim->ip_mask, discrim->ip_mask_bits)) ) @@ -5715,46 +5813,80 @@ discrim_match(discrim_t discrim, struct userNode *user) if (discrim->modes) { unsigned int ii, matches = 0; + unsigned int negate = 0; for (ii = 0; ii < strlen(discrim->modes); ii++) { switch(discrim->modes[ii]) { + case '+': + negate = 0; + matches++; + break; + case '-': + negate = 1; + matches++; + break; case 'O': - if(IsOper(user)) matches++; + if(IsOper(user) != 0 != negate) matches++; break; case 'o': - if(IsOper(user)) matches++; + if(IsOper(user) != 0 != negate) matches++; break; case 'i': - if(IsInvisible(user)) matches++; + if(IsInvisible(user) != 0 != negate) matches++; break; case 'w': - if(IsWallOp(user)) matches++; + if(IsWallOp(user) != 0 != negate) matches++; break; case 'd': - if(IsDeaf(user)) matches++; + if(IsDeaf(user) != 0 != negate) matches++; break; case 'k': - if(IsService(user)) matches++; + if(IsService(user) != 0 != negate) matches++; break; case 'g': - if(IsGlobal(user)) matches++; + if(IsGlobal(user) != 0 != negate) matches++; break; case 'h': - if(IsSetHost(user)) matches++; + if(IsSetHost(user) != 0 != negate) matches++; break; case 'B': - if(IsBotM(user)) matches++; + if(IsBotM(user) != 0 != negate) matches++; break; + case 'p': case 'n': - if(IsHideChans(user)) matches++; + if(IsHideChans(user) != 0 != negate) matches++; break; case 'I': - if(IsHideIdle(user)) matches++; + if(IsHideIdle(user) != 0 != negate) matches++; break; case 'X': - if(IsXtraOp(user)) matches++; + if(IsXtraOp(user) != 0 != negate) matches++; break; case 'x': - if(IsHiddenHost(user)) matches++; + if(IsHiddenHost(user) != 0 != negate) matches++; + break; + case 'a': + if(IsAdmin(user) != 0 != negate) matches++; + break; + case 'z': + if(IsSSL(user) != 0 != negate) matches++; + break; + case 'D': + if(IsPrivDeaf(user) != 0 != negate) matches++; + break; + case 'R': + if(IsAccountOnly(user) != 0 != negate) matches++; + break; + case 'W': + if(IsWhoisNotice(user) != 0 != negate) matches++; + break; + case 'H': + if(IsHideOper(user) != 0 != negate) matches++; + break; + case 'L': + if(IsHideOper(user) != 0 != negate) matches++; + break; + case 'q': + if(IsCommonChansOnly(user) != 0 != negate) matches++; break; } } @@ -5954,6 +6086,18 @@ trace_shun_func(struct userNode *match, void *extra) return 0; } +static int +trace_tempshun_func(struct userNode *match, void *extra) +{ + struct discrim_and_source *das = extra; + + if (is_oper_victim(das->source, match, das->discrim->match_opers, 1) && is_trust_victim(match, das->discrim->match_trusted)) { + opserv_tempshun(match, das->source->handle_info->handle, das->discrim->reason); + } + + return 0; +} + static int trace_kill_func(struct userNode *match, void *extra) { @@ -6191,6 +6335,8 @@ static MODCMD_FUNC(cmd_trace) action = trace_gline_func; else if (!irccasecmp(argv[1], "shun")) action = trace_shun_func; + else if (!irccasecmp(argv[1], "tempshun")) + action = trace_tempshun_func; else if (!irccasecmp(argv[1], "kill")) action = trace_kill_func; else if (!irccasecmp(argv[1], "gag")) @@ -6216,7 +6362,7 @@ static MODCMD_FUNC(cmd_trace) das.dict = NULL; das.source = user; das.destination = cmd->parent->bot; - das.discrim = opserv_discrim_create(user, cmd->parent->bot, argc-2, argv+2, 1); + das.discrim = opserv_discrim_create(user, cmd->parent->bot, argc-2, argv+2, 1, argv[1]); if (!das.discrim) return 0; @@ -6754,6 +6900,9 @@ alert_check_user(const char *key, void *data, void *extra) case REACT_SHUN: opserv_shun(user, alert->owner, alert->discrim->reason, alert->discrim->duration); return 1; + case REACT_TEMPSHUN: + opserv_tempshun(user, alert->owner, alert->discrim->reason); + return 1; case REACT_SVSJOIN: opserv_svsjoin(user, alert->owner, alert->discrim->reason, alert->discrim->chantarget, alert->discrim->checkrestrictions); break; @@ -6784,12 +6933,18 @@ alert_check_user(const char *key, void *data, void *extra) add_track_user(user); #endif break; + case REACT_NOTICEUSER: + irc_notice_user(opserv, user, alert->discrim->reason); + break; + case REACT_MSGUSER: + irc_privmsg_user(opserv, user, alert->discrim->reason); + break; } return 0; } static void -opserv_alert_check_account(struct userNode *user, UNUSED_ARG(struct handle_info *old_handle)) +opserv_alert_check_account(struct userNode *user, UNUSED_ARG(struct handle_info *old_handle), UNUSED_ARG(void *extra)) { dict_foreach(opserv_account_based_alerts, alert_check_user, user); } @@ -6812,7 +6967,7 @@ opserv_alert_check_nick(struct userNode *user, UNUSED_ARG(const char *old_nick), } static void -opserv_staff_alert(struct userNode *user, UNUSED_ARG(struct handle_info *old_handle)) +opserv_staff_alert(struct userNode *user, UNUSED_ARG(struct handle_info *old_handle), UNUSED_ARG(void *extra)) { const char *type; @@ -6961,6 +7116,8 @@ static MODCMD_FUNC(cmd_addalert) #endif } else if (!irccasecmp(argv[2], "shun")) reaction = REACT_SHUN; + else if(!irccasecmp(argv[2], "tempshun")) + reaction = REACT_TEMPSHUN; else if(!irccasecmp(argv[2], "svsjoin")) reaction = REACT_SVSJOIN; else if(!irccasecmp(argv[2], "svspart")) @@ -6969,6 +7126,10 @@ static MODCMD_FUNC(cmd_addalert) reaction = REACT_VERSION; else if(!irccasecmp(argv[2], "mark")) reaction = REACT_MARK; + else if(!irccasecmp(argv[2], "noticeuser")) + reaction = REACT_NOTICEUSER; + else if(!irccasecmp(argv[2], "msguser")) + reaction = REACT_MSGUSER; else { reply("OSMSG_UNKNOWN_REACTION", argv[2]); return 0; @@ -6978,7 +7139,7 @@ static MODCMD_FUNC(cmd_addalert) expire = now + ParseInterval(argv[4]); if (!svccmd_can_invoke(user, opserv_service->bot, subcmd, channel, SVCCMD_NOISY) - || !opserv_add_user_alert(user, name, reaction, unsplit_string(argv + (expire ? 5 : 3), argc - (expire ? 5 : 3), NULL), 0, expire)) { + || !opserv_add_user_alert(user, name, reaction, unsplit_string(argv + (expire ? 5 : 3), argc - (expire ? 5 : 3), NULL), 0, expire, argv[2])) { reply("OSMSG_ALERT_ADD_FAILED"); return 0; } @@ -7215,7 +7376,7 @@ opserv_db_init(void) { } static void -opserv_db_cleanup(void) +opserv_db_cleanup(UNUSED_ARG(void* extra)) { unsigned int nn; @@ -7253,9 +7414,12 @@ init_opserv(const char *nick) opserv_define_func("ACCESS", cmd_access, 0, 0, 0); opserv_define_func("ADDALERT", cmd_addalert, 800, 0, 4); opserv_define_func("ADDALERT NOTICE", NULL, 0, 0, 0); + opserv_define_func("ADDALERT NOTICEUSER", NULL, 0, 0, 0); + opserv_define_func("ADDALERT MSGUSER", NULL, 0, 0, 0); opserv_define_func("ADDALERT SILENT", NULL, 900, 0, 0); opserv_define_func("ADDALERT GLINE", NULL, 900, 0, 0); opserv_define_func("ADDALERT SHUN", NULL, 900, 0, 0); + opserv_define_func("ADDALERT TEMPSHUN", NULL, 900, 0, 0); opserv_define_func("ADDALERT TRACK", NULL, 900, 0, 0); opserv_define_func("ADDALERT KILL", NULL, 900, 0, 0); opserv_define_func("ADDALERT SVSJOIN", NULL, 999, 0, 0); @@ -7369,6 +7533,7 @@ init_opserv(const char *nick) opserv_define_func("TRACE DOMAINS", NULL, 0, 0, 0); opserv_define_func("TRACE GLINE", NULL, 600, 0, 0); opserv_define_func("TRACE SHUN", NULL, 600, 0, 0); + opserv_define_func("TRACE TEMPSHUN", NULL, 600, 0, 0); opserv_define_func("TRACE GAG", NULL, 600, 0, 0); opserv_define_func("TRACE KILL", NULL, 600, 0, 0); opserv_define_func("TRACE VERSION", NULL, 999, 0, 0); @@ -7401,10 +7566,10 @@ init_opserv(const char *nick) reg_nick_change_func(opserv_alert_check_nick, NULL); reg_del_user_func(opserv_user_cleanup, NULL); reg_new_channel_func(opserv_channel_check, NULL); - reg_del_channel_func(opserv_channel_delete); + reg_del_channel_func(opserv_channel_delete, NULL); reg_join_func(opserv_join_check, NULL); - reg_auth_func(opserv_staff_alert); - reg_auth_func(opserv_alert_check_account); + reg_auth_func(opserv_staff_alert, NULL); + reg_auth_func(opserv_alert_check_account, NULL); reg_notice_func(opserv, opserv_notice_handler); opserv_db_init(); @@ -7422,6 +7587,6 @@ init_opserv(const char *nick) /* start the karma timer, using the saved one if available */ routing_karma_timer(dict_find(opserv_routing_plan_options, "KARMA_TIMER", NULL)); - reg_exit_func(opserv_db_cleanup); + reg_exit_func(opserv_db_cleanup, NULL); message_register_table(msgtab); }