# HG changeset patch
# User Nathan Phillip Brink <ohnobinki@ohnopublishing.net>
# Date 1310610964 14400
# Node ID 40301e7eef4bb5db3dfe5878f2de87b46cd99a6b
# Parent  0b71aa85809ca9435adf5d2baa70e51558d9f079
Add optional oper::require-modes setting to the oper block. (#4008 by katsklaw)

Any attempt to /OPER by someone who doesn't have one of the listed
usermodes is rejected. This can be used to restrict oper blocks to
registered nicks (+r) or secure clients (SSL, +z).

diff -r 0b71aa85809c -r 40301e7eef4b Changes
--- a/Changes	Wed Jul 13 13:11:57 2011 -0400
+++ b/Changes	Wed Jul 13 22:36:04 2011 -0400
@@ -2300,3 +2300,8 @@
   --with-spath=<dpath>/bin/ircd.
 - Add missing quotation to doc/help.fr.conf (#4026 by MewT).
 - Remove temporary message (Unreal3.2.1) regarding cloaking modules.
+- Add optional oper::require-modes setting to the oper block. Any
+  attempt to /OPER by someone who doesn't have one of the listed
+  usermodes is rejected. This can be used to restrict oper blocks to
+  registered nicks (+r) or secure clients (SSL, +z) (#4008 by
+  katsklaw).
diff -r 0b71aa85809c -r 40301e7eef4b doc/unreal32docs.html
--- a/doc/unreal32docs.html	Wed Jul 13 13:11:57 2011 -0400
+++ b/doc/unreal32docs.html	Wed Jul 13 22:36:04 2011 -0400
@@ -985,6 +985,7 @@
 		userhost &lt;hostmask&gt;;
 	};
 	password &lt;password&gt; { &lt;auth-type&gt;; };
+	require-modes &lt;modes&gt;
 	class &lt;class-name&gt;;
 	flags &lt;flags&gt;;
 	flags {
@@ -1001,7 +1002,12 @@
 <p>The oper block allows you to assign IRC Operators for your server. The <b>oper::</b> 
   specifies the login name for the /oper. The <b>oper::from::userhost</b> is a user@host 
   mask that the user must match, you can specify more than one hostmask by creating 
-  more than one oper::from::userhost.
+  more than one oper::from::userhost. The
+  optional <b>oper::require-modes</b> setting lets one specify modes
+  (such as <em>r</em> or <em>z</em>) that a user must have acquired
+  before being allowed to OPER. This might be used to require users
+  to register with nickserv or be using secure connections before
+  being able to become operators.
 </p>
 <p id="operblock_password">The <b>oper::password::</b> is the password the oper must specify.
   <b>oper::password::auth-type</b> allows you to specify an authentication method 
diff -r 0b71aa85809c -r 40301e7eef4b include/numeric.h
--- a/include/numeric.h	Wed Jul 13 13:11:57 2011 -0400
+++ b/include/numeric.h	Wed Jul 13 22:36:04 2011 -0400
@@ -145,6 +145,7 @@
 #define ERR_OPERONLY		 520
 #define ERR_LISTSYNTAX       521
 
+#define ERR_NOOPERMODES     554
 /*
  * Numberic replies from server commands.
  * These are currently in the range 200-399.
diff -r 0b71aa85809c -r 40301e7eef4b include/struct.h
--- a/include/struct.h	Wed Jul 13 13:11:57 2011 -0400
+++ b/include/struct.h	Wed Jul 13 22:36:04 2011 -0400
@@ -1214,7 +1214,7 @@
 	anAuthStruct	 *auth;
 	ConfigItem_class *class;
 	ConfigItem	 *from;
-	unsigned long	 modes;
+	unsigned long	 modes, require_modes;
 	long		 oflags;
 	int			maxlogins;
 };
diff -r 0b71aa85809c -r 40301e7eef4b src/modules/m_oper.c
--- a/src/modules/m_oper.c	Wed Jul 13 13:11:57 2011 -0400
+++ b/src/modules/m_oper.c	Wed Jul 13 22:36:04 2011 -0400
@@ -211,6 +211,21 @@
 		sptr->since += 7;
 		return 0;
 	}
+
+	/* Check oper::require_modes */
+	if (aconf->require_modes & ~sptr->umodes)
+	{
+		sendto_one(sptr, err_str(ERR_NOOPERMODES), me.name, parv[0]);
+		sendto_snomask_global
+			(SNO_OPER, "Failed OPER attempt by %s (%s@%s) [lacking modes '%s' in oper::require-modes]",
+			 parv[0], sptr->user->username, sptr->sockhost, get_modestr(aconf->require_modes & ~sptr->umodes));
+		ircd_log(LOG_OPER, "OPER MISSINGMODES (%s) by (%s!%s@%s), needs modes=%s",
+			 name, parv[0], sptr->user->username, sptr->sockhost,
+			 get_modestr(aconf->require_modes & ~sptr->umodes));
+		sptr->since += 7;
+		return 0;
+	}
+
 	strlcpy(nuhhost, make_user_host(sptr->user->username, sptr->user->realhost), sizeof(nuhhost));
 	strlcpy(nuhhost2, make_user_host(sptr->user->username, Inet_ia2p(&sptr->ip)), sizeof(nuhhost2));
 	for (oper_from = (ConfigItem_oper_from *) aconf->from;
diff -r 0b71aa85809c -r 40301e7eef4b src/s_conf.c
--- a/src/s_conf.c	Wed Jul 13 13:11:57 2011 -0400
+++ b/src/s_conf.c	Wed Jul 13 22:36:04 2011 -0400
@@ -3672,6 +3672,10 @@
 		{
 			oper->modes = set_usermode(cep->ce_vardata);
 		}
+		else if (!strcmp(cep->ce_varname, "require-modes"))
+		{
+			oper->require_modes = set_usermode(cep->ce_vardata);
+		}
 		else if (!strcmp(cep->ce_varname, "maxlogins"))
 		{
 			oper->maxlogins = atoi(cep->ce_vardata);
@@ -3702,7 +3706,7 @@
 int	_test_oper(ConfigFile *conf, ConfigEntry *ce)
 {
 	char has_class = 0, has_password = 0, has_flags = 0, has_swhois = 0, has_snomask = 0;
-	char has_modes = 0, has_from = 0, has_maxlogins = 0;
+	char has_modes = 0, has_require_modes = 0, has_from = 0, has_maxlogins = 0;
 	int oper_flags = 0;
 	ConfigEntry *cep;
 	ConfigEntry *cepp;
@@ -3778,7 +3782,7 @@
 				has_snomask = 1;
 			}
 			/* oper::modes */
-			else if (!strcmp(cep->ce_varname, "modes")) 
+			else if (!strcmp(cep->ce_varname, "modes"))
 			{
 				char *p;
 				for (p = cep->ce_vardata; *p; p++)
@@ -3796,6 +3800,24 @@
 				}
 				has_modes = 1;
 			}
+			/* oper::require-modes */
+			else if (!strcmp(cep->ce_varname, "require-modes"))
+			{
+				char *p;
+				for (p = cep->ce_vardata; *p; p++)
+					if (strchr("oOaANC", *p))
+					{
+						config_warn("%s:%i: oper::require-modes probably shouldn't include mode '%c'",
+							cep->ce_fileptr->cf_filename, cep->ce_varlinenum, *p);
+					}
+				if (has_require_modes)
+				{
+					config_warn_duplicate(cep->ce_fileptr->cf_filename,
+						cep->ce_varlinenum, "oper::require-modes");
+					continue;
+				}
+				has_require_modes = 1;
+			}
 			/* oper::maxlogins */
 			else if (!strcmp(cep->ce_varname, "maxlogins"))
 			{
diff -r 0b71aa85809c -r 40301e7eef4b src/s_err.c
--- a/src/s_err.c	Wed Jul 13 13:11:57 2011 -0400
+++ b/src/s_err.c	Wed Jul 13 22:36:04 2011 -0400
@@ -610,7 +610,7 @@
 /* 551 */ NULL, /* quakenet */
 /* 552 */ NULL, /* quakenet */
 /* 553 */ NULL, /* quakenet */
-/* 554 */ NULL,
+/* 554    ERR_NOOPERMODES */ ":%s 554 %s :You are missing user modes required to OPER",
 /* 555 */ NULL,
 /* 556 */ NULL,
 /* 557 */ NULL,
