From 03b8f45e5712f9d4a46dc03f695dd9ac5426626e Mon Sep 17 00:00:00 2001 From: Michael Poole Date: Mon, 17 May 2004 23:13:44 +0000 Subject: [PATCH] Replace privilege-controlling Feature settings with privilege-controlling Class and Operator settings, giving server admins more flexibility to delegate privileges. git-svn-id: file:///home/klmitch/undernet-ircu/undernet-ircu-svn/ircu2/trunk@1071 c9e4aea6-c8fd-4c43-8297-357d70d61c8c --- ChangeLog | 19 +++++ doc/example.conf | 130 +++++++++++++++------------------- include/class.h | 5 +- include/client.h | 4 +- include/ircd_features.h | 43 ----------- ircd/client.c | 153 +++++++++++++--------------------------- ircd/ircd_features.c | 43 ----------- ircd/ircd_lexer.l | 40 +++++------ ircd/ircd_parser.y | 54 +++++++++----- ircd/m_oper.c | 13 ++-- ircd/s_debug.c | 36 ---------- 11 files changed, 189 insertions(+), 351 deletions(-) diff --git a/ChangeLog b/ChangeLog index 0f3286f..584a95f 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,22 @@ +2004-05-17 Michael Poole + + * include/ircd_features.h, ircd/ircd_features.c, ircd/s_debug.c: + Rip out feature settings related to oper privileges. + + * include/client.h: Comment a few unexplained privileges. + + * ircd/ircd_lexer.l: Rename privilege keywords to match their + names in code and /PRIVS output. Add support for two "new" + privileges (FORCE_OPMODE, FORCE_LOCAL_OPMODE). + + * include/class.h, ircd/client.c, ircd/ircd_parser.y, + ircd/m_oper.c: Replace the removed feature settings with + per-connection class operator privileges. + + * doc/example.conf: Document the change. + + * ircd/ircd_parser.y (portblock): Fix slight memory leak. + 2004-05-16 Michael Poole * doc/example.conf: Make this show the new NICKLEN default. diff --git a/doc/example.conf b/doc/example.conf index 327f270..c55148c 100644 --- a/doc/example.conf +++ b/doc/example.conf @@ -161,7 +161,57 @@ Class { sendq = 160000; maxlinks = 400; }; +Class { + name = "Opers"; + pingfreq = 1 minutes 30 seconds; + sendq = 160000; + maxlinks = 10; + + # For connection classes intended for operator use, you can specify + # privileges used when the Operator block (see below) names this + # class. The local (aka globally_opered) privilege MUST be defined + # by either the Class or Operator block. The following privileges + # exist: + # + # local (or propagate, with the opposite sense) + # whox (can use x flag with /WHO) + # display (oper status visible to lusers) + # chan_limit (can join local channels when in + # MAXCHANNELSPERUSER channels) + # mode_lchan (can /MODE &channel without chanops) + # deop_lchan (cannot be deopped or kicked on local channels) + # walk_lchan (can forcibly /JOIN &channel OVERRIDE) + # show_invis (see +i users in /WHO x) + # show_all_invis (see +i users in /WHO x) + # unlimit_query (show more results from /WHO) + # local_kill (can kill clients on this server) + # rehash (can use /REHASH) + # die (can use /DIE) + # local_jupe_server (not used) + # set (can use /SET) + # local_gline (can set a G-line for this server only) + # local_badchan (can set a Gchan for this server only) + # see_chan (can see users in +s channels in /WHO) + # wide_gline (can use ! to force a wide G-line) + # see_opers (can see opers without DISPLAY privilege) + # force_local_opmode (can use OPMODE/CLEARMODE on quarantined local channels) + # kill (can kill clients on other servers) + # gline (can issue G-lines to other servers) + # jupe_server (not used) + # opmode (can use /OPMODE) + # badchan (can issue Gchans to other servers) + # force_opmode (can use OPMODE/CLEARMODE on quarantined global channels) + # + # For global opers (with propagate = yes or local = no), the default + # is to grant all of the above privileges. For local opers, the + # default is to grant ONLY the following privileges: + # chan_limit, mode_lchan, show_invis, show_all_invis, local_kill, + # rehash, local_gline, local_jupe, local_opmode, whox, display, + # force_local_opmode + # Any privileges listed in a Class block override the defaults. + local = no; +}; # [Client] # # To allow clients to connect, they need authorization. This can be @@ -567,47 +617,14 @@ CRULE # them from using Uworld as well. # # Operator { -# local = yes; # host = "host/IP mask"; # name = "opername"; # password = "encryptedpass"; # class = "classname"; -# -# # You can also specify per-operator privileges, many of which can -# # be globally disabled by settings in the "features" block (as -# # indicated). -# extended_who_information = yes; -# oper_status_display = yes; -# globally_opered = no; # inverted alias for local -# bypass_local_channel_limits = yes; # unless OPER_NO_CHAN_LIMIT = FALSE -# set_local_channel_modes = yes; # unless OPER_MODE_LCHAN = FALSE -# protected_local_channel = yes; # unless NO_OPER_DEOP_LCHAN = FALSE -# bypass_join_local_channels = yes; # unless OPER_WALK_THROUGH_LMODES = FALSE -# see_invisible_users = yes; # unless SHOW_INVISIBLE_USERS = FALSE -# list_all_invisible_users = yes; # unless SHOW_ALL_INVISIBLE_USERS = FALSE -# unlimited_who_queries = yes; # unless UNLIMIT_OPER_QUERY = FALSE -# -# # The following privileges have two settings in the "features" block; -# # one to globally disable for local operators, one to globally disable -# # the privilege for global operators. -# local_kill = yes; # unless {OPER,LOCOP}_KILL = FALSE -# rehash = yes; # unless {OPER,LOCOP}_REHASH = FALSE -# die = yes; # unless {OPER,LOCOP}_DIE = FALSE -# local_gline = yes; # unless {OPER,LOCOP}_LGLINE = FALSE -# local_jupe_server = yes; # unless {OPER,LOCOP}_LJUPE = FALSE -# change_settings = yes; # unless {OPER,LOCOP}_SET = FALSE -# local_gline_channels = yes; # unless {OPER,LOCOP}_LBADCHAN = FALSE -# see_private_channels = yes; # unless {OPER,LOCOP}_SEE_IN_SECRET_CHANNELS = FALSE -# wide_glines = yes; # unless {OPER,LOCOP}_WIDE_GLINE = FALSE -# -# # The following privileges default to yes for global operators and -# # to no for local operators. -# see_other_opers = yes; # unless local -# global_kill = yes; # unless local or LOCAL_KILL_ONLY = TRUE -# gline = yes; # unless local or OPER_GLINE = FALSE -# jupe_server = yes; # unless local or OPER_JUPE = FALSE -# hack_channel_modes = yes; # unless local or OPER_OPMODE = FALSE -# gline_channels = yes; # unless local or OPER_BADCHAN = FALSE +# # You can also set any operator privilege; see the Class block +# # documentation for details. A privilege defined for a single +# # Operator will override the privilege settings for the Class +# # and the default setting. # }; # # The encrypted password is optional. If you wish to encrypt your @@ -625,11 +642,10 @@ Operator { class = "Local"; }; Operator { - local = yes; host = "*@*.uu.net"; password = "notencryptedpass"; name = "Niels"; - class = "Local"; + class = "Opers"; }; # Note that the is optional, but leaving it away @@ -789,43 +805,7 @@ features # "IPCHECK_CLONE_PERIOD" = "40"; # "IPCHECK_CLONE_DELAY" = "600"; # "CRYPT_OPER_PASSWORD" = "TRUE"; -# "OPER_NO_CHAN_LIMIT" = "TRUE"; -# "OPER_MODE_LCHAN" = "TRUE"; -# "OPER_WALK_THROUGH_LMODES" = "FALSE"; -# "NO_OPER_DEOP_LCHAN" = "FALSE"; -# "SHOW_INVISIBLE_USERS" = "TRUE"; -# "SHOW_ALL_INVISIBLE_USERS" = "TRUE"; -# "UNLIMIT_OPER_QUERY" = "FALSE"; -# "LOCAL_KILL_ONLY" = "FALSE"; # "CONFIG_OPERCMDS" = "FALSE"; -# "OPER_KILL" = "TRUE"; -# "OPER_REHASH" = "TRUE"; -# "OPER_RESTART" = "TRUE"; -# "OPER_DIE" = "TRUE"; -# "OPER_GLINE" = "TRUE"; -# "OPER_LGLINE" = "TRUE"; -# "OPER_JUPE" = "TRUE"; -# "OPER_LJUPE" = "TRUE"; -# "OPER_OPMODE" = "TRUE"; -# "OPER_LOPMODE" = "TRUE"; -# "OPER_BADCHAN" = "FALSE"; -# "OPER_LBADCHAN" = "FALSE"; -# "OPER_SET" = "FALSE"; -# "OPERS_SEE_IN_SECRET_CHANNELS" = "TRUE"; -# "OPER_WIDE_GLINE" = "TRUE"; -# "OPER_LIST_CHAN" = "TRUE"; -# "LOCOP_KILL" = "TRUE"; -# "LOCOP_REHASH" = "TRUE"; -# "LOCOP_RESTART" = "FALSE"; -# "LOCOP_DIE" = "FALSE"; -# "LOCOP_LGLINE" = "TRUE"; -# "LOCOP_LJUPE" = "TRUE"; -# "LOCOP_LOPMODE" = "TRUE"; -# "LOCOP_LBADCHAN" = "FALSE"; -# "LOCOP_SET" = "FALSE"; -# "LOCOP_SEE_IN_SECRET_CHANNELS" = "FALSE"; -# "LOCOP_WIDE_GLINE" = "FALSE"; -# "LOCOP_LIST_CHAN" = "FALSE"; # "OPLEVELS" = "TRUE"; # "LOCAL_CHANNELS" = "TRUE"; }; diff --git a/include/class.h b/include/class.h index 374c21b..e5d0b54 100644 --- a/include/class.h +++ b/include/class.h @@ -26,7 +26,8 @@ #define INCLUDED_sys_types_h #endif -struct Client; +#include "client.h" + struct ConfItem; struct StatDesc; @@ -37,6 +38,8 @@ struct ConnectionClass { struct ConnectionClass* next; char *cc_name; char *default_umode; + struct Privs privs; + struct Privs privs_dirty; unsigned int max_sendq; short ping_freq; short conn_freq; diff --git a/include/client.h b/include/client.h index f6500bc..cb67796 100644 --- a/include/client.h +++ b/include/client.h @@ -113,8 +113,8 @@ enum Priv PRIV_SEE_OPERS, /* display hidden opers */ PRIV_WIDE_GLINE, /* oper can set wider G-lines */ PRIV_LIST_CHAN, /* oper can list secret channels */ - PRIV_FORCE_OPMODE, - PRIV_FORCE_LOCAL_OPMODE, + PRIV_FORCE_OPMODE, /* can hack modes on quarantined channels */ + PRIV_FORCE_LOCAL_OPMODE, /* can hack modes on quarantined local channels */ PRIV_LAST_PRIV /* must be the same as the last priv */ }; diff --git a/include/ircd_features.h b/include/ircd_features.h index 533e380..b1e0cc5 100644 --- a/include/ircd_features.h +++ b/include/ircd_features.h @@ -90,52 +90,9 @@ enum Feature { /* features that affect all operators */ FEAT_CRYPT_OPER_PASSWORD, - FEAT_OPER_NO_CHAN_LIMIT, - FEAT_OPER_MODE_LCHAN, - FEAT_OPER_WALK_THROUGH_LMODES, - FEAT_NO_OPER_DEOP_LCHAN, - FEAT_SHOW_INVISIBLE_USERS, - FEAT_SHOW_ALL_INVISIBLE_USERS, - FEAT_UNLIMIT_OPER_QUERY, - FEAT_LOCAL_KILL_ONLY, FEAT_CONFIG_OPERCMDS, FEAT_LIST_CHAN, - /* features that affect global opers on this server */ - FEAT_OPER_KILL, - FEAT_OPER_REHASH, - FEAT_OPER_RESTART, - FEAT_OPER_DIE, - FEAT_OPER_GLINE, - FEAT_OPER_LGLINE, - FEAT_OPER_JUPE, - FEAT_OPER_LJUPE, - FEAT_OPER_OPMODE, - FEAT_OPER_LOPMODE, - FEAT_OPER_FORCE_OPMODE, - FEAT_OPER_FORCE_LOPMODE, - FEAT_OPER_BADCHAN, - FEAT_OPER_LBADCHAN, - FEAT_OPER_SET, - FEAT_OPERS_SEE_IN_SECRET_CHANNELS, - FEAT_OPER_WIDE_GLINE, - FEAT_OPER_LIST_CHAN, - - /* features that affect local opers on this server */ - FEAT_LOCOP_KILL, - FEAT_LOCOP_REHASH, - FEAT_LOCOP_RESTART, - FEAT_LOCOP_DIE, - FEAT_LOCOP_LGLINE, - FEAT_LOCOP_LJUPE, - FEAT_LOCOP_LOPMODE, - FEAT_LOCOP_FORCE_LOPMODE, - FEAT_LOCOP_LBADCHAN, - FEAT_LOCOP_SET, - FEAT_LOCOP_SEE_IN_SECRET_CHANNELS, - FEAT_LOCOP_WIDE_GLINE, - FEAT_LOCOP_LIST_CHAN, - /* HEAD_IN_SAND Features */ FEAT_HIS_SNOTICES, FEAT_HIS_SNOTICES_OPER_ONLY, diff --git a/ircd/client.c b/ircd/client.c index 0b4e4f9..8bfdfe8 100644 --- a/ircd/client.c +++ b/ircd/client.c @@ -120,75 +120,9 @@ void client_add_sendq(struct Connection* con, struct Connection** con_p) } } -enum FeatureFlag { - FEATFLAG_NULL, - FEATFLAG_DISABLES_PRIV, - FEATFLAG_ENABLES_PRIV, - FEATFLAG_GLOBAL_OPERS, - FEATFLAG_LOCAL_OPERS, - FEATFLAG_ALL_OPERS -}; - -static struct -{ - enum Priv priv; - enum Feature feat; - enum FeatureFlag flag; -} feattab[] = - { - { PRIV_WHOX, FEAT_LAST_F, FEATFLAG_ALL_OPERS }, - { PRIV_DISPLAY, FEAT_LAST_F, FEATFLAG_ALL_OPERS }, - { PRIV_CHAN_LIMIT, FEAT_OPER_NO_CHAN_LIMIT, FEATFLAG_ALL_OPERS }, - { PRIV_MODE_LCHAN, FEAT_OPER_MODE_LCHAN, FEATFLAG_ALL_OPERS }, - { PRIV_LOCAL_OPMODE, FEAT_OPER_MODE_LCHAN, FEATFLAG_ALL_OPERS }, - { PRIV_WALK_LCHAN, FEAT_OPER_WALK_THROUGH_LMODES, FEATFLAG_ALL_OPERS }, - { PRIV_DEOP_LCHAN, FEAT_NO_OPER_DEOP_LCHAN, FEATFLAG_ALL_OPERS }, - { PRIV_SHOW_INVIS, FEAT_SHOW_INVISIBLE_USERS, FEATFLAG_ALL_OPERS }, - { PRIV_SHOW_ALL_INVIS, FEAT_SHOW_ALL_INVISIBLE_USERS, FEATFLAG_ALL_OPERS }, - { PRIV_UNLIMIT_QUERY, FEAT_UNLIMIT_OPER_QUERY, FEATFLAG_ALL_OPERS }, - - { PRIV_KILL, FEAT_LOCAL_KILL_ONLY, FEATFLAG_DISABLES_PRIV }, - { PRIV_GLINE, FEAT_CONFIG_OPERCMDS, FEATFLAG_ENABLES_PRIV }, - { PRIV_JUPE, FEAT_CONFIG_OPERCMDS, FEATFLAG_ENABLES_PRIV }, - { PRIV_OPMODE, FEAT_CONFIG_OPERCMDS, FEATFLAG_ENABLES_PRIV }, - { PRIV_BADCHAN, FEAT_CONFIG_OPERCMDS, FEATFLAG_ENABLES_PRIV }, - - { PRIV_PROPAGATE, FEAT_LAST_F, FEATFLAG_GLOBAL_OPERS }, - { PRIV_SEE_OPERS, FEAT_LAST_F, FEATFLAG_GLOBAL_OPERS }, - { PRIV_KILL, FEAT_OPER_KILL, FEATFLAG_GLOBAL_OPERS }, - { PRIV_LOCAL_KILL, FEAT_OPER_KILL, FEATFLAG_GLOBAL_OPERS }, - { PRIV_REHASH, FEAT_OPER_REHASH, FEATFLAG_GLOBAL_OPERS }, - { PRIV_RESTART, FEAT_OPER_RESTART, FEATFLAG_GLOBAL_OPERS }, - { PRIV_DIE, FEAT_OPER_DIE, FEATFLAG_GLOBAL_OPERS }, - { PRIV_GLINE, FEAT_OPER_GLINE, FEATFLAG_GLOBAL_OPERS }, - { PRIV_LOCAL_GLINE, FEAT_OPER_LGLINE, FEATFLAG_GLOBAL_OPERS }, - { PRIV_JUPE, FEAT_OPER_JUPE, FEATFLAG_GLOBAL_OPERS }, - { PRIV_LOCAL_JUPE, FEAT_OPER_LJUPE, FEATFLAG_GLOBAL_OPERS }, - { PRIV_OPMODE, FEAT_OPER_OPMODE, FEATFLAG_GLOBAL_OPERS }, - { PRIV_LOCAL_OPMODE, FEAT_OPER_LOPMODE, FEATFLAG_GLOBAL_OPERS }, - { PRIV_FORCE_OPMODE, FEAT_OPER_FORCE_OPMODE, FEATFLAG_GLOBAL_OPERS }, - { PRIV_FORCE_LOCAL_OPMODE, FEAT_OPER_FORCE_LOPMODE, FEATFLAG_GLOBAL_OPERS }, - { PRIV_BADCHAN, FEAT_OPER_BADCHAN, FEATFLAG_GLOBAL_OPERS }, - { PRIV_LOCAL_BADCHAN, FEAT_OPER_LBADCHAN, FEATFLAG_GLOBAL_OPERS }, - { PRIV_SET, FEAT_OPER_SET, FEATFLAG_GLOBAL_OPERS }, - { PRIV_SEE_CHAN, FEAT_OPERS_SEE_IN_SECRET_CHANNELS, FEATFLAG_GLOBAL_OPERS }, - { PRIV_WIDE_GLINE, FEAT_OPER_WIDE_GLINE, FEATFLAG_GLOBAL_OPERS }, - - { PRIV_LOCAL_KILL, FEAT_LOCOP_KILL, FEATFLAG_LOCAL_OPERS }, - { PRIV_REHASH, FEAT_LOCOP_REHASH, FEATFLAG_LOCAL_OPERS }, - { PRIV_RESTART, FEAT_LOCOP_RESTART, FEATFLAG_LOCAL_OPERS }, - { PRIV_DIE, FEAT_LOCOP_DIE, FEATFLAG_LOCAL_OPERS }, - { PRIV_LOCAL_GLINE, FEAT_LOCOP_LGLINE, FEATFLAG_LOCAL_OPERS }, - { PRIV_LOCAL_JUPE, FEAT_LOCOP_LJUPE, FEATFLAG_LOCAL_OPERS }, - { PRIV_LOCAL_OPMODE, FEAT_LOCOP_LOPMODE, FEATFLAG_LOCAL_OPERS }, - { PRIV_FORCE_LOCAL_OPMODE, FEAT_LOCOP_FORCE_LOPMODE, FEATFLAG_LOCAL_OPERS }, - { PRIV_LOCAL_BADCHAN, FEAT_LOCOP_LBADCHAN, FEATFLAG_LOCAL_OPERS }, - { PRIV_SET, FEAT_LOCOP_SET, FEATFLAG_LOCAL_OPERS }, - { PRIV_SEE_CHAN, FEAT_LOCOP_SEE_IN_SECRET_CHANNELS, FEATFLAG_LOCAL_OPERS }, - { PRIV_WIDE_GLINE, FEAT_LOCOP_WIDE_GLINE, FEATFLAG_LOCAL_OPERS }, - - { PRIV_LAST_PRIV, FEAT_LAST_F, FEATFLAG_NULL } - }; +static struct Privs privs_global; +static struct Privs privs_local; +static int privs_defaults_set; /* client_set_privs(struct Client* client) * @@ -197,8 +131,27 @@ static struct void client_set_privs(struct Client *client, struct ConfItem *oper) { - int i; + struct Privs *source, *defaults; + enum Priv priv; + if (!privs_defaults_set) + { + memset(&privs_global, -1, sizeof(privs_global)); + memset(&privs_local, 0, sizeof(privs_local)); + PrivSet(&privs_local, PRIV_CHAN_LIMIT); + PrivSet(&privs_local, PRIV_MODE_LCHAN); + PrivSet(&privs_local, PRIV_SHOW_INVIS); + PrivSet(&privs_local, PRIV_SHOW_ALL_INVIS); + PrivSet(&privs_local, PRIV_LOCAL_KILL); + PrivSet(&privs_local, PRIV_REHASH); + PrivSet(&privs_local, PRIV_LOCAL_GLINE); + PrivSet(&privs_local, PRIV_LOCAL_JUPE); + PrivSet(&privs_local, PRIV_LOCAL_OPMODE); + PrivSet(&privs_local, PRIV_WHOX); + PrivSet(&privs_local, PRIV_DISPLAY); + PrivSet(&privs_local, PRIV_FORCE_LOCAL_OPMODE); + privs_defaults_set = 1; + } memset(&(cli_privs(client)), 0, sizeof(struct Privs)); if (!IsAnOper(client)) @@ -212,49 +165,41 @@ client_set_privs(struct Client *client, struct ConfItem *oper) else if (oper == NULL) return; - /* Copy across privs from the config. */ - cli_privs(client) = oper->privs; + /* Clear out client's privileges. */ + memset(&cli_privs(client), 0, sizeof(struct Privs)); + + /* Decide whether to use global or local oper defaults. */ + if (PrivHas(&oper->privs_dirty, PRIV_PROPAGATE)) + defaults = PrivHas(&oper->privs, PRIV_PROPAGATE) ? &privs_global : &privs_local; + else if (PrivHas(&oper->conn_class->privs_dirty, PRIV_PROPAGATE)) + defaults = PrivHas(&oper->conn_class->privs, PRIV_PROPAGATE) ? &privs_global : &privs_local; + else + assert(0 && "Oper has no propagation and neither does connection class"); - /* Now go through the features and set the non-dirty flags to their feature - * determined defaults... + /* For each feature, figure out whether it comes from the operator + * conf, the connection class conf, or the defaults, then apply it. */ - for (i = 0; feattab[i].priv != PRIV_LAST_PRIV; i++) + for (priv = 0; priv < PRIV_LAST_PRIV; ++priv) { - if (PrivHas(&oper->privs_dirty, feattab[i].priv)) - continue; - if (feattab[i].feat != FEAT_LAST_F && !feature_bool(feattab[i].feat)) - continue; - switch (feattab[i].flag) - { - case FEATFLAG_ENABLES_PRIV: - if (!feature_bool(feattab[i].feat)) - continue; - PrivSet(&cli_privs(client), feattab[i].priv); - continue; - case FEATFLAG_DISABLES_PRIV: - PrivClr(&cli_privs(client), feattab[i].priv); - continue; - case FEATFLAG_ALL_OPERS: - if (IsAnOper(client)) - PrivSet(&cli_privs(client), feattab[i].priv); - continue; - case FEATFLAG_GLOBAL_OPERS: - if (IsOper(client)) - PrivSet(&cli_privs(client), feattab[i].priv); - continue; - case FEATFLAG_LOCAL_OPERS: - if (IsLocOp(client)) - PrivSet(&cli_privs(client), feattab[i].priv); - continue; - default: - continue; /* ?? */ - } + /* Figure out most applicable definition for the privilege. */ + if (PrivHas(&oper->privs_dirty, priv)) + source = &oper->privs; + else if (PrivHas(&oper->conn_class->privs_dirty, priv)) + source = &oper->conn_class->privs; + else + source = defaults; + + /* Set it if necessary (privileges were already cleared). */ + if (PrivHas(source, priv)) + PrivSet(&cli_privs(client), priv); } /* This should be handled in the config, but lets be sure... */ if (PrivHas(&cli_privs(client), PRIV_PROPAGATE)) + { /* force propagating opers to display */ PrivSet(&cli_privs(client), PRIV_DISPLAY); + } else { /* if they don't propagate oper status, prevent desyncs */ diff --git a/ircd/ircd_features.c b/ircd/ircd_features.c index eab84ce..9fe5195 100644 --- a/ircd/ircd_features.c +++ b/ircd/ircd_features.c @@ -296,52 +296,9 @@ static struct FeatureDesc { /* features that affect all operators */ F_B(CRYPT_OPER_PASSWORD, FEAT_MYOPER | FEAT_READ, 1, 0), - F_B(OPER_NO_CHAN_LIMIT, 0, 1, 0), - F_B(OPER_MODE_LCHAN, 0, 1, 0), - F_B(OPER_WALK_THROUGH_LMODES, 0, 0, 0), - F_B(NO_OPER_DEOP_LCHAN, 0, 0, 0), - F_B(SHOW_INVISIBLE_USERS, 0, 1, 0), - F_B(SHOW_ALL_INVISIBLE_USERS, 0, 1, 0), - F_B(UNLIMIT_OPER_QUERY, 0, 0, 0), - F_B(LOCAL_KILL_ONLY, 0, 0, 0), F_B(CONFIG_OPERCMDS, 0, 0, 0), F_B(LIST_CHAN, 0, 1, 0), - /* features that affect global opers on this server */ - F_B(OPER_KILL, 0, 1, 0), - F_B(OPER_REHASH, 0, 1, 0), - F_B(OPER_RESTART, 0, 1, 0), - F_B(OPER_DIE, 0, 1, 0), - F_B(OPER_GLINE, 0, 1, 0), - F_B(OPER_LGLINE, 0, 1, 0), - F_B(OPER_JUPE, 0, 1, 0), - F_B(OPER_LJUPE, 0, 1, 0), - F_B(OPER_OPMODE, 0, 1, 0), - F_B(OPER_LOPMODE, 0, 1, 0), - F_B(OPER_FORCE_OPMODE, 0, 1, 0), - F_B(OPER_FORCE_LOPMODE, 0, 1, 0), - F_B(OPER_BADCHAN, 0, 0, 0), - F_B(OPER_LBADCHAN, 0, 0, 0), - F_B(OPER_SET, 0, 0, 0), - F_B(OPERS_SEE_IN_SECRET_CHANNELS, 0, 1, 0), - F_B(OPER_WIDE_GLINE, 0, 1, 0), - F_B(OPER_LIST_CHAN, 0, 1, 0), - - /* features that affect local opers on this server */ - F_B(LOCOP_KILL, 0, 1, 0), - F_B(LOCOP_REHASH, 0, 1, 0), - F_B(LOCOP_RESTART, 0, 0, 0), - F_B(LOCOP_DIE, 0, 0, 0), - F_B(LOCOP_LGLINE, 0, 1, 0), - F_B(LOCOP_LJUPE, 0, 1, 0), - F_B(LOCOP_LOPMODE, 0, 1, 0), - F_B(LOCOP_FORCE_LOPMODE, 0, 1, 0), - F_B(LOCOP_LBADCHAN, 0, 0, 0), - F_B(LOCOP_SET, 0, 0, 0), - F_B(LOCOP_SEE_IN_SECRET_CHANNELS, 0, 0, 0), - F_B(LOCOP_WIDE_GLINE, 0, 0, 0), - F_B(LOCOP_LIST_CHAN, 0, 0, 0), - /* HEAD_IN_SAND Features */ F_B(HIS_SNOTICES, 0, 1, 0), F_B(HIS_SNOTICES_OPER_ONLY, 0, 1, 0), diff --git a/ircd/ircd_lexer.l b/ircd/ircd_lexer.l index 71569a2..91f022f 100644 --- a/ircd/ircd_lexer.l +++ b/ircd/ircd_lexer.l @@ -123,32 +123,32 @@ kill return KILL; quarantine return QUARANTINE; features return FEATURES; channel return CHANNEL; -bypass_local_channel_limits return TPRIV_CHAN_LIMIT; -set_local_channel_modes return TPRIV_MODE_LCHAN; -protected_local_channel return TPRIV_DEOP_LCHAN; -bypass_join_local_channels return TPRIV_WALK_LCHAN; -global_kill return TPRIV_KILL; +chan_limit return TPRIV_CHAN_LIMIT; +mode_lchan return TPRIV_MODE_LCHAN; +deop_lchan return TPRIV_DEOP_LCHAN; +walk_lchan return TPRIV_WALK_LCHAN; local_kill return TPRIV_LOCAL_KILL; rehash return TPRIV_REHASH; restart return TPRIV_RESTART; die return TPRIV_DIE; gline return TPRIV_GLINE; local_gline return TPRIV_LOCAL_GLINE; -jupe_server return TPRIV_JUPE; -local_jupe_server return TPRIV_LOCAL_JUPE; -hack_channel_modes return TPRIV_OPMODE; -change_settings return TPRIV_SET; -extended_who_information return TPRIV_WHOX; -gline_channels return TPRIV_BADCHAN; -local_gline_channels return TPRIV_LOCAL_BADCHAN; -see_private_channels return TPRIV_SEE_CHAN; -see_invisible_users return TPRIV_SHOW_INVIS; -list_all_invisible_users return TPRIV_SHOW_ALL_INVIS; -globally_opered return TPRIV_PROPAGATE; -unlimited_who_queries return TPRIV_UNLIMIT_QUERY; -oper_status_display return TPRIV_DISPLAY; -see_other_opers return TPRIV_SEE_OPERS; -wide_glines return TPRIV_WIDE_GLINE; +local_jupe return TPRIV_LOCAL_JUPE; +opmode return TPRIV_OPMODE; +set return TPRIV_SET; +whox return TPRIV_WHOX; +badchan return TPRIV_BADCHAN; +local_badchan return TPRIV_LOCAL_BADCHAN; +see_chan return TPRIV_SEE_CHAN; +show_invis return TPRIV_SHOW_INVIS; +show_all_invis return TPRIV_SHOW_ALL_INVIS; +propagate return TPRIV_PROPAGATE; +unlimit_query return TPRIV_UNLIMIT_QUERY; +display return TPRIV_DISPLAY; +see_opers return TPRIV_SEE_OPERS; +wide_gline return TPRIV_WIDE_GLINE; +force_opmode return TPRIV_FORCE_OPMODE; +force_local_opmode return TPRIV_FORCE_LOCAL_OPMODE; pseudo return PSEUDO; prepend return PREPEND; usermode return USERMODE; diff --git a/ircd/ircd_parser.y b/ircd/ircd_parser.y index 8233077..cb22a29 100644 --- a/ircd/ircd_parser.y +++ b/ircd/ircd_parser.y @@ -79,6 +79,8 @@ struct ServerConf *sconf; struct qline *qconf = NULL; struct s_map *smap; + struct Privs privs; + struct Privs privs_dirty; static void parse_error(char *pattern,...) { static char error_buffer[1024]; @@ -157,12 +159,12 @@ static void parse_error(char *pattern,...) { %token USERMODE /* and now a lot of priviledges... */ %token TPRIV_CHAN_LIMIT TPRIV_MODE_LCHAN TPRIV_DEOP_LCHAN TPRIV_WALK_LCHAN -%token TPRIV_KILL TPRIV_LOCAL_KILL TPRIV_REHASH TPRIV_RESTART TPRIV_DIE -%token TPRIV_GLINE TPRIV_LOCAL_GLINE TPRIV_JUPE TPRIV_LOCAL_JUPE +%token TPRIV_LOCAL_KILL TPRIV_REHASH TPRIV_RESTART TPRIV_DIE +%token TPRIV_GLINE TPRIV_LOCAL_GLINE TPRIV_LOCAL_JUPE TPRIV_LOCAL_BADCHAN %token TPRIV_LOCAL_OPMODE TPRIV_OPMODE TPRIV_SET TPRIV_WHOX TPRIV_BADCHAN -%token TPRIV_LOCAL_BADCHAN %token TPRIV_SEE_CHAN TPRIV_SHOW_INVIS TPRIV_SHOW_ALL_INVIS TPRIV_PROPAGATE %token TPRIV_UNLIMIT_QUERY TPRIV_DISPLAY TPRIV_SEE_OPERS TPRIV_WIDE_GLINE +%token TPRIV_FORCE_OPMODE TPRIV_FORCE_LOCAL_OPMODE /* and some types... */ %type sizespec %type timespec timefactor factoredtimes factoredtime @@ -330,12 +332,18 @@ classblock: CLASS { maxlinks = 0; sendq = 0; pass = NULL; + memset(&privs, 0, sizeof(privs)); + memset(&privs_dirty, 0, sizeof(privs_dirty)); } '{' classitems '}' { if (name != NULL) { - add_class(name, tping, tconn, maxlinks, sendq); - find_class(name)->default_umode = pass; + struct ConnectionClass *c_class; + add_class(name, tping, tconn, maxlinks, sendq); + c_class = find_class(name); + c_class->default_umode = pass; + memcpy(&c_class->privs, &privs, sizeof(c_class->privs)); + memcpy(&c_class->privs_dirty, &privs_dirty, sizeof(c_class->privs_dirty)); } else { parse_error("Missing name in class block"); @@ -344,7 +352,7 @@ classblock: CLASS { } ';'; classitems: classitem classitems | classitem; classitem: classname | classpingfreq | classconnfreq | classmaxlinks | - classsendq | classusermode | error; + classsendq | classusermode | priv | error; classname: NAME '=' QSTRING ';' { MyFree(name); @@ -502,11 +510,19 @@ operblock: OPER { aconf = (struct ConfItem*) MyMalloc(sizeof(*aconf)); memset(aconf, 0, sizeof(*aconf)); + memset(&privs, 0, sizeof(privs)); + memset(&privs_dirty, 0, sizeof(privs_dirty)); aconf->status = CONF_OPERATOR; } '{' operitems '}' ';' { - if (aconf->name != NULL && aconf->passwd != NULL && aconf->host != NULL) + if (aconf->name != NULL && aconf->passwd != NULL && aconf->host != NULL + && aconf->conn_class != NULL) { + memcpy(&aconf->privs, &privs, sizeof(aconf->privs)); + memcpy(&aconf->privs_dirty, &privs_dirty, sizeof(aconf->privs_dirty)); + if (!PrivHas(&privs_dirty, PRIV_PROPAGATE) + && !PrivHas(&aconf->conn_class->privs_dirty, PRIV_PROPAGATE)) + parse_error("Operator block for %s and class %s have no LOCAL setting", aconf->name, aconf->conn_class->cc_name); aconf->next = GlobalConfList; GlobalConfList = aconf; } @@ -521,7 +537,7 @@ operblock: OPER } }; operitems: operitem | operitems operitem; -operitem: opername | operpass | operhost | operclass | operpriv | error; +operitem: opername | operpass | operhost | operclass | priv | error; opername: NAME '=' QSTRING ';' { @@ -554,13 +570,13 @@ operclass: CLASS '=' QSTRING ';' aconf->conn_class = find_class(yylval.text); }; -operpriv: privtype '=' yesorno ';' +priv: privtype '=' yesorno ';' { - PrivSet(&aconf->privs_dirty, $1); + PrivSet(&privs_dirty, $1); if (($3 == 1) ^ invert) - PrivSet(&aconf->privs, $1); + PrivSet(&privs, $1); else - PrivClr(&aconf->privs, $1); + PrivClr(&privs, $1); invert = 0; }; @@ -568,14 +584,14 @@ privtype: TPRIV_CHAN_LIMIT { $$ = PRIV_CHAN_LIMIT; } | TPRIV_MODE_LCHAN { $$ = PRIV_MODE_LCHAN; } | TPRIV_DEOP_LCHAN { $$ = PRIV_DEOP_LCHAN; } | TPRIV_WALK_LCHAN { $$ = PRIV_WALK_LCHAN; } | - TPRIV_KILL { $$ = PRIV_KILL; } | + KILL { $$ = PRIV_KILL; } | TPRIV_LOCAL_KILL { $$ = PRIV_LOCAL_KILL; } | TPRIV_REHASH { $$ = PRIV_REHASH; } | TPRIV_RESTART { $$ = PRIV_RESTART; } | TPRIV_DIE { $$ = PRIV_DIE; } | TPRIV_GLINE { $$ = PRIV_GLINE; } | TPRIV_LOCAL_GLINE { $$ = PRIV_LOCAL_GLINE; } | - TPRIV_JUPE { $$ = PRIV_JUPE; } | + JUPE { $$ = PRIV_JUPE; } | TPRIV_LOCAL_JUPE { $$ = PRIV_LOCAL_JUPE; } | TPRIV_LOCAL_OPMODE { $$ = PRIV_LOCAL_OPMODE; } | TPRIV_OPMODE { $$ = PRIV_OPMODE; }| @@ -591,7 +607,9 @@ privtype: TPRIV_CHAN_LIMIT { $$ = PRIV_CHAN_LIMIT; } | TPRIV_DISPLAY { $$ = PRIV_DISPLAY; } | TPRIV_SEE_OPERS { $$ = PRIV_SEE_OPERS; } | TPRIV_WIDE_GLINE { $$ = PRIV_WIDE_GLINE; } | - LOCAL { $$ = PRIV_PROPAGATE; invert = 1; }; + LOCAL { $$ = PRIV_PROPAGATE; invert = 1; } | + TPRIV_FORCE_OPMODE { $$ = PRIV_FORCE_OPMODE; } | + TPRIV_FORCE_LOCAL_OPMODE { $$ = PRIV_FORCE_LOCAL_OPMODE; }; yesorno: YES { $$ = 1; } | NO { $$ = 0; }; @@ -609,14 +627,14 @@ portblock: PORT { if (port > 0 && port <= 0xFFFF) { add_listener(port, host, pass, tconn, tping); - host = pass = NULL; } else { - MyFree(host); - MyFree(pass); parse_error("Bad port block"); } + MyFree(host); + MyFree(pass); + host = pass = NULL; }; portitems: portitem portitems | portitem; portitem: portnumber | portvhost | portmask | portserver | porthidden | error; diff --git a/ircd/m_oper.c b/ircd/m_oper.c index d23e2f2..002b36d 100644 --- a/ircd/m_oper.c +++ b/ircd/m_oper.c @@ -163,14 +163,10 @@ int m_oper(struct Client* cptr, struct Client* sptr, int parc, char* parv[]) cli_sockhost(sptr)); return 0; } - if (!PrivHas(&aconf->privs, PRIV_PROPAGATE)) { - ClearOper(sptr); - SetLocOp(sptr); - } - else { - /* - * prevent someone from being both oper and local oper - */ + SetLocOp(sptr); + client_set_privs(sptr, aconf); + if (HasPriv(sptr, PRIV_PROPAGATE)) + { ClearLocOp(sptr); SetOper(sptr); ++UserStats.opers; @@ -182,7 +178,6 @@ int m_oper(struct Client* cptr, struct Client* sptr, int parc, char* parv[]) SetFlag(sptr, FLAG_DEBUG); set_snomask(sptr, SNO_OPERDEFAULT, SNO_ADD); - client_set_privs(sptr, aconf); cli_max_sendq(sptr) = 0; /* Get the sendq from the oper's class */ send_umode_out(cptr, sptr, &old_mode, HasPriv(sptr, PRIV_PROPAGATE)); send_reply(sptr, RPL_YOUREOPER); diff --git a/ircd/s_debug.c b/ircd/s_debug.c index da19929..6899c74 100644 --- a/ircd/s_debug.c +++ b/ircd/s_debug.c @@ -93,54 +93,18 @@ const char* debug_serveropts(void) AddC('D'); #endif - if (feature_bool(FEAT_LOCOP_REHASH)) - AddC('e'); - - if (feature_bool(FEAT_OPER_REHASH)) - AddC('E'); - - if (feature_bool(FEAT_OPER_NO_CHAN_LIMIT)) - AddC('F'); - - if (feature_bool(FEAT_OPER_MODE_LCHAN)) - AddC('f'); - if (feature_bool(FEAT_HUB)) AddC('H'); - if (feature_bool(FEAT_SHOW_ALL_INVISIBLE_USERS)) - AddC('I'); - else if (feature_bool(FEAT_SHOW_INVISIBLE_USERS)) - AddC('i'); - - if (feature_bool(FEAT_OPER_KILL)) { - if (feature_bool(FEAT_LOCAL_KILL_ONLY)) - AddC('k'); - else - AddC('K'); - } - - if (feature_bool(FEAT_OPER_WALK_THROUGH_LMODES)) - AddC('l'); - if (feature_bool(FEAT_IDLE_FROM_MSG)) AddC('M'); - if (feature_bool(FEAT_NO_OPER_DEOP_LCHAN)) - AddC('o'); - if (feature_bool(FEAT_CRYPT_OPER_PASSWORD)) AddC('p'); if (feature_bool(FEAT_RELIABLE_CLOCK)) AddC('R'); - if (feature_bool(FEAT_LOCOP_RESTART)) - AddC('s'); - - if (feature_bool(FEAT_OPER_RESTART)) - AddC('S'); - #if defined(USE_POLL) && defined(HAVE_POLL_H) AddC('U'); #endif -- 2.20.1