dbus/dbus dbus-auth.c,1.34,1.35

Kristian Hogsberg krh at pdx.freedesktop.org
Wed Jun 2 07:04:00 PDT 2004


Update of /cvs/dbus/dbus/dbus
In directory pdx:/tmp/cvs-serv19402/dbus

Modified Files:
	dbus-auth.c 
Log Message:
2004-06-02  Kristian Høgsberg  <krh at redhat.com>
 
	* dbus/dbus-auth.c: Rewrite auth protocol handling to use a state
	machine approach.  A state is implemented as a function that
	handles incoming events as specified for that state.
	
	* doc/dbus-specification.xml: Update auth protocol state machine
	specification to match implementation.  Remove some leftover
	base64 examples.


Index: dbus-auth.c
===================================================================
RCS file: /cvs/dbus/dbus/dbus/dbus-auth.c,v
retrieving revision 1.34
retrieving revision 1.35
diff -u -d -r1.34 -r1.35
--- a/dbus-auth.c	17 May 2004 23:34:55 -0000	1.34
+++ b/dbus-auth.c	2 Jun 2004 14:03:58 -0000	1.35
@@ -66,23 +66,6 @@
  */
 
 /**
- * Processes a command. Returns whether we had enough memory to
- * complete the operation.
- */
-typedef dbus_bool_t (* DBusProcessAuthCommandFunction) (DBusAuth         *auth,
-                                                        const DBusString *command,
-                                                        const DBusString *args);
-
-/**
- * Handler for a given auth protocol command
- */
-typedef struct
-{
-  const char *command; /**< Name of the command */
-  DBusProcessAuthCommandFunction func; /**< Function to handle the command */
-} DBusAuthCommandHandler;
-
-/**
  * This function appends an initial client response to the given string
  */
 typedef dbus_bool_t (* DBusInitialResponseFunction)  (DBusAuth         *auth,
@@ -132,16 +115,49 @@
 } DBusAuthMechanismHandler;
 
 /**
+ * Enumeration for the known authentication commands.
+ */
+typedef enum {
+  DBUS_AUTH_COMMAND_AUTH,
+  DBUS_AUTH_COMMAND_CANCEL,
+  DBUS_AUTH_COMMAND_DATA,
+  DBUS_AUTH_COMMAND_BEGIN,
+  DBUS_AUTH_COMMAND_REJECTED,
+  DBUS_AUTH_COMMAND_OK,
+  DBUS_AUTH_COMMAND_ERROR,
+  DBUS_AUTH_COMMAND_UNKNOWN
+} DBusAuthCommand;
+
+/**
+ * Auth state function, determines the reaction to incoming events for
+ * a particular state. Returns whether we had enough memory to
+ * complete the operation.
+ */
+typedef dbus_bool_t (* DBusAuthStateFunction) (DBusAuth         *auth,
+                                               DBusAuthCommand   command,
+                                               const DBusString *args);
+
+/**
+ * Information about a auth state.
+ */
+typedef struct
+{
+  const char *name;               /**< Name of the state */
+  DBusAuthStateFunction handler;  /**< State function for this state */
+} DBusAuthStateData;
+
+/**
  * Internal members of DBusAuth.
  */
 struct DBusAuth
 {
   int refcount;           /**< reference count */
+  const char *side;       /**< Client or server */
 
   DBusString incoming;    /**< Incoming data buffer */
   DBusString outgoing;    /**< Outgoing data buffer */
   
-  const DBusAuthCommandHandler *handlers; /**< Handlers for commands */
+  const DBusAuthStateData *state;         /**< Current protocol state */
 
   const DBusAuthMechanismHandler *mech;   /**< Current auth mechanism */
 
@@ -169,10 +185,6 @@
   unsigned int needed_memory : 1;   /**< We needed memory to continue since last
                                      * successful getting something done
                                      */
-  unsigned int need_disconnect : 1; /**< We've given up, time to disconnect */
-  unsigned int authenticated : 1;   /**< We are authenticated */
-  unsigned int authenticated_pending_output : 1; /**< Authenticated once we clear outgoing buffer */
-  unsigned int authenticated_pending_begin : 1;  /**< Authenticated once we get BEGIN */
   unsigned int already_got_mechanisms : 1;       /**< Client already got mech list */
   unsigned int already_asked_for_initial_response : 1; /**< Already sent a blank challenge to get an initial response */
   unsigned int buffer_outstanding : 1; /**< Buffer is "checked out" for reading data into */
@@ -201,36 +213,8 @@
   
 } DBusAuthServer;
 
-static dbus_bool_t process_auth         (DBusAuth         *auth,
-                                         const DBusString *command,
-                                         const DBusString *args);
-static dbus_bool_t process_cancel       (DBusAuth         *auth,
-                                         const DBusString *command,
-                                         const DBusString *args);
-static dbus_bool_t process_begin        (DBusAuth         *auth,
-                                         const DBusString *command,
-                                         const DBusString *args);
-static dbus_bool_t process_data_server  (DBusAuth         *auth,
-                                         const DBusString *command,
-                                         const DBusString *args);
-static dbus_bool_t process_error_server (DBusAuth         *auth,
-                                         const DBusString *command,
-                                         const DBusString *args);
-static dbus_bool_t process_rejected     (DBusAuth         *auth,
-                                         const DBusString *command,
-                                         const DBusString *args);
-static dbus_bool_t process_ok           (DBusAuth         *auth,
-                                         const DBusString *command,
-                                         const DBusString *args);
-static dbus_bool_t process_data_client  (DBusAuth         *auth,
-                                         const DBusString *command,
-                                         const DBusString *args);
-static dbus_bool_t process_error_client (DBusAuth         *auth,
-                                         const DBusString *command,
-                                         const DBusString *args);
-
-
-static dbus_bool_t client_try_next_mechanism (DBusAuth *auth);
+static void        goto_state                (DBusAuth                       *auth,
+                                              const DBusAuthStateData        *new_state);
 static dbus_bool_t send_auth                 (DBusAuth *auth,
                                               const DBusAuthMechanismHandler *mech);
 static dbus_bool_t send_data                 (DBusAuth *auth,
@@ -242,35 +226,81 @@
 static dbus_bool_t send_begin                (DBusAuth *auth);
 static dbus_bool_t send_cancel               (DBusAuth *auth);
 
-static DBusAuthCommandHandler
-server_handlers[] = {
-  { "AUTH", process_auth },
-  { "CANCEL", process_cancel },
-  { "BEGIN", process_begin },
-  { "DATA", process_data_server },
-  { "ERROR", process_error_server },
-  { NULL, NULL }
+/**
+ * Client states
+ */
+ 
+static dbus_bool_t handle_server_state_waiting_for_auth  (DBusAuth         *auth,
+                                                          DBusAuthCommand   command,
+                                                          const DBusString *args);
+static dbus_bool_t handle_server_state_waiting_for_data  (DBusAuth         *auth,
+                                                          DBusAuthCommand   command,
+                                                          const DBusString *args);
+static dbus_bool_t handle_server_state_waiting_for_begin (DBusAuth         *auth,
+                                                          DBusAuthCommand   command,
+                                                          const DBusString *args);
+  
+static const DBusAuthStateData server_state_waiting_for_auth = {
+  "WaitingForAuth", handle_server_state_waiting_for_auth
+};
+static const DBusAuthStateData server_state_waiting_for_data = {
+  "WaitingForData", handle_server_state_waiting_for_data
 };
+static const DBusAuthStateData server_state_waiting_for_begin = {
+  "WaitingForBegin", handle_server_state_waiting_for_begin
+};
+  
+/**
+ * Client states
+ */
+ 
+static dbus_bool_t handle_client_state_waiting_for_data   (DBusAuth         *auth,
+                                                           DBusAuthCommand   command,
+                                                           const DBusString *args);
+static dbus_bool_t handle_client_state_waiting_for_ok     (DBusAuth         *auth,
+                                                           DBusAuthCommand   command,
+                                                           const DBusString *args);
+static dbus_bool_t handle_client_state_waiting_for_reject (DBusAuth         *auth,
+                                                           DBusAuthCommand   command,
+                                                           const DBusString *args);
 
-static DBusAuthCommandHandler
-client_handlers[] = {
-  { "REJECTED", process_rejected },
-  { "OK", process_ok },
-  { "DATA", process_data_client },
-  { "ERROR", process_error_client },
-  { NULL, NULL }
+static const DBusAuthStateData client_state_need_send_auth = {
+  "NeedSendAuth", NULL
+};
+static const DBusAuthStateData client_state_waiting_for_data = {
+  "WaitingForData", handle_client_state_waiting_for_data
+};
+static const DBusAuthStateData client_state_waiting_for_ok = {
+  "WaitingForOK", handle_client_state_waiting_for_ok
+};
+static const DBusAuthStateData client_state_waiting_for_reject = {
+  "WaitingForReject", handle_client_state_waiting_for_reject
+};
+  
+/**
+ * Common terminal states.  Terminal states have handler == NULL.
+ */
+
+static const DBusAuthStateData common_state_authenticated = {
+  "Authenticated",  NULL
 };
 
+static const DBusAuthStateData common_state_need_disconnect = {
+  "NeedDisconnect",  NULL
+};
+
+static const char auth_side_client[] = "client";
+static const char auth_side_server[] = "server";
 /**
  * @param auth the auth conversation
  * @returns #TRUE if the conversation is the server side
  */
-#define DBUS_AUTH_IS_SERVER(auth) ((auth)->handlers == server_handlers)
+#define DBUS_AUTH_IS_SERVER(auth) ((auth)->side == auth_side_server)
 /**
  * @param auth the auth conversation
  * @returns #TRUE if the conversation is the client side
  */
-#define DBUS_AUTH_IS_CLIENT(auth) ((auth)->handlers == client_handlers)
+#define DBUS_AUTH_IS_CLIENT(auth) ((auth)->side == auth_side_client)
 /**
  * @param auth the auth conversation
  * @returns auth cast to DBusAuthClient
@@ -287,7 +317,7 @@
  * @param auth the auth conversation
  * @returns a string
  */
-#define DBUS_AUTH_NAME(auth)      (DBUS_AUTH_IS_SERVER(auth) ? "server" : "client")
+#define DBUS_AUTH_NAME(auth)      ((auth)->side)
 
 static DBusAuth*
 _dbus_auth_new (int size)
@@ -355,8 +385,6 @@
 shutdown_mech (DBusAuth *auth)
 {
   /* Cancel any auth */
-  auth->authenticated_pending_begin = FALSE;
-  auth->authenticated = FALSE;
   auth->already_asked_for_initial_response = FALSE;
   _dbus_string_set_length (&auth->identity, 0);
 
@@ -591,6 +619,7 @@
   if (!send_data (auth, &tmp2))
     goto out;
       
+  goto_state (auth, &server_state_waiting_for_data);
   retval = TRUE;
   
  out:
@@ -685,7 +714,6 @@
                  DBUS_AUTH_NAME (auth), auth->desired_identity.uid);
   
   auth->authorized_identity = auth->desired_identity;
-  auth->authenticated_pending_begin = TRUE;
   retval = TRUE;
   
  out_3:
@@ -1022,8 +1050,6 @@
       
       auth->authorized_identity.uid = auth->desired_identity.uid;
       
-      auth->authenticated_pending_begin = TRUE;
-      
       return TRUE;
     }
   else
@@ -1199,7 +1225,9 @@
     }
 
   _dbus_string_free (&auth_command);
+  shutdown_mech (auth);
   auth->mech = mech;      
+  goto_state (auth, &client_state_waiting_for_data);
 
   return TRUE;
 }
@@ -1275,7 +1303,9 @@
   server_auth->failures += 1;
 
   if (server_auth->failures >= server_auth->max_failures)
-    auth->need_disconnect = TRUE;
+    goto_state (auth, &common_state_need_disconnect);
+  else
+    goto_state (auth, &server_state_waiting_for_auth);
 
   _dbus_string_free (&command);
   
@@ -1296,35 +1326,87 @@
 static dbus_bool_t
 send_ok (DBusAuth *auth)
 {
-  return _dbus_string_append (&auth->outgoing, "OK\r\n");
+  if (_dbus_string_append (&auth->outgoing, "OK\r\n"))
+    {
+      goto_state (auth, &server_state_waiting_for_begin);
+      return TRUE;
+    }
+  else
+    return FALSE;
 }
 
 static dbus_bool_t
 send_begin (DBusAuth *auth)
 {
-  return _dbus_string_append (&auth->outgoing, "BEGIN\r\n");
+  if (_dbus_string_append (&auth->outgoing, "BEGIN\r\n"))
+    {
+      goto_state (auth, &common_state_authenticated);
+      return TRUE;
+    }
+  else
+    return FALSE;
 }
 
 static dbus_bool_t
 send_cancel (DBusAuth *auth)
 {
-  return _dbus_string_append (&auth->outgoing, "CANCEL\r\n");
+  if (_dbus_string_append (&auth->outgoing, "CANCEL\r\n"))
+    {
+      goto_state (auth, &client_state_waiting_for_reject);
+      return TRUE;
+    }
+  else
+    return FALSE;
 }
 
 static dbus_bool_t
-process_auth (DBusAuth         *auth,
-              const DBusString *command,
-              const DBusString *args)
+process_data (DBusAuth             *auth,
+             const DBusString     *args,
+             DBusAuthDataFunction  data_func)
 {
-  if (auth->mech)
+  int end;
+  DBusString decoded;
+
+  if (!_dbus_string_init (&decoded))
+    return FALSE;
+
+  if (!_dbus_string_hex_decode (args, 0, &end, &decoded, 0))
     {
-      /* We are already using a mechanism, client is on crack */
-      if (!send_error (auth, "Sent AUTH while another AUTH in progress"))
+      _dbus_string_free (&decoded);
+      return FALSE;
+    }
+
+  if (_dbus_string_get_length (args) != end)
+    {
+      _dbus_string_free (&decoded);
+      if (!send_error (auth, "Invalid hex encoding"))
         return FALSE;
 
       return TRUE;
     }
-  else if (_dbus_string_get_length (args) == 0)
+
+#ifdef DBUS_ENABLE_VERBOSE_MODE
+  if (_dbus_string_validate_ascii (&decoded, 0,
+                                   _dbus_string_get_length (&decoded)))
+    _dbus_verbose ("%s: data: '%s'\n",
+                   DBUS_AUTH_NAME (auth),
+                   _dbus_string_get_const_data (&decoded));
+#endif
+      
+  if (!(* data_func) (auth, &decoded))
+    {
+      _dbus_string_free (&decoded);
+      return FALSE;
+    }
+
+  _dbus_string_free (&decoded);
+  return TRUE;
+}
+
+static dbus_bool_t
+handle_auth (DBusAuth *auth, const DBusString *args)
+{
+  if (_dbus_string_get_length (args) == 0)
     {
       /* No args to the auth, send mechanisms */
       if (!send_rejected (auth))
@@ -1334,10 +1416,9 @@
     }
   else
     {
-      int i, end;
+      int i;
       DBusString mech;
       DBusString hex_response;
-      DBusString decoded_response;
       
       _dbus_string_find_blank (args, 0, &i);
 
@@ -1350,55 +1431,37 @@
           return FALSE;
         }
       
-      if (!_dbus_string_init (&decoded_response))
-        {
-          _dbus_string_free (&mech);
-          _dbus_string_free (&hex_response);
-          return FALSE;
-        }
-
       if (!_dbus_string_copy_len (args, 0, i, &mech, 0))
         goto failed;
 
       _dbus_string_skip_blank (args, i, &i);
       if (!_dbus_string_copy (args, i, &hex_response, 0))
         goto failed;
-
-      if (!_dbus_string_hex_decode (&hex_response, 0, &end,
-				    &decoded_response, 0))
-	goto failed;
-
-      if (_dbus_string_get_length (&hex_response) != end)
-	{
-	  if (!send_error (auth, "Invalid hex encoding"))
-	    goto failed;
-
-	  goto out;
-        }
      
       auth->mech = find_mech (&mech, auth->allowed_mechs);
       if (auth->mech != NULL)
         {
-          _dbus_verbose ("%s: Trying mechanism %s with initial response of %d bytes\n",
+          _dbus_verbose ("%s: Trying mechanism %s\n",
                          DBUS_AUTH_NAME (auth),
-                         auth->mech->mechanism,
-                         _dbus_string_get_length (&decoded_response));
+                         auth->mech->mechanism);
           
-          if (!(* auth->mech->server_data_func) (auth,
-                                                 &decoded_response))
+          if (!process_data (auth, &hex_response,
+                             auth->mech->server_data_func))
             goto failed;
         }
       else
         {
           /* Unsupported mechanism */
+          _dbus_verbose ("%s: Unsupported mechanism %s\n",
+                         DBUS_AUTH_NAME (auth),
+                         _dbus_string_get_const_data (&mech));
+          
           if (!send_rejected (auth))
             goto failed;
         }
 
-    out:
       _dbus_string_free (&mech);      
       _dbus_string_free (&hex_response);
-      _dbus_string_free (&decoded_response);
 
       return TRUE;
       
@@ -1406,106 +1469,95 @@
       auth->mech = NULL;
       _dbus_string_free (&mech);
       _dbus_string_free (&hex_response);
-      _dbus_string_free (&decoded_response);
       return FALSE;
     }
 }
 
 static dbus_bool_t
-process_cancel (DBusAuth         *auth,
-                const DBusString *command,
-                const DBusString *args)
-{
-  if (!send_rejected (auth))
-    return FALSE;
-  
-  return TRUE;
-}
-
-static dbus_bool_t
-process_begin (DBusAuth         *auth,
-               const DBusString *command,
-               const DBusString *args)
+handle_server_state_waiting_for_auth  (DBusAuth         *auth,
+                                       DBusAuthCommand   command,
+                                       const DBusString *args)
 {
-  if (auth->authenticated_pending_begin)
-    auth->authenticated = TRUE;
-  else
+  switch (command)
     {
-      auth->need_disconnect = TRUE; /* client trying to send data before auth,
-                                     * kick it
-                                     */
-      shutdown_mech (auth);
+    case DBUS_AUTH_COMMAND_AUTH:
+      return handle_auth (auth, args);
+
+    case DBUS_AUTH_COMMAND_CANCEL:
+    case DBUS_AUTH_COMMAND_DATA:
+      return send_error (auth, "Not currently in an auth conversation");
+
+    case DBUS_AUTH_COMMAND_BEGIN:
+      goto_state (auth, &common_state_need_disconnect);
+      return TRUE;
+
+    case DBUS_AUTH_COMMAND_ERROR:
+      return send_rejected (auth);
+
+    case DBUS_AUTH_COMMAND_REJECTED:
+    case DBUS_AUTH_COMMAND_OK:
+    case DBUS_AUTH_COMMAND_UNKNOWN:
+    default:
+      return send_error (auth, "Unknown command");
     }
-  
-  return TRUE;
 }
 
 static dbus_bool_t
-process_data_server (DBusAuth         *auth,
-                     const DBusString *command,
-                     const DBusString *args)
+handle_server_state_waiting_for_data  (DBusAuth         *auth,
+                                       DBusAuthCommand   command,
+                                       const DBusString *args)
 {
-  int end;
-
-  if (auth->mech != NULL)
+  switch (command)
     {
-      DBusString decoded;
-
-      if (!_dbus_string_init (&decoded))
-        return FALSE;
-
-      if (!_dbus_string_hex_decode (args, 0, &end, &decoded, 0))
-	{
-          _dbus_string_free (&decoded);
-	  return FALSE;
-	}
+    case DBUS_AUTH_COMMAND_AUTH:
+      return send_error (auth, "Sent AUTH while another AUTH in progress");
 
-      if (_dbus_string_get_length (args) != end)
-	{
-          _dbus_string_free (&decoded);
-	  if (!send_error (auth, "Invalid hex encoding"))
-	    return FALSE;
+    case DBUS_AUTH_COMMAND_CANCEL:
+    case DBUS_AUTH_COMMAND_ERROR:
+      return send_rejected (auth);
 
-	  return TRUE;
-        }
+    case DBUS_AUTH_COMMAND_DATA:
+      return process_data (auth, args, auth->mech->server_data_func);
 
-#ifdef DBUS_ENABLE_VERBOSE_MODE
-      if (_dbus_string_validate_ascii (&decoded, 0,
-                                       _dbus_string_get_length (&decoded)))
-        _dbus_verbose ("%s: data: '%s'\n",
-                       DBUS_AUTH_NAME (auth),
-                       _dbus_string_get_const_data (&decoded));
-#endif
-      
-      if (!(* auth->mech->server_data_func) (auth, &decoded))
-        {
-          _dbus_string_free (&decoded);
-          return FALSE;
-        }
+    case DBUS_AUTH_COMMAND_BEGIN:
+      goto_state (auth, &common_state_need_disconnect);
+      return TRUE;
 
-      _dbus_string_free (&decoded);
-    }
-  else
-    {
-      if (!send_error (auth, "Not currently in an auth conversation"))
-        return FALSE;
+    case DBUS_AUTH_COMMAND_REJECTED:
+    case DBUS_AUTH_COMMAND_OK:
+    case DBUS_AUTH_COMMAND_UNKNOWN:
+    default:
+      return send_error (auth, "Unknown command");
     }
-  
-  return TRUE;
 }
 
 static dbus_bool_t
-process_error_server (DBusAuth         *auth,
-                      const DBusString *command,
-                      const DBusString *args)
+handle_server_state_waiting_for_begin (DBusAuth         *auth,
+                                       DBusAuthCommand   command,
+                                       const DBusString *args)
 {
-  /* Server got error from client, reject the auth,
-   * as we don't have anything more intelligent to do.
-   */
-  if (!send_rejected (auth))
-    return FALSE;
-  
-  return TRUE;
+  switch (command)
+    {
+    case DBUS_AUTH_COMMAND_AUTH:
+      return send_error (auth, "Sent AUTH while expecting BEGIN");
+
+    case DBUS_AUTH_COMMAND_DATA:
+      return send_error (auth, "Sent DATA while expecting BEGIN");
+
+    case DBUS_AUTH_COMMAND_BEGIN:
+      goto_state (auth, &common_state_authenticated);
+      return TRUE;
+
+    case DBUS_AUTH_COMMAND_REJECTED:
+    case DBUS_AUTH_COMMAND_OK:
+    case DBUS_AUTH_COMMAND_UNKNOWN:
+    default:
+      return send_error (auth, "Unknown command");
+
+    case DBUS_AUTH_COMMAND_CANCEL:
+    case DBUS_AUTH_COMMAND_ERROR:
+      return send_rejected (auth);
+    }
 }
 
 /* return FALSE if no memory, TRUE if all OK */
@@ -1532,7 +1584,6 @@
 
 static dbus_bool_t
 record_mechanisms (DBusAuth         *auth,
-                   const DBusString *command,
                    const DBusString *args)
 {
   int next;
@@ -1602,157 +1653,173 @@
 }
 
 static dbus_bool_t
-client_try_next_mechanism (DBusAuth *auth)
+process_rejected (DBusAuth *auth, const DBusString *args)
 {
   const DBusAuthMechanismHandler *mech;
   DBusAuthClient *client;
 
   client = DBUS_AUTH_CLIENT (auth);
 
-  _dbus_assert (client->mechs_to_try != NULL);
-
-  mech = client->mechs_to_try->data;
-
-  if (!send_auth (auth, mech))
-    return FALSE;
-
-  _dbus_list_pop_first (&client->mechs_to_try);
-
-  _dbus_verbose ("%s: Trying mechanism %s\n",
-                 DBUS_AUTH_NAME (auth),
-                 auth->mech->mechanism);
-  
-  return TRUE;
-}
-
-static dbus_bool_t
-process_rejected (DBusAuth         *auth,
-                  const DBusString *command,
-                  const DBusString *args)
-{
-  shutdown_mech (auth);
-  
   if (!auth->already_got_mechanisms)
     {
-      if (!record_mechanisms (auth, command, args))
+      if (!record_mechanisms (auth, args))
         return FALSE;
     }
   
   if (DBUS_AUTH_CLIENT (auth)->mechs_to_try != NULL)
     {
-      if (!client_try_next_mechanism (auth))
+      mech = client->mechs_to_try->data;
+
+      if (!send_auth (auth, mech))
         return FALSE;
+
+      _dbus_list_pop_first (&client->mechs_to_try);
+
+      _dbus_verbose ("%s: Trying mechanism %s\n",
+                     DBUS_AUTH_NAME (auth),
+                     mech->mechanism);
     }
   else
     {
       /* Give up */
       _dbus_verbose ("%s: Disconnecting because we are out of mechanisms to try using\n",
                      DBUS_AUTH_NAME (auth));
-      auth->need_disconnect = TRUE;
+      goto_state (auth, &common_state_need_disconnect);
     }
   
   return TRUE;
 }
 
+
 static dbus_bool_t
-process_ok (DBusAuth         *auth,
-            const DBusString *command,
-            const DBusString *args)
+handle_client_state_waiting_for_data (DBusAuth         *auth,
+                                      DBusAuthCommand   command,
+                                      const DBusString *args)
 {
-  if (!send_begin (auth))
-    return FALSE;
-  
-  auth->authenticated_pending_output = TRUE;
-  
-  return TRUE;
+  _dbus_assert (auth->mech != NULL);
+ 
+  switch (command)
+    {
+    case DBUS_AUTH_COMMAND_DATA:
+      return process_data (auth, args, auth->mech->client_data_func);
+
+    case DBUS_AUTH_COMMAND_REJECTED:
+      return process_rejected (auth, args);
+
+    case DBUS_AUTH_COMMAND_OK:
+      return send_begin (auth);
+
+    case DBUS_AUTH_COMMAND_ERROR:
+      return send_cancel (auth);
+
+    case DBUS_AUTH_COMMAND_AUTH:
+    case DBUS_AUTH_COMMAND_CANCEL:
+    case DBUS_AUTH_COMMAND_BEGIN:
+    case DBUS_AUTH_COMMAND_UNKNOWN:
+    default:
+      return send_error (auth, "Unknown command");
+    }
 }
 
 static dbus_bool_t
-process_data_client (DBusAuth         *auth,
-                     const DBusString *command,
-                     const DBusString *args)
+handle_client_state_waiting_for_ok (DBusAuth         *auth,
+                                    DBusAuthCommand   command,
+                                    const DBusString *args)
 {
-  int end;
-
-  if (auth->mech != NULL)
+  switch (command)
     {
-      DBusString decoded;
-
-      if (!_dbus_string_init (&decoded))
-        return FALSE;
-
-      if (!_dbus_string_hex_decode (args, 0, &end, &decoded, 0))
-        {
-          _dbus_string_free (&decoded);
-	  return FALSE;
-	}
+    case DBUS_AUTH_COMMAND_REJECTED:
+      return process_rejected (auth, args);
 
-      if (_dbus_string_get_length (args) != end)
-	{
-          _dbus_string_free (&decoded);
-	  if (!send_error (auth, "Invalid hex encoding"))
-	    return FALSE;
-	  
-	  return TRUE;
-        }
+    case DBUS_AUTH_COMMAND_OK:
+      return send_begin (auth);
 
-#ifdef DBUS_ENABLE_VERBOSE_MODE
-      if (_dbus_string_validate_ascii (&decoded, 0,
-                                       _dbus_string_get_length (&decoded)))
-        {
-          _dbus_verbose ("%s: data: '%s'\n",
-                         DBUS_AUTH_NAME (auth),
-                         _dbus_string_get_const_data (&decoded));
-        }
-#endif
-      
-      if (!(* auth->mech->client_data_func) (auth, &decoded))
-        {
-          _dbus_string_free (&decoded);
-          return FALSE;
-        }
+    case DBUS_AUTH_COMMAND_DATA:
+    case DBUS_AUTH_COMMAND_ERROR:
+      return send_cancel (auth);
 
-      _dbus_string_free (&decoded);
+    case DBUS_AUTH_COMMAND_AUTH:
+    case DBUS_AUTH_COMMAND_CANCEL:
+    case DBUS_AUTH_COMMAND_BEGIN:
+    case DBUS_AUTH_COMMAND_UNKNOWN:
+    default:
+      return send_error (auth, "Unknown command");
     }
-  else
+}
+
+static dbus_bool_t
+handle_client_state_waiting_for_reject (DBusAuth         *auth,
+                                        DBusAuthCommand   command,
+                                        const DBusString *args)
+{
+  switch (command)
     {
-      if (!send_error (auth, "Got DATA when not in an auth exchange"))
-        return FALSE;
+    case DBUS_AUTH_COMMAND_REJECTED:
+      return process_rejected (auth, args);
+      
+    case DBUS_AUTH_COMMAND_AUTH:
+    case DBUS_AUTH_COMMAND_CANCEL:
+    case DBUS_AUTH_COMMAND_DATA:
+    case DBUS_AUTH_COMMAND_BEGIN:
+    case DBUS_AUTH_COMMAND_OK:
+    case DBUS_AUTH_COMMAND_ERROR:
+    case DBUS_AUTH_COMMAND_UNKNOWN:
+    default:
+      goto_state (auth, &common_state_need_disconnect);
+      return TRUE;
     }
-  
-  return TRUE;
 }
 
-static dbus_bool_t
-process_error_client (DBusAuth         *auth,
-                      const DBusString *command,
-                      const DBusString *args)
+/**
+ * Mapping from command name to enum
+ */
+typedef struct {
+  const char *name;        /**< Name of the command */
+  DBusAuthCommand command; /**< Corresponding enum */
+} DBusAuthCommandName;
+
+static DBusAuthCommandName auth_command_names[] = {
+  { "AUTH",     DBUS_AUTH_COMMAND_AUTH },
+  { "CANCEL",   DBUS_AUTH_COMMAND_CANCEL },
+  { "DATA",     DBUS_AUTH_COMMAND_DATA },
+  { "BEGIN",    DBUS_AUTH_COMMAND_BEGIN },
+  { "REJECTED", DBUS_AUTH_COMMAND_REJECTED },
+  { "OK",       DBUS_AUTH_COMMAND_OK },
+  { "ERROR",    DBUS_AUTH_COMMAND_ERROR }
+};
+
+static DBusAuthCommand
+lookup_command_from_name (DBusString *command)
 {
-  /* Cancel current mechanism, as we don't have anything
-   * more clever to do.
-   */
-  if (!send_cancel (auth))
-    return FALSE;
-  
-  return TRUE;
+  int i;
+
+  for (i = 0; i < _DBUS_N_ELEMENTS (auth_command_names); i++)
+    {
+      if (_dbus_string_equal_c_str (command,
+                                    auth_command_names[i].name))
+        return auth_command_names[i].command;
+    }
+
+  return DBUS_AUTH_COMMAND_UNKNOWN;
 }
 
-static dbus_bool_t
-process_unknown (DBusAuth         *auth,
-                 const DBusString *command,
-                 const DBusString *args)
+static void
+goto_state (DBusAuth *auth, const DBusAuthStateData *state)
 {
-  if (!send_error (auth, "Unknown command"))
-    return FALSE;
+  _dbus_verbose ("%s: going from state %s to state %s\n",
+                 DBUS_AUTH_NAME (auth),
+                 auth->state->name,
+                 state->name);
 
-  return TRUE;
+  auth->state = state;
 }
 
 /* returns whether to call it again right away */
 static dbus_bool_t
 process_command (DBusAuth *auth)
 {
-  DBusString command;
+  DBusAuthCommand command;
+  DBusString line;
   DBusString args;
   int eol;
   int i, j;
@@ -1766,7 +1833,7 @@
   if (!_dbus_string_find (&auth->incoming, 0, "\r\n", &eol))
     return FALSE;
   
-  if (!_dbus_string_init (&command))
+  if (!_dbus_string_init (&line))
     {
       auth->needed_memory = TRUE;
       return FALSE;
@@ -1774,16 +1841,16 @@
 
   if (!_dbus_string_init (&args))
     {
-      _dbus_string_free (&command);
+      _dbus_string_free (&line);
       auth->needed_memory = TRUE;
       return FALSE;
     }
   
-  if (!_dbus_string_copy_len (&auth->incoming, 0, eol, &command, 0))
+  if (!_dbus_string_copy_len (&auth->incoming, 0, eol, &line, 0))
     goto out;
 
-  if (!_dbus_string_validate_ascii (&command, 0,
-                                    _dbus_string_get_length (&command)))
+  if (!_dbus_string_validate_ascii (&line, 0,
+                                    _dbus_string_get_length (&line)))
     {
       _dbus_verbose ("%s: Command contained non-ASCII chars or embedded nul\n",
                      DBUS_AUTH_NAME (auth));
@@ -1795,40 +1862,20 @@
   
   _dbus_verbose ("%s: got command \"%s\"\n",
                  DBUS_AUTH_NAME (auth),
-                 _dbus_string_get_const_data (&command));
+                 _dbus_string_get_const_data (&line));
   
-  _dbus_string_find_blank (&command, 0, &i);
-  _dbus_string_skip_blank (&command, i, &j);
+  _dbus_string_find_blank (&line, 0, &i);
+  _dbus_string_skip_blank (&line, i, &j);
 
   if (j > i)
-    _dbus_string_delete (&command, i, j - i);
+    _dbus_string_delete (&line, i, j - i);
   
-  if (!_dbus_string_move (&command, i, &args, 0))
+  if (!_dbus_string_move (&line, i, &args, 0))
     goto out;
   
-  i = 0;
-  while (auth->handlers[i].command != NULL)
-    {
-      if (_dbus_string_equal_c_str (&command,
-                                    auth->handlers[i].command))
-        {
-          _dbus_verbose ("%s: Processing auth command %s\n",
-                         DBUS_AUTH_NAME (auth),
-                         auth->handlers[i].command);
-          
-          if (!(* auth->handlers[i].func) (auth, &command, &args))
-            goto out;
-
-          break;
-        }
-      ++i;
-    }
-
-  if (auth->handlers[i].command == NULL)
-    {
-      if (!process_unknown (auth, &command, &args))
-        goto out;
-    }
+  command = lookup_command_from_name (&line);
+  if (!(* auth->state->handler) (auth, command, &args))
+    goto out;
 
  next_command:
   
@@ -1845,7 +1892,7 @@
   
  out:
   _dbus_string_free (&args);
-  _dbus_string_free (&command);
+  _dbus_string_free (&line);
 
   if (!retval)
     auth->needed_memory = TRUE;
@@ -1880,7 +1927,8 @@
   if (auth == NULL)
     return NULL;
 
-  auth->handlers = server_handlers;
+  auth->side = auth_side_server;
+  auth->state = &server_state_waiting_for_auth;
 
   server_auth = DBUS_AUTH_SERVER (auth);
 
@@ -1909,7 +1957,8 @@
   if (auth == NULL)
     return NULL;
 
-  auth->handlers = client_handlers;
+  auth->side = auth_side_client;
+  auth->state = &client_state_need_send_auth;
 
   /* Start the auth conversation by sending AUTH for our default
    * mechanism */
@@ -2008,7 +2057,7 @@
  * @param auth the auth conversation object
  * @returns #TRUE if we're in a final state
  */
-#define DBUS_AUTH_IN_END_STATE(auth) ((auth)->need_disconnect || (auth)->authenticated)
+#define DBUS_AUTH_IN_END_STATE(auth) ((auth)->state->handler == NULL)
 
 /**
  * Analyzes buffered input and moves the auth conversation forward,
@@ -2033,7 +2082,7 @@
       if (_dbus_string_get_length (&auth->incoming) > MAX_BUFFER ||
           _dbus_string_get_length (&auth->outgoing) > MAX_BUFFER)
         {
-          auth->need_disconnect = TRUE;
+          goto_state (auth, &common_state_need_disconnect);
           _dbus_verbose ("%s: Disconnecting due to excessive data buffered in auth phase\n",
                          DBUS_AUTH_NAME (auth));
           break;
@@ -2041,16 +2090,15 @@
     }
   while (process_command (auth));
 
-  if (auth->need_disconnect)
-    return DBUS_AUTH_STATE_NEED_DISCONNECT;
-  else if (auth->authenticated)
-    return DBUS_AUTH_STATE_AUTHENTICATED;
-  else if (auth->needed_memory)
+  if (auth->needed_memory)
     return DBUS_AUTH_STATE_WAITING_FOR_MEMORY;
   else if (_dbus_string_get_length (&auth->outgoing) > 0)
     return DBUS_AUTH_STATE_HAVE_BYTES_TO_SEND;
-  else
-    return DBUS_AUTH_STATE_WAITING_FOR_INPUT;
+  else if (auth->state == &common_state_need_disconnect)
+    return DBUS_AUTH_STATE_NEED_DISCONNECT;
+  else if (auth->state == &common_state_authenticated)
+    return DBUS_AUTH_STATE_AUTHENTICATED;
+  else return DBUS_AUTH_STATE_WAITING_FOR_INPUT;
 }
 
 /**
@@ -2071,9 +2119,6 @@
 
   *str = NULL;
   
-  if (DBUS_AUTH_IN_END_STATE (auth))
-    return FALSE;
-
   if (_dbus_string_get_length (&auth->outgoing) == 0)
     return FALSE;
 
@@ -2101,10 +2146,6 @@
   
   _dbus_string_delete (&auth->outgoing,
                        0, bytes_sent);
-  
-  if (auth->authenticated_pending_output &&
-      _dbus_string_get_length (&auth->outgoing) == 0)
-    auth->authenticated = TRUE;
 }
 
 /**
@@ -2190,7 +2231,7 @@
 dbus_bool_t
 _dbus_auth_needs_encoding (DBusAuth *auth)
 {
-  if (!auth->authenticated)
+  if (auth->state != &common_state_authenticated)
     return FALSE;
   
   if (auth->mech != NULL)
@@ -2221,7 +2262,7 @@
 {
   _dbus_assert (plaintext != encoded);
   
-  if (!auth->authenticated)
+  if (auth->state != &common_state_authenticated)
     return FALSE;
   
   if (_dbus_auth_needs_encoding (auth))
@@ -2249,7 +2290,7 @@
 dbus_bool_t
 _dbus_auth_needs_decoding (DBusAuth *auth)
 {
-  if (!auth->authenticated)
+  if (auth->state != &common_state_authenticated)
     return FALSE;
     
   if (auth->mech != NULL)
@@ -2284,7 +2325,7 @@
 {
   _dbus_assert (plaintext != encoded);
   
-  if (!auth->authenticated)
+  if (auth->state != &common_state_authenticated)
     return FALSE;
   
   if (_dbus_auth_needs_decoding (auth))
@@ -2326,7 +2367,7 @@
 _dbus_auth_get_identity (DBusAuth               *auth,
                          DBusCredentials        *credentials)
 {
-  if (auth->authenticated)
+  if (auth->state == &common_state_authenticated)
     *credentials = auth->authorized_identity;
   else
     _dbus_credentials_clear (credentials);




More information about the dbus-commit mailing list