]> git.ipfire.org Git - thirdparty/openvpn.git/commitdiff
Refactored username and password authentication code
authorAdriaan de Jong <dejong@fox-it.com>
Thu, 30 Jun 2011 08:48:18 +0000 (10:48 +0200)
committerDavid Sommerseth <davids@redhat.com>
Fri, 21 Oct 2011 12:51:45 +0000 (14:51 +0200)
Signed-off-by: Adriaan de Jong <dejong@fox-it.com>
Acked-by: James Yonan <james@openvpn.net>
Signed-off-by: David Sommerseth <davids@redhat.com>
ssl.c
ssl.h
ssl_common.h
ssl_verify.c
ssl_verify.h

diff --git a/ssl.c b/ssl.c
index fbb0d02d20782e3dbb0c5c9d3481c59fb027bd3f..ec524e7a8b3e9280c6185e2f4a89b4c9f25cdd7c 100644 (file)
--- a/ssl.c
+++ b/ssl.c
@@ -1086,45 +1086,6 @@ verify_callback (int preverify_ok, X509_STORE_CTX * ctx)
 
 /** @} name Function for authenticating a new connection from a remote OpenVPN peer */
 
-
-static bool
-tls_lock_username (struct tls_multi *multi, const char *username)
-{
-  if (multi->locked_username)
-    {
-      if (!username || strcmp (username, multi->locked_username))
-       {
-         msg (D_TLS_ERRORS, "TLS Auth Error: username attempted to change from '%s' to '%s' -- tunnel disabled",
-              multi->locked_username,
-              np(username));
-
-         /* disable the tunnel */
-         tls_deauthenticate (multi);
-         return false;
-       }
-    }
-  else
-    {
-      if (username)
-       multi->locked_username = string_alloc (username, NULL);
-    }
-  return true;
-}
-
-const char *
-tls_username (const struct tls_multi *multi, const bool null)
-{
-  const char *ret = NULL;
-  if (multi)
-    ret = multi->locked_username;
-  if (ret && strlen (ret))
-    return ret;
-  else if (null)
-    return NULL;
-  else
-    return "UNDEF";
-}
-
 #ifdef ENABLE_X509_TRACK
 
 void
@@ -1150,234 +1111,6 @@ x509_track_add (const struct x509_track **ll_head, const char *name, int msgleve
 
 #endif
 
-#ifdef ENABLE_DEF_AUTH
-/* key_state_test_auth_control_file return values,
-   NOTE: acf_merge indexing depends on these values */
-#define ACF_UNDEFINED 0
-#define ACF_SUCCEEDED 1
-#define ACF_DISABLED  2
-#define ACF_FAILED    3
-#endif
-
-#ifdef MANAGEMENT_DEF_AUTH
-static void
-man_def_auth_set_client_reason (struct tls_multi *multi, const char *client_reason)
-{
-  if (multi->client_reason)
-    {
-      free (multi->client_reason);
-      multi->client_reason = NULL;
-    }
-  if (client_reason && strlen (client_reason))
-    multi->client_reason = string_alloc (client_reason, NULL);
-}
-
-static inline unsigned int
-man_def_auth_test (const struct key_state *ks)
-{
-  if (management_enable_def_auth (management))
-    return ks->mda_status;
-  else
-    return ACF_DISABLED;
-}
-#endif
-
-#ifdef PLUGIN_DEF_AUTH
-
-/*
- * auth_control_file functions
- */
-
-static void
-key_state_rm_auth_control_file (struct key_state *ks)
-{
-  if (ks && ks->auth_control_file)
-    {
-      delete_file (ks->auth_control_file);
-      free (ks->auth_control_file);
-      ks->auth_control_file = NULL;
-    }
-}
-
-static void
-key_state_gen_auth_control_file (struct key_state *ks, const struct tls_options *opt)
-{
-  struct gc_arena gc = gc_new ();
-  const char *acf;
-
-  key_state_rm_auth_control_file (ks);
-  acf = create_temp_file (opt->tmp_dir, "acf", &gc);
-  if( acf ) {
-    ks->auth_control_file = string_alloc (acf, NULL);
-    setenv_str (opt->es, "auth_control_file", ks->auth_control_file);
-  } /* FIXME: Should have better error handling? */
-  gc_free (&gc);                                         
-}
-
-static unsigned int
-key_state_test_auth_control_file (struct key_state *ks)
-{
-  if (ks && ks->auth_control_file)
-    {
-      unsigned int ret = ks->auth_control_status;
-      if (ret == ACF_UNDEFINED)
-       {
-         FILE *fp = fopen (ks->auth_control_file, "r");
-         if (fp)
-           {
-             const int c = fgetc (fp);
-             if (c == '1')
-               ret = ACF_SUCCEEDED;
-             else if (c == '0')
-               ret = ACF_FAILED;
-             fclose (fp);
-             ks->auth_control_status = ret;
-           }
-       }
-      return ret;
-    }
-  return ACF_DISABLED;
-}
-
-#endif
-
-/*
- * Return current session authentication state.  Return
- * value is TLS_AUTHENTICATION_x.
- */
-
-int
-tls_authentication_status (struct tls_multi *multi, const int latency)
-{
-  bool deferred = false;
-  bool success = false;
-  bool active = false;
-
-#ifdef ENABLE_DEF_AUTH
-  static const unsigned char acf_merge[] =
-    {
-      ACF_UNDEFINED, /* s1=ACF_UNDEFINED s2=ACF_UNDEFINED */
-      ACF_UNDEFINED, /* s1=ACF_UNDEFINED s2=ACF_SUCCEEDED */
-      ACF_UNDEFINED, /* s1=ACF_UNDEFINED s2=ACF_DISABLED */
-      ACF_FAILED,    /* s1=ACF_UNDEFINED s2=ACF_FAILED */
-      ACF_UNDEFINED, /* s1=ACF_SUCCEEDED s2=ACF_UNDEFINED */
-      ACF_SUCCEEDED, /* s1=ACF_SUCCEEDED s2=ACF_SUCCEEDED */
-      ACF_SUCCEEDED, /* s1=ACF_SUCCEEDED s2=ACF_DISABLED */
-      ACF_FAILED,    /* s1=ACF_SUCCEEDED s2=ACF_FAILED */
-      ACF_UNDEFINED, /* s1=ACF_DISABLED  s2=ACF_UNDEFINED */
-      ACF_SUCCEEDED, /* s1=ACF_DISABLED  s2=ACF_SUCCEEDED */
-      ACF_DISABLED,  /* s1=ACF_DISABLED  s2=ACF_DISABLED */
-      ACF_FAILED,    /* s1=ACF_DISABLED  s2=ACF_FAILED */
-      ACF_FAILED,    /* s1=ACF_FAILED    s2=ACF_UNDEFINED */
-      ACF_FAILED,    /* s1=ACF_FAILED    s2=ACF_SUCCEEDED */
-      ACF_FAILED,    /* s1=ACF_FAILED    s2=ACF_DISABLED */
-      ACF_FAILED     /* s1=ACF_FAILED    s2=ACF_FAILED */
-    };
-#endif
-
-  if (multi)
-    {
-      int i;
-
-#ifdef ENABLE_DEF_AUTH
-      if (latency && multi->tas_last && multi->tas_last + latency >= now)
-       return TLS_AUTHENTICATION_UNDEFINED;
-      multi->tas_last = now;
-#endif
-
-      for (i = 0; i < KEY_SCAN_SIZE; ++i)
-       {
-         struct key_state *ks = multi->key_scan[i];
-         if (DECRYPT_KEY_ENABLED (multi, ks))
-           {
-             active = true;
-             if (ks->authenticated)
-               {
-#ifdef ENABLE_DEF_AUTH
-                 unsigned int s1 = ACF_DISABLED;
-                 unsigned int s2 = ACF_DISABLED;
-#ifdef PLUGIN_DEF_AUTH
-                 s1 = key_state_test_auth_control_file (ks); 
-#endif
-#ifdef MANAGEMENT_DEF_AUTH
-                 s2 = man_def_auth_test (ks);
-#endif
-                 ASSERT (s1 < 4 && s2 < 4);
-                 switch (acf_merge[(s1<<2) + s2])
-                   {
-                   case ACF_SUCCEEDED:
-                   case ACF_DISABLED:
-                     success = true;
-                     ks->auth_deferred = false;
-                     break;
-                   case ACF_UNDEFINED:
-                     if (now < ks->auth_deferred_expire)
-                       deferred = true;
-                     break;
-                   case ACF_FAILED:
-                     ks->authenticated = false;
-                     break;
-                   default:
-                     ASSERT (0);
-                   }
-#else
-                 success = true;
-#endif
-               }
-           }
-       }
-    }
-
-#if 0
-  dmsg (D_TLS_ERRORS, "TAS: a=%d s=%d d=%d", active, success, deferred);
-#endif
-
-  if (success)
-    return TLS_AUTHENTICATION_SUCCEEDED;
-  else if (!active || deferred)
-    return TLS_AUTHENTICATION_DEFERRED;
-  else
-    return TLS_AUTHENTICATION_FAILED;
-}
-
-#ifdef MANAGEMENT_DEF_AUTH
-/*
- * For deferred auth, this is where the management interface calls (on server)
- * to indicate auth failure/success.
- */
-bool
-tls_authenticate_key (struct tls_multi *multi, const unsigned int mda_key_id, const bool auth, const char *client_reason)
-{
-  bool ret = false;
-  if (multi)
-    {
-      int i;
-      man_def_auth_set_client_reason (multi, client_reason);
-      for (i = 0; i < KEY_SCAN_SIZE; ++i)
-       {
-         struct key_state *ks = multi->key_scan[i];
-         if (ks->mda_key_id == mda_key_id)
-           {
-             ks->mda_status = auth ? ACF_SUCCEEDED : ACF_FAILED;
-             ret = true;
-           }
-       }
-    }
-  return ret;
-}
-#endif
-
-void
-tls_deauthenticate (struct tls_multi *multi)
-{
-  if (multi)
-    {
-      int i, j;
-      for (i = 0; i < TM_SIZE; ++i)
-       for (j = 0; j < KS_SIZE; ++j)
-         multi->session[i].key[j].authenticated = false;
-    }
-}
 
 /*
  * Initialize SSL context.
@@ -2658,173 +2391,6 @@ read_string_discard (struct buffer *buf)
     free (data);
 }
 
-/*
- * Authenticate a client using username/password.
- * Runs on server.
- *
- * If you want to add new authentication methods,
- * this is the place to start.
- */
-
-static bool
-verify_user_pass_script (struct tls_session *session, const struct user_pass *up)
-{
-  struct gc_arena gc = gc_new ();
-  struct argv argv = argv_new ();
-  const char *tmp_file = "";
-  bool ret = false;
-
-  /* Is username defined? */
-  if ((session->opt->ssl_flags & SSLF_AUTH_USER_PASS_OPTIONAL) || strlen (up->username))
-    {
-      /* Set environmental variables prior to calling script */
-      setenv_str (session->opt->es, "script_type", "user-pass-verify");
-
-      if (session->opt->auth_user_pass_verify_script_via_file)
-       {
-         struct status_output *so;
-
-         tmp_file = create_temp_file (session->opt->tmp_dir, "up", &gc);
-          if( tmp_file ) {
-            so = status_open (tmp_file, 0, -1, NULL, STATUS_OUTPUT_WRITE);
-            status_printf (so, "%s", up->username);
-            status_printf (so, "%s", up->password);
-            if (!status_close (so))
-              {
-                msg (D_TLS_ERRORS, "TLS Auth Error: could not write username/password to file: %s",
-                     tmp_file);
-                goto done;
-              }
-          } else {
-            msg (D_TLS_ERRORS, "TLS Auth Error: could not create write "
-                 "username/password to temp file");
-          }
-        }
-      else
-       {
-         setenv_str (session->opt->es, "username", up->username);
-         setenv_str (session->opt->es, "password", up->password);
-       }
-
-      /* setenv incoming cert common name for script */
-      setenv_str (session->opt->es, "common_name", session->common_name);
-
-      /* setenv client real IP address */
-      setenv_untrusted (session);
-
-      /* format command line */
-      argv_printf (&argv, "%sc %s", session->opt->auth_user_pass_verify_script, tmp_file);
-
-      /* call command */
-      ret = openvpn_run_script (&argv, session->opt->es, 0,
-                               "--auth-user-pass-verify");
-
-      if (!session->opt->auth_user_pass_verify_script_via_file)
-       setenv_del (session->opt->es, "password");
-    }
-  else
-    {
-      msg (D_TLS_ERRORS, "TLS Auth Error: peer provided a blank username");
-    }
-
- done:
-  if (tmp_file && strlen (tmp_file) > 0)
-    delete_file (tmp_file);
-
-  argv_reset (&argv);
-  gc_free (&gc);
-  return ret;
-}
-
-static int
-verify_user_pass_plugin (struct tls_session *session, const struct user_pass *up, const char *raw_username)
-{
-  int retval = OPENVPN_PLUGIN_FUNC_ERROR;
-  struct key_state *ks = &session->key[KS_PRIMARY];       /* primary key */
-
-  /* Is username defined? */
-  if ((session->opt->ssl_flags & SSLF_AUTH_USER_PASS_OPTIONAL) || strlen (up->username))
-    {
-      /* set username/password in private env space */
-      setenv_str (session->opt->es, "username", raw_username);
-      setenv_str (session->opt->es, "password", up->password);
-
-      /* setenv incoming cert common name for script */
-      setenv_str (session->opt->es, "common_name", session->common_name);
-
-      /* setenv client real IP address */
-      setenv_untrusted (session);
-
-#ifdef PLUGIN_DEF_AUTH
-      /* generate filename for deferred auth control file */
-      key_state_gen_auth_control_file (ks, session->opt);
-#endif
-
-      /* call command */
-      retval = plugin_call (session->opt->plugins, OPENVPN_PLUGIN_AUTH_USER_PASS_VERIFY, NULL, NULL, session->opt->es, -1, NULL);
-
-#ifdef PLUGIN_DEF_AUTH
-      /* purge auth control filename (and file itself) for non-deferred returns */
-      if (retval != OPENVPN_PLUGIN_FUNC_DEFERRED)
-       key_state_rm_auth_control_file (ks);
-#endif
-
-      setenv_del (session->opt->es, "password");
-      setenv_str (session->opt->es, "username", up->username);
-    }
-  else
-    {
-      msg (D_TLS_ERRORS, "TLS Auth Error (verify_user_pass_plugin): peer provided a blank username");
-    }
-
-  return retval;
-}
-
-/*
- * MANAGEMENT_DEF_AUTH internal ssl.c status codes
- */
-#define KMDA_ERROR   0
-#define KMDA_SUCCESS 1
-#define KMDA_UNDEF   2
-#define KMDA_DEF     3
-
-#ifdef MANAGEMENT_DEF_AUTH
-static int
-verify_user_pass_management (struct tls_session *session, const struct user_pass *up, const char *raw_username)
-{
-  int retval = KMDA_ERROR;
-  struct key_state *ks = &session->key[KS_PRIMARY];       /* primary key */
-
-  /* Is username defined? */
-  if ((session->opt->ssl_flags & SSLF_AUTH_USER_PASS_OPTIONAL) || strlen (up->username))
-    {
-      /* set username/password in private env space */
-      setenv_str (session->opt->es, "username", raw_username);
-      setenv_str (session->opt->es, "password", up->password);
-
-      /* setenv incoming cert common name for script */
-      setenv_str (session->opt->es, "common_name", session->common_name);
-
-      /* setenv client real IP address */
-      setenv_untrusted (session);
-
-      if (management)
-       management_notify_client_needing_auth (management, ks->mda_key_id, session->opt->mda_context, session->opt->es);
-
-      setenv_del (session->opt->es, "password");
-      setenv_str (session->opt->es, "username", up->username);
-
-      retval = KMDA_SUCCESS;
-    }
-  else
-    {
-      msg (D_TLS_ERRORS, "TLS Auth Error (verify_user_pass_management): peer provided a blank username");
-    }
-
-  return retval;
-}
-#endif
-
 /*
  * Handle the reading and writing of key data to and from
  * the TLS control channel (cleartext).
@@ -3091,23 +2657,18 @@ key_method_2_read (struct buffer *buf, struct tls_multi *multi, struct tls_sessi
 {
   struct key_state *ks = &session->key[KS_PRIMARY];       /* primary key */
   struct key_state *ks_lame = &session->key[KS_LAME_DUCK]; /* retiring key */
-  struct gc_arena gc = gc_new ();
+
   int key_method_flags;
-  char *options;
-  struct user_pass *up;
+  bool username_status, password_status;
 
-  bool man_def_auth = KMDA_UNDEF;
+  struct gc_arena gc = gc_new ();
+  char *options;
 
-#ifdef MANAGEMENT_DEF_AUTH
-  if (management_enable_def_auth (management))
-    man_def_auth = KMDA_DEF;
-#endif
+  /* allocate temporary objects */
+  ALLOC_ARRAY_CLEAR_GC (options, char, TLS_OPTIONS_LEN, &gc);
 
   ASSERT (session->opt->key_method == 2);
 
-  /* allocate temporary objects */
-  ALLOC_ARRAY_CLEAR_GC (options, char, TLS_OPTIONS_LEN, &gc);
-                 
   /* discard leading uint32 */
   ASSERT (buf_advance (buf, 4));
 
@@ -3135,21 +2696,17 @@ key_method_2_read (struct buffer *buf, struct tls_multi *multi, struct tls_sessi
       goto error;
     }
 
-  /* should we check username/password? */
   ks->authenticated = false;
-  if (session->opt->auth_user_pass_verify_script
-      || plugin_defined (session->opt->plugins, OPENVPN_PLUGIN_AUTH_USER_PASS_VERIFY)
-      || man_def_auth == KMDA_DEF)
+
+  if (verify_user_pass_enabled(session))
     {
-      int s1 = OPENVPN_PLUGIN_FUNC_SUCCESS;
-      bool s2 = true;
-      char *raw_username;
-      bool username_status, password_status;
+      /* Perform username/password authentication */
+      struct user_pass *up;
 
-      /* get username/password from plaintext buffer */
       ALLOC_OBJ_CLEAR_GC (up, struct user_pass, &gc);
       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);
@@ -3160,76 +2717,18 @@ key_method_2_read (struct buffer *buf, struct tls_multi *multi, struct tls_sessi
            }
        }
 
-      /* preserve raw username before string_mod remapping, for plugins */
-      ALLOC_ARRAY_CLEAR_GC (raw_username, char, USER_PASS_LEN, &gc);
-      strcpy (raw_username, up->username);
-      string_mod (raw_username, CC_PRINT, CC_CRLF, '_');
-
-      /* enforce character class restrictions in username/password */
-      string_mod_sslname (up->username, COMMON_NAME_CHAR_CLASS, session->opt->ssl_flags);
-      string_mod (up->password, CC_PRINT, CC_CRLF, '_');
-
-      /* 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
-      if (plugin_defined (session->opt->plugins, OPENVPN_PLUGIN_AUTH_USER_PASS_VERIFY))
-       s1 = verify_user_pass_plugin (session, up, raw_username);
-      if (session->opt->auth_user_pass_verify_script)
-       s2 = verify_user_pass_script (session, up);
-
-      /* check sizing of username if it will become our common name */
-      if ((session->opt->ssl_flags & SSLF_USERNAME_AS_COMMON_NAME) && strlen (up->username) >= TLS_USERNAME_LEN)
-       {
-         msg (D_TLS_ERRORS, "TLS Auth Error: --username-as-common name specified and username is longer than the maximum permitted Common Name length of %d characters", TLS_USERNAME_LEN);
-         s1 = OPENVPN_PLUGIN_FUNC_ERROR;
-       }
-
-      /* auth succeeded? */
-      if ((s1 == OPENVPN_PLUGIN_FUNC_SUCCESS
-#ifdef PLUGIN_DEF_AUTH
-          || s1 == OPENVPN_PLUGIN_FUNC_DEFERRED
-#endif
-          ) && s2 && man_def_auth != KMDA_ERROR
-         && tls_lock_username (multi, up->username))
-       {
-         ks->authenticated = true;
-#ifdef PLUGIN_DEF_AUTH
-         if (s1 == OPENVPN_PLUGIN_FUNC_DEFERRED)
-           ks->auth_deferred = true;
-#endif
-#ifdef MANAGEMENT_DEF_AUTH
-         if (man_def_auth != KMDA_UNDEF)
-           ks->auth_deferred = true;
-#endif
-         if ((session->opt->ssl_flags & SSLF_USERNAME_AS_COMMON_NAME))
-           set_common_name (session, up->username);
-#ifdef ENABLE_DEF_AUTH
-         msg (D_HANDSHAKE, "TLS: Username/Password authentication %s for username '%s' %s",
-              ks->auth_deferred ? "deferred" : "succeeded",
-              up->username,
-              (session->opt->ssl_flags & SSLF_USERNAME_AS_COMMON_NAME) ? "[CN SET]" : "");
-#else
-         msg (D_HANDSHAKE, "TLS: Username/Password authentication %s for username '%s' %s",
-              "succeeded",
-              up->username,
-              (session->opt->ssl_flags & SSLF_USERNAME_AS_COMMON_NAME) ? "[CN SET]" : "");
-#endif
-       }
-      else
-       {
-         msg (D_TLS_ERRORS, "TLS Auth Error: Auth Username/Password verification failed for peer");
-       }
 
+      verify_user_pass(up, multi, session);
       CLEAR (*up);
     }
   else
     {
+      /* Session verification should have occurred during TLS negotiation*/
       if (!session->verified)
        {
          msg (D_TLS_ERRORS,
diff --git a/ssl.h b/ssl.h
index 91bc142e6a8b9e72aa2deba9e5b0397c483ffe39..0963c37a58ef3f092b66220698ed32b5e963d95d 100644 (file)
--- a/ssl.h
+++ b/ssl.h
 #define P_FIRST_OPCODE                 1
 #define P_LAST_OPCODE                  8
 
-/** @addtogroup control_processor
- *  @{ */
-/**
- * @name Control channel negotiation states
- *
- * These states represent the different phases of control channel
- * negotiation between OpenVPN peers.  OpenVPN servers and clients
- * progress through the states in a different order, because of their
- * different roles during exchange of random material.  The references to
- * the \c key_source2 structure in the list below is only valid if %key
- * method 2 is being used.  See the \link key_generation data channel key
- * generation\endlink related page for more information.
- *
- * Clients follow this order:
- *   -# \c S_INITIAL, ready to begin three-way handshake and control
- *      channel negotiation.
- *   -# \c S_PRE_START, have started three-way handshake, waiting for
- *      acknowledgment from remote.
- *   -# \c S_START, initial three-way handshake complete.
- *   -# \c S_SENT_KEY, have sent local part of \c key_source2 random
- *      material.
- *   -# \c S_GOT_KEY, have received remote part of \c key_source2 random
- *      material.
- *   -# \c S_ACTIVE, normal operation during remaining handshake window.
- *   -# \c S_NORMAL_OP, normal operation.
- *
- * Servers follow the same order, except for \c S_SENT_KEY and \c
- * S_GOT_KEY being reversed, because the server first receives the
- * client's \c key_source2 random material before generating and sending
- * its own.
- *
- * @{
- */
-#define S_ERROR          -1     /**< Error state.  */
-#define S_UNDEF           0     /**< Undefined state, used after a \c
-                                 *   key_state is cleaned up. */
-#define S_INITIAL         1     /**< Initial \c key_state state after
-                                 *   initialization by \c key_state_init()
-                                 *   before start of three-way handshake. */
-#define S_PRE_START       2     /**< Waiting for the remote OpenVPN peer
-                                 *   to acknowledge during the initial
-                                 *   three-way handshake. */
-#define S_START           3     /**< Three-way handshake is complete,
-                                 *   start of key exchange. */
-#define S_SENT_KEY        4     /**< Local OpenVPN process has sent its
-                                 *   part of the key material. */
-#define S_GOT_KEY         5     /**< Local OpenVPN process has received
-                                 *   the remote's part of the key
-                                 *   material. */
-#define S_ACTIVE          6     /**< Operational \c key_state state
-                                 *   immediately after negotiation has
-                                 *   completed while still within the
-                                 *   handshake window. */
-/* ready to exchange data channel packets */
-#define S_NORMAL_OP       7     /**< Normal operational \c key_state
-                                 *   state. */
-/** @} name Control channel negotiation states */
-/** @} addtogroup control_processor */
-
-
-#define DECRYPT_KEY_ENABLED(multi, ks) ((ks)->state >= (S_GOT_KEY - (multi)->opt.server))
-                                /**< Check whether the \a ks \c key_state
-                                 *   is ready to receive data channel
-                                 *   packets.
-                                 *   @ingroup data_crypto
-                                 *
-                                 *   If true, it is safe to assume that
-                                 *   this session has been authenticated
-                                 *   by TLS.
-                                 *
-                                 *   @note This macro only works if
-                                 *       S_SENT_KEY + 1 == S_GOT_KEY. */
-
 /* Should we aggregate TLS
  * acknowledgements, and tack them onto
  * control packets? */
@@ -521,15 +448,7 @@ bool tls_send_payload (struct tls_multi *multi,
 bool tls_rec_payload (struct tls_multi *multi,
                      struct buffer *buf);
 
-#define TLS_AUTHENTICATION_SUCCEEDED  0
-#define TLS_AUTHENTICATION_FAILED     1
-#define TLS_AUTHENTICATION_DEFERRED   2
-#define TLS_AUTHENTICATION_UNDEFINED  3
-int tls_authentication_status (struct tls_multi *multi, const int latency);
-
 #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)
 {
@@ -577,16 +496,6 @@ tls_set_single_session (struct tls_multi *multi)
     multi->opt.single_session = true;
 }
 
-static inline const char *
-tls_client_reason (struct tls_multi *multi)
-{
-#ifdef ENABLE_DEF_AUTH
-  return multi->client_reason;
-#else
-  return NULL;
-#endif
-}
-
 /*
  * protocol_dump() flags
  */
index 408744c8fe027f53996b5a23d588df7765e5dba9..525a1daf36d956838408510a8f3c52f8ef531620 100644 (file)
 #define UP_TYPE_AUTH        "Auth"
 #define UP_TYPE_PRIVATE_KEY "Private Key"
 
+/** @addtogroup control_processor
+ *  @{ */
+/**
+ * @name Control channel negotiation states
+ *
+ * These states represent the different phases of control channel
+ * negotiation between OpenVPN peers.  OpenVPN servers and clients
+ * progress through the states in a different order, because of their
+ * different roles during exchange of random material.  The references to
+ * the \c key_source2 structure in the list below is only valid if %key
+ * method 2 is being used.  See the \link key_generation data channel key
+ * generation\endlink related page for more information.
+ *
+ * Clients follow this order:
+ *   -# \c S_INITIAL, ready to begin three-way handshake and control
+ *      channel negotiation.
+ *   -# \c S_PRE_START, have started three-way handshake, waiting for
+ *      acknowledgment from remote.
+ *   -# \c S_START, initial three-way handshake complete.
+ *   -# \c S_SENT_KEY, have sent local part of \c key_source2 random
+ *      material.
+ *   -# \c S_GOT_KEY, have received remote part of \c key_source2 random
+ *      material.
+ *   -# \c S_ACTIVE, normal operation during remaining handshake window.
+ *   -# \c S_NORMAL_OP, normal operation.
+ *
+ * Servers follow the same order, except for \c S_SENT_KEY and \c
+ * S_GOT_KEY being reversed, because the server first receives the
+ * client's \c key_source2 random material before generating and sending
+ * its own.
+ *
+ * @{
+ */
+#define S_ERROR          -1     /**< Error state.  */
+#define S_UNDEF           0     /**< Undefined state, used after a \c
+                                 *   key_state is cleaned up. */
+#define S_INITIAL         1     /**< Initial \c key_state state after
+                                 *   initialization by \c key_state_init()
+                                 *   before start of three-way handshake. */
+#define S_PRE_START       2     /**< Waiting for the remote OpenVPN peer
+                                 *   to acknowledge during the initial
+                                 *   three-way handshake. */
+#define S_START           3     /**< Three-way handshake is complete,
+                                 *   start of key exchange. */
+#define S_SENT_KEY        4     /**< Local OpenVPN process has sent its
+                                 *   part of the key material. */
+#define S_GOT_KEY         5     /**< Local OpenVPN process has received
+                                 *   the remote's part of the key
+                                 *   material. */
+#define S_ACTIVE          6     /**< Operational \c key_state state
+                                 *   immediately after negotiation has
+                                 *   completed while still within the
+                                 *   handshake window. */
+/* ready to exchange data channel packets */
+#define S_NORMAL_OP       7     /**< Normal operational \c key_state
+                                 *   state. */
+/** @} name Control channel negotiation states */
+/** @} addtogroup control_processor */
+
 /**
  * Container for one half of random material to be used in %key method 2
  * \ref key_generation "data channel key generation".
index b8f66f765acf3a7f21ba69fe5bb27289861c733b..16d294df0dabe69345fc37be291fab631b65c9e7 100644 (file)
 #include "ssl_verify_openssl.h"
 #endif
 
+/** Legal characters in a common name */
+#define COMMON_NAME_CHAR_CLASS (CC_ALNUM|CC_UNDERBAR|CC_DASH|CC_DOT|CC_AT|CC_SLASH)
+
+/** Maximum length of common name */
+#define TLS_USERNAME_LEN 64
+
+static void
+string_mod_sslname (char *str, const unsigned int restrictive_flags, const unsigned int ssl_flags)
+{
+  if (ssl_flags & SSLF_NO_NAME_REMAPPING)
+    string_mod (str, CC_PRINT, CC_CRLF, '_');
+  else
+    string_mod (str, restrictive_flags, 0, '_');
+}
+
+/*
+ * Export the untrusted IP address and port to the environment
+ */
+static void
+setenv_untrusted (struct tls_session *session)
+{
+  setenv_link_socket_actual (session->opt->es, "untrusted", &session->untrusted_addr, SA_IP_PORT);
+}
+
+/*
+ * Remove authenticated state from all sessions in the given tunnel
+ */
 static void
 tls_deauthenticate (struct tls_multi *multi)
 {
@@ -97,6 +124,43 @@ tls_lock_common_name (struct tls_multi *multi)
     multi->locked_cn = string_alloc (cn, NULL);
 }
 
+static bool
+tls_lock_username (struct tls_multi *multi, const char *username)
+{
+  if (multi->locked_username)
+    {
+      if (!username || strcmp (username, multi->locked_username))
+       {
+         msg (D_TLS_ERRORS, "TLS Auth Error: username attempted to change from '%s' to '%s' -- tunnel disabled",
+              multi->locked_username,
+              np(username));
+
+         /* disable the tunnel */
+         tls_deauthenticate (multi);
+         return false;
+       }
+    }
+  else
+    {
+      if (username)
+       multi->locked_username = string_alloc (username, NULL);
+    }
+  return true;
+}
+
+const char *
+tls_username (const struct tls_multi *multi, const bool null)
+{
+  const char *ret = NULL;
+  if (multi)
+    ret = multi->locked_username;
+  if (ret && strlen (ret))
+    return ret;
+  else if (null)
+    return NULL;
+  else
+    return "UNDEF";
+}
 
 void
 cert_hash_remember (struct tls_session *session, const int error_depth, const unsigned char *sha1_hash)
@@ -201,6 +265,495 @@ tls_lock_cert_hash_set (struct tls_multi *multi)
 }
 
 
+/* ***************************************************************************
+ * Functions for the management of deferred authentication when using
+ * user/password authentication.
+ *************************************************************************** */
+
+#ifdef ENABLE_DEF_AUTH
+/* key_state_test_auth_control_file return values,
+   NOTE: acf_merge indexing depends on these values */
+#define ACF_UNDEFINED 0
+#define ACF_SUCCEEDED 1
+#define ACF_DISABLED  2
+#define ACF_FAILED    3
+#endif
+
+#ifdef MANAGEMENT_DEF_AUTH
+void
+man_def_auth_set_client_reason (struct tls_multi *multi, const char *client_reason)
+{
+  if (multi->client_reason)
+    {
+      free (multi->client_reason);
+      multi->client_reason = NULL;
+    }
+  if (client_reason && strlen (client_reason))
+    multi->client_reason = string_alloc (client_reason, NULL);
+}
+
+static inline unsigned int
+man_def_auth_test (const struct key_state *ks)
+{
+  if (management_enable_def_auth (management))
+    return ks->mda_status;
+  else
+    return ACF_DISABLED;
+}
+#endif
+
+#ifdef PLUGIN_DEF_AUTH
+
+/*
+ * auth_control_file functions
+ */
+
+void
+key_state_rm_auth_control_file (struct key_state *ks)
+{
+  if (ks && ks->auth_control_file)
+    {
+      delete_file (ks->auth_control_file);
+      free (ks->auth_control_file);
+      ks->auth_control_file = NULL;
+    }
+}
+
+static void
+key_state_gen_auth_control_file (struct key_state *ks, const struct tls_options *opt)
+{
+  struct gc_arena gc = gc_new ();
+  const char *acf;
+
+  key_state_rm_auth_control_file (ks);
+  acf = create_temp_file (opt->tmp_dir, "acf", &gc);
+  if (acf) {
+    ks->auth_control_file = string_alloc (acf, NULL);
+    setenv_str (opt->es, "auth_control_file", ks->auth_control_file);
+  } /* FIXME: Should have better error handling? */
+
+  gc_free (&gc);
+}
+
+static unsigned int
+key_state_test_auth_control_file (struct key_state *ks)
+{
+  if (ks && ks->auth_control_file)
+    {
+      unsigned int ret = ks->auth_control_status;
+      if (ret == ACF_UNDEFINED)
+       {
+         FILE *fp = fopen (ks->auth_control_file, "r");
+         if (fp)
+           {
+             const int c = fgetc (fp);
+             if (c == '1')
+               ret = ACF_SUCCEEDED;
+             else if (c == '0')
+               ret = ACF_FAILED;
+             fclose (fp);
+             ks->auth_control_status = ret;
+           }
+       }
+      return ret;
+    }
+  return ACF_DISABLED;
+}
+
+#endif
+
+/*
+ * Return current session authentication state.  Return
+ * value is TLS_AUTHENTICATION_x.
+ */
+
+int
+tls_authentication_status (struct tls_multi *multi, const int latency)
+{
+  bool deferred = false;
+  bool success = false;
+  bool active = false;
+
+#ifdef ENABLE_DEF_AUTH
+  static const unsigned char acf_merge[] =
+    {
+      ACF_UNDEFINED, /* s1=ACF_UNDEFINED s2=ACF_UNDEFINED */
+      ACF_UNDEFINED, /* s1=ACF_UNDEFINED s2=ACF_SUCCEEDED */
+      ACF_UNDEFINED, /* s1=ACF_UNDEFINED s2=ACF_DISABLED */
+      ACF_FAILED,    /* s1=ACF_UNDEFINED s2=ACF_FAILED */
+      ACF_UNDEFINED, /* s1=ACF_SUCCEEDED s2=ACF_UNDEFINED */
+      ACF_SUCCEEDED, /* s1=ACF_SUCCEEDED s2=ACF_SUCCEEDED */
+      ACF_SUCCEEDED, /* s1=ACF_SUCCEEDED s2=ACF_DISABLED */
+      ACF_FAILED,    /* s1=ACF_SUCCEEDED s2=ACF_FAILED */
+      ACF_UNDEFINED, /* s1=ACF_DISABLED  s2=ACF_UNDEFINED */
+      ACF_SUCCEEDED, /* s1=ACF_DISABLED  s2=ACF_SUCCEEDED */
+      ACF_DISABLED,  /* s1=ACF_DISABLED  s2=ACF_DISABLED */
+      ACF_FAILED,    /* s1=ACF_DISABLED  s2=ACF_FAILED */
+      ACF_FAILED,    /* s1=ACF_FAILED    s2=ACF_UNDEFINED */
+      ACF_FAILED,    /* s1=ACF_FAILED    s2=ACF_SUCCEEDED */
+      ACF_FAILED,    /* s1=ACF_FAILED    s2=ACF_DISABLED */
+      ACF_FAILED     /* s1=ACF_FAILED    s2=ACF_FAILED */
+    };
+#endif /* ENABLE_DEF_AUTH */
+
+  if (multi)
+    {
+      int i;
+
+#ifdef ENABLE_DEF_AUTH
+      if (latency && multi->tas_last && multi->tas_last + latency >= now)
+       return TLS_AUTHENTICATION_UNDEFINED;
+      multi->tas_last = now;
+#endif /* ENABLE_DEF_AUTH */
+
+      for (i = 0; i < KEY_SCAN_SIZE; ++i)
+       {
+         struct key_state *ks = multi->key_scan[i];
+         if (DECRYPT_KEY_ENABLED (multi, ks))
+           {
+             active = true;
+             if (ks->authenticated)
+               {
+#ifdef ENABLE_DEF_AUTH
+                 unsigned int s1 = ACF_DISABLED;
+                 unsigned int s2 = ACF_DISABLED;
+#ifdef PLUGIN_DEF_AUTH
+                 s1 = key_state_test_auth_control_file (ks);
+#endif /* PLUGIN_DEF_AUTH */
+#ifdef MANAGEMENT_DEF_AUTH
+                 s2 = man_def_auth_test (ks);
+#endif /* MANAGEMENT_DEF_AUTH */
+                 ASSERT (s1 < 4 && s2 < 4);
+                 switch (acf_merge[(s1<<2) + s2])
+                   {
+                   case ACF_SUCCEEDED:
+                   case ACF_DISABLED:
+                     success = true;
+                     ks->auth_deferred = false;
+                     break;
+                   case ACF_UNDEFINED:
+                     if (now < ks->auth_deferred_expire)
+                       deferred = true;
+                     break;
+                   case ACF_FAILED:
+                     ks->authenticated = false;
+                     break;
+                   default:
+                     ASSERT (0);
+                   }
+#else /* !ENABLE_DEF_AUTH */
+                 success = true;
+#endif /* ENABLE_DEF_AUTH */
+               }
+           }
+       }
+    }
+
+#if 0
+  dmsg (D_TLS_ERRORS, "TAS: a=%d s=%d d=%d", active, success, deferred);
+#endif
+
+  if (success)
+    return TLS_AUTHENTICATION_SUCCEEDED;
+  else if (!active || deferred)
+    return TLS_AUTHENTICATION_DEFERRED;
+  else
+    return TLS_AUTHENTICATION_FAILED;
+}
+
+#ifdef MANAGEMENT_DEF_AUTH
+/*
+ * For deferred auth, this is where the management interface calls (on server)
+ * to indicate auth failure/success.
+ */
+bool
+tls_authenticate_key (struct tls_multi *multi, const unsigned int mda_key_id, const bool auth, const char *client_reason)
+{
+  bool ret = false;
+  if (multi)
+    {
+      int i;
+      man_def_auth_set_client_reason (multi, client_reason);
+      for (i = 0; i < KEY_SCAN_SIZE; ++i)
+       {
+         struct key_state *ks = multi->key_scan[i];
+         if (ks->mda_key_id == mda_key_id)
+           {
+             ks->mda_status = auth ? ACF_SUCCEEDED : ACF_FAILED;
+             ret = true;
+           }
+       }
+    }
+  return ret;
+}
+#endif
+
+
+/* ****************************************************************************
+ * Functions to verify username and password
+ *
+ * Authenticate a client using username/password.
+ * Runs on server.
+ *
+ * If you want to add new authentication methods,
+ * this is the place to start.
+ *************************************************************************** */
+
+/*
+ * Verify the user name and password using a script
+ */
+static bool
+verify_user_pass_script (struct tls_session *session, const struct user_pass *up)
+{
+  struct gc_arena gc = gc_new ();
+  struct argv argv = argv_new ();
+  const char *tmp_file = "";
+  bool ret = false;
+
+  /* Is username defined? */
+  if ((session->opt->ssl_flags & SSLF_AUTH_USER_PASS_OPTIONAL) || strlen (up->username))
+    {
+      /* Set environmental variables prior to calling script */
+      setenv_str (session->opt->es, "script_type", "user-pass-verify");
+
+      if (session->opt->auth_user_pass_verify_script_via_file)
+       {
+         struct status_output *so;
+
+         tmp_file = create_temp_file (session->opt->tmp_dir, "up", &gc);
+          if( tmp_file ) {
+           so = status_open (tmp_file, 0, -1, NULL, STATUS_OUTPUT_WRITE);
+           status_printf (so, "%s", up->username);
+           status_printf (so, "%s", up->password);
+           if (!status_close (so))
+             {
+               msg (D_TLS_ERRORS, "TLS Auth Error: could not write username/password to file: %s",
+                    tmp_file);
+               goto done;
+             }
+          } else {
+            msg (D_TLS_ERRORS, "TLS Auth Error: could not create write "
+                 "username/password to temp file");
+          }
+       }
+      else
+       {
+         setenv_str (session->opt->es, "username", up->username);
+         setenv_str (session->opt->es, "password", up->password);
+       }
+
+      /* setenv incoming cert common name for script */
+      setenv_str (session->opt->es, "common_name", session->common_name);
+
+      /* setenv client real IP address */
+      setenv_untrusted (session);
+
+      /* format command line */
+      argv_printf (&argv, "%sc %s", session->opt->auth_user_pass_verify_script, tmp_file);
+
+      /* call command */
+      ret = openvpn_run_script (&argv, session->opt->es, 0,
+                               "--auth-user-pass-verify");
+
+      if (!session->opt->auth_user_pass_verify_script_via_file)
+       setenv_del (session->opt->es, "password");
+    }
+  else
+    {
+      msg (D_TLS_ERRORS, "TLS Auth Error: peer provided a blank username");
+    }
+
+ done:
+  if (tmp_file && strlen (tmp_file) > 0)
+    delete_file (tmp_file);
+
+  argv_reset (&argv);
+  gc_free (&gc);
+  return ret;
+}
+
+/*
+ * Verify the username and password using a plugin
+ */
+static int
+verify_user_pass_plugin (struct tls_session *session, const struct user_pass *up, const char *raw_username)
+{
+  int retval = OPENVPN_PLUGIN_FUNC_ERROR;
+  struct key_state *ks = &session->key[KS_PRIMARY];       /* primary key */
+
+  /* Is username defined? */
+  if ((session->opt->ssl_flags & SSLF_AUTH_USER_PASS_OPTIONAL) || strlen (up->username))
+    {
+      /* set username/password in private env space */
+      setenv_str (session->opt->es, "username", raw_username);
+      setenv_str (session->opt->es, "password", up->password);
+
+      /* setenv incoming cert common name for script */
+      setenv_str (session->opt->es, "common_name", session->common_name);
+
+      /* setenv client real IP address */
+      setenv_untrusted (session);
+
+#ifdef PLUGIN_DEF_AUTH
+      /* generate filename for deferred auth control file */
+      key_state_gen_auth_control_file (ks, session->opt);
+#endif
+
+      /* call command */
+      retval = plugin_call (session->opt->plugins, OPENVPN_PLUGIN_AUTH_USER_PASS_VERIFY, NULL, NULL, session->opt->es, -1, NULL);
+
+#ifdef PLUGIN_DEF_AUTH
+      /* purge auth control filename (and file itself) for non-deferred returns */
+      if (retval != OPENVPN_PLUGIN_FUNC_DEFERRED)
+       key_state_rm_auth_control_file (ks);
+#endif
+
+      setenv_del (session->opt->es, "password");
+      setenv_str (session->opt->es, "username", up->username);
+    }
+  else
+    {
+      msg (D_TLS_ERRORS, "TLS Auth Error (verify_user_pass_plugin): peer provided a blank username");
+    }
+
+  return retval;
+}
+
+
+#ifdef MANAGEMENT_DEF_AUTH
+/*
+ * MANAGEMENT_DEF_AUTH internal ssl_verify.c status codes
+ */
+#define KMDA_ERROR   0
+#define KMDA_SUCCESS 1
+#define KMDA_UNDEF   2
+#define KMDA_DEF     3
+
+static int
+verify_user_pass_management (struct tls_session *session, const struct user_pass *up, const char *raw_username)
+{
+  int retval = KMDA_ERROR;
+  struct key_state *ks = &session->key[KS_PRIMARY];       /* primary key */
+
+  /* Is username defined? */
+  if ((session->opt->ssl_flags & SSLF_AUTH_USER_PASS_OPTIONAL) || strlen (up->username))
+    {
+      /* set username/password in private env space */
+      setenv_str (session->opt->es, "username", raw_username);
+      setenv_str (session->opt->es, "password", up->password);
+
+      /* setenv incoming cert common name for script */
+      setenv_str (session->opt->es, "common_name", session->common_name);
+
+      /* setenv client real IP address */
+      setenv_untrusted (session);
+
+      if (management)
+       management_notify_client_needing_auth (management, ks->mda_key_id, session->opt->mda_context, session->opt->es);
+
+      setenv_del (session->opt->es, "password");
+      setenv_str (session->opt->es, "username", up->username);
+
+      retval = KMDA_SUCCESS;
+    }
+  else
+    {
+      msg (D_TLS_ERRORS, "TLS Auth Error (verify_user_pass_management): peer provided a blank username");
+    }
+
+  return retval;
+}
+#endif
+
+/*
+ * Main username/password verification entry point
+ */
+void
+verify_user_pass(struct user_pass *up, struct tls_multi *multi,
+    struct tls_session *session)
+{
+  int s1 = OPENVPN_PLUGIN_FUNC_SUCCESS;
+  bool s2 = true;
+  struct key_state *ks = &session->key[KS_PRIMARY];       /* primary key */
+
+  struct gc_arena gc = gc_new ();
+  char *raw_username;
+
+#ifdef MANAGEMENT_DEF_AUTH
+  int man_def_auth = KMDA_UNDEF;
+
+  if (management_enable_def_auth (management))
+    man_def_auth = KMDA_DEF;
+#endif
+
+  /* preserve raw username before string_mod remapping, for plugins */
+  ALLOC_ARRAY_CLEAR_GC (raw_username, char, USER_PASS_LEN, &gc);
+  strcpy (raw_username, up->username);
+  string_mod (raw_username, CC_PRINT, CC_CRLF, '_');
+
+  /* enforce character class restrictions in username/password */
+  string_mod_sslname (up->username, COMMON_NAME_CHAR_CLASS, session->opt->ssl_flags);
+  string_mod (up->password, CC_PRINT, CC_CRLF, '_');
+
+  /* call plugin(s) and/or script */
+#ifdef MANAGEMENT_DEF_AUTH
+  if (man_def_auth == KMDA_DEF)
+    man_def_auth = verify_user_pass_management (session, up, raw_username);
+#endif
+  if (plugin_defined (session->opt->plugins, OPENVPN_PLUGIN_AUTH_USER_PASS_VERIFY))
+    s1 = verify_user_pass_plugin (session, up, raw_username);
+  if (session->opt->auth_user_pass_verify_script)
+    s2 = verify_user_pass_script (session, up);
+
+  /* check sizing of username if it will become our common name */
+  if ((session->opt->ssl_flags & SSLF_USERNAME_AS_COMMON_NAME) && strlen (up->username) >= TLS_USERNAME_LEN)
+    {
+      msg (D_TLS_ERRORS, "TLS Auth Error: --username-as-common name specified and username is longer than the maximum permitted Common Name length of %d characters", TLS_USERNAME_LEN);
+      s1 = OPENVPN_PLUGIN_FUNC_ERROR;
+    }
+
+  /* auth succeeded? */
+  if ((s1 == OPENVPN_PLUGIN_FUNC_SUCCESS
+#ifdef PLUGIN_DEF_AUTH
+       || s1 == OPENVPN_PLUGIN_FUNC_DEFERRED
+#endif
+       ) && s2
+#ifdef MANAGEMENT_DEF_AUTH
+       && man_def_auth != KMDA_ERROR
+#endif
+      && tls_lock_username (multi, up->username))
+    {
+      ks->authenticated = true;
+#ifdef PLUGIN_DEF_AUTH
+      if (s1 == OPENVPN_PLUGIN_FUNC_DEFERRED)
+       ks->auth_deferred = true;
+#endif
+#ifdef MANAGEMENT_DEF_AUTH
+      if (man_def_auth != KMDA_UNDEF)
+       ks->auth_deferred = true;
+#endif
+      if ((session->opt->ssl_flags & SSLF_USERNAME_AS_COMMON_NAME))
+       set_common_name (session, up->username);
+#ifdef ENABLE_DEF_AUTH
+      msg (D_HANDSHAKE, "TLS: Username/Password authentication %s for username '%s' %s",
+          ks->auth_deferred ? "deferred" : "succeeded",
+          up->username,
+          (session->opt->ssl_flags & SSLF_USERNAME_AS_COMMON_NAME) ? "[CN SET]" : "");
+#else
+      msg (D_HANDSHAKE, "TLS: Username/Password authentication %s for username '%s' %s",
+          "succeeded",
+          up->username,
+          (session->opt->ssl_flags & SSLF_USERNAME_AS_COMMON_NAME) ? "[CN SET]" : "");
+#endif
+    }
+  else
+    {
+      msg (D_TLS_ERRORS, "TLS Auth Error: Auth Username/Password verification failed for peer");
+    }
+
+  gc_free (&gc);
+}
+
 void
 verify_final_auth_checks(struct tls_multi *multi, struct tls_session *session)
 {
index b76a16a54a8c0934ab4ca68722c84ed2f8dc81d7..ad94bc685664bf167ccf05ce88193a500810aaeb 100644 (file)
@@ -58,6 +58,36 @@ struct cert_hash_set {
 };
 
 
+#define TLS_AUTHENTICATION_SUCCEEDED  0
+#define TLS_AUTHENTICATION_FAILED     1
+#define TLS_AUTHENTICATION_DEFERRED   2
+#define TLS_AUTHENTICATION_UNDEFINED  3
+
+/*
+ * Return current session authentication state.  Return
+ * value is TLS_AUTHENTICATION_x.
+ *
+ * TODO: document this function
+ */
+int tls_authentication_status (struct tls_multi *multi, const int latency);
+
+/** Check whether the \a ks \c key_state is ready to receive data channel
+ *   packets.
+ *   @ingroup data_crypto
+ *
+ *   If true, it is safe to assume that this session has been authenticated
+ *   by TLS.
+ *
+ *   @note This macro only works if S_SENT_KEY + 1 == S_GOT_KEY. */
+#define DECRYPT_KEY_ENABLED(multi, ks) ((ks)->state >= (S_GOT_KEY - (multi)->opt.server))
+
+/**
+ * Remove the given key state's auth control file, if it exists.
+ *
+ * @param ks   The key state the remove the file for
+ */
+void key_state_rm_auth_control_file (struct key_state *ks);
+
 /**
  * Frees the given set of certificate hashes.
  *
@@ -87,7 +117,13 @@ void tls_lock_common_name (struct tls_multi *multi);
  */
 const char *tls_common_name (const struct tls_multi* multi, const bool null);
 
-void tls_set_common_name (struct tls_multi *multi, const char *common_name);
+/**
+ * Returns the username field for the given tunnel
+ *
+ * @param multi        The tunnel to return the username for
+ * @param null Whether null may be returned. If not, "UNDEF" will be returned.
+ */
+const char *tls_username (const struct tls_multi *multi, const bool null);
 
 #ifdef ENABLE_PF
 
@@ -118,6 +154,38 @@ tls_common_name_hash (const struct tls_multi *multi, const char **cn, uint32_t *
 
 #endif
 
+/**
+ * Returns whether or not the server should check for username/password
+ *
+ * @param session      The current TLS session
+ *
+ * @return             true if username and password verification is enabled,
+ *                     false if not.
+ *
+ */
+static inline bool verify_user_pass_enabled(struct tls_session *session)
+{
+  return (session->opt->auth_user_pass_verify_script
+        || plugin_defined (session->opt->plugins, OPENVPN_PLUGIN_AUTH_USER_PASS_VERIFY)
+        || management_enable_def_auth (management));
+}
+
+/**
+ * Verify the given username and password, using either an external script, a
+ * plugin, or the management interface.
+ *
+ * If authentication succeeds, the appropriate state is filled into the
+ * session's primary key state's authenticated field. Authentication may also
+ * be deferred, in which case the key state's auth_deferred field is filled in.
+ *
+ * @param up           The username and password to verify.
+ * @param multi                The TLS multi structure to verify usernames against.
+ * @param session      The current TLS session
+ *
+ */
+void verify_user_pass(struct user_pass *up, struct tls_multi *multi,
+    struct tls_session *session);
+
 /**
  * Perform final authentication checks, including locking of the cn, the allowed
  * certificate hashes, and whether a client config entry exists in the
@@ -129,5 +197,24 @@ tls_common_name_hash (const struct tls_multi *multi, const char **cn, uint32_t *
  */
 void verify_final_auth_checks(struct tls_multi *multi, struct tls_session *session);
 
+/*
+ * TODO: document
+ */
+#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);
+void man_def_auth_set_client_reason (struct tls_multi *multi, const char *client_reason);
+#endif
+
+static inline const char *
+tls_client_reason (struct tls_multi *multi)
+{
+#ifdef ENABLE_DEF_AUTH
+  return multi->client_reason;
+#else
+  return NULL;
+#endif
+}
+
 
 #endif /* SSL_VERIFY_H_ */
+