Rework oper hiding

As it stands, oper hiding is rather messy and inconsistent. Add
SeesOper(target, source), which is true iff target should appear as an
oper to source. If I haven't missed something, all commands that reveal
oper status now use the same logic.

general::hide_opers_in_whois is a special case, and affects /whois only.

general::hide_opers is introduced, and has the same effect as giving
everyone oper:hidden. All commands that reveal oper status respect both.
This commit is contained in:
Ed Kellett 2019-07-07 04:57:53 +01:00
parent f7f1c50494
commit 1123eefcb0
No known key found for this signature in database
GPG key ID: CB9986DEF342FABC
10 changed files with 27 additions and 18 deletions

View file

@ -239,6 +239,7 @@ struct config_file_entry
int certfp_method; int certfp_method;
int hide_opers_in_whois; int hide_opers_in_whois;
int hide_opers;
}; };
struct config_channel_entry struct config_channel_entry

View file

@ -166,6 +166,8 @@ extern void cluster_generic(struct Client *, const char *, int cltype,
#define IsOperRemoteBan(x) (HasPrivilege((x), "oper:remoteban")) #define IsOperRemoteBan(x) (HasPrivilege((x), "oper:remoteban"))
#define IsOperMassNotice(x) (HasPrivilege((x), "oper:mass_notice")) #define IsOperMassNotice(x) (HasPrivilege((x), "oper:mass_notice"))
#define SeesOper(target, source) (IsOper((target)) && (!ConfigFileEntry.hide_opers && !HasPrivilege((target), "oper:hidden") || IsOper((source))))
extern struct oper_conf *make_oper_conf(void); extern struct oper_conf *make_oper_conf(void);
extern void free_oper_conf(struct oper_conf *); extern void free_oper_conf(struct oper_conf *);
extern void clear_oper_conf(void); extern void clear_oper_conf(void);

View file

@ -2797,6 +2797,7 @@ static struct ConfEntry conf_general_table[] =
{ "max_ratelimit_tokens", CF_INT, NULL, 0, &ConfigFileEntry.max_ratelimit_tokens }, { "max_ratelimit_tokens", CF_INT, NULL, 0, &ConfigFileEntry.max_ratelimit_tokens },
{ "away_interval", CF_INT, NULL, 0, &ConfigFileEntry.away_interval }, { "away_interval", CF_INT, NULL, 0, &ConfigFileEntry.away_interval },
{ "hide_opers_in_whois", CF_YESNO, NULL, 0, &ConfigFileEntry.hide_opers_in_whois }, { "hide_opers_in_whois", CF_YESNO, NULL, 0, &ConfigFileEntry.hide_opers_in_whois },
{ "hide_opers", CF_YESNO, NULL, 0, &ConfigFileEntry.hide_opers },
{ "certfp_method", CF_STRING, conf_set_general_certfp_method, 0, NULL }, { "certfp_method", CF_STRING, conf_set_general_certfp_method, 0, NULL },
{ "\0", 0, NULL, 0, NULL } { "\0", 0, NULL, 0, NULL }
}; };

View file

@ -809,6 +809,7 @@ set_default_conf(void)
ConfigFileEntry.nicklen = NICKLEN; ConfigFileEntry.nicklen = NICKLEN;
ConfigFileEntry.certfp_method = RB_SSL_CERTFP_METH_CERT_SHA1; ConfigFileEntry.certfp_method = RB_SSL_CERTFP_METH_CERT_SHA1;
ConfigFileEntry.hide_opers_in_whois = 0; ConfigFileEntry.hide_opers_in_whois = 0;
ConfigFileEntry.hide_opers = 0;
if (!alias_dict) if (!alias_dict)
alias_dict = rb_dictionary_create("alias", rb_strcasecmp); alias_dict = rb_dictionary_create("alias", rb_strcasecmp);

View file

@ -167,7 +167,7 @@ do_etrace(struct Client *source_p, int ipv4, int ipv6)
sendto_one(source_p, form_str(RPL_ETRACE), sendto_one(source_p, form_str(RPL_ETRACE),
me.name, source_p->name, me.name, source_p->name,
IsOper(target_p) ? "Oper" : "User", SeesOper(target_p, source_p) ? "Oper" : "User",
get_client_class(target_p), get_client_class(target_p),
target_p->name, target_p->username, target_p->host, target_p->name, target_p->username, target_p->host,
show_ip(source_p, target_p) ? target_p->sockhost : "255.255.255.255", show_ip(source_p, target_p) ? target_p->sockhost : "255.255.255.255",
@ -206,14 +206,14 @@ do_single_etrace(struct Client *source_p, struct Client *target_p)
if(!show_ip(source_p, target_p)) if(!show_ip(source_p, target_p))
sendto_one(source_p, form_str(RPL_ETRACEFULL), sendto_one(source_p, form_str(RPL_ETRACEFULL),
me.name, source_p->name, me.name, source_p->name,
IsOper(target_p) ? "Oper" : "User", SeesOper(target_p, source_p) ? "Oper" : "User",
get_client_class(target_p), get_client_class(target_p),
target_p->name, target_p->username, target_p->host, target_p->name, target_p->username, target_p->host,
"255.255.255.255", "<hidden> <hidden>", target_p->info); "255.255.255.255", "<hidden> <hidden>", target_p->info);
else else
sendto_one(source_p, form_str(RPL_ETRACEFULL), sendto_one(source_p, form_str(RPL_ETRACEFULL),
me.name, source_p->name, me.name, source_p->name,
IsOper(target_p) ? "Oper" : "User", SeesOper(target_p, source_p) ? "Oper" : "User",
get_client_class(target_p), get_client_class(target_p),
target_p->name, target_p->username, target_p->name, target_p->username,
target_p->host, target_p->sockhost, target_p->host, target_p->sockhost,
@ -278,7 +278,7 @@ m_chantrace(struct MsgBuf *msgbuf_p, struct Client *client_p, struct Client *sou
sendto_one(source_p, form_str(RPL_ETRACE), sendto_one(source_p, form_str(RPL_ETRACE),
me.name, source_p->name, me.name, source_p->name,
IsOper(target_p) ? "Oper" : "User", SeesOper(target_p, source_p) ? "Oper" : "User",
/* class field -- pretend its server.. */ /* class field -- pretend its server.. */
target_p->servptr->name, target_p->servptr->name,
target_p->name, target_p->username, target_p->host, target_p->name, target_p->username, target_p->host,
@ -323,7 +323,7 @@ match_masktrace(struct Client *source_p, rb_dlink_list *list,
sendto_one(source_p, form_str(RPL_ETRACE), sendto_one(source_p, form_str(RPL_ETRACE),
me.name, source_p->name, me.name, source_p->name,
IsOper(target_p) ? "Oper" : "User", SeesOper(target_p, source_p) ? "Oper" : "User",
/* class field -- pretend its server.. */ /* class field -- pretend its server.. */
target_p->servptr->name, target_p->servptr->name,
target_p->name, target_p->username, target_p->host, target_p->name, target_p->username, target_p->host,

View file

@ -830,7 +830,7 @@ stats_operedup (struct Client *source_p)
{ {
target_p = oper_ptr->data; target_p = oper_ptr->data;
if(IsOperInvis(target_p) && !IsOper(source_p)) if(!SeesOper(target_p, source_p))
continue; continue;
if(target_p->user->away) if(target_p->user->away)

View file

@ -204,6 +204,9 @@ m_trace(struct MsgBuf *msgbuf_p, struct Client *client_p, struct Client *source_
if(!doall && wilds && (match(tname, target_p->name) == 0)) if(!doall && wilds && (match(tname, target_p->name) == 0))
continue; continue;
if(!SeesOper(target_p, source_p))
continue;
report_this_status(source_p, target_p); report_this_status(source_p, target_p);
} }
@ -233,14 +236,14 @@ m_trace(struct MsgBuf *msgbuf_p, struct Client *client_p, struct Client *source_
target_p = ptr->data; target_p = ptr->data;
/* dont show invisible users to remote opers */ /* dont show invisible users to remote opers */
if(IsInvisible(target_p) && dow && !MyConnect(source_p) && !IsOper(target_p)) if(IsInvisible(target_p) && dow && !MyConnect(source_p) && !SeesOper(target_p, source_p))
continue; continue;
if(!doall && wilds && !match(tname, target_p->name)) if(!doall && wilds && !match(tname, target_p->name))
continue; continue;
/* remote opers may not see invisible normal users */ /* remote opers may not see invisible normal users */
if(dow && !MyConnect(source_p) && !IsOper(target_p) && if(dow && !MyConnect(source_p) && !SeesOper(target_p, source_p) &&
IsInvisible(target_p)) IsInvisible(target_p))
continue; continue;
@ -379,8 +382,8 @@ report_this_status(struct Client *source_p, struct Client *target_p)
case STAT_CLIENT: case STAT_CLIENT:
{ {
sendto_one_numeric(source_p, sendto_one_numeric(source_p,
IsOper(target_p) ? RPL_TRACEOPERATOR : RPL_TRACEUSER, SeesOper(target_p, source_p) ? RPL_TRACEOPERATOR : RPL_TRACEUSER,
IsOper(target_p) ? form_str(RPL_TRACEOPERATOR) : form_str(RPL_TRACEUSER), SeesOper(target_p, source_p) ? form_str(RPL_TRACEOPERATOR) : form_str(RPL_TRACEUSER),
class_name, name, class_name, name,
show_ip(source_p, target_p) ? ip : empty_sockhost, show_ip(source_p, target_p) ? ip : empty_sockhost,
(unsigned long)(rb_current_time() - target_p->localClient->lasttime), (unsigned long)(rb_current_time() - target_p->localClient->lasttime),

View file

@ -33,6 +33,7 @@
#include "parse.h" #include "parse.h"
#include "modules.h" #include "modules.h"
#include "s_conf.h" #include "s_conf.h"
#include "s_newconf.h"
static const char userhost_desc[] = static const char userhost_desc[] =
"Provides the USERHOST command to show a user's host"; "Provides the USERHOST command to show a user's host";
@ -85,7 +86,7 @@ m_userhost(struct MsgBuf *msgbuf_p, struct Client *client_p, struct Client *sour
{ {
rl = sprintf(response, "%s%s=%c%s@%s ", rl = sprintf(response, "%s%s=%c%s@%s ",
target_p->name, target_p->name,
IsOper(target_p) ? "*" : "", SeesOper(target_p, source_p) ? "*" : "",
(target_p->user->away) ? '-' : '+', (target_p->user->away) ? '-' : '+',
target_p->username, target_p->username,
target_p->sockhost); target_p->sockhost);
@ -94,7 +95,7 @@ m_userhost(struct MsgBuf *msgbuf_p, struct Client *client_p, struct Client *sour
{ {
rl = sprintf(response, "%s%s=%c%s@%s ", rl = sprintf(response, "%s%s=%c%s@%s ",
target_p->name, target_p->name,
IsOper(target_p) ? "*" : "", SeesOper(target_p, source_p) ? "*" : "",
(target_p->user->away) ? '-' : '+', (target_p->user->away) ? '-' : '+',
target_p->username, target_p->host); target_p->username, target_p->host);
} }

View file

@ -218,7 +218,7 @@ m_who(struct MsgBuf *msgbuf_p, struct Client *client_p, struct Client *source_p,
/* '/who nick' */ /* '/who nick' */
if(((target_p = find_named_person(mask)) != NULL) && if(((target_p = find_named_person(mask)) != NULL) &&
(!server_oper || IsOper(target_p))) (!server_oper || SeesOper(target_p, source_p)))
{ {
int isinvis = 0; int isinvis = 0;
@ -314,7 +314,7 @@ who_common_channel(struct Client *source_p, struct Channel *chptr,
if(!IsInvisible(target_p) || IsMarked(target_p)) if(!IsInvisible(target_p) || IsMarked(target_p))
continue; continue;
if(server_oper && !IsOper(target_p)) if(server_oper && !SeesOper(target_p, source_p))
continue; continue;
SetMark(target_p); SetMark(target_p);
@ -387,7 +387,7 @@ who_global(struct Client *source_p, const char *mask, int server_oper, int opers
continue; continue;
} }
if(server_oper && !IsOper(target_p)) if(server_oper && !SeesOper(target_p, source_p))
continue; continue;
if(maxmatches > 0) if(maxmatches > 0)
@ -435,7 +435,7 @@ do_who_on_channel(struct Client *source_p, struct Channel *chptr,
msptr = ptr->data; msptr = ptr->data;
target_p = msptr->client_p; target_p = msptr->client_p;
if(server_oper && !IsOper(target_p)) if(server_oper && !SeesOper(target_p, source_p))
continue; continue;
if(member || !IsInvisible(target_p)) if(member || !IsInvisible(target_p))
@ -488,7 +488,7 @@ do_who(struct Client *source_p, struct Client *target_p, struct membership *mspt
const char *q; const char *q;
sprintf(status, "%c%s%s", sprintf(status, "%c%s%s",
target_p->user->away ? 'G' : 'H', IsOper(target_p) ? "*" : "", msptr ? find_channel_status(msptr, fmt->fields || IsCapable(source_p, CLICAP_MULTI_PREFIX)) : ""); target_p->user->away ? 'G' : 'H', SeesOper(target_p, source_p) ? "*" : "", msptr ? find_channel_status(msptr, fmt->fields || IsCapable(source_p, CLICAP_MULTI_PREFIX)) : "");
if (fmt->fields == 0) if (fmt->fields == 0)
sendto_one(source_p, form_str(RPL_WHOREPLY), me.name, sendto_one(source_p, form_str(RPL_WHOREPLY), me.name,

View file

@ -309,7 +309,7 @@ single_whois(struct Client *source_p, struct Client *target_p, int operspy)
sendto_one_numeric(source_p, RPL_AWAY, form_str(RPL_AWAY), sendto_one_numeric(source_p, RPL_AWAY, form_str(RPL_AWAY),
target_p->name, target_p->user->away); target_p->name, target_p->user->away);
if(IsOper(target_p) && (!ConfigFileEntry.hide_opers_in_whois || IsOper(source_p))) if((!ConfigFileEntry.hide_opers_in_whois || IsOper(source_p)) && SeesOper(target_p, source_p))
{ {
sendto_one_numeric(source_p, RPL_WHOISOPERATOR, form_str(RPL_WHOISOPERATOR), sendto_one_numeric(source_p, RPL_WHOISOPERATOR, form_str(RPL_WHOISOPERATOR),
target_p->name, target_p->name,