diff --git a/include/s_conf.h b/include/s_conf.h index f7681ce5..b31db910 100644 --- a/include/s_conf.h +++ b/include/s_conf.h @@ -140,6 +140,12 @@ struct ConfItem #define IsConfAllowSCTP(x) ((x)->flags & CONF_FLAGS_ALLOW_SCTP) #define IsConfKlineSpoof(x) ((x)->flags & CONF_FLAGS_KLINE_SPOOF) +enum stats_l_oper_only { + STATS_L_OPER_ONLY_NO, + STATS_L_OPER_ONLY_SELF, + STATS_L_OPER_ONLY_YES, +}; + /* flag definitions for opers now in client.h */ struct config_file_entry @@ -191,6 +197,7 @@ struct config_file_entry int stats_h_oper_only; int stats_o_oper_only; int stats_k_oper_only; + enum stats_l_oper_only stats_l_oper_only; int stats_i_oper_only; int stats_P_oper_only; int map_oper_only; diff --git a/ircd/newconf.c b/ircd/newconf.c index ee54fc78..e00d4a71 100644 --- a/ircd/newconf.c +++ b/ircd/newconf.c @@ -1542,6 +1542,21 @@ conf_set_general_stats_i_oper_only(void *data) conf_report_error("Invalid setting '%s' for general::stats_i_oper_only.", val); } +static void +conf_set_general_stats_l_oper_only(void *data) +{ + char *val = data; + + if(rb_strcasecmp(val, "yes") == 0) + ConfigFileEntry.stats_l_oper_only = STATS_L_OPER_ONLY_YES; + else if(rb_strcasecmp(val, "self") == 0) + ConfigFileEntry.stats_l_oper_only = STATS_L_OPER_ONLY_SELF; + else if(rb_strcasecmp(val, "no") == 0) + ConfigFileEntry.stats_l_oper_only = STATS_L_OPER_ONLY_NO; + else + conf_report_error("Invalid setting '%s' for general::stats_l_oper_only.", val); +} + static void conf_set_general_compression_level(void *data) { @@ -2651,8 +2666,9 @@ static struct ConfEntry conf_general_table[] = { "compression_level", CF_INT, conf_set_general_compression_level, 0, NULL }, { "havent_read_conf", CF_YESNO, conf_set_general_havent_read_conf, 0, NULL }, { "hide_error_messages",CF_STRING, conf_set_general_hide_error_messages,0, NULL }, - { "stats_k_oper_only", CF_STRING, conf_set_general_stats_k_oper_only, 0, NULL }, { "stats_i_oper_only", CF_STRING, conf_set_general_stats_i_oper_only, 0, NULL }, + { "stats_k_oper_only", CF_STRING, conf_set_general_stats_k_oper_only, 0, NULL }, + { "stats_l_oper_only", CF_STRING, conf_set_general_stats_l_oper_only, 0, NULL }, { "default_umodes", CF_QSTRING, conf_set_general_default_umodes, 0, NULL }, { "default_operstring", CF_QSTRING, NULL, REALLEN, &ConfigFileEntry.default_operstring }, diff --git a/ircd/s_conf.c b/ircd/s_conf.c index 2aae3dde..ebdee51f 100644 --- a/ircd/s_conf.c +++ b/ircd/s_conf.c @@ -738,6 +738,7 @@ set_default_conf(void) ConfigFileEntry.stats_e_disabled = false; ConfigFileEntry.stats_o_oper_only = false; ConfigFileEntry.stats_k_oper_only = 1; /* masked */ + ConfigFileEntry.stats_l_oper_only = 1; /* self */ ConfigFileEntry.stats_i_oper_only = 1; /* masked */ ConfigFileEntry.stats_P_oper_only = false; ConfigFileEntry.stats_c_oper_only = false; diff --git a/modules/m_stats.c b/modules/m_stats.c index 53faa1bb..2464eed9 100644 --- a/modules/m_stats.c +++ b/modules/m_stats.c @@ -1523,12 +1523,17 @@ stats_ltrace(struct Client *source_p, int parc, const char *parv[]) const char *name; char statchar = parv[1][0]; + if (ConfigFileEntry.stats_l_oper_only == STATS_L_OPER_ONLY_YES && !IsOperGeneral(source_p)) + { + sendto_one_numeric(source_p, ERR_NOPRIVILEGES, form_str(ERR_NOPRIVILEGES)); + return; + } + /* this is def targeted at us somehow.. */ - if(parc > 2 && !EmptyString(parv[2])) + if (parc > 2 && !EmptyString(parv[2])) { /* directed at us generically? */ - if(match(parv[2], me.name) || - (!MyClient(source_p) && !irccmp(parv[2], me.id))) + if (match(parv[2], me.name) || (!MyClient(source_p) && !irccmp(parv[2], me.id))) { name = me.name; doall = true; @@ -1540,24 +1545,31 @@ stats_ltrace(struct Client *source_p, int parc, const char *parv[]) } /* must be directed at a specific person thats not us */ - if(!doall && !wilds) + if (!doall && !wilds) { struct Client *target_p; - if(MyClient(source_p)) + if (MyClient(source_p)) target_p = find_named_person(name); else target_p = find_person(name); - if(target_p != NULL) + if (target_p != source_p && ConfigFileEntry.stats_l_oper_only != STATS_L_OPER_ONLY_NO + && !IsOperGeneral(source_p)) + { + sendto_one_numeric(source_p, ERR_NOPRIVILEGES, form_str(ERR_NOPRIVILEGES)); + } + else if (target_p != NULL) { stats_spy(source_p, statchar, target_p->name); stats_l_client(source_p, target_p, statchar); } else + { sendto_one_numeric(source_p, ERR_NOSUCHSERVER, form_str(ERR_NOSUCHSERVER), name); + } return; } @@ -1570,7 +1582,16 @@ stats_ltrace(struct Client *source_p, int parc, const char *parv[]) stats_spy(source_p, statchar, name); - if(doall) + if (ConfigFileEntry.stats_l_oper_only != STATS_L_OPER_ONLY_NO && !IsOperGeneral(source_p)) + { + if (doall && MyClient(source_p)) + stats_l_client(source_p, source_p, statchar); + else + sendto_one_numeric(source_p, ERR_NOPRIVILEGES, form_str(ERR_NOPRIVILEGES)); + return; + } + + if (doall) { /* local opers get everyone */ if(MyOper(source_p))