> >> 3) Add a flag to the PUSH_REPLY list indicating if it is immutable

I cooked up a patch that would do that:
https://community.openvpn.net/openvpn/attachment/ticket/29/0001-Make-some-push-options-not-resetable-by-ccd-config.patch


        Make some push options not resetable by ccd config

        Fixes bug ticket 29
        <https://community.openvpn.net/openvpn/ticket/29>

        When client configuration has a 'push-reset' option,
        non-immutable global options will not be pushed to client.

        Only options added after the *last* push-reset will be set
        immutable.

        This way, if push-reset is given in ccd files and plugin
        returned list, only the configuration options from the plugin
        will be set immutable.


I tried the following scenarios (in topology subnet):
client with no ccd file and no options returned by connect_v2 plugin
call -> OK
client with push-reset in ccd file and push reset in connect_v2 plugin
call -> OK (only connect_v2 options are pushed to client)
client with push-reset in ccd file and no push-reset in connect_v2
plugin call -> OK (only got options from ccd file and connect_v2)
client with ccd file and options returned by connect_v2 plugin call (no
push-reset in either case) -> OK (got global config + ccd file config +
connect_v2 config)

I am not really happy with all those 
last_option = mi->context.options.push_list.tail;
...
if (mi->context.options.push_reset){}

But this is the only way I can think off in order to make sure that the
latest push-reset will take precedence.

Any comments are welcome.

Tks

chantra

-- 
http://www.debuntu.org
>From 05a33ce2a522e404d99b0815f4dca8eb914bd642 Mon Sep 17 00:00:00 2001
From: chantra <chan...@debuntu.org>
List-Post: openvpn-devel@lists.sourceforge.net
Date: Thu, 29 Jul 2010 10:14:26 +0200
Subject: [PATCH] Make some push options not resetable by ccd config

Fixes bug ticket 29
<https://community.openvpn.net/openvpn/ticket/29>

When client configuration has a 'push-reset' option,
non-immutable global options will not be pushed to client.

Only options added after the *last* push-reset will be set
immutable.

This way, if push-reset is given in ccd files and plugin
returned list, only the configuration options from the plugin
will be set immutable.

Signed-off-by: chantra <chan...@debuntu.org>
---
 helper.c   |    5 ++++
 multi.c    |   66 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-
 options.c  |    3 +-
 options.h  |    1 +
 push.c     |    3 +-
 pushlist.h |    1 +
 6 files changed, 76 insertions(+), 3 deletions(-)

diff --git a/helper.c b/helper.c
index a9d7fd9..44723b4 100644
--- a/helper.c
+++ b/helper.c
@@ -256,11 +256,13 @@ helper_client_server (struct options *o)
 	      o->ifconfig_pool_netmask = o->server_netmask;

 	      push_option (o, print_opt_route_gateway (o->server_network + 1, &o->gc), M_USAGE);
+	      o->push_list.tail->immutable = true;
 	    }
 	  else
 	    ASSERT (0);

 	  push_option (o, print_opt_topology (topology, &o->gc), M_USAGE);
+	  o->push_list.tail->immutable = true;
 	}
       else if (dev == DEV_TYPE_TAP)
 	{
@@ -283,6 +285,7 @@ helper_client_server (struct options *o)
 	  o->ifconfig_pool_netmask = o->server_netmask;

 	  push_option (o, print_opt_route_gateway (o->server_network + 1, &o->gc), M_USAGE);
+	  o->push_list.tail->immutable = true;
 	}
       else
 	{
@@ -355,10 +358,12 @@ helper_client_server (struct options *o)
 	  ifconfig_pool_verify_range (M_USAGE, o->ifconfig_pool_start, o->ifconfig_pool_end);
 	  o->ifconfig_pool_netmask = o->server_bridge_netmask;
 	  push_option (o, print_opt_route_gateway (o->server_bridge_ip, &o->gc), M_USAGE);
+	  o->push_list.tail->immutable = true;
 	}
       else if (o->server_bridge_proxy_dhcp && !(o->server_flags & SF_NO_PUSH_ROUTE_GATEWAY))
 	{
 	  push_option (o, print_opt_route_gateway_dhcp (&o->gc), M_USAGE);
+	  o->push_list.tail->immutable = true;
 	}
     }
   else
diff --git a/multi.c b/multi.c
index dc26a02..899a345 100644
--- a/multi.c
+++ b/multi.c
@@ -1283,6 +1283,20 @@ multi_set_virtual_addr_env (struct multi_context *m, struct multi_instance *mi)
 }

 /*
+ * Set list entry immutable flag to immutable
+ * until end of list
+ */
+static void
+multi_client_connect_post_set_immutable (struct push_entry *e,
+			   bool immutable)
+{
+	while( e ){
+		e->immutable = immutable;
+		e = e->next;
+	}
+}
+
+/*
  * Called after client-connect script is called
  */
 static void
@@ -1442,6 +1456,8 @@ multi_connection_established (struct multi_context *m, struct multi_instance *mi
     {
       struct gc_arena gc = gc_new ();
       unsigned int option_types_found = 0;
+      struct push_entry *immutable_from_option = NULL, *last_option = NULL;
+      bool push_reset = false;

       const unsigned int option_permissions_mask =
 	  OPT_P_INSTANCE
@@ -1487,12 +1503,18 @@ multi_connection_established (struct multi_context *m, struct multi_instance *mi
 	  /* try common-name file */
 	  if (test_file (ccd_file))
 	    {
+	      last_option = mi->context.options.push_list.tail;
 	      options_server_import (&mi->context.options,
 				     ccd_file,
 				     D_IMPORT_ERRORS|M_OPTERR,
 				     option_permissions_mask,
 				     &option_types_found,
 				     mi->context.c2.es);
+	      if (mi->context.options.push_reset){
+				     immutable_from_option = last_option;
+				     push_reset = true;
+				     mi->context.options.push_reset = false;
+					}
 	    }
 	  else /* try default file */
 	    {
@@ -1502,12 +1524,19 @@ multi_connection_established (struct multi_context *m, struct multi_instance *mi

 	      if (test_file (ccd_file))
 		{
+		  last_option = mi->context.options.push_list.tail;
 		  options_server_import (&mi->context.options,
 					 ccd_file,
 					 D_IMPORT_ERRORS|M_OPTERR,
 					 option_permissions_mask,
 					 &option_types_found,
 					 mi->context.c2.es);
+
+		   if (mi->context.options.push_reset){
+					 immutable_from_option = last_option;
+					 push_reset = true;
+					 mi->context.options.push_reset = false;
+	     }
 		}
 	    }
 	}
@@ -1545,7 +1574,14 @@ multi_connection_established (struct multi_context *m, struct multi_instance *mi
 	    }
 	  else
 	    {
+	      last_option = mi->context.options.push_list.tail;
 	      multi_client_connect_post (m, mi, dc_file, option_permissions_mask, &option_types_found);
+	      if (mi->context.options.push_reset){
+						immutable_from_option = last_option;
+						push_reset = true;
+						mi->context.options.push_reset = false;
+	      }
+
 	      ++cc_succeeded_count;
 	    }
         script_depr_failed:
@@ -1566,8 +1602,15 @@ multi_connection_established (struct multi_context *m, struct multi_instance *mi
 	    }
 	  else
 	    {
+	      last_option = mi->context.options.push_list.tail;
 	      multi_client_connect_post_plugin (m, mi, &pr, option_permissions_mask, &option_types_found);
 	      ++cc_succeeded_count;
+	      if (mi->context.options.push_reset){
+						immutable_from_option = last_option;
+						push_reset = true;
+						mi->context.options.push_reset = false;
+				}
+
 	    }

 	  plugin_return_free (&pr);
@@ -1596,8 +1639,14 @@ multi_connection_established (struct multi_context *m, struct multi_instance *mi

 	  if (openvpn_execve_check (&argv, mi->context.c2.es, S_SCRIPT, "client-connect command failed"))
 	    {
+	      last_option = mi->context.options.push_list.tail;
 	      multi_client_connect_post (m, mi, dc_file, option_permissions_mask, &option_types_found);
 	      ++cc_succeeded_count;
+	      if (mi->context.options.push_reset){
+						immutable_from_option = last_option;
+						push_reset = true;
+						mi->context.options.push_reset = false;
+	      }
 	    }
 	  else
 	    cc_succeeded = false;
@@ -1611,8 +1660,14 @@ multi_connection_established (struct multi_context *m, struct multi_instance *mi
 #ifdef MANAGEMENT_DEF_AUTH
       if (cc_succeeded && mi->cc_config)
 	{
+	  last_option = mi->context.options.push_list.tail;
 	  multi_client_connect_mda (m, mi, mi->cc_config, option_permissions_mask, &option_types_found);
 	  ++cc_succeeded_count;
+	  if (mi->context.options.push_reset){
+		    immutable_from_option = last_option;
+		    push_reset = true;
+		    mi->context.options.push_reset = false;
+	  }
 	}
 #endif

@@ -1625,7 +1680,16 @@ multi_connection_established (struct multi_context *m, struct multi_instance *mi
 	  msg (D_MULTI_ERRORS, "MULTI: client has been rejected due to 'disable' directive");
 	  cc_succeeded = false;
 	}
-
+  /*
+   * Set option push_reset to true if push-reset option
+   * was ever encountered, and set to immutable
+   * options added since last push-reset
+   */
+  mi->context.options.push_reset = push_reset;
+  if( push_reset ){
+		multi_client_connect_post_set_immutable(
+			immutable_from_option ? immutable_from_option->next : mi->context.options.push_list.head, true);
+  }
       if (cc_succeeded)
 	{
 	  /*
diff --git a/options.c b/options.c
index b78158e..20c5f60 100644
--- a/options.c
+++ b/options.c
@@ -691,6 +691,7 @@ init_options (struct options *o, const bool init_gc)
   o->route_delay_window = 30;
   o->max_routes = MAX_ROUTES_DEFAULT;
   o->resolve_retry_seconds = RESOLV_RETRY_INFINITE;
+  o->push_reset = false;
 #ifdef ENABLE_OCC
   o->occ = true;
 #endif
@@ -4789,7 +4790,7 @@ add_option (struct options *options,
   else if (streq (p[0], "push-reset"))
     {
       VERIFY_PERMISSION (OPT_P_INSTANCE);
-      push_reset (options);
+      options->push_reset = true;
     }
   else if (streq (p[0], "ifconfig-pool") && p[1] && p[2])
     {
diff --git a/options.h b/options.h
index 240f3bb..4b1597f 100644
--- a/options.h
+++ b/options.h
@@ -378,6 +378,7 @@ struct options
   in_addr_t server_bridge_pool_end;

   struct push_list push_list;
+  bool push_reset;
   bool ifconfig_pool_defined;
   in_addr_t ifconfig_pool_start;
   in_addr_t ifconfig_pool_end;
diff --git a/push.c b/push.c
index 1320bec..9d994a5 100644
--- a/push.c
+++ b/push.c
@@ -183,7 +183,7 @@ send_push_reply (struct context *c)

   while (e)
     {
-      if (e->enable)
+      if (e->enable && (!c->options.push_reset || e->immutable))
 	{
 	  const int l = strlen (e->option);
 	  if (BLEN (&buf) + l >= safe_cap)
@@ -290,6 +290,7 @@ clone_push_list (struct options *o)
       while (e)
 	{
 	  push_option_ex (o, string_alloc (e->option, &o->gc), true, M_FATAL);
+	  o->push_list.tail->immutable = e->immutable;
 	  e = e->next;
 	}
     }
diff --git a/pushlist.h b/pushlist.h
index b252676..11356dd 100644
--- a/pushlist.h
+++ b/pushlist.h
@@ -30,6 +30,7 @@
 struct push_entry {
   struct push_entry *next;
   bool enable;
+  bool immutable;
   const char *option;
 };

-- 
1.5.6.5

Reply via email to