<URL: http://bugs.freeciv.org/Ticket/Display.html?id=40466 >

Version 2 disallows non-hack connections from setting
the timeout to less than 30 at any time.

This is achieved by adding a 'struct connection' parameter
to each of the setting validate callback definitions.
The access level of the set command caller is checked
in the timeout callback and if it is less than ALLOW_HACK,
then values less than 30 are disallowed.

This is to prevent abuse on public servers, where setting
-1 (the server burns CPU until the game ends), 0 (the server
blocks indefinitely) or a very low timeout value (clients
do not have time to react to packets sent by server), would
be undesirable.

Unfortunately this patch is somewhat bloated by having to
update all of the setting callback arguments to match the
new definitions of the validate function typedefs. 

The timeout setting help text is also updated.


----------------------------------------------------------------------
社会なしでいいのだろう。
 server/report.c    |    4 +++-
 server/report.h    |    4 +++-
 server/settings.c  |   46 +++++++++++++++++++++++++++++++++++++---------
 server/settings.h  |   16 +++++++++++++---
 server/stdinhand.c |   27 ++++++++++++++++++---------
 5 files changed, 74 insertions(+), 23 deletions(-)

diff --git a/server/report.c b/server/report.c
index 6834cb0..7bb265e 100644
--- a/server/report.c
+++ b/server/report.c
@@ -663,7 +663,9 @@ static void dem_line_item(char *outptr, size_t out_size,
   Other settings callback functions are in settings.c, but this one uses
   static values from this file so it's done separately.
 *************************************************************************/
-bool is_valid_demography(const char *demography, const char **error_string)
+bool is_valid_demography(const char *demography,
+                         struct connection *caller,
+                         const char **error_string)
 {
   int len = strlen(demography), i;
 
diff --git a/server/report.h b/server/report.h
index 4dc515f..7a94fd2 100644
--- a/server/report.h
+++ b/server/report.h
@@ -24,7 +24,9 @@ void page_conn(struct conn_list *dest, const char *caption, const char *headline
 void make_history_report(void);
 void report_wonders_of_the_world(struct conn_list *dest);
 void report_top_five_cities(struct conn_list *dest);
-bool is_valid_demography(const char *demography, const char **error_message);
+bool is_valid_demography(const char *demography,
+                         struct connection *caller,
+                         const char **error_message);
 void report_demographics(struct connection *pconn);
 void report_final_scores(void);
 
diff --git a/server/settings.c b/server/settings.c
index 3937593..197069b 100644
--- a/server/settings.c
+++ b/server/settings.c
@@ -50,7 +50,9 @@ const int OLEVELS_NUM = ARRAY_SIZE(sset_level_names);
   Verify that a given allowtake string is valid.  See
   game.allow_take.
 *************************************************************************/
-static bool allowtake_callback(const char *value, const char **error_string)
+static bool allowtake_callback(const char *value,
+                               struct connection *caller,
+                               const char **error_string)
 {
   int len = strlen(value), i;
   bool havecharacter_state = FALSE;
@@ -92,7 +94,9 @@ static bool allowtake_callback(const char *value, const char **error_string)
   Verify that a given startunits string is valid.  See
   game.info.start_units.
 *************************************************************************/
-static bool startunits_callback(const char *value, const char **error_string)
+static bool startunits_callback(const char *value,
+                                struct connection *caller,
+                                const char **error_string)
 {
   int len = strlen(value), i;
   bool have_founder = FALSE;
@@ -131,7 +135,9 @@ static bool startunits_callback(const char *value, const char **error_string)
 /*************************************************************************
   Verify that a given endyear is valid.
 *************************************************************************/
-static bool endyear_callback(int value, const char **error_string)
+static bool endyear_callback(int value,
+                             struct connection *caller,
+                             const char **error_string)
 {
   if (value < game.info.year) {
     /* Tried to set endyear earlier than current year */
@@ -144,7 +150,9 @@ static bool endyear_callback(int value, const char **error_string)
 /*************************************************************************
   Verify that a given maxplayers string is valid.
 *************************************************************************/
-static bool maxplayers_callback(int value, const char **error_string)
+static bool maxplayers_callback(int value,
+                                struct connection *caller,
+                                const char **error_string)
 {
 #ifdef GGZ_SERVER
   if (with_ggz) {
@@ -161,7 +169,25 @@ static bool maxplayers_callback(int value, const char **error_string)
     return FALSE;
   }
 
-  error_string = NULL;
+  *error_string = NULL;
+  return TRUE;
+}
+
+/*************************************************************************
+  Disallow low timeout values for non-hack connections.
+*************************************************************************/
+static bool timeout_callback(int value,
+                             struct connection *caller,
+                             const char **error_string)
+{
+  if (caller && caller->access_level < ALLOW_HACK
+      && value < 30) {
+    *error_string = _("You are not allowed to set timeout values less "
+                      "than 30 seconds.");
+    return FALSE;
+  }
+
+  *error_string = NULL;
   return TRUE;
 }
 
@@ -854,10 +880,12 @@ struct settings_s settings[] = {
 	  N_("If all players have not hit \"Turn Done\" before this "
 	     "time is up, then the turn ends automatically. Zero "
 	     "means there is no timeout. In servers compiled with "
-	     "debugging, a timeout "
-	     "of -1 sets the autogame test mode. Use this with the command "
-	     "\"timeoutincrease\" to have a dynamic timer."), NULL, 
-	   GAME_MIN_TIMEOUT, GAME_MAX_TIMEOUT, GAME_DEFAULT_TIMEOUT)
+             "debugging, a timeout of -1 sets the autogame test mode. "
+             "Only connections with hack level access may set the "
+             "timeout to lower than 30 seconds. Use this with the "
+             "command \"timeoutincrease\" to have a dynamic timer."),
+          timeout_callback,
+          GAME_MIN_TIMEOUT, GAME_MAX_TIMEOUT, GAME_DEFAULT_TIMEOUT)
 
   GEN_INT("timeaddenemymove", game.timeoutaddenemymove,
 	  SSET_META, SSET_INTERNAL, SSET_VITAL, SSET_TO_CLIENT,
diff --git a/server/settings.h b/server/settings.h
index 5a84f3b..7f1606e 100644
--- a/server/settings.h
+++ b/server/settings.h
@@ -53,6 +53,16 @@ enum sset_level {
 extern const char *sset_level_names[];
 extern const int OLEVELS_NUM;
 
+typedef bool (*bool_validate_func_t)(bool value,
+                                     struct connection *pconn,
+                                     const char **reject_message);
+typedef bool (*int_validate_func_t)(int value,
+                                    struct connection *pconn,
+                                    const char **reject_message);
+typedef bool (*string_validate_func_t)(const char * value,
+                                       struct connection *pconn,
+                                       const char **reject_message);
+
 struct settings_s {
   const char *name;
   enum sset_class sclass;
@@ -84,18 +94,18 @@ struct settings_s {
   /*** bool part ***/
   bool *bool_value;
   bool bool_default_value;
-  bool (*bool_validate)(bool value, const char **reject_message);
+  bool_validate_func_t bool_validate;
 
   /*** int part ***/
   int *int_value;
   int int_default_value;
-  bool (*int_validate)(int value, const char **reject_message);
+  int_validate_func_t int_validate;
   int int_min_value, int_max_value;
 
   /*** string part ***/
   char *string_value;
   const char *string_default_value;
-  bool (*string_validate)(const char * value, const char **reject_message);
+  string_validate_func_t string_validate;
   size_t string_value_size;	/* max size we can write into string_value */
 };
 
diff --git a/server/stdinhand.c b/server/stdinhand.c
index 23a8346..30042c6 100644
--- a/server/stdinhand.c
+++ b/server/stdinhand.c
@@ -2519,10 +2519,13 @@ static bool set_command(struct connection *caller, char *str, bool check)
       bool b_val = (val != 0);
 
       if (settings[cmd].bool_validate
-	  && !settings[cmd].bool_validate(b_val, &reject_message)) {
-	cmd_reply(CMD_SET, caller, C_SYNTAX, reject_message);
+          && !settings[cmd].bool_validate(b_val, caller,
+                                          &reject_message)) {
+        cmd_reply(CMD_SET, caller, C_SYNTAX, reject_message);
         return FALSE;
-      } else if (!check) {
+      }
+
+      if (!check) {
 	*(op->bool_value) = b_val;
 	my_snprintf(buffer, sizeof(buffer),
 		    _("Option: %s has been set to %d."), op->name,
@@ -2559,10 +2562,13 @@ static bool set_command(struct connection *caller, char *str, bool check)
       const char *reject_message = NULL;
 
       if (settings[cmd].int_validate
-	  && !settings[cmd].int_validate(val, &reject_message)) {
-	cmd_reply(CMD_SET, caller, C_SYNTAX, reject_message);
+          && !settings[cmd].int_validate(val, caller,
+                                         &reject_message)) {
+        cmd_reply(CMD_SET, caller, C_SYNTAX, reject_message);
         return FALSE;
-      } else if (!check) {
+      }
+
+      if (!check) {
 	*(op->int_value) = val;
 	my_snprintf(buffer, sizeof(buffer),
 		    _("Option: %s has been set to %d."), op->name,
@@ -2581,10 +2587,13 @@ static bool set_command(struct connection *caller, char *str, bool check)
       const char *reject_message = NULL;
 
       if (settings[cmd].string_validate
-	  && !settings[cmd].string_validate(arg, &reject_message)) {
-	cmd_reply(CMD_SET, caller, C_SYNTAX, reject_message);
+          && !settings[cmd].string_validate(arg, caller,
+                                            &reject_message)) {
+        cmd_reply(CMD_SET, caller, C_SYNTAX, reject_message);
         return FALSE;
-      } else if (!check) {
+      }
+
+      if (!check) {
 	strcpy(op->string_value, arg);
 	my_snprintf(buffer, sizeof(buffer),
 		    _("Option: %s has been set to \"%s\"."), op->name,
 server/report.c    |    4 +++-
 server/report.h    |    4 +++-
 server/settings.c  |   50 ++++++++++++++++++++++++++++++++++++++++----------
 server/settings.h  |   16 +++++++++++++---
 server/stdinhand.c |   27 ++++++++++++++++++---------
 5 files changed, 77 insertions(+), 24 deletions(-)

diff --git a/server/report.c b/server/report.c
index 6a11776..52cbe04 100644
--- a/server/report.c
+++ b/server/report.c
@@ -709,7 +709,9 @@ static void dem_line_item(char *outptr, size_t out_size,
   Other settings callback functions are in settings.c, but this one uses
   static values from this file so it's done separately.
 *************************************************************************/
-bool is_valid_demography(const char *demography, const char **error_string)
+bool is_valid_demography(const char *demography,
+                         struct connection *caller,
+                         const char **error_string)
 {
   int len = strlen(demography), i;
 
diff --git a/server/report.h b/server/report.h
index 4dc515f..7a94fd2 100644
--- a/server/report.h
+++ b/server/report.h
@@ -24,7 +24,9 @@ void page_conn(struct conn_list *dest, const char *caption, const char *headline
 void make_history_report(void);
 void report_wonders_of_the_world(struct conn_list *dest);
 void report_top_five_cities(struct conn_list *dest);
-bool is_valid_demography(const char *demography, const char **error_message);
+bool is_valid_demography(const char *demography,
+                         struct connection *caller,
+                         const char **error_message);
 void report_demographics(struct connection *pconn);
 void report_final_scores(void);
 
diff --git a/server/settings.c b/server/settings.c
index d480d77..fa923ca 100644
--- a/server/settings.c
+++ b/server/settings.c
@@ -51,7 +51,9 @@ const int OLEVELS_NUM = ARRAY_SIZE(sset_level_names);
   Verify that a given allowtake string is valid.  See
   game.allow_take.
 *************************************************************************/
-static bool allowtake_callback(const char *value, const char **error_string)
+static bool allowtake_callback(const char *value,
+                               struct connection *caller,
+                               const char **error_string)
 {
   int len = strlen(value), i;
   bool havecharacter_state = FALSE;
@@ -93,7 +95,9 @@ static bool allowtake_callback(const char *value, const char **error_string)
   Verify that a given startunits string is valid.  See
   game.info.start_units.
 *************************************************************************/
-static bool startunits_callback(const char *value, const char **error_string)
+static bool startunits_callback(const char *value,
+                                struct connection *caller,
+                                const char **error_string)
 {
   int len = strlen(value), i;
   bool have_founder = FALSE;
@@ -132,7 +136,9 @@ static bool startunits_callback(const char *value, const char **error_string)
 /*************************************************************************
   Verify that a given endyear is valid.
 *************************************************************************/
-static bool endyear_callback(int value, const char **error_string)
+static bool endyear_callback(int value,
+                             struct connection *caller,
+                             const char **error_string)
 {
   if (value < game.info.year) {
     /* Tried to set endyear earlier than current year */
@@ -145,7 +151,9 @@ static bool endyear_callback(int value, const char **error_string)
 /*************************************************************************
   Verify that a given maxplayers string is valid.
 *************************************************************************/
-static bool maxplayers_callback(int value, const char **error_string)
+static bool maxplayers_callback(int value,
+                                struct connection *caller,
+                                const char **error_string)
 {
 #ifdef GGZ_SERVER
   if (with_ggz) {
@@ -162,7 +170,25 @@ static bool maxplayers_callback(int value, const char **error_string)
     return FALSE;
   }
 
-  error_string = NULL;
+  *error_string = NULL;
+  return TRUE;
+}
+
+/*************************************************************************
+  Disallow low timeout values for non-hack connections.
+*************************************************************************/
+static bool timeout_callback(int value,
+                             struct connection *caller,
+                             const char **error_string)
+{
+  if (caller && caller->access_level < ALLOW_HACK
+      && value < 30) {
+    *error_string = _("You are not allowed to set timeout values less "
+                      "than 30 seconds.");
+    return FALSE;
+  }
+
+  *error_string = NULL;
   return TRUE;
 }
 
@@ -171,7 +197,9 @@ static bool maxplayers_callback(int value, const char **error_string)
   phases. NB: Assumes that it is not possible to first set team
   alternating phase mode then make teamless players.
 *************************************************************************/
-static bool phasemode_callback(int value, const char **error_string)
+static bool phasemode_callback(int value,
+                               struct connection *caller,
+                               const char **error_string)
 {
   if (value == PMT_TEAMS_ALTERNATE) {
     players_iterate(pplayer) {
@@ -881,10 +909,12 @@ struct settings_s settings[] = {
 	  N_("If all players have not hit \"Turn Done\" before this "
 	     "time is up, then the turn ends automatically. Zero "
 	     "means there is no timeout. In servers compiled with "
-	     "debugging, a timeout "
-	     "of -1 sets the autogame test mode. Use this with the command "
-	     "\"timeoutincrease\" to have a dynamic timer."), NULL, 
-	   GAME_MIN_TIMEOUT, GAME_MAX_TIMEOUT, GAME_DEFAULT_TIMEOUT)
+             "debugging, a timeout of -1 sets the autogame test mode. "
+             "Only connections with hack level access may set the "
+             "timeout to lower than 30 seconds. Use this with the "
+             "command \"timeoutincrease\" to have a dynamic timer."),
+          timeout_callback,
+          GAME_MIN_TIMEOUT, GAME_MAX_TIMEOUT, GAME_DEFAULT_TIMEOUT)
 
   GEN_INT("timeaddenemymove", game.timeoutaddenemymove,
 	  SSET_META, SSET_INTERNAL, SSET_VITAL, SSET_TO_CLIENT,
diff --git a/server/settings.h b/server/settings.h
index 5a84f3b..7f1606e 100644
--- a/server/settings.h
+++ b/server/settings.h
@@ -53,6 +53,16 @@ enum sset_level {
 extern const char *sset_level_names[];
 extern const int OLEVELS_NUM;
 
+typedef bool (*bool_validate_func_t)(bool value,
+                                     struct connection *pconn,
+                                     const char **reject_message);
+typedef bool (*int_validate_func_t)(int value,
+                                    struct connection *pconn,
+                                    const char **reject_message);
+typedef bool (*string_validate_func_t)(const char * value,
+                                       struct connection *pconn,
+                                       const char **reject_message);
+
 struct settings_s {
   const char *name;
   enum sset_class sclass;
@@ -84,18 +94,18 @@ struct settings_s {
   /*** bool part ***/
   bool *bool_value;
   bool bool_default_value;
-  bool (*bool_validate)(bool value, const char **reject_message);
+  bool_validate_func_t bool_validate;
 
   /*** int part ***/
   int *int_value;
   int int_default_value;
-  bool (*int_validate)(int value, const char **reject_message);
+  int_validate_func_t int_validate;
   int int_min_value, int_max_value;
 
   /*** string part ***/
   char *string_value;
   const char *string_default_value;
-  bool (*string_validate)(const char * value, const char **reject_message);
+  string_validate_func_t string_validate;
   size_t string_value_size;	/* max size we can write into string_value */
 };
 
diff --git a/server/stdinhand.c b/server/stdinhand.c
index e31aa45..8976c14 100644
--- a/server/stdinhand.c
+++ b/server/stdinhand.c
@@ -2555,10 +2555,13 @@ static bool set_command(struct connection *caller, char *str, bool check)
       bool b_val = (val != 0);
 
       if (settings[cmd].bool_validate
-	  && !settings[cmd].bool_validate(b_val, &reject_message)) {
-	cmd_reply(CMD_SET, caller, C_SYNTAX, reject_message);
+          && !settings[cmd].bool_validate(b_val, caller,
+                                          &reject_message)) {
+        cmd_reply(CMD_SET, caller, C_SYNTAX, reject_message);
         return FALSE;
-      } else if (!check) {
+      }
+
+      if (!check) {
 	*(op->bool_value) = b_val;
 	my_snprintf(buffer, sizeof(buffer),
 		    _("Option: %s has been set to %d."), op->name,
@@ -2595,10 +2598,13 @@ static bool set_command(struct connection *caller, char *str, bool check)
       const char *reject_message = NULL;
 
       if (settings[cmd].int_validate
-	  && !settings[cmd].int_validate(val, &reject_message)) {
-	cmd_reply(CMD_SET, caller, C_SYNTAX, reject_message);
+          && !settings[cmd].int_validate(val, caller,
+                                         &reject_message)) {
+        cmd_reply(CMD_SET, caller, C_SYNTAX, reject_message);
         return FALSE;
-      } else if (!check) {
+      }
+
+      if (!check) {
 	*(op->int_value) = val;
 	my_snprintf(buffer, sizeof(buffer),
 		    _("Option: %s has been set to %d."), op->name,
@@ -2618,10 +2624,13 @@ static bool set_command(struct connection *caller, char *str, bool check)
       const char *reject_message = NULL;
 
       if (settings[cmd].string_validate
-	  && !settings[cmd].string_validate(arg, &reject_message)) {
-	cmd_reply(CMD_SET, caller, C_SYNTAX, reject_message);
+          && !settings[cmd].string_validate(arg, caller,
+                                            &reject_message)) {
+        cmd_reply(CMD_SET, caller, C_SYNTAX, reject_message);
         return FALSE;
-      } else if (!check) {
+      }
+
+      if (!check) {
 	strcpy(op->string_value, arg);
 	my_snprintf(buffer, sizeof(buffer),
 		    _("Option: %s has been set to \"%s\"."), op->name,
_______________________________________________
Freeciv-dev mailing list
Freeciv-dev@gna.org
https://mail.gna.org/listinfo/freeciv-dev

Reply via email to