Author: Kev <klmitch@mit.edu>
authorKevin L. Mitchell <klmitch@mit.edu>
Sat, 16 Dec 2000 08:20:48 +0000 (08:20 +0000)
committerKevin L. Mitchell <klmitch@mit.edu>
Sat, 16 Dec 2000 08:20:48 +0000 (08:20 +0000)
Log message:

Implement an ACL for IRC operators; set ACL out of information provided by
the .conf through the feature system.

Testing:

It's been tested on one server all by its lonesome, and seems to work fine;
it needs to be rigorously tested on a network with other users, and by both
local and global operators, with various fiddling of the /set's.  This big
a change to the privileges structure can lead to interesting anomolies.
Unfortunately, documentation is sparse; I'll look into correcting that when
I can, but don't hold your breath.

git-svn-id: file:///home/klmitch/undernet-ircu/undernet-ircu-svn/ircu2/trunk@344 c9e4aea6-c8fd-4c43-8297-357d70d61c8c

33 files changed:
ChangeLog
config/config-sh.in
doc/Configure.help
include/channel.h
include/client.h
include/ircd_features.h
include/s_debug.h
include/whocmds.h
ircd/channel.c
ircd/client.c
ircd/gline.c
ircd/ircd_features.c
ircd/m_clearmode.c
ircd/m_die.c
ircd/m_gline.c
ircd/m_join.c
ircd/m_jupe.c
ircd/m_kick.c
ircd/m_kill.c
ircd/m_mode.c
ircd/m_oper.c
ircd/m_opmode.c
ircd/m_rehash.c
ircd/m_restart.c
ircd/m_userhost.c
ircd/m_userip.c
ircd/m_version.c
ircd/m_who.c
ircd/m_whois.c
ircd/parse.c
ircd/s_debug.c
ircd/s_user.c
ircd/whocmds.c

index 1f0909d5009c6d010a87af57fc2582bf8283a89f..674ba51a3ef820f66895ccdd7c0747f725c615bb 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,99 @@
+2000-12-16  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * ircd/whocmds.c (do_who): use HasPriv to determine whether or not
+       to indicate a user is an oper
+
+       * ircd/s_user.c: clear privileges setting when deopping; don't
+       propagate +o unless user has PRIV_PROPAGATE privilege
+
+       * ircd/s_debug.c (debug_serveropts): created debug_serveropts()
+       function and replaced how the server option string is generated
+
+       * ircd/parse.c: remove conditional on CONFIG_OPERCMDS
+
+       * ircd/m_whois.c (do_whois): use HasPriv to determine whether or
+       not to indicate the user is an operator
+
+       * ircd/m_who.c: use HasPriv to determine whether or not a user
+       should be displayed in the list of opers
+
+       * ircd/m_version.c: call debug_serveropts() to get server option
+       string
+
+       * ircd/m_userip.c (userip_formatter): use HasPriv to determine
+       whether or not to show oper status
+
+       * ircd/m_userhost.c (userhost_formatter): use HasPriv to determine
+       whether or not to show oper status
+
+       * ircd/m_restart.c (mo_restart): replace ugly #ifdef conditional
+       checks with HasPriv check; remove dead code
+
+       * ircd/m_rehash.c (mo_rehash): replace ugly #ifdef conditional
+       checks with HasPriv check
+
+       * ircd/m_opmode.c (mo_opmode): use HasPriv to check permissions;
+       use feature_bool to check if disabled
+
+       * ircd/m_oper.c (m_oper): set oper priviliges
+
+       * ircd/m_mode.c (m_mode): replace #ifdef conditional with HasPriv
+       check
+
+       * ircd/m_kill.c (mo_kill): use HasPriv checks to determine if we
+       can kill
+
+       * ircd/m_kick.c (m_kick): replace #ifdef conditional with HasPriv
+       check
+
+       * ircd/m_jupe.c (mo_jupe): rework permissions checking structure;
+       use feature_bool to check if disabled
+
+       * ircd/m_join.c (m_join): remove BADCHAN conditional; replace
+       #ifdef conditional with a HasPriv check
+
+       * ircd/m_gline.c (mo_gline): rework permissions checking
+       structure; use feature_bool to check if any part is disabled
+
+       * ircd/m_die.c: replace ugly #ifdef conditionals with HasPriv
+       check; remove dead code
+
+       * ircd/m_clearmode.c: use feature_bool() to detect if we're
+       disabled; use HasPriv to figure out what we're permitted to do;
+       only allow clearmode on moded channels
+
+       * ircd/ircd_features.c: define various features; use HasPriv to
+       verify permissions to set/reset
+
+       * ircd/gline.c (gline_add): use HasPriv instead of #ifdef
+       conditionals
+
+       * ircd/client.c (client_set_privs): function to set an oper's
+       privileges
+
+       * ircd/channel.c: use HasPriv calls instead of #ifdef conditionals
+
+       * include/whocmds.h: deconditionalize several macros and
+       substitute appropriate calls to HasPriv()
+
+       * include/s_debug.h: get rid of global serveropts[]; define new
+       function debug_serveropts() to build that string on the fly
+
+       * include/ircd_features.h: define some features
+
+       * include/client.h: add privs member to struct Connection; define
+       various priviledges
+
+       * include/channel.h: no longer using IsOperOnLocalChannel; remove
+       conditional of MAGIC_OPER_OVERRIDE on OPER_WALK_THROUGH_LMODES
+
+       * doc/Configure.help: remove help information for deprecated
+       options
+
+       * config/config-sh.in: remove certain deprecated options having to
+       do with what opers can and cannot do--first stage in moving
+       compile-time constants into the .conf
+
 2000-12-16  Isomer <Isomer@coders.net>
        * ircd/parse.c: detect if the prefix is missing and try and recover
        instead of coring.
index bf2c4307152c4799fbe92e4257577abfabfdaecc..d464cd82afc170fceeb91168ed6346635ca9d810 100644 (file)
@@ -225,19 +225,6 @@ comment 'Paths and files'
   string 'File for server pid' PPATH 'ircd.pid'
 endmenu
 
-mainmenu_option next_comment
-comment 'Logging (filenames are either full paths or files within DPATH)'
-
-comment 'Bad Channel G-Lines allow operators to add channel masks to a list which prohibits local clients from being able joining channels which match the mask.  Remote BadChan Glines allow Uworld to add or remove channels from the servers internal list of badchans'
-  bool 'Do you want to enable Bad Channel G-lines' BADCHAN y
-    if [ "$BADCHAN" = "y" ]; then
-      echo " "
-      echo " WARNING DO _NOT_ USE LOCAL BADCHANNEL GLINES ON UNDERNET"
-      echo " Use of LOCAL BAD Channel G-Lines can be cause for REMOVAL"
-      bool 'Allow LOCAL BAD Channel G-lines' LOCAL_BADCHAN
-    fi
-endmenu
-
 mainmenu_option next_comment
 comment 'Configuration'
   bool 'Use crypted passwords for operators' CRYPT_OPER_PASSWORD y
@@ -267,34 +254,6 @@ comment 'Configuration'
   bool 'Kill connecting clients when forward and reverse DNS mismatch' KILL_IPMISMATCH n
 endmenu
 
-mainmenu_option next_comment
-comment 'Oper commands'
-  bool 'Allow (local) Opers to see all local invisible users' SHOW_INVISIBLE_USERS y
-  if [ "$SHOW_INVISIBLE_USERS" = "y" ]; then
-    bool 'Allow Opers to see all invisible users' SHOW_ALL_INVISIBLE_USERS y
-  fi
-  bool 'Allow global Opers (O:) to see inside secret channels' OPERS_SEE_IN_SECRET_CHANNELS y
-  if [ "$OPERS_SEE_IN_SECRET_CHANNELS" = "y" ]; then
-    bool 'Allow local Opers (o:) to see inside secret channels' LOCOP_SEE_IN_SECRET_CHANNELS n
-  fi
-  bool 'Do not truncate obnoxiously long /who output for opers' UNLIMIT_OPER_QUERY
-  bool 'Allow Opers to use the KILL command' OPER_KILL y
-  bool 'Allow Opers to use the REHASH command' OPER_REHASH y
-  bool 'Allow Opers to use the RESTART command' OPER_RESTART y
-  bool 'Allow Opers to use the DIE command' OPER_DIE y
-  bool 'Allow Opers to add local G-lines' OPER_LGLINE y
-  bool 'Allow Opers to connect from a remote site' OPER_REMOTE y
-  bool 'Allow local opers to use the REHASH command' LOCOP_REHASH y
-  bool 'Allow local opers to use the RESTART command' LOCOP_RESTART
-  bool 'Allow local opers to use the DIE command' LOCOP_DIE
-  bool 'Allow local opers to add local G-lines' LOCOP_LGLINE y
-  bool 'Allow local/global opers to be on any number of channels' OPER_NO_CHAN_LIMIT y
-  bool 'Allow local/global opers to set modes on local channels' OPER_MODE_LCHAN y
-  bool 'Allow local/global opers to walk through local channels modes' OPER_WALK_THROUGH_LMODES n
-  bool 'Prevent local/global opers from being kicked or deoped on local channels' NO_OPER_DEOP_LCHAN n
-
-endmenu
-
 mainmenu_option next_comment
 comment 'Server characteristics'
   bool 'Do you want to have a default LIST parameter' CONFIG_LIST y
@@ -312,11 +271,6 @@ endmenu
 mainmenu_option next_comment
 comment 'Mandatory defines (you should leave these untouched)'
   int 'Max auto connects per class (1!)' MAXIMUM_LINKS 1
-  if [ "$OPER_KILL" = "y" ]; then
-    bool 'Only allow KILLs of local clients' LOCAL_KILL_ONLY
-  else
-    define_bool LOCAL_KILL_ONLY $LOCAL_KILL_ONLY
-  fi
   int 'KILL nick chase time limit (30)' KILLCHASETIMELIMIT 30
   int 'Max number of channels per user' MAXCHANNELSPERUSER 10
   int 'Max number of silence masks (15!)' MAXSILES 15
@@ -331,8 +285,3 @@ comment 'Mandatory defines (you should leave these untouched)'
   int 'connect(2) timeout (90!)' CONNECTTIMEOUT 90
   int 'Max send queue (40000)' DEFAULTMAXSENDQLENGTH 40000
 endmenu
-
-mainmenu_option next_comment
-comment 'Experimental options (Do you know what you'\''re doing?)'
-  bool 'Use new oper commands (JUPE, CLEARMODE, OPMODE, GLINE)' CONFIG_OPERCMDS y
-endmenu
index e4b979be2e0edd3c484ee5a6ec43786daf4b8373..d66b16e36b547400b321ccaa938f7dfa6f8e0544 100644 (file)
@@ -628,119 +628,6 @@ R_LINES_OFTEN
   Note that this is -very- likely to cause a severe drain on your resources.
   Use at your own risk, specify 'n' unless your really sure.
 
-Allow (local) Opers to see all local invisible users
-SHOW_INVISIBLE_USERS
-  If you specify 'y' here, then your (local) IRC Operators will be able to
-  see all local invisible users (clients connected to your own server).
-  The reason for this is to hunt for clone bots, make sure your Operators do
-  not use this "feature" for spying on individuals and respect the user that
-  wishes to be invisible (mostly meaning that they don't want to be found when
-  on certain channels).
-  Note: If you answer 'n' here, then you will also not be able to see remote
-  invisible users (if you specify 'y' you will also get a configuration
-  question that asks you to specify whether or not you want your Opers to see
-  remote invisible users or not).
-
-Allow Opers to see all invisible users
-SHOW_ALL_INVISIBLE_USERS
-  If you specify 'y' here, then your global IRC Operators (O:) will be able
-  to see ALL invisible users.  The reason for this is to hunt for clone bots,
-  make sure your Operators do not use this "feature" for spying on individuals
-  and respect the user that wishes to be invisible (mostly meaning that they
-  don't want to be found when on certain channels).
-
-Allow global Opers (O:) to see inside secret channels
-OPERS_SEE_IN_SECRET_CHANNELS
-  If you specify 'y' here, then your global IRC Operators (O:) will be able
-  to see who is on a specified, secret channel, without joining themselfs.
-  This can be needed to make a reasonable judgement in the case of a "channel
-  takeover" being reported, while the channel is set invite only.
-  See doc/readme.who for more details.
-
-Allow local Opers (o:) to see inside secret channels
-LOCOP_SEE_IN_SECRET_CHANNELS
-  If you specify 'y' here, then your local IRC Operators (o:) will be able
-  to see who is on a specified, secret channel, without joining themselfs.
-  This can be needed to make a reasonable judgement in the case of a "channel
-  takeover" being reported, while the channel is set invite only.
-  See doc/readme.who for more details.
-  If unsure, specify 'n'.
-
-Don't truncate obnoxiously long /who output for opers
-UNLIMIT_OPER_QUERY
-  A /who command can sometimes return several hundred lines of info. To
-  reduce flooding and sending too much, the output is truncated. By
-  answering 'y' to this, when an IRC Operator uses /who, the output will
-  not be truncated, no matter how much data is returned.
-
-Allow Opers to use the KILL command
-OPER_KILL
-  You can select 'n' if you don't think operators should be able
-  to use the KILL command, and wish to prevent your operators from
-  using it.  This will not, however, prevent operators on other
-  servers from issuing KILLs to your clients.  You probably want to
-  select 'y' for this unless you really really don't think KILL
-  should -ever- be used by an operator.
-
-Allow Opers to use the REHASH command
-OPER_REHASH
-  Allows operators to use the REHASH command to reload the servers
-  configuration file (ircd.conf) if you select 'n', you can still
-  reload the configuration file with a unix command,
-  kill -HUP `cat ircd.pid`.  If unsure, select 'y'.
-
-Allow Opers to use the RESTART command
-OPER_RESTART
-  Allows an operator to use the RESTART command to cause the server
-  to restart, using the ircd executable in SPATH.  If unsure, select 'y'.
-
-Allow Opers to use the DIE command
-OPER_DIE
-  Allows an operator to use the DIE command to shutdown the server
-  online.  If you select 'n' you will need to send the server a kill
-  signal to shutdown the server.  If unsure, select 'y'.
-
-Allow Opers to add local G-lines
-OPER_LGLINE
-  Allows operators to add local G-lines with the GLINE command.  This is
-  like a *local* KILL, except that the user being killed can't immediately
-  reconnect: He will have to wait for the G-line to expire.
-  The reason for adding this is that a KILL is rather useless for removing
-  (or 'warning') abusers (it is still THE command to remove ghosts and
-  a-like, the reason KILL was added in the first place).  However, adding
-  G-lines for a dynamic IP with expire times larger then 10 minutes is highly
-  discouraged: The user will already have dialed in via another IP or account
-  and the G-line would only harm other, innocent, users.
-
-Allow Opers to connect from a remote site
-OPER_REMOTE
-  If you select 'n' for this, clients must be on the 'same network' as
-  the server in order to gain oper privledges.  If you're not sure, just
-  select 'y'.
-
-Allow local opers to use the REHASH command
-LOCOP_REHASH
-  Allows a local operator (defined by a lowercase o:line in ircd.conf)
-  to cause the server to reload its configuration file (ircd.conf) with
-  the REHASH command.  If unsure, select 'n'.
-
-Allow local opers to use the RESTART command
-LOCOP_RESTART
-  Allows a local operator (defined by a lowercase o:line in ircd.conf)
-  to use the RESTART command.  If unsure, select 'n'.
-
-Allow local opers to use the DIE command
-LOCOP_DIE
-  Allows a local operator (defined by a lowercase o:line in ircd.conf)
-  to use the DIE command.  If unsure, select 'n'.
-
-Allow local opers to add local G-lines
-LOCOP_LGLINE
-  Allows a local operator (defined by a lowercase o:line in ircd.conf)
-  to add local G-lines with the GLINE command.  This is like a *local* KILL,
-  except that the user being killed can't immediately reconnect: He will
-  have to wait for the G-line to expire.
-
 Do you want to have a default LIST parameter
 CONFIG_LIST
   Pre-Undernet, the LIST command could either be given with one channel
@@ -827,14 +714,6 @@ MSGLOG_SIZE
   of _static_ memory! Recommended value is 128. You must include this even if
   you selected 'n' for MSGLOG_ENABLED.
 
-Only allow KILLs of local clients
-LOCAL_KILL_ONLY
-  This only allows operators of this server to KILL clients directly connected
-  to this server.  Operators will not be able to issue KILLs for clients on
-  other servers.  Some networks (not Undernet) require that this be defined
-  for newly linking servers, but if you haven't been told to do otherwise,
-  specify 'n' here.
-
 Max server idle time (60)
 TIMESEC
   This is the maximum idle time for the server. If no messages are received
@@ -937,11 +816,3 @@ DEFAULTMAXSENDQLENGTH
   (see doc/example.conf for details on Y: lines).  You will probably
   always override this value in your "ircd.conf" with the Y: lines.
   The given value used to be an often used value for client sendqs.
-
-Use new oper commands (JUPE, CLEARMODE, OPMODE, GLINE)
-CONFIG_OPERCMDS
-  Several new oper-only commands were added to the server source
-  during the Uworld integration project.  Until all servers are
-  upgraded to versions that understand the new server<->server
-  traffic, they must remain disabled, however.  This option activates
-  the client-side part of those changes.
index b59b4027991421e616f79fd842035f7d76f0d7d2..565548726ea15c69f655efbff5c0a4379b08aaea 100644 (file)
@@ -116,12 +116,6 @@ struct Client;
 #define IsChannelName(name)     (*(name) == '#' || \
                                 IsModelessChannel(name) || IsLocalChannel(name))
 
-/*
- * Check if a sptr is an oper, and chptr is a local channel.
- */
-#define IsOperOnLocalChannel(sptr,chname) \
-                ((IsAnOper(sptr)) && (IsLocalChannel(chname)))
-
 typedef enum ChannelGetType {
   CGT_NO_CREATE,
   CGT_CREATE
@@ -153,12 +147,10 @@ typedef enum ChannelGetType {
  */
 #define MAGIC_REMOTE_JOIN_TS 1270080000
 
-#ifdef OPER_WALK_THROUGH_LMODES
 /*
  * used in can_join to determine if an oper forced a join on a channel
  */
 #define MAGIC_OPER_OVERRIDE 1000
-#endif
 
 
 extern const char* const PartFmt1;
index 3bbce511ba98f5ea9ee435c8b5c298d9e6ddc56d..910ee6ed4d91b07084a73818d159b4026535f1cc 100644 (file)
@@ -138,6 +138,7 @@ struct Client {
   struct in_addr cli_ip;        /* Real ip# NOT defined for remote servers! */
   short          cli_status;    /* Client type */
   unsigned char  cli_local;     /* local or remote client */
+  unsigned int   cli_privs;     /* Oper privileges */
   char cli_name[HOSTLEN + 1];   /* Unique name of the client, nick or host */
   char cli_username[USERLEN + 1]; /* username here now for auth stuff */
   char cli_info[REALLEN + 1];   /* Free form additional client information */
@@ -162,6 +163,7 @@ struct Client {
 #define cli_ip(cli)            ((cli)->cli_ip)
 #define cli_status(cli)                ((cli)->cli_status)
 #define cli_local(cli)         ((cli)->cli_local)
+#define cli_privs(cli)         ((cli)->cli_privs)
 #define cli_name(cli)          ((cli)->cli_name)
 #define cli_username(cli)      ((cli)->cli_username)
 #define cli_info(cli)          ((cli)->cli_info)
@@ -403,6 +405,37 @@ struct Client {
 #define SNO_OPER (SNO_CONNEXIT|SNO_OLDREALOP)
 #define SNO_NOISY (SNO_SERVKILL|SNO_UNAUTH)
 
+#define PRIV_CHAN_LIMIT                0x00000001 /* no channel limit on oper */
+#define PRIV_MODE_LCHAN                0x00000002 /* oper can mode local chans */
+#define PRIV_WALK_LCHAN                0x00000004 /* oper can walk thru local modes */
+#define PRIV_DEOP_LCHAN                0x00000008 /* no deop oper on local chans */
+#define PRIV_SHOW_INVIS                0x00000010 /* show local invisible users */
+#define PRIV_SHOW_ALL_INVIS    0x00000020 /* show all invisible users */
+#define PRIV_UNLIMIT_QUERY     0x00000040 /* unlimit who queries */
+
+#define PRIV_KILL              0x00000080 /* oper can KILL */
+#define PRIV_LOCAL_KILL                0x00000100 /* oper can local KILL */
+#define PRIV_REHASH            0x00000200 /* oper can REHASH */
+#define PRIV_RESTART           0x00000400 /* oper can RESTART */
+#define PRIV_DIE               0x00000800 /* oper can DIE */
+#define PRIV_GLINE             0x00001000 /* oper can GLINE */
+#define PRIV_LOCAL_GLINE       0x00002000 /* oper can local GLINE */
+#define PRIV_JUPE              0x00004000 /* oper can JUPE */
+#define PRIV_LOCAL_JUPE                0x00008000 /* oper can local JUPE */
+#define PRIV_OPMODE            0x00010000 /* oper can OP/CLEARMODE */
+#define PRIV_LOCAL_OPMODE      0x00020000 /* oper can local OP/CLEARMODE */
+#define PRIV_SET               0x00040000 /* oper can SET */
+#define PRIV_WHOX              0x00080000 /* oper can use /who x */
+#define PRIV_BADCHAN           0x00100000 /* oper can BADCHAN */
+#define PRIV_LOCAL_BADCHAN     0x00200000 /* oper can local BADCHAN */
+#define PRIV_SEE_CHAN          0x00400000 /* oper can see in secret chans */
+
+#define PRIV_PROPAGATE         0x00800000 /* propagate oper status */
+#define PRIV_DISPLAY           0x01000000 /* "Is an oper" displayed */
+#define PRIV_SEE_OPERS         0x02000000 /* display hidden opers */
+
+#define HasPriv(cli, priv)     (cli_privs(cli) & (priv))
+
 typedef enum ShowIPType {
   HIDE_IP,
   SHOW_IP,
@@ -414,6 +447,7 @@ extern int client_get_ping(const struct Client* local_client);
 extern void client_drop_sendq(struct Connection* con);
 extern void client_add_sendq(struct Connection* con,
                             struct Connection** con_p);
+extern void client_set_privs(struct Client* client);
 
 #endif /* INCLUDED_client_h */
 
index e76140ee23b3f481ff70bff8ca5950569b1b09ce..2335fa6900dedac87a1ee34f07f43aac4b3ebea2 100644 (file)
@@ -25,6 +25,41 @@ struct Client;
 
 enum Feature {
   FEAT_LOG,
+
+  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_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_BADCHAN,
+  FEAT_OPER_LBADCHAN,
+  FEAT_OPERS_SEE_IN_SECRET_CHANNELS,
+
+  FEAT_LOCOP_KILL,
+  FEAT_LOCOP_REHASH,
+  FEAT_LOCOP_RESTART,
+  FEAT_LOCOP_DIE,
+  FEAT_LOCOP_LGLINE,
+  FEAT_LOCOP_LJUPE,
+  FEAT_LOCOP_LOPMODE,
+  FEAT_LOCOP_LBADCHAN,
+  FEAT_LOCOP_SEE_IN_SECRET_CHANNELS,
+
   FEAT_LAST_F
 };
 
index 8eefe1fa0779996bf1b9ba6f0105e21671444a8d..a707a718ca218d931405df0483e1bcf972d4b40f 100644 (file)
@@ -56,8 +56,8 @@ extern void send_usage(struct Client *cptr, char *nick);
 
 #endif /* !DEBUGMODE */
 
+extern const char* debug_serveropts(void);
 extern void debug_init(int use_tty);
 extern void count_memory(struct Client *cptr, char *nick);
-extern char serveropts[];
 
 #endif /* INCLUDED_s_debug_h */
index e02358a9a408293b886c3b8d862c7424abda6162..247f6c5a027e39ff6f1226f2d5102c81f244fc3a 100644 (file)
@@ -44,33 +44,13 @@ struct Channel;
 
 #define IS_VISIBLE_USER(s,ac) ((s==ac) || (!IsInvisible(ac)))
 
-#if defined(SHOW_INVISIBLE_LUSERS) || defined(SHOW_ALL_INVISIBLE_USERS)
-#define SEE_LUSER(s, ac, b) (IS_VISIBLE_USER(s, ac) || ((b & WHOSELECT_EXTRA) && MyConnect(ac) && IsAnOper(s)))
-#else
-#define SEE_LUSER(s, ac, b) (IS_VISIBLE_USER(s, ac))
-#endif
+#define SEE_LUSER(s, ac, b) (IS_VISIBLE_USER(s, ac) || ((b & WHOSELECT_EXTRA) && MyConnect(ac) && HasPriv((s), PRIV_SHOW_INVIS | PRIV_SHOW_ALL_INVIS)))
 
-#ifdef SHOW_ALL_INVISIBLE_USERS
-#define SEE_USER(s, ac, b) (SEE_LUSER(s, ac, b) || ((b & WHOSELECT_EXTRA) && IsOper(s)))
-#else
-#define SEE_USER(s, ac, b) (SEE_LUSER(s, ac, b))
-#endif
+#define SEE_USER(s, ac, b) (SEE_LUSER(s, ac, b) || ((b & WHOSELECT_EXTRA) && HasPriv((s), PRIV_SHOW_ALL_INVIS)))
 
-#ifdef UNLIMIT_OPER_QUERY
-#define SHOW_MORE(sptr, counter) (IsAnOper(sptr) || (!(counter-- < 0)) )
-#else
-#define SHOW_MORE(sptr, counter) (!(counter-- < 0))
-#endif
+#define SHOW_MORE(sptr, counter) (HasPriv(sptr, PRIV_UNLIMIT_QUERY) || (!(counter-- < 0)) )
 
-#ifdef OPERS_SEE_IN_SECRET_CHANNELS
-#ifdef LOCOP_SEE_IN_SECRET_CHANNELS
-#define SEE_CHANNEL(s, chptr, b) (!SecretChannel(chptr) || ((b & WHOSELECT_EXTRA) && IsAnOper(s)))
-#else
-#define SEE_CHANNEL(s, chptr, b) (!SecretChannel(chptr) || ((b & WHOSELECT_EXTRA) && IsOper(s)))
-#endif
-#else
-#define SEE_CHANNEL(s, chptr, b) (!SecretChannel(chptr))
-#endif
+#define SEE_CHANNEL(s, chptr, b) (!SecretChannel(chptr) || ((b & WHOSELECT_EXTRA) && HasPriv((s), PRIV_SEE_CHAN)))
 
 #define MAX_WHOIS_LINES 50
 
index 68d7a86cd677f6e9a32f84125f00bc4b8ccae438..114deb0938487e662f8c07961fd0a8827ebb2468 100644 (file)
@@ -1053,15 +1053,12 @@ int can_join(struct Client *sptr, struct Channel *chptr, char *key)
     if (lp->value.chptr == chptr)
       return 0;
   
-#ifdef OPER_WALK_THROUGH_LMODES
   /* An oper can force a join on a local channel using "OVERRIDE" as the key. 
      a HACK(4) notice will be sent if he would not have been supposed
      to join normally. */ 
-  if (IsOperOnLocalChannel(sptr,chptr->chname) && !BadPtr(key) && compall("OVERRIDE",key) == 0)
-  {
+  if (IsLocalChannel(chptr->chname) && HasPriv(sptr, PRIV_WALK_LCHAN) &&
+      !BadPtr(key) && compall("OVERRIDE",key) == 0)
     overrideJoin = MAGIC_OPER_OVERRIDE;
-  }
-#endif
 
   if (chptr->mode.mode & MODE_INVITEONLY)
        return overrideJoin + ERR_INVITEONLYCHAN;
@@ -2386,17 +2383,15 @@ mode_process_clients(struct ParseState *state)
        }
       }
 
-#ifdef NO_OPER_DEOP_LCHAN
       /* don't allow local opers to be deopped on local channels */
       if (MyUser(state->sptr) && state->cli_change[i].client != state->sptr &&
-         IsOperOnLocalChannel(state->cli_change[i].client,
-                              state->chptr->chname)) {
+         IsLocalChannel(state->chptr->chname) &&
+         HasPriv(state->cli_change[i].client, PRIV_DEOP_LCHAN)) {
        send_reply(state->sptr, ERR_ISOPERLCHAN,
                   cli_name(state->cli_change[i].client),
                   state->chptr->chname);
        continue;
       }
-#endif
     }
 
     /* accumulate the change */
index 317efc7fb03db697a75d40b3b65ceb700c4c3b4c..33d45ee8ed92be94f0008bb6c21e654f4064e59b 100644 (file)
@@ -21,6 +21,7 @@
 #include "client.h"
 #include "class.h"
 #include "ircd.h"
+#include "ircd_features.h"
 #include "ircd_reply.h"
 #include "list.h"
 #include "numeric.h"
@@ -92,3 +93,103 @@ void client_add_sendq(struct Connection* con, struct Connection** con_p)
     *con_p = con;
   }
 }
+
+/* client_set_privs(struct Client* client)
+ *
+ * Sets the privileges for opers.
+ */
+void
+client_set_privs(struct Client* client)
+{
+  unsigned int privs = 0;
+  unsigned int antiprivs = 0;
+
+  if (!IsAnOper(client)) {
+    cli_privs(client) = 0; /* clear privilege mask */
+    return;
+  } else if (!MyConnect(client)) {
+    cli_privs(client) = ~(PRIV_SET); /* everything but set... */
+    return;
+  }
+
+  /* This sequence is temporary until the .conf is carefully rewritten */
+
+  privs |= (PRIV_WHOX | PRIV_DISPLAY);
+  if (feature_bool(FEAT_OPER_NO_CHAN_LIMIT))
+    privs |= PRIV_CHAN_LIMIT;
+  if (feature_bool(FEAT_OPER_MODE_LCHAN))
+    privs |= (PRIV_MODE_LCHAN | PRIV_LOCAL_OPMODE);
+  if (feature_bool(FEAT_OPER_WALK_THROUGH_LMODES))
+    privs |= PRIV_WALK_LCHAN;
+  if (feature_bool(FEAT_NO_OPER_DEOP_LCHAN))
+    privs |= PRIV_DEOP_LCHAN;
+  if (feature_bool(FEAT_SHOW_INVISIBLE_USERS))
+    privs |= PRIV_SHOW_INVIS;
+  if (feature_bool(FEAT_SHOW_ALL_INVISIBLE_USERS))
+    privs |= PRIV_SHOW_ALL_INVIS;
+  if (feature_bool(FEAT_UNLIMIT_OPER_QUERY))
+    privs |= PRIV_UNLIMIT_QUERY;
+  if (feature_bool(FEAT_LOCAL_KILL_ONLY))
+    antiprivs |= PRIV_KILL;
+  if (!feature_bool(FEAT_CONFIG_OPERCMDS))
+    antiprivs |= (PRIV_GLINE | PRIV_JUPE | PRIV_OPMODE | PRIV_BADCHAN);
+
+  if (IsOper(client)) {
+    privs |= (PRIV_SET | PRIV_PROPAGATE | PRIV_SEE_OPERS);
+    if (feature_bool(FEAT_OPER_KILL))
+      privs |= (PRIV_KILL | PRIV_LOCAL_KILL);
+    if (feature_bool(FEAT_OPER_REHASH))
+      privs |= PRIV_REHASH;
+    if (feature_bool(FEAT_OPER_RESTART))
+      privs |= PRIV_RESTART;
+    if (feature_bool(FEAT_OPER_DIE))
+      privs |= PRIV_DIE;
+    if (feature_bool(FEAT_OPER_GLINE))
+      privs |= PRIV_GLINE;
+    if (feature_bool(FEAT_OPER_LGLINE))
+      privs |= PRIV_LOCAL_GLINE;
+    if (feature_bool(FEAT_OPER_JUPE))
+      privs |= PRIV_JUPE;
+    if (feature_bool(FEAT_OPER_LJUPE))
+      privs |= PRIV_LOCAL_JUPE;
+    if (feature_bool(FEAT_OPER_OPMODE))
+      privs |= PRIV_OPMODE;
+    if (feature_bool(FEAT_OPER_LOPMODE))
+      privs |= PRIV_LOCAL_OPMODE;
+    if (feature_bool(FEAT_OPER_BADCHAN))
+      privs |= PRIV_BADCHAN;
+    if (feature_bool(FEAT_OPER_LBADCHAN))
+      privs |= PRIV_LOCAL_BADCHAN;
+    if (feature_bool(FEAT_OPERS_SEE_IN_SECRET_CHANNELS))
+      privs |= PRIV_SEE_CHAN;
+  } else { /* is a local operator */
+    if (feature_bool(FEAT_LOCOP_KILL))
+      privs |= PRIV_LOCAL_KILL;
+    if (feature_bool(FEAT_LOCOP_REHASH))
+      privs |= PRIV_REHASH;
+    if (feature_bool(FEAT_LOCOP_RESTART))
+      privs |= PRIV_RESTART;
+    if (feature_bool(FEAT_LOCOP_DIE))
+      privs |= PRIV_DIE;
+    if (feature_bool(FEAT_LOCOP_LGLINE))
+      privs |= PRIV_LOCAL_GLINE;
+    if (feature_bool(FEAT_LOCOP_LJUPE))
+      privs |= PRIV_LOCAL_JUPE;
+    if (feature_bool(FEAT_LOCOP_LOPMODE))
+      privs |= PRIV_LOCAL_OPMODE;
+    if (feature_bool(FEAT_LOCOP_LBADCHAN))
+      privs |= PRIV_LOCAL_BADCHAN;
+    if (feature_bool(FEAT_LOCOP_SEE_IN_SECRET_CHANNELS))
+      privs |= PRIV_SEE_CHAN;
+  }
+
+  /* This is the end of the gross section */
+
+  if (privs & PRIV_PROPAGATE)
+    privs |= PRIV_DISPLAY;
+  else
+    antiprivs |= (PRIV_KILL | PRIV_GLINE | PRIV_JUPE | PRIV_OPMODE |
+                 PRIV_BADCHAN);
+
+  cli_privs(client) = privs & ~antiprivs;
+}
index 565d7113af8e4dd467ca405bd1d7a3b3ad713042..6746af259568eb9f72fbb5397f823957c183f879 100644 (file)
@@ -248,10 +248,9 @@ gline_add(struct Client *cptr, struct Client *sptr, char *userhost,
       || userhost[2] == '#' || userhost[2] == '&' || userhost[2] == '+'
 # endif /* OLD_GLINE */
       ) {
-# ifndef LOCAL_BADCHAN
-    if (flags & GLINE_LOCAL)
-      return 0;
-# endif
+    if ((flags & GLINE_LOCAL) && !HasPriv(sptr, PRIV_LOCAL_BADCHAN))
+      return send_reply(sptr, ERR_NOPRIVILEGES);
+
     flags |= GLINE_BADCHAN;
   }
 
index 2ac639841d32be76d3862fa50577581e828e756a..7e6a62d8e13b560bbffddec10ff91f83eb19cbdc 100644 (file)
@@ -205,16 +205,58 @@ static struct FeatureDesc {
   feat_report_call report;  /* report feature values */
 } features[] = {
 #define F(type, flags, v_int, v_str, set, reset, get, unmark, mark, report)   \
-  { FEAT_##type, #type, (flags),                                             \
-    0, (v_int), 0, (v_str),                                                  \
-    (set), (reset), (get),                                                   \
-    (unmark), (mark),                                                        \
-    (report) }
+  { FEAT_ ## type, #type, (flags), 0, (v_int), 0, (v_str),                   \
+    (set), (reset), (get), (unmark), (mark), (report) }
+#define F_I(type, v_int)                                                     \
+  { FEAT_ ## type, #type, FEAT_INT, 0, (v_int), 0, 0, 0, 0, 0, 0, 0, 0 }
+#define F_B(type, v_int)                                                     \
+  { FEAT_ ## type, #type, FEAT_BOOL, 0, (v_int), 0, 0, 0, 0, 0, 0, 0, 0 }
+#define F_S(type, flags, v_int)                                                      \
+  { FEAT_ ## type, #type, FEAT_STR | (flags), 0, 0, 0, (v_str),                      \
+    0, 0, 0, 0, 0, 0 }
 
   F(LOG, FEAT_NONE | FEAT_MYOPER, 0, 0,
     feature_log_set, feature_log_reset, feature_log_get,
     log_feature_unmark, log_feature_mark, log_feature_report),
 
+  F_B(OPER_NO_CHAN_LIMIT, 1),
+  F_B(OPER_MODE_LCHAN, 1),
+  F_B(OPER_WALK_THROUGH_LMODES, 0),
+  F_B(NO_OPER_DEOP_LCHAN, 0),
+  F_B(SHOW_INVISIBLE_USERS, 1),
+  F_B(SHOW_ALL_INVISIBLE_USERS, 1),
+  F_B(UNLIMIT_OPER_QUERY, 0),
+  F_B(LOCAL_KILL_ONLY, 0),
+  F_B(CONFIG_OPERCMDS, 1), /* XXX change default before release */
+
+  F_B(OPER_KILL, 1),
+  F_B(OPER_REHASH, 1),
+  F_B(OPER_RESTART, 1),
+  F_B(OPER_DIE, 1),
+  F_B(OPER_GLINE, 1),
+  F_B(OPER_LGLINE, 1),
+  F_B(OPER_JUPE, 1),
+  F_B(OPER_LJUPE, 1),
+  F_B(OPER_OPMODE, 1),
+  F_B(OPER_LOPMODE, 1),
+  F_B(OPER_BADCHAN, 0),
+  F_B(OPER_LBADCHAN, 0),
+  F_B(OPERS_SEE_IN_SECRET_CHANNELS, 1),
+
+  F_B(LOCOP_KILL, 0),
+  F_B(LOCOP_REHASH, 1),
+  F_B(LOCOP_RESTART, 0),
+  F_B(LOCOP_DIE, 0),
+  F_B(LOCOP_LGLINE, 1),
+  F_B(LOCOP_LJUPE, 1),
+  F_B(LOCOP_LOPMODE, 1),
+  F_B(LOCOP_LBADCHAN, 0),
+  F_B(LOCOP_SEE_IN_SECRET_CHANNELS, 0),
+
+#undef F_S
+#undef F_B
+#undef F_I
+#undef F
   { FEAT_LAST_F, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }
 };
 
@@ -246,6 +288,9 @@ feature_set(struct Client* from, const char* const* fields, int count)
   int i;
   struct FeatureDesc *feat;
 
+  if (from && !HasPriv(from, PRIV_SET))
+    return send_reply(from, ERR_NOPRIVILEGES);
+
   if (count < 1) {
     if (from) /* report an error in the number of arguments */
       need_more_params(from, "SET");
@@ -348,6 +393,9 @@ feature_reset(struct Client* from, const char* const* fields, int count)
 
   assert(0 != from);
 
+  if (!HasPriv(from, PRIV_SET))
+    return send_reply(from, ERR_NOPRIVILEGES);
+
   if (count < 1) /* check arguments */
     need_more_params(from, "RESET");
   else if ((feat = feature_desc(from, fields[0]))) { /* get descriptor */
index 5eca38b8e37561462d33e63f764d42b116dcfbda..b64dd001bc2381f575081dcc2397895a55582a80 100644 (file)
@@ -93,6 +93,7 @@
 #include "hash.h"
 #include "ircd.h"
 #include "ircd_alloc.h"
+#include "ircd_features.h"
 #include "ircd_log.h"
 #include "ircd_reply.h"
 #include "ircd_string.h"
@@ -281,12 +282,12 @@ ms_clearmode(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
 int
 mo_clearmode(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
 {
-#ifndef CONFIG_OPERCMDS
-  return send_reply(sptr, ERR_DISABLED, "CLEARMODE");
-#else
   struct Channel *chptr;
   char *control = "ovpsmikbl"; /* default control string */
 
+  if (!feature_bool(FEAT_CONFIG_OPERCMDS))
+    return send_reply(sptr, ERR_DISABLED, "CLEARMODE");
+
   if (parc < 2)
     return need_more_params(sptr, "CLEARMODE");
 
@@ -295,12 +296,12 @@ mo_clearmode(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
 
   clean_channelname(parv[1]);
 
-  if (!IsOper(sptr) && !IsLocalChannel(parv[1]))
+  if (!HasPriv(sptr,
+              IsLocalChannel(parv[1]) ? PRIV_LOCAL_OPMODE : PRIV_OPMODE))
     return send_reply(sptr, ERR_NOPRIVILEGES);
 
-  if (!IsChannelName(parv[1]) || !(chptr = FindChannel(parv[1])))
+  if (('#' != *parv[1] && '&' != *parv[1]) || !(chptr = FindChannel(parv[1])))
     return send_reply(sptr, ERR_NOSUCHCHANNEL, parv[1]);
 
   return do_clearmode(cptr, sptr, chptr, control);
-#endif /* CONFIG_OPERCMDS */
 }
index 228813087ec64a8f7d34d816300e63bf984431b6..fbc1c427829665adbe2dc1306499b59cdb5f3f6f 100644 (file)
  */
 int mo_die(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
 {
-#if defined(OPER_DIE) || defined(LOCOP_DIE)
   struct Client *acptr;
   int i;
 
-#ifndef LOCOP_DIE
-  if (!MyUser(sptr) || !IsOper(sptr))
-#else
-#ifdef  OPER_DIE
-  if (!MyUser(sptr) || !IsAnOper(sptr))
-#else
-  if (!MyUser(sptr) || !IsLocOp(sptr))
-#endif
-#endif
-  {
+  if (!HasPriv(sptr, PRIV_DIE))
     return send_reply(sptr, ERR_NOPRIVILEGES);
-  }
 
   for (i = 0; i <= HighestFd; i++)
   {
@@ -134,49 +123,6 @@ int mo_die(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
                    get_client_name(sptr, HIDE_IP));
   }
   server_die("received DIE");
-#endif /* defined(OPER_DIE) || defined(LOCOP_DIE) */
-  return 0;
-}
-
-  
-#if 0
-#if defined(OPER_DIE) || defined(LOCOP_DIE)
-/*
- * m_die
- */
-int m_die(struct Client *cptr, struct Client *sptr, int parc, char *parv[])
-{
-  struct Client *acptr;
-  int i;
-
-#ifndef LOCOP_DIE
-  if (!MyUser(sptr) || !IsOper(sptr))
-#else
-#ifdef  OPER_DIE
-  if (!MyUser(sptr) || !IsAnOper(sptr))
-#else
-  if (!MyUser(sptr) || !IsLocOp(sptr))
-#endif
-#endif
-  {
-    sendto_one(sptr, err_str(ERR_NOPRIVILEGES), me.name, parv[0]); /* XXX DEAD */
-    return 0;
-  }
 
-  for (i = 0; i <= HighestFd; i++)
-  {
-    if (!(acptr = LocalClientArray[i]))
-      continue;
-    if (IsUser(acptr))
-      sendto_one(acptr, ":%s NOTICE %s :Server Terminating. %s", /* XXX DEAD */
-                 me.name, acptr->name, get_client_name(sptr, HIDE_IP));
-    else if (IsServer(acptr))
-      sendto_one(acptr, ":%s ERROR :Terminated by %s", /* XXX DEAD */
-                 me.name, get_client_name(sptr, HIDE_IP));
-  }
-  server_die("received DIE");
   return 0;
 }
-#endif
-#endif /* 0 */
-
index 7f01f9b846cea3591194a9e79e3e6fe1ecf363fc..6a5f1e037cc0cb135cc78b89718c50394f49d8f4 100644 (file)
@@ -91,6 +91,7 @@
 #include "gline.h"
 #include "hash.h"
 #include "ircd.h"
+#include "ircd_features.h"
 #include "ircd_reply.h"
 #include "ircd_string.h"
 #include "match.h"
@@ -227,16 +228,12 @@ mo_gline(struct Client *cptr, struct Client *sptr, int parc, char *parv[])
   if (*mask == '+') {
     flags |= GLINE_ACTIVE;
     mask++;
+
   } else if (*mask == '-')
     mask++;
   else
     return gline_list(sptr, mask);
 
-#ifndef LOCOP_LGLINE
-  if (!IsOper(sptr))
-    return send_reply(sptr, ERR_NOPRIVILEGES);
-#endif
-
   if (parc == 4) {
     expire_off = atoi(parv[2]);
     reason = parv[3];
@@ -254,28 +251,26 @@ mo_gline(struct Client *cptr, struct Client *sptr, int parc, char *parv[])
        return send_reply(sptr, ERR_NOSUCHSERVER, target);
 
       if (!IsMe(acptr)) { /* manually propagate, since we don't set it */
-#ifndef CONFIG_OPERCMDS
-       return send_reply(sptr, ERR_DISABLED, "GLINE");
-#else
-       if (!IsOper(sptr))
+       if (!feature_bool(FEAT_CONFIG_OPERCMDS))
+         return send_reply(sptr, ERR_DISABLED, "GLINE");
+
+       if (!HasPriv(sptr, PRIV_GLINE))
          return send_reply(sptr, ERR_NOPRIVILEGES);
 
        sendcmdto_one(sptr, CMD_GLINE, acptr, "%C %c%s %s %Tu :%s", acptr,
-                     flags & GLINE_ACTIVE ? '?' : '-', mask, parv[3],
+                     flags & GLINE_ACTIVE ? '+' : '-', mask, parv[3],
                      TStime(), reason);
        return 0;
-#endif
-      }
+      } else if (!HasPriv(sptr, PRIV_LOCAL_GLINE))
+       return send_reply(sptr, ERR_NOPRIVILEGES);
 
       flags |= GLINE_LOCAL;
-    } else if (!IsOper(sptr))
+    } else if (!HasPriv(sptr, PRIV_GLINE))
       return send_reply(sptr, ERR_NOPRIVILEGES);
   }
 
-#ifndef CONFIG_OPERCMDS
-  if (!(flags & GLINE_LOCAL))
+  if (!(flags & GLINE_LOCAL) && !feature_bool(FEAT_CONFIG_OPERCMDS))
     return send_reply(sptr, ERR_DISABLED, "GLINE");
-#endif /* CONFIG_OPERCMDS */
 
   agline = gline_find(mask, GLINE_ANY | GLINE_EXACT);
 
index 051216ee1d4db9ddca98fff28ea783df073b657e..b0d28d7729afc24c129fbd81ef83bb4312bfb162 100644 (file)
@@ -172,9 +172,7 @@ int m_join(struct Client *cptr, struct Client *sptr, int parc, char *parv[])
   struct Channel *chptr;
   struct JoinBuf join;
   struct JoinBuf create;
-#ifdef BADCHAN
   struct Gline *gline;
-#endif
   unsigned int flags = 0;
   int i;
   char *p = 0;
@@ -204,14 +202,12 @@ int m_join(struct Client *cptr, struct Client *sptr, int parc, char *parv[])
       continue;
     }
 
-#ifdef BADCHAN
     /* BADCHANed channel */
     if ((gline = gline_find(name, GLINE_BADCHAN | GLINE_EXACT)) &&
        GlineIsActive(gline) && !IsAnOper(sptr)) {
       send_reply(sptr, ERR_BANNEDFROMCHAN, name);
       continue;
     }
-#endif
 
     if ((chptr = FindChannel(name))) {
       if (find_member_link(chptr, sptr))
@@ -221,12 +217,8 @@ int m_join(struct Client *cptr, struct Client *sptr, int parc, char *parv[])
     } else
       flags = IsModelessChannel(name) ? CHFL_DEOPPED : CHFL_CHANOP;
 
-    if (cli_user(sptr)->joined >= MAXCHANNELSPERUSER
-#ifdef OPER_NO_CHAN_LIMIT
-       /* Opers are allowed to join any number of channels */
-       && !IsAnOper(sptr)
-#endif
-       ) {
+    if (cli_user(sptr)->joined >= MAXCHANNELSPERUSER &&
+       !HasPriv(sptr, PRIV_CHAN_LIMIT)) {
       send_reply(sptr, ERR_TOOMANYCHANNELS, chptr ? chptr->chname : name);
       break; /* no point processing the other channels */
     }
@@ -235,7 +227,6 @@ int m_join(struct Client *cptr, struct Client *sptr, int parc, char *parv[])
       if (check_target_limit(sptr, chptr, chptr->chname, 0))
        continue; /* exceeded target limit */
       else if ((i = can_join(sptr, chptr, keys))) {
-#ifdef OPER_WALK_THROUGH_LMODES
        if (i > MAGIC_OPER_OVERRIDE) { /* oper overrode mode */
          switch (i - MAGIC_OPER_OVERRIDE) {
          case ERR_CHANNELISFULL: /* figure out which mode */
@@ -262,10 +253,6 @@ int m_join(struct Client *cptr, struct Client *sptr, int parc, char *parv[])
          send_reply(sptr, i, chptr->chname);
          continue;
        }
-#else
-       send_reply(sptr, i, chptr->chname);
-       continue;
-#endif
       } /* else if ((i = can_join(sptr, chptr, keys))) { */
 
       joinbuf_join(&join, chptr, flags);
index 4be685655c6914c88655d01911ee3a4736e9069f..3926f32eaeb3ac92ee2e728a80c5a08ef39078bd 100644 (file)
@@ -92,6 +92,7 @@
 #include "jupe.h"
 #include "hash.h"
 #include "ircd.h"
+#include "ircd_features.h"
 #include "ircd_reply.h"
 #include "ircd_string.h"
 #include "match.h"
@@ -192,7 +193,6 @@ int ms_jupe(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
  * parv[4] = [Comment]
  *
  */
-#ifdef CONFIG_OPERCMDS
 int mo_jupe(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
 {
   struct Client *acptr = 0;
@@ -212,6 +212,9 @@ int mo_jupe(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
   else
     return jupe_list(sptr, server);
 
+  if (!feature_bool(FEAT_CONFIG_OPERCMDS))
+    return send_reply(sptr, ERR_DISABLED, "JUPE");
+
   if (parc == 4) {
     expire_off = atoi(parv[2]);
     reason = parv[3];
@@ -229,17 +232,18 @@ int mo_jupe(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
        return send_reply(sptr, ERR_NOSUCHSERVER, target);
 
       if (!IsMe(acptr)) { /* manually propagate, since we don't set it */
-       if (!IsOper(sptr))
+       if (!HasPriv(sptr, PRIV_GLINE))
          return send_reply(sptr, ERR_NOPRIVILEGES);
 
        sendcmdto_one(sptr, CMD_JUPE, acptr, "%C %c%s %s %Tu :%s", acptr,
                      flags & JUPE_ACTIVE ? '+' : '-', server, parv[3],
                      TStime(), reason);
        return 0;
-      }
+      } else if (!HasPriv(sptr, PRIV_LOCAL_GLINE))
+       return send_reply(sptr, ERR_NOPRIVILEGES);
 
       flags |= JUPE_LOCAL;
-    } else if (!IsOper(sptr))
+    } else if (!HasPriv(sptr, PRIV_GLINE))
       return send_reply(sptr, ERR_NOPRIVILEGES);
   }
 
@@ -258,7 +262,6 @@ int mo_jupe(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
 
   return jupe_add(cptr, sptr, server, reason, expire_off, TStime(), flags);
 }
-#endif /* CONFIG_OPERCMDS */
 
 /*
  * m_jupe - user message handler
index 4703216fd25b302775c27496d4c10e32bb4dcaba..6252247e3217db49270f8873873a51242858c44f 100644 (file)
@@ -136,11 +136,9 @@ int m_kick(struct Client *cptr, struct Client *sptr, int parc, char *parv[])
   if (IsChannelService(who))
     return send_reply(sptr, ERR_ISCHANSERVICE, cli_name(who), chptr->chname);
 
-#ifdef NO_OPER_DEOP_LCHAN
   /* Prevent kicking opers from local channels -DM- */
-  if (IsOperOnLocalChannel(who, chptr->chname))
+  if (IsLocalChannel(chptr->chname) && HasPriv(who, PRIV_DEOP_LCHAN))
     return send_reply(sptr, ERR_ISOPERLCHAN, cli_name(who), chptr->chname);
-#endif
 
   /* check if kicked user is actually on the channel */
   if (!(member = find_member_link(chptr, who)) || IsZombie(member))
index dd5b36ad6da8e1e5e89155811e8190e085ffb7a1..52c64a4195712e4dce2c8f6ebdcd2d696de37026 100644 (file)
@@ -244,8 +244,6 @@ int mo_kill(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
   assert(cptr == sptr);
   assert(IsAnOper(sptr));
 
-#if defined(OPER_KILL)
-
   if (parc < 3 || EmptyString(parv[parc - 1]))
     return need_more_params(sptr, "KILL");
 
@@ -262,7 +260,7 @@ int mo_kill(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
     sendcmdto_one(&me, CMD_NOTICE, sptr, "%C :Changed KILL %s into %s", sptr,
                  user, cli_name(victim));
   }
-  if (!MyConnect(victim) && IsLocOp(cptr))
+  if (!HasPriv(sptr, MyConnect(victim) ? PRIV_LOCAL_KILL : PRIV_KILL))
     return send_reply(sptr, ERR_NOPRIVILEGES);
 
   if (IsServer(victim) || IsMe(victim)) {
@@ -275,13 +273,12 @@ int mo_kill(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
     return send_reply(sptr, ERR_ISCHANSERVICE, "KILL", cli_name(victim));
 
 
-#ifdef LOCAL_KILL_ONLY
-  if (!MyConnect(victim)) {
-    sendcmdto_one(&me, CMD_NOTICE, sptr, "%C :Nick %s isnt on your server", sptr,
-              cli_name(victim));
+  if (!MyConnect(victim) && !HasPriv(sptr, PRIV_KILL)) {
+    sendcmdto_one(&me, CMD_NOTICE, sptr, "%C :Nick %s isnt on your server",
+                 sptr, cli_name(victim));
     return 0;
   }
-#endif
+
   /*
    * The kill originates from this server, initialize path.
    * (In which case the 'path' may contain user suplied
@@ -346,12 +343,6 @@ int mo_kill(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
   }
 
   return exit_client(cptr, victim, sptr, buf);
-
-#else /* !defined(OPER_KILL) */
-
-  return send_reply(sptr, ERR_NOPRIVILEGES);
-
-#endif /* !defined(OPER_KILL) */
 }
 
 #if 0
index 54abb04587ea7c8ddef28bb0da7c6ff74bfa02f4..74792320bcf3d8e73e92ec7cdf2c0bdaf96e2748 100644 (file)
@@ -129,8 +129,7 @@ m_mode(struct Client *cptr, struct Client *sptr, int parc, char *parv[])
   }
 
   if (!(member = find_member_link(chptr, sptr)) || !IsChanOp(member)) {
-#ifdef OPER_MODE_LCHAN
-    if (IsOperOnLocalChannel(sptr, chptr->chname)) {
+    if (IsLocalChannel(chptr->chname) && HasPriv(sptr, PRIV_MODE_LCHAN)) {
       modebuf_init(&mbuf, sptr, cptr, chptr,
                   (MODEBUF_DEST_CHANNEL | /* Send mode to channel */
                    MODEBUF_DEST_HACK4));  /* Send HACK(4) notice */
@@ -139,7 +138,6 @@ m_mode(struct Client *cptr, struct Client *sptr, int parc, char *parv[])
                  MODE_PARSE_FORCE)); /* Force it to take */
       return modebuf_flush(&mbuf);
     } else
-#endif
       mode_parse(0, cptr, sptr, chptr, parc - 2, parv + 2,
                 (member ? MODE_PARSE_NOTOPER : MODE_PARSE_NOTMEMBER));
     return 0;
index 3681506e15385512b8cb1cacaefc6af848f526ee..b57c685e4af76c2b0df565dfc3616c3ba6e1239b 100644 (file)
@@ -189,6 +189,7 @@ int m_oper(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
     cli_flags(sptr) |= (FLAGS_WALLOP | FLAGS_SERVNOTICE | FLAGS_DEBUG);
 
     set_snomask(sptr, SNO_OPERDEFAULT, SNO_ADD);
+    client_set_privs(sptr);
     send_umode_out(cptr, sptr, old_mode);
     send_reply(sptr, RPL_YOUREOPER);
 
index fb4d52486f97daee1fc9477e3c81533b9c37e3c0..af9b03f5e12dd2c0ace4a895a497961767dd9f85 100644 (file)
@@ -92,6 +92,7 @@
 #include "channel.h"
 #include "hash.h"
 #include "ircd.h"
+#include "ircd_features.h"
 #include "ircd_reply.h"
 #include "ircd_string.h"
 #include "msg.h"
@@ -140,18 +141,22 @@ int ms_opmode(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
  */
 int mo_opmode(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
 {
-#ifndef CONFIG_OPERCMDS
-  return send_reply(sptr, ERR_DISABLED, "OPMODE");
-#else
   struct Channel *chptr = 0;
   struct ModeBuf mbuf;
   struct Membership *member;
 
+  if (!feature_bool(FEAT_CONFIG_OPERCMDS))
+    return send_reply(sptr, ERR_DISABLED, "OPMODE");
+
   if (parc < 3)
     return need_more_params(sptr, "OPMODE");
 
   clean_channelname(parv[1]);
 
+  if (!HasPriv(sptr,
+              IsLocalChannel(parv[1]) ? PRIV_LOCAL_OPMODE : PRIV_OPMODE))
+    return send_reply(sptr, ERR_NOPRIVILEGES);
+
   if (('#' != *parv[1] && '&' != *parv[1]) || !(chptr = FindChannel(parv[1])))
     return send_reply(sptr, ERR_NOSUCHCHANNEL, parv[1]);
 
@@ -172,6 +177,5 @@ int mo_opmode(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
   modebuf_flush(&mbuf); /* flush the modes */
 
   return 0;
-#endif /* CONFIG_OPERCMDS */
 }
 
index f95562cd198fc432e8b6965b79db9bb325c22460..28864e7846763669952367503553f73451e52827 100644 (file)
  */
 int mo_rehash(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
 {
-#if defined(OPER_REHASH) || defined(LOCOP_REHASH)
   int flag = 0;
 
-# if !defined(OPER_REHASH) || !defined(LOCOP_REHASH)
-  if (
-#  ifdef OPER_REHASH
-      !IsOper(sptr)
-#  else
-      !IsLocOp(sptr)
-#  endif
-      )
+  if (!HasPriv(sptr, PRIV_REHASH))
     return send_reply(sptr, ERR_NOPRIVILEGES);
-# endif
 
   if (parc > 1) { /* special processing */
     if (*parv[1] == 'm') {
@@ -142,7 +133,5 @@ int mo_rehash(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
   log_write(LS_SYSTEM, L_INFO, 0, "REHASH From %#C", sptr);
 
   return rehash(cptr, flag);
-#endif /* defined(OPER_REHASH) || defined(LOCOP_REHASH) */
-  return 0;
 }
 
index aed3bf6e5ed3222ca51136d0a32e33ebe1c094e4..d566eae6101bcfd0f4da4ce8eb5b1715e6a5ea6d 100644 (file)
  */
 int mo_restart(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
 {
-#if defined(OPER_RESTART) || defined(LOCOP_RESTART)
-#ifndef LOCOP_RESTART
-  if (!MyUser(sptr) || !IsOper(sptr))
-#else
-#ifdef  OPER_RESTART
-  if (!MyUser(sptr) || !IsAnOper(sptr))
-#else
-  if (!MyUser(sptr) || !IsLocOp(sptr))
-#endif
-#endif
-  {
-    send_reply(sptr, ERR_NOPRIVILEGES);
-    return 0;
-  }
+  if (!HasPriv(sptr, PRIV_RESTART))
+    return send_reply(sptr, ERR_NOPRIVILEGES);
+
   log_write(LS_SYSTEM, L_NOTICE, 0, "Server RESTART by %#C", sptr);
   server_restart("received RESTART");
 
-#endif /* defined(OPER_RESTART) || defined(LOCOP_RESTART) */
   return 0;
 }
-
-
-#if 0
-#if defined(OPER_RESTART) || defined(LOCOP_RESTART)
-/*
- * m_restart
- */
-int m_restart(struct Client *cptr, struct Client *sptr, int parc,
-    char *parv[])
-{
-#ifndef LOCOP_RESTART
-  if (!MyUser(sptr) || !IsOper(sptr))
-#else
-#ifdef  OPER_RESTART
-  if (!MyUser(sptr) || !IsAnOper(sptr))
-#else
-  if (!MyUser(sptr) || !IsLocOp(sptr))
-#endif
-#endif
-  {
-    sendto_one(sptr, err_str(ERR_NOPRIVILEGES), me.name, parv[0]); /* XXX DEAD */
-    return 0;
-  }
-  ircd_log(L_NOTICE, "Server RESTART by %s\n", get_client_name(sptr, HIDE_IP)); /* XXX DEAD */
-  server_restart("received RESTART");
-  return 0;
-}
-#endif
-#endif /* 0 */
index d8ffb955dc480daf1cd03d7b6a8fb016e4585b7e..63b0a5102ccf60070e7092d20950f5c9c61573c6 100644 (file)
 static void userhost_formatter(struct Client* cptr, struct MsgBuf* mb)
 {
   assert(IsUser(cptr));
-  msgq_append(0, mb, "%s%s=%c%s@%s", cli_name(cptr), IsAnOper(cptr) ? "*" : "",
+  msgq_append(0, mb, "%s%s=%c%s@%s", cli_name(cptr),
+             HasPriv(cptr, PRIV_DISPLAY) ? "*" : "",
              cli_user(cptr)->away ? '-' : '+', cli_user(cptr)->username,
              cli_user(cptr)->host);
 }
index 4fa321d02fe77dfa8daab53ef194298c7ee4d984..41aa223926a080ee0e31c0c40cb4505291f2febd 100644 (file)
 static void userip_formatter(struct Client* cptr, struct MsgBuf* mb)
 {
   assert(IsUser(cptr));
-  msgq_append(0, mb, "%s%s=%c%s@%s", cli_name(cptr), IsAnOper(cptr) ? "*" : "",
+  msgq_append(0, mb, "%s%s=%c%s@%s", cli_name(cptr),
+             HasPriv(cptr, PRIV_DISPLAY) ? "*" : "",
              cli_user(cptr)->away ? '-' : '+', cli_user(cptr)->username,
              ircd_ntoa((const char*) &(cli_ip(cptr))));
 }
index 6bbc79502457a923b05b62cce8cfb9ab5ec522b6..1366879cb1ee9b1a8455378c1f31fc5b8edbc854 100644 (file)
@@ -130,7 +130,8 @@ int m_version(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
     
     sprintf_irc(featurebuf,FEATURES,FEATURESVALUES);
     
-    send_reply(sptr, RPL_VERSION, version, debugmode, cli_name(&me), serveropts);
+    send_reply(sptr, RPL_VERSION, version, debugmode, cli_name(&me),
+              debug_serveropts());
     send_reply(sptr, RPL_ISUPPORT, featurebuf);
   }
 
@@ -160,7 +161,8 @@ int ms_version(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
   if (hunt_server_cmd(sptr, CMD_VERSION, cptr, 0, ":%C", 1, parc, parv) ==
       HUNTED_ISME)
   {
-    send_reply(sptr, RPL_VERSION, version, debugmode, cli_name(&me), serveropts);
+    send_reply(sptr, RPL_VERSION, version, debugmode, cli_name(&me),
+              debug_serveropts());
   }
 
   return 0;
index dd31cf15bbfe4f7282bd50e7e3f1cdf8dc01af2d..ecb27b4dc302e3a8239d1e6dbc7ebb5aaccd168f 100644 (file)
@@ -188,7 +188,7 @@ int m_who(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
         case 'x':
         case 'X':
           bitsel |= WHOSELECT_EXTRA;
-          if (IsAnOper(sptr))
+          if (HasPriv(sptr, PRIV_WHOX))
            log_write(LS_WHO, L_INFO, LOG_NOSNOTICE, "%#C WHO %s %s", sptr,
                      (BadPtr(parv[3]) ? parv[1] : parv[3]), parv[2]);
           continue;
@@ -316,7 +316,9 @@ int m_who(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
           for (member = chptr->members; member; member = member->next_member)
           {
             acptr = member->user;
-            if ((bitsel & WHOSELECT_OPER) && !(IsAnOper(acptr)))
+            if ((bitsel & WHOSELECT_OPER) &&
+               !(IsAnOper(acptr) && (HasPriv(acptr, PRIV_DISPLAY) ||
+                                     HasPriv(sptr, PRIV_SEE_OPERS))))
               continue;
             if ((acptr != sptr) && (member->status & CHFL_ZOMBIE))
               continue;
@@ -333,7 +335,9 @@ int m_who(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
       else
       {
         if ((acptr = FindUser(nick)) &&
-            ((!(bitsel & WHOSELECT_OPER)) || IsAnOper(acptr)) &&
+            ((!(bitsel & WHOSELECT_OPER)) ||
+            (IsAnOper(acptr) && (HasPriv(acptr, PRIV_DISPLAY) ||
+                                 HasPriv(sptr, PRIV_SEE_OPERS)))) &&
             Process(acptr) && SHOW_MORE(sptr, counter))
         {
           do_who(sptr, acptr, 0, fields, qrt);
@@ -377,8 +381,10 @@ int m_who(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
           if (!(IsUser(acptr) && Process(acptr)))
             continue;           /* Now Process() is at the beginning, if we fail
                                    we'll never have to show this acptr in this query */
-          if ((bitsel & WHOSELECT_OPER) && !IsAnOper(acptr))
-            continue;
+         if ((bitsel & WHOSELECT_OPER) &&
+             !(IsAnOper(acptr) && (HasPriv(acptr, PRIV_DISPLAY) ||
+                                   HasPriv(sptr, PRIV_SEE_OPERS))))
+           continue;
           if ((mask) &&
               ((!(matchsel & WHO_FIELD_NIC))
               || matchexec(cli_name(acptr), mymask, minlen))
@@ -408,8 +414,10 @@ int m_who(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
       {
         if (!(IsUser(acptr) && Process(acptr)))
           continue;
-        if ((bitsel & WHOSELECT_OPER) && !IsAnOper(acptr))
-          continue;
+       if ((bitsel & WHOSELECT_OPER) &&
+           !(IsAnOper(acptr) && (HasPriv(acptr, PRIV_DISPLAY) ||
+                                 HasPriv(sptr, PRIV_SEE_OPERS))))
+         continue;
         if (!(SEE_USER(sptr, acptr, bitsel)))
           continue;
         if ((mask) &&
index 9c6ea1bb6de95855fb28a41f9e491264a61b3232..5a46bdf33c93623b7c58316efb7d799638ff1927 100644 (file)
@@ -194,7 +194,7 @@ static void do_whois(struct Client* sptr, struct Client *acptr)
     if (user->away)
        send_reply(sptr, RPL_AWAY, name, user->away);
 
-    if (IsAnOper(acptr))
+    if (HasPriv(acptr, PRIV_DISPLAY) || HasPriv(sptr, PRIV_SEE_OPERS))
        send_reply(sptr, RPL_WHOISOPERATOR, name);
    
     /* Hint: if your looking to add more flags to a user, eg +h, here's
index da26232ec4958ffd9f6bc1cbefd851034c118a42..700eec655f2e28616e8c7a48a6e1415bad2ebc22 100644 (file)
@@ -448,11 +448,7 @@ struct Message msgtab[] = {
     TOK_JUPE,
     0, MAXPARA, MFLG_SLOW, 0,
     /* UNREG, CLIENT, SERVER, OPER, SERVICE */
-#ifdef CONFIG_OPERCMDS
     { m_unregistered, m_jupe, ms_jupe, mo_jupe, m_ignore }
-#else
-    { m_unregistered, m_jupe, ms_jupe, m_jupe, m_ignore }
-#endif /* CONFIG_OPERCMDS */
   },
   {
     MSG_OPMODE,
index 32134b9f74f6b3ecd1193cd352ebe6b046fd2739..482e077413763a4a437527bb581af7680c0b076f 100644 (file)
@@ -26,6 +26,7 @@
 #include "client.h"
 #include "hash.h"
 #include "ircd_alloc.h"
+#include "ircd_features.h"
 #include "ircd_log.h"
 #include "ircd_osdep.h"
 #include "ircd_reply.h"
 #include <string.h>
 #include <unistd.h>
 
-/* *INDENT-OFF* */
-
 /*
  * Option string.  Must be before #ifdef DEBUGMODE.
  */
-char serveropts[] = {
+static char serveropts[256]; /* should be large enough for anything */
+
+const char* debug_serveropts(void)
+{
+  int i = 0;
+#define AddC(c)        serveropts[i++] = (c)
+
 #if BUFFERPOOL < 1000000
-    'b',
+  AddC('b');
 #if BUFFERPOOL > 99999
-    (char)('0' + (BUFFERPOOL/100000)),
+  AddC((char)('0' + (BUFFERPOOL/100000)));
 #endif
 #if BUFFERPOOL > 9999
-    (char)('0' + (BUFFERPOOL/10000) % 10),
+  AddC((char)('0' + (BUFFERPOOL/10000) % 10));
 #endif
-    (char)('0' + (BUFFERPOOL/1000) % 10),
+  AddC((char)('0' + (BUFFERPOOL/1000) % 10));
 #else
-    'B',
+  AddC('B');
 #if BUFFERPOOL > 99999999
-    (char)('0' + (BUFFERPOOL/100000000)),
+  AddC((char)('0' + (BUFFERPOOL/100000000)));
 #endif
 #if BUFFERPOOL > 9999999
-    (char)('0' + (BUFFERPOOL/10000000) % 10),
+  AddC((char)('0' + (BUFFERPOOL/10000000) % 10));
 #endif
-    (char)('0' + (BUFFERPOOL/1000000) % 10),
+  AddC((char)('0' + (BUFFERPOOL/1000000) % 10));
 #endif
 #ifdef  CHROOTDIR
-    'c',
+  AddC('c');
 #endif
 #ifdef  CMDLINE_CONFIG
-    'C',
-#endif
-#ifdef  DO_ID
-    'd',
+  AddC('C');
 #endif
 #ifdef  DEBUGMODE
-    'D',
-#endif
-#ifdef  LOCOP_REHASH
-    'e',
-#endif
-#ifdef  OPER_REHASH
-    'E',
-#endif
-#ifdef OPER_NO_CHAN_LIMIT
-    'F',
-#endif
-#ifdef OPER_MODE_LCHAN
-    'f',
+  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');
+
 #ifdef  HUB
-    'H',
-#endif
-#if defined(SHOW_INVISIBLE_USERS) ||  defined(SHOW_ALL_INVISIBLE_USERS)
-#ifdef  SHOW_ALL_INVISIBLE_USERS
-    'I',
-#else
-    'i',
-#endif
-#endif
-#ifdef  OPER_KILL
-#ifdef  LOCAL_KILL_ONLY
-    'k',
-#else
-    'K',
-#endif
-#endif
-#ifdef  LEAST_IDLE
-    'L',
-#endif
-#ifdef OPER_WALK_THROUGH_LMODES
-    'l',
+  AddC('H');
 #endif
+
+  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');
+
 #ifdef  IDLE_FROM_MSG
-    'M',
+  AddC('M');
 #endif
 #ifdef  USEONE
-    'O',
-#endif
-#ifdef NO_OPER_DEOP_LCHAN
-    'o',
+  AddC('O');
 #endif
+
+  if (feature_bool(FEAT_NO_OPER_DEOP_LCHAN))
+    AddC('o');
+
 #ifdef  CRYPT_OPER_PASSWORD
-    'p',
+  AddC('p');
 #endif
 #ifdef  CRYPT_LINK_PASSWORD
-    'P',
-#endif
-#ifdef  DEBUGMALLOC
-#ifdef  MEMLEAKSTATS
-    'Q',
-#else
-    'q',
-#endif
+  AddC('P');
 #endif
 #ifdef  RELIABLE_CLOCK
-    'R',
-#endif
-#ifdef  LOCOP_RESTART
-    's',
-#endif
-#ifdef  OPER_RESTART
-    'S',
-#endif
-#ifdef  OPER_REMOTE
-    't',
+  AddC('R');
 #endif
+
+  if (feature_bool(FEAT_LOCOP_RESTART))
+    AddC('s');
+
+  if (feature_bool(FEAT_OPER_RESTART))
+    AddC('S');
+
 #if defined(USE_POLL) && defined(HAVE_POLL_H)
-    'U',
+  AddC('U');
 #endif
 #ifdef  VIRTUAL_HOST
-    'v',
-#endif
-#ifdef BADCHAN
-    'W',
-#ifdef LOCAL_BADCHAN
-    'x',
+  AddC('v');
 #endif
-#endif
-    '\0'
-};
 
-/* *INDENT-ON* */
+  serveropts[i] = '\0';
 
+  return serveropts;
+}
 
 /*
  * debug_init
index ea7b01fa3596d9ca273b651a5600b4d653add9c2..15393697c3da18fb20c5dd6409979b4946346483 100644 (file)
@@ -1005,7 +1005,8 @@ void send_umode_out(struct Client *cptr, struct Client *sptr, int old)
   int i;
   struct Client *acptr;
 
-  send_umode(NULL, sptr, old, SEND_UMODES);
+  send_umode(NULL, sptr, old,
+            SEND_UMODES & ~(HasPriv(sptr, PRIV_PROPAGATE) ? 0 : FLAGS_OPER));
 
   for (i = HighestFd; i >= 0; i--) {
     if ((acptr = LocalClientArray[i]) && IsServer(acptr) &&
@@ -1238,10 +1239,14 @@ int set_user_mode(struct Client *cptr, struct Client *sptr, int parc, char *parv
    * Compare new flags with old flags and send string which
    * will cause servers to update correctly.
    */
-  if ((setflags & FLAGS_OPER) && !IsOper(sptr))
+  if ((setflags & FLAGS_OPER) && !IsOper(sptr)) {
     --UserStats.opers;
-  if (!(setflags & FLAGS_OPER) && IsOper(sptr))
+    client_set_privs(sptr);
+  }
+  if (!(setflags & FLAGS_OPER) && IsOper(sptr)) {
     ++UserStats.opers;
+    client_set_privs(sptr);
+  }
   if ((setflags & FLAGS_INVISIBLE) && !IsInvisible(sptr))
     --UserStats.inv_clients;
   if (!(setflags & FLAGS_INVISIBLE) && IsInvisible(sptr))
@@ -1261,7 +1266,11 @@ char *umode_str(struct Client *cptr)
   int   i;
   int   c_flags;
 
-  c_flags = cli_flags(cptr) & SEND_UMODES;        /* cleaning up the original code */
+  c_flags = cli_flags(cptr) & SEND_UMODES; /* cleaning up the original code */
+  if (HasPriv(cptr, PRIV_PROPAGATE))
+    c_flags |= FLAGS_OPER;
+  else
+    c_flags &= ~FLAGS_OPER;
 
   for (i = 0; i < USERMODELIST_SIZE; ++i) {
     if ( (c_flags & userModeList[i].flag))
index 775ad39dcf77df1e94c7b1dbdd068b5c1f9a824e..f1b2d50c50da31aedc43e3982b8efd83aa2f2808 100644 (file)
@@ -152,7 +152,8 @@ void do_who(struct Client* sptr, struct Client* acptr, struct Channel* repchan,
       *(p1++) = 'G';
     else
       *(p1++) = 'H';
-    if (IsAnOper(acptr))
+    if (IsAnOper(acptr) &&
+       (HasPriv(acptr, PRIV_DISPLAY) || HasPriv(sptr, PRIV_SEE_OPERS)))
       *(p1++) = '*';
     if (fields) {
       /* If you specified flags then we assume you know how to parse