]> git.ipfire.org Git - thirdparty/openvpn.git/commitdiff
Implemented a key/value auth channel from client to server.
authorJames Yonan <james@openvpn.net>
Tue, 1 Jun 2010 07:12:27 +0000 (07:12 +0000)
committerJames Yonan <james@openvpn.net>
Tue, 1 Jun 2010 07:12:27 +0000 (07:12 +0000)
Version 2.1.1i

git-svn-id: http://svn.openvpn.net/projects/openvpn/branches/BETA21/openvpn@5668 e7ae566f-a301-0410-adde-c780ea21d3b5

14 files changed:
common.h
init.c
manage.c
manage.h
multi.c
options.c
options.h
push.c
route.c
route.h
ssl.c
ssl.h
syshead.h
version.m4

index b1f5818ea5610dea54b1e4b11455907136bbe8f5..5548f7c1a69e6fdc960f25f4cb27371ba5ea5653 100644 (file)
--- a/common.h
+++ b/common.h
@@ -76,8 +76,15 @@ typedef unsigned long ptr_type;
 /*
  * This parameter controls the TLS channel buffer size and the
  * maximum size of a single TLS message (cleartext).
+ * This parameter must be >= PUSH_BUNDLE_SIZE
  */
-#define TLS_CHANNEL_BUF_SIZE 1024
+#define TLS_CHANNEL_BUF_SIZE 2048
+
+/*
+ * This parameter controls the maximum size of a bundle
+ * of pushed options.
+ */
+#define PUSH_BUNDLE_SIZE 1024
 
 /*
  * A sort of pseudo-filename for data provided inline within
diff --git a/init.c b/init.c
index a6f6bcebcb35d19865f5c797459d9742b64bf1a6..5e45ccd42d7c05c9a077978c31e150d19104a7aa 100644 (file)
--- a/init.c
+++ b/init.c
@@ -2007,6 +2007,9 @@ do_init_crypto_tls (struct context *c, const unsigned int flags)
   to.renegotiate_packets = options->renegotiate_packets;
   to.renegotiate_seconds = options->renegotiate_seconds;
   to.single_session = options->single_session;
+#ifdef ENABLE_PUSH_PEER_INFO
+  to.push_peer_info = options->push_peer_info;
+#endif
 
   /* should we not xmit any packets until we get an initial
      response from client? */
index 209472330338e8110eea7183302d0df566e724a3..820621e5916eda23d4489566cbd40ccb9159e2b3 100644 (file)
--- a/manage.c
+++ b/manage.c
@@ -2275,6 +2275,58 @@ man_output_extra_env (struct management *man)
   gc_free (&gc);
 }
 
+static bool
+validate_peer_info_line(const char *line)
+{
+  uint8_t c;
+  int state = 0;
+  while ((c=*line++))
+    {
+      switch (state)
+       {
+       case 0:
+       case 1:
+         if (c == '=' && state == 1)
+           state = 2;
+         else if (isalnum(c) || c == '_')
+           state = 1;
+         else
+           return false;
+       case 2:
+         if (isprint(c))
+           ;
+         else
+           return false;
+       }
+    }
+  return (state == 2);
+}
+
+static void
+man_output_peer_info_env (struct management *man, struct man_def_auth_context *mdac)
+{
+  char line[256];
+  if (man->persist.callback.get_peer_info)
+    {
+      const char *peer_info = (*man->persist.callback.get_peer_info) (man->persist.callback.arg, mdac->cid);
+      if (peer_info)
+       {
+         struct buffer buf;
+         buf_set_read (&buf, (const uint8_t *) peer_info, strlen(peer_info));
+         while (buf_parse (&buf, '\n', line, sizeof (line)))
+           {
+             chomp (line);
+             if (validate_peer_info_line(line))
+               {
+                 msg (M_CLIENT, ">CLIENT:ENV,%s", line);
+               }
+             else
+               msg (D_MANAGEMENT, "validation failed on peer_info line received from client");
+           }
+       }
+    }
+}
+
 void
 management_notify_client_needing_auth (struct management *management,
                                       const unsigned int mda_key_id,
@@ -2288,6 +2340,7 @@ management_notify_client_needing_auth (struct management *management,
        mode = "REAUTH";
       msg (M_CLIENT, ">CLIENT:%s,%lu,%u", mode, mdac->cid, mda_key_id);
       man_output_extra_env (management);
+      man_output_peer_info_env(management, mdac);
       man_output_env (es, true, management->connection.env_filter_level);
       mdac->flags |= DAF_INITIAL_AUTH;
     }
index bb738ac280e0ee1c3694ecea8c29c21f3bc5e309..6a9ccd885966010ddce2e0eacd04af3459307db0 100644 (file)
--- a/manage.h
+++ b/manage.h
@@ -164,6 +164,7 @@ struct management_callback
                       const char *reason,
                       const char *client_reason,
                       struct buffer_list *cc_config); /* ownership transferred */
+  char *(*get_peer_info) (void *arg, const unsigned long cid);
 #endif
 #ifdef MANAGEMENT_PF
   bool (*client_pf) (void *arg,
diff --git a/multi.c b/multi.c
index 5c80c462e316de68406550b30519485f432dc906..2808c9b72d661dbcfa3eca19a0e1a9897e35b230 100644 (file)
--- a/multi.c
+++ b/multi.c
@@ -2597,6 +2597,20 @@ management_client_auth (void *arg,
     buffer_list_free (cc_config);
   return ret;
 }
+
+static char *
+management_get_peer_info (void *arg, const unsigned long cid)
+{
+  struct multi_context *m = (struct multi_context *) arg;
+  struct multi_instance *mi = lookup_by_cid (m, cid);
+  char *ret = NULL;
+
+  if (mi)
+      ret = tls_get_peer_info (mi->context.c2.tls_multi);
+
+  return ret;
+}
+
 #endif
 
 #ifdef MANAGEMENT_PF
@@ -2637,6 +2651,7 @@ init_management_callback_multi (struct multi_context *m)
 #ifdef MANAGEMENT_DEF_AUTH
       cb.kill_by_cid = management_kill_by_cid;
       cb.client_auth = management_client_auth;
+      cb.get_peer_info = management_get_peer_info;
 #endif
 #ifdef MANAGEMENT_PF
       cb.client_pf = management_client_pf;
index 2c823db08507ec78bd267e8e4b4bbc5464c83f97..bb377f6579901b1668d9581904fc4b55825566d4 100644 (file)
--- a/options.c
+++ b/options.c
@@ -196,6 +196,9 @@ static const char usage_message[] =
   "                  Add 'bypass-dns' flag to similarly bypass tunnel for DNS.\n"
   "--redirect-private [flags]: Like --redirect-gateway, but omit actually changing\n"
   "                  the default gateway.  Useful when pushing private subnets.\n"
+#ifdef ENABLE_PUSH_PEER_INFO
+  "--push-peer-info : (client only) push client info to server.\n"
+#endif
   "--setenv name value : Set a custom environmental variable to pass to script.\n"
   "--setenv FORWARD_COMPATIBLE 1 : Relax config file syntax checking to allow\n"
   "                  directives for future OpenVPN versions to be ignored.\n"
@@ -1348,6 +1351,9 @@ show_settings (const struct options *o)
   SHOW_INT (transition_window);
 
   SHOW_BOOL (single_session);
+#ifdef ENABLE_PUSH_PEER_INFO
+  SHOW_BOOL (push_peer_info);
+#endif
   SHOW_BOOL (tls_exit);
 
   SHOW_STR (tls_auth_file);
@@ -2057,6 +2063,9 @@ options_postprocess_verify_ce (const struct options *options, const struct conne
       MUST_BE_UNDEF (transition_window);
       MUST_BE_UNDEF (tls_auth_file);
       MUST_BE_UNDEF (single_session);
+#ifdef ENABLE_PUSH_PEER_INFO
+      MUST_BE_UNDEF (push_peer_info);
+#endif
       MUST_BE_UNDEF (tls_exit);
       MUST_BE_UNDEF (crl_file);
       MUST_BE_UNDEF (key_method);
@@ -5672,6 +5681,13 @@ add_option (struct options *options,
       VERIFY_PERMISSION (OPT_P_GENERAL);
       options->single_session = true;
     }
+#ifdef ENABLE_PUSH_PEER_INFO
+  else if (streq (p[0], "push-peer-info"))
+    {
+      VERIFY_PERMISSION (OPT_P_GENERAL);
+      options->push_peer_info = true;
+    }
+#endif
   else if (streq (p[0], "tls-exit"))
     {
       VERIFY_PERMISSION (OPT_P_GENERAL);
index a000ccb4505bc1a5972dcdb45675e6417483dcb8..240f3bb5f23c48f6d3247a26e0267496048aa99c 100644 (file)
--- a/options.h
+++ b/options.h
@@ -520,6 +520,10 @@ struct options
   /* Allow only one session */
   bool single_session;
 
+#ifdef ENABLE_PUSH_PEER_INFO
+  bool push_peer_info;
+#endif
+
   bool tls_exit;
 
 #endif /* USE_SSL */
diff --git a/push.c b/push.c
index d05cc1d0449270a854a0c59db8b0bab319d7b6e8..9ddc90027a92210fd92db27a69fe5a91c9627199 100644 (file)
--- a/push.c
+++ b/push.c
@@ -102,8 +102,8 @@ send_auth_failed (struct context *c, const char *client_reason)
   schedule_exit (c, c->options.scheduled_exit_interval, SIGTERM);
 
   len = (client_reason ? strlen(client_reason)+1 : 0) + sizeof(auth_failed);
-  if (len > TLS_CHANNEL_BUF_SIZE)
-    len = TLS_CHANNEL_BUF_SIZE;
+  if (len > PUSH_BUNDLE_SIZE)
+    len = PUSH_BUNDLE_SIZE;
 
   {
     struct buffer buf = alloc_buf_gc (len, &gc);
@@ -171,7 +171,7 @@ bool
 send_push_reply (struct context *c)
 {
   struct gc_arena gc = gc_new ();
-  struct buffer buf = alloc_buf_gc (TLS_CHANNEL_BUF_SIZE, &gc);
+  struct buffer buf = alloc_buf_gc (PUSH_BUNDLE_SIZE, &gc);
   struct push_entry *e = c->options.push_list.head;
   bool multi_push = false;
   static char cmd[] = "PUSH_REPLY";
diff --git a/route.c b/route.c
index 7ab82ff260a96a706372cda2093fbea194f17f85..2635afdff5727521176ecc4a68512eb6113e6261 100644 (file)
--- a/route.c
+++ b/route.c
@@ -2186,7 +2186,7 @@ get_bypass_addresses (struct route_bypass *rb, const unsigned int flags)  /* PLA
 
 #endif
 
-#if AUTO_USERID
+#if AUTO_USERID || defined(ENABLE_PUSH_PEER_INFO)
 
 #if defined(TARGET_LINUX)
 
diff --git a/route.h b/route.h
index 2def1d29c9def4ea1ed72a1bf808f13a2cf13678..c5cbb7cffe747c772ccd21c0fceaeadc9fac70dc 100644 (file)
--- a/route.h
+++ b/route.h
@@ -174,7 +174,7 @@ bool get_default_gateway (in_addr_t *ip, in_addr_t *netmask);
 #define TLA_LOCAL           2
 int test_local_addr (const in_addr_t addr);
 
-#if AUTO_USERID
+#if AUTO_USERID || defined(ENABLE_PUSH_PEER_INFO)
 bool get_default_gateway_mac_addr (unsigned char *macaddr);
 #endif
 
diff --git a/ssl.c b/ssl.c
index 3387943156f04d76ca3df72bdb5507b658b6033e..9801b0eb9907b20687889cdaf87e18d0b38f522e 100644 (file)
--- a/ssl.c
+++ b/ssl.c
@@ -2558,6 +2558,8 @@ tls_multi_free (struct tls_multi *multi, bool clear)
 
 #ifdef MANAGEMENT_DEF_AUTH
   man_def_auth_set_client_reason(multi, NULL);  
+
+  free (multi->peer_info);
 #endif
 
   if (multi->locked_cn)
@@ -3105,6 +3107,14 @@ write_string (struct buffer *buf, const char *str, const int maxlen)
   return true;
 }
 
+static bool
+write_empty_string (struct buffer *buf)
+{
+  if (!buf_write_u16 (buf, 0))
+    return false;
+  return true;
+}
+
 static bool
 read_string (struct buffer *buf, char *str, const unsigned int capacity)
 {
@@ -3117,6 +3127,33 @@ read_string (struct buffer *buf, char *str, const unsigned int capacity)
   return true;
 }
 
+static char *
+read_string_alloc (struct buffer *buf)
+{
+  const int len = buf_read_u16 (buf);
+  char *str;
+
+  if (len < 1)
+    return NULL;
+  str = (char *) malloc(len);
+  check_malloc_return(str);
+  if (!buf_read (buf, str, len))
+    {
+      free (str);
+      return NULL;
+    }
+  str[len-1] = '\0';
+  return str;
+}
+
+void
+read_string_discard (struct buffer *buf)
+{
+  char *data = read_string_alloc(buf);
+  if (data)
+    free (data);
+}
+
 /*
  * Authenticate a client using username/password.
  * Runs on server.
@@ -3327,6 +3364,73 @@ key_method_1_write (struct buffer *buf, struct tls_session *session)
   return true;
 }
 
+static bool
+push_peer_info(struct buffer *buf, struct tls_session *session)
+{
+  struct gc_arena gc = gc_new ();
+  bool ret = false;
+
+#ifdef ENABLE_PUSH_PEER_INFO
+  if (session->opt->push_peer_info) /* write peer info */
+    {
+      struct env_set *es = session->opt->es;
+      struct env_item *e;
+      struct buffer out = alloc_buf_gc (512*3, &gc);
+
+      /* push version */
+      buf_printf (&out, "IV_VER=%s\n", PACKAGE_VERSION);
+
+      /* push platform */
+#if defined(TARGET_LINUX)
+      buf_printf (&out, "IV_PLAT=linux\n");
+#elif defined(TARGET_SOLARIS)
+      buf_printf (&out, "IV_PLAT=solaris\n");
+#elif defined(TARGET_OPENBSD)
+      buf_printf (&out, "IV_PLAT=openbsd\n");
+#elif defined(TARGET_DARWIN)
+      buf_printf (&out, "IV_PLAT=mac\n");
+#elif defined(TARGET_NETBSD)
+      buf_printf (&out, "IV_PLAT=netbsd\n");
+#elif defined(TARGET_FREEBSD)
+      buf_printf (&out, "IV_PLAT=freebsd\n");
+#elif defined(WIN32)
+      buf_printf (&out, "IV_PLAT=win\n");
+#endif
+
+      /* push mac addr */
+      {
+       bool get_default_gateway_mac_addr (unsigned char *macaddr);
+       uint8_t macaddr[6];
+       get_default_gateway_mac_addr (macaddr);
+       buf_printf (&out, "IV_HWADDR=%s\n", format_hex_ex (macaddr, 6, 0, 1, ":", &gc));
+      }
+
+      /* push env vars that begin with UV_ */
+      for (e=es->list; e != NULL; e=e->next)
+       {
+         if (e->string)
+           {
+             if (!strncmp(e->string, "UV_", 3) && buf_safe(&out, strlen(e->string)+1))
+               buf_printf (&out, "%s\n", e->string);
+           }
+       }
+
+      if (!write_string(buf, BSTR(&out), -1))
+       goto error;
+    }
+  else
+#endif
+    {
+      if (!write_empty_string (buf)) /* no peer info */
+       goto error;
+    }
+  ret = true;
+
+ error:
+  gc_free (&gc);
+  return ret;
+}
+
 static bool
 key_method_2_write (struct buffer *buf, struct tls_session *session)
 {
@@ -3361,6 +3465,16 @@ key_method_2_write (struct buffer *buf, struct tls_session *session)
        goto error;
       purge_user_pass (&auth_user_pass, false);
     }
+  else
+    {
+      if (!write_empty_string (buf)) /* no username */
+       goto error;
+      if (!write_empty_string (buf)) /* no password */
+       goto error;
+    }
+
+  if (!push_peer_info (buf, session))
+    goto error;
 
   /*
    * generate tunnel keys if server
@@ -3507,11 +3621,13 @@ key_method_2_read (struct buffer *buf, struct tls_multi *multi, struct tls_sessi
       int s1 = OPENVPN_PLUGIN_FUNC_SUCCESS;
       bool s2 = true;
       char *raw_username;
+      bool username_status, password_status;
 
       /* get username/password from plaintext buffer */
       ALLOC_OBJ_CLEAR_GC (up, struct user_pass, &gc);
-      if (!read_string (buf, up->username, USER_PASS_LEN)
-         || !read_string (buf, up->password, USER_PASS_LEN))
+      username_status = read_string (buf, up->username, USER_PASS_LEN);
+      password_status = read_string (buf, up->password, USER_PASS_LEN);
+      if (!username_status || !password_status)
        {
          CLEAR (*up);
          if (!(session->opt->ssl_flags & SSLF_AUTH_USER_PASS_OPTIONAL))
@@ -3532,6 +3648,10 @@ key_method_2_read (struct buffer *buf, struct tls_multi *multi, struct tls_sessi
 
       /* call plugin(s) and/or script */
 #ifdef MANAGEMENT_DEF_AUTH
+      /* get peer info from control channel */
+      free (multi->peer_info);
+      multi->peer_info = read_string_alloc (buf);
+
       if (man_def_auth == KMDA_DEF)
        man_def_auth = verify_user_pass_management (session, up, raw_username);
 #endif
diff --git a/ssl.h b/ssl.h
index 830240225500672899855c622f8ed1733e9270a5..e895bb20305ce4c69007315b4f1896471113d070 100644 (file)
--- a/ssl.h
+++ b/ssl.h
@@ -431,6 +431,9 @@ struct tls_options
   bool single_session;
 #ifdef ENABLE_OCC
   bool disable_occ;
+#endif
+#ifdef ENABLE_PUSH_PEER_INFO
+  bool push_peer_info;
 #endif
   int transition_window;
   int handshake_window;
@@ -618,6 +621,12 @@ struct tls_multi
    */
   char *client_reason;
 
+  /*
+   * A multi-line string of general-purpose info received from peer
+   * over control channel.
+   */
+  char *peer_info;
+
   /* Time of last call to tls_authentication_status */
   time_t tas_last;
 #endif
@@ -721,6 +730,12 @@ void tls_deauthenticate (struct tls_multi *multi);
 
 #ifdef MANAGEMENT_DEF_AUTH
 bool tls_authenticate_key (struct tls_multi *multi, const unsigned int mda_key_id, const bool auth, const char *client_reason);
+
+static inline char *
+tls_get_peer_info(const struct tls_multi *multi)
+{
+  return multi->peer_info;
+}
 #endif
 
 /*
index b159bf9315e70b044aebf9ee1940961574cf686a..d2ea8de60012d47bf0537d7f2493ecf242a9cd4f 100644 (file)
--- a/syshead.h
+++ b/syshead.h
@@ -662,4 +662,9 @@ socket_defined (const socket_descriptor_t sd)
 #define AUTO_USERID 0
 #endif
 
+/*
+ * Do we support pushing peer info?
+ */
+#define ENABLE_PUSH_PEER_INFO
+
 #endif
index 4b2dcb9df2ea29b5115073b2eed675fb5d92d331..8df30d5b08b43ed2c9ad9519df1befeb6184d73f 100644 (file)
@@ -1,5 +1,5 @@
 dnl define the OpenVPN version
-define(PRODUCT_VERSION,[2.1.1h])
+define(PRODUCT_VERSION,[2.1.1i])
 dnl define the TAP version
 define(PRODUCT_TAP_ID,[tap0901])
 define(PRODUCT_TAP_WIN32_MIN_MAJOR,[9])