# ircd-ratbox-1.3* hidden oper patch
# adds an oper flag (hidden_oper) and a umode (+p) to hide an opered client
# from the STATS p output.  also adds a config option (hidden_oper_confonly)
# to prevent opers from setting/resetting the 'p' umode
# by Erik Schorr (felix@efnet) 2004-01-18
# The code within this patch is provided under the same license(s) covering
# ircd-ratbox.  Standard free software disclaimers apply.
diff -urN ircd-ratbox-1.3-1/doc/example.conf ircd-ratbox-1.3-1+hiddenoper/doc/example.conf
--- ircd-ratbox-1.3-1/doc/example.conf	2003-11-05 08:10:49.000000000 -0800
+++ ircd-ratbox-1.3-1+hiddenoper/doc/example.conf	2004-01-18 15:09:31.000000000 -0800
@@ -325,6 +325,7 @@
 	 * xline:	 allows use of /quote xline/unxline
 	 * operwall:     allows the oper to send operwalls
 	 * oper_spy:     allows use of operspy tools, if loaded
+	 * hidden_oper:  don't appear in STATS p output
 	 */
 	flags = global_kill, remote, kline, unkline, gline,
 		die, rehash, admin, xline, operwall;
@@ -933,6 +934,7 @@
 	 * +k - skill      - See server generated KILL messages
 	 * +l - locops     - See LOCOPS messages
 	 * +n - nchange    - See client nick changes
+	 * +p - hidden_oper - Keep oper from showing up in STATS p
 	 * +r - rej        - See rejected client notices
 	 * +s - servnotice - See general server notices
 	 * +u - unauth     - See unauthorised client notices
@@ -945,11 +947,17 @@
 	 
 	/* oper only umodes: usermodes only opers may set */
 	oper_only_umodes = bots, cconn, debug, full, skill, nchange, 
-                     rej, spy, external, operwall, locops, unauth;
+        rej, spy, external, operwall, locops, unauth, hidden_oper;
 
 	/* oper umodes: default usermodes opers get when they /oper */
 	oper_umodes = locops, servnotice, operwall, wallop;
 
+	/* hidden_oper_confonly: prevent oper clients from setting/resetting +p
+	 * (hidden_oper) flag/umode.  defaults to yes
+	 */
+	hidden_oper_confonly = yes;
+
+
 	/* servlink path: path to 'servlink' program used by ircd to handle
 	 * encrypted/compressed server <-> server links.
 	 *
diff -urN ircd-ratbox-1.3-1/doc/example.efnet.conf ircd-ratbox-1.3-1+hiddenoper/doc/example.efnet.conf
--- ircd-ratbox-1.3-1/doc/example.efnet.conf	2003-11-05 08:10:49.000000000 -0800
+++ ircd-ratbox-1.3-1+hiddenoper/doc/example.efnet.conf	2004-01-18 15:10:13.000000000 -0800
@@ -323,6 +323,7 @@
 	 *		 will not have the admin lines in
 	 *		 stats p and whois.
 	 * oper_spy:     give access to operspy tools, if loaded
+	 * hidden_oper:  don't appear in STATS p output
 	 */
 
         flags = global_kill, remote, kline, unkline, gline,
@@ -978,6 +979,7 @@
 	 * +k - skill      - See server generated KILL messages
 	 * +l - locops     - See LOCOPS messages
 	 * +n - nchange    - See client nick changes
+	 * +p - hidden_oper - Keep oper from showing up in STATS p
 	 * +r - rej        - See rejected client notices
 	 * +s - servnotice - See general server notices
 	 * +u - unauth     - See unauthorised client notices
@@ -990,11 +992,16 @@
 	 
 	/* oper only umodes: usermodes only opers may set */
 	oper_only_umodes = bots, cconn, debug, full, skill, nchange, 
-                     rej, spy, external, operwall, locops, unauth;
+        rej, spy, external, operwall, locops, unauth, hidden_oper;
 
 	/* oper umodes: default usermodes opers get when they /oper */
 	oper_umodes = locops, servnotice, operwall, wallop;
 
+	/* hidden_oper_confonly: prevent oper clients from setting/resetting +p
+	 * (hidden_oper) flag/umode.  defaults to yes
+	 */
+	hidden_oper_confonly = yes;
+
 	/* servlink path: path to 'servlink' program used by ircd to handle
 	 * encrypted/compressed server <-> server links.
 	 *
diff -urN ircd-ratbox-1.3-1/include/client.h ircd-ratbox-1.3-1+hiddenoper/include/client.h
--- ircd-ratbox-1.3-1/include/client.h	2003-11-27 12:20:10.000000000 -0800
+++ ircd-ratbox-1.3-1+hiddenoper/include/client.h	2004-01-18 13:52:07.000000000 -0800
@@ -383,6 +383,7 @@
 /* user information flags, only settable by remote mode or local oper */
 #define UMODE_OPER         0x20000	/* Operator */
 #define UMODE_ADMIN        0x40000	/* Admin on server */
+#define UMODE_HIDDENOPER   0x80000	/* Oper hidden from stats p */
 
 #define UMODE_ALL	   UMODE_SERVNOTICE
 
@@ -403,10 +404,6 @@
 #define OPER_RESV		0x001000 /* XXX - only here for shared {}; */
 #define OPER_OPERWALL		0x002000
 #define OPER_HIDDENADMIN        0x004000
-#define OPER_FLAGS      (OPER_GLOBAL_KILL | OPER_REMOTE | OPER_UNKLINE |\
-                         OPER_GLINE | OPER_N | OPER_K | OPER_DIE |\
-                         OPER_REHASH | OPER_ADMIN | OPER_XLINE | OPER_OPERWALL|\
-                         OPER_SPY | OPER_HIDDENADMIN | OPER_LOCAL_KILL)
 
 #define FLAGS2_EXEMPTGLINE      0x008000
 #define FLAGS2_EXEMPTKLINE      0x010000
@@ -418,6 +415,13 @@
 #define FLAGS2_IP_SPOOFING      0x400000
 #define FLAGS2_FLOODDONE        0x800000
 #define FLAGS2_EXEMPTSPAMBOT	0x1000000
+#define OPER_HIDDENOPER			0x2000000
+
+#define OPER_FLAGS      (OPER_GLOBAL_KILL | OPER_REMOTE | OPER_UNKLINE |\
+                         OPER_GLINE | OPER_N | OPER_K | OPER_DIE |\
+                         OPER_REHASH | OPER_ADMIN | OPER_XLINE | OPER_OPERWALL|\
+                         OPER_SPY | OPER_HIDDENADMIN | OPER_LOCAL_KILL |\
+                         OPER_HIDDENOPER)
 
 #define SEND_UMODES  (UMODE_INVISIBLE | UMODE_OPER | UMODE_WALLOP | \
                       UMODE_ADMIN)
@@ -425,7 +429,8 @@
                       UMODE_REJ | UMODE_SKILL | UMODE_FULL | UMODE_SPY | \
                       UMODE_NCHANGE | UMODE_OPERWALL | UMODE_DEBUG | \
                       UMODE_BOTS | UMODE_EXTERNAL | UMODE_LOCOPS | \
- 		      UMODE_ADMIN | UMODE_UNAUTH | UMODE_CALLERID | UMODE_OPERSPY)
+ 		      UMODE_ADMIN | UMODE_UNAUTH | UMODE_CALLERID | UMODE_OPERSPY | \
+                      UMODE_HIDDENOPER)
 
 #define FLAGS_ID     (FLAGS_NEEDID | FLAGS_GOTID)
 
@@ -493,6 +498,8 @@
 #define SetWallops(x)           ((x)->umodes |= UMODE_WALLOP)
 #define SetCallerId(x)		((x)->umodes |= UMODE_CALLERID)
 #define IsSetCallerId(x)	((x)->umodes & UMODE_CALLERID)
+#define IsHiddenOper(x)		(((x)->umodes & UMODE_HIDDENOPER) || ((x)->flags2 & OPER_HIDDENOPER))
+#define SetIsHiddenOper(x)	((x)->umodes |= UMODE_HIDDENOPER)
 
 #define SetNeedId(x)            ((x)->flags |= FLAGS_NEEDID)
 #define IsNeedId(x)             (((x)->flags & FLAGS_NEEDID) != 0)
diff -urN ircd-ratbox-1.3-1/include/s_conf.h ircd-ratbox-1.3-1+hiddenoper/include/s_conf.h
--- ircd-ratbox-1.3-1/include/s_conf.h	2003-12-19 09:32:49.000000000 -0800
+++ ircd-ratbox-1.3-1+hiddenoper/include/s_conf.h	2004-01-18 14:37:03.000000000 -0800
@@ -253,6 +253,7 @@
 	int reject_ban_time;
 	int reject_after_count;
 	int reject_duration;
+	int hidden_oper_confonly;
 	char default_operstring[REALLEN];
 	char default_adminstring[REALLEN];
 
diff -urN ircd-ratbox-1.3-1/modules/m_info.c ircd-ratbox-1.3-1+hiddenoper/modules/m_info.c
--- ircd-ratbox-1.3-1/modules/m_info.c	2003-11-28 07:14:51.000000000 -0800
+++ ircd-ratbox-1.3-1+hiddenoper/modules/m_info.c	2004-01-18 14:36:42.000000000 -0800
@@ -521,6 +521,11 @@
 	 OUTPUT_DECIMAL,
 	 &ConfigServerHide.links_delay,
 	 "Links rehash delay"},
+	{
+	 "hidden_oper_confonly",
+	 OUTPUT_BOOLEAN_YN,
+	 &ConfigFileEntry.hidden_oper_confonly,
+	 "hidden_oper umode (+p) can't be changed by client"},
 	/* --[  END OF TABLE  ]---------------------------------------------- */
 	{
 	 (char *) 0,
diff -urN ircd-ratbox-1.3-1/modules/m_stats.c ircd-ratbox-1.3-1+hiddenoper/modules/m_stats.c
--- ircd-ratbox-1.3-1/modules/m_stats.c	2003-11-28 07:14:51.000000000 -0800
+++ ircd-ratbox-1.3-1+hiddenoper/modules/m_stats.c	2004-01-18 13:18:09.000000000 -0800
@@ -744,8 +744,6 @@
 	{
 		target_p = oper_ptr->data;
 
-		j++;
-
 		if(MyClient(source_p) && IsOper(source_p))
 		{
 			ptr = target_p->localClient->confs.head;
@@ -757,14 +755,18 @@
 				   oper_privs_as_string(target_p, aconf->port),
 				   target_p->name, target_p->username, target_p->host,
 				   (int) (CurrentTime - target_p->user->last));
+			j++;
 		}
 		else
 		{
-			sendto_one(source_p, ":%s %d %s p :[%c] %s (%s@%s) Idle: %d",
-				   me.name, RPL_STATSDEBUG, source_p->name,
-				   IsAdmin(target_p) ? 'A' : 'O',
-				   target_p->name, target_p->username, target_p->host,
-				   (int) (CurrentTime - target_p->user->last));
+			if (!IsHiddenOper(target_p)) {
+				sendto_one(source_p, ":%s %d %s p :[%c] %s (%s@%s) Idle: %d",
+					   me.name, RPL_STATSDEBUG, source_p->name,
+					   IsAdmin(target_p) ? 'A' : 'O',
+					   target_p->name, target_p->username, target_p->host,
+					   (int) (CurrentTime - target_p->user->last));
+				j++;
+			}
 		}
 	}
 
diff -urN ircd-ratbox-1.3-1/src/newconf.c ircd-ratbox-1.3-1+hiddenoper/src/newconf.c
--- ircd-ratbox-1.3-1/src/newconf.c	2003-12-19 09:33:03.000000000 -0800
+++ ircd-ratbox-1.3-1+hiddenoper/src/newconf.c	2004-01-18 14:41:49.000000000 -0800
@@ -78,6 +78,7 @@
 	{"spy", UMODE_SPY},
 	{"operwall", UMODE_OPERWALL},
 	{"operspy", UMODE_OPERSPY},
+	{"hidden_oper", UMODE_HIDDENOPER},
 	{NULL}
 };
 
@@ -96,6 +97,7 @@
 	{"xline", OPER_XLINE},
 	{"operwall", OPER_OPERWALL},
 	{"oper_spy", OPER_SPY},
+	{"hidden_oper", OPER_HIDDENOPER},
 	{NULL}
 };
 
@@ -944,6 +946,17 @@
 		yy_achead->port &= ~OPER_SPY;
 }
 
+static void
+conf_set_oper_hidden_oper(void *data)
+{
+	int yesno = *(int *) data;
+
+	if(yesno)
+		yy_achead->port |= OPER_HIDDENOPER;
+	else
+		yy_achead->port &= ~OPER_HIDDENOPER;
+}
+
 static int
 conf_begin_class(struct TopConf *tc)
 {
@@ -2528,6 +2541,12 @@
 }
 
 static void
+conf_set_general_hidden_oper_confonly(void *data)
+{
+	ConfigFileEntry.hidden_oper_confonly = *(unsigned int *) data;
+}
+
+static void
 conf_set_general_min_nonwildcard(void *data)
 {
 	ConfigFileEntry.min_nonwildcard = *(unsigned int *) data;
@@ -2981,6 +3000,7 @@
 	add_conf_item("operator", "rehash", CF_YESNO, conf_set_oper_rehash);
 	add_conf_item("operator", "admin", CF_YESNO, conf_set_oper_admin);
 	add_conf_item("operator", "hidden_admin", CF_YESNO, conf_set_oper_hidden_admin);
+	add_conf_item("operator", "hidden_oper", CF_YESNO, conf_set_oper_hidden_oper);
 	add_conf_item("operator", "oper_spy", CF_YESNO, conf_set_oper_spy);
 	add_conf_item("operator", "encrypted", CF_YESNO, conf_set_oper_encrypted);
 	add_conf_item("operator", "rsa_public_key_file", CF_QSTRING,
@@ -3130,6 +3150,7 @@
 	add_conf_item("general", "use_egd", CF_YESNO, conf_set_general_use_egd);
 	add_conf_item("general", "egdpool_path", CF_QSTRING, conf_set_general_egdpool_path);
 	add_conf_item("general", "oper_umodes", CF_STRING | CF_FLIST, conf_set_general_oper_umodes);
+	add_conf_item("general", "hidden_oper_confonly", CF_YESNO, conf_set_general_hidden_oper_confonly);
 	add_conf_item("general", "caller_id_wait", CF_TIME, conf_set_general_caller_id_wait);
 	add_conf_item("general", "default_floodcount", CF_INT, conf_set_general_default_floodcount);
 	add_conf_item("general", "min_nonwildcard", CF_INT, conf_set_general_min_nonwildcard);
diff -urN ircd-ratbox-1.3-1/src/s_conf.c ircd-ratbox-1.3-1+hiddenoper/src/s_conf.c
--- ircd-ratbox-1.3-1/src/s_conf.c	2003-12-19 09:33:03.000000000 -0800
+++ ircd-ratbox-1.3-1+hiddenoper/src/s_conf.c	2004-01-18 14:37:48.000000000 -0800
@@ -1304,6 +1304,7 @@
 	ConfigFileEntry.oper_umodes = UMODE_LOCOPS | UMODE_SERVNOTICE |
 		UMODE_OPERWALL | UMODE_WALLOP;
 	ConfigFileEntry.oper_only_umodes = UMODE_DEBUG | UMODE_OPERSPY;
+	ConfigFileEntry.hidden_oper_confonly=YES;
 
 	ConfigChannel.use_except = YES;
 	ConfigChannel.use_invex = YES;
diff -urN ircd-ratbox-1.3-1/src/s_user.c ircd-ratbox-1.3-1+hiddenoper/src/s_user.c
--- ircd-ratbox-1.3-1/src/s_user.c	2003-12-04 12:30:38.000000000 -0800
+++ ircd-ratbox-1.3-1+hiddenoper/src/s_user.c	2004-01-18 14:38:09.000000000 -0800
@@ -85,6 +85,7 @@
 	{UMODE_LOCOPS, 'l'},
 	{UMODE_NCHANGE, 'n'},
 	{UMODE_OPER, 'o'},
+	{UMODE_HIDDENOPER, 'p'},
 	{UMODE_REJ, 'r'},
 	{UMODE_SERVNOTICE, 's'},
 	{UMODE_UNAUTH, 'u'},
@@ -147,7 +148,7 @@
 	0,			/* m */
 	UMODE_NCHANGE,		/* n */
 	UMODE_OPER,		/* o */
-	0,			/* p */
+	UMODE_HIDDENOPER,	/* p */
 	0,			/* q */
 	UMODE_REJ,		/* r */
 	UMODE_SERVNOTICE,	/* s */
@@ -993,6 +994,19 @@
 				}
 				break;
 
+			case 'p':
+				if (MyConnect(source_p)) {
+					if (ConfigFileEntry.hidden_oper_confonly || !IsOper(source_p)) {
+							badflag=YES;
+					} else {
+						if(what == MODE_ADD)
+							source_p->umodes |= UMODE_HIDDENOPER;
+						else
+							source_p->umodes &= ~UMODE_HIDDENOPER;
+					}
+				}
+				break;
+							
 				/* we may not get these,
 				 * but they shouldnt be in default
 				 */
