Merge "Optional autogen.sh flag --enable-kdbus-transport added allowing to compile...
[platform/upstream/dbus.git] / dbus / dbus-auth.c
index b23b147..86e3223 100644 (file)
@@ -1,7 +1,8 @@
-/* -*- mode: C; c-file-style: "gnu" -*- */
+/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
 /* dbus-auth.c Authentication
  *
  * Copyright (C) 2002, 2003, 2004 Red Hat Inc.
+ * Copyright (C) 2013  Samsung Electronics
  *
  * Licensed under the Academic Free License version 2.1
  * 
  * 
  * You should have received a copy of the GNU General Public License
  * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
  *
  */
+
+#include <config.h>
 #include "dbus-auth.h"
 #include "dbus-string.h"
 #include "dbus-list.h"
@@ -122,7 +125,9 @@ typedef enum {
   DBUS_AUTH_COMMAND_REJECTED,
   DBUS_AUTH_COMMAND_OK,
   DBUS_AUTH_COMMAND_ERROR,
-  DBUS_AUTH_COMMAND_UNKNOWN
+  DBUS_AUTH_COMMAND_UNKNOWN,
+  DBUS_AUTH_COMMAND_NEGOTIATE_UNIX_FD,
+  DBUS_AUTH_COMMAND_AGREE_UNIX_FD
 } DBusAuthCommand;
 
 /**
@@ -184,6 +189,9 @@ struct DBusAuth
   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 */
+
+  unsigned int unix_fd_possible : 1;  /**< This side could do unix fd passing */
+  unsigned int unix_fd_negotiated : 1; /**< Unix fd was successfully negotiated */
 };
 
 /**
@@ -223,9 +231,10 @@ static dbus_bool_t send_rejected             (DBusAuth *auth);
 static dbus_bool_t send_error                (DBusAuth *auth,
                                               const char *message);
 static dbus_bool_t send_ok                   (DBusAuth *auth);
-static dbus_bool_t send_begin                (DBusAuth *auth,
-                                              const DBusString *args_from_ok);
+static dbus_bool_t send_begin                (DBusAuth *auth);
 static dbus_bool_t send_cancel               (DBusAuth *auth);
+static dbus_bool_t send_negotiate_unix_fd    (DBusAuth *auth);
+static dbus_bool_t send_agree_unix_fd        (DBusAuth *auth);
 
 /**
  * Client states
@@ -264,6 +273,9 @@ static dbus_bool_t handle_client_state_waiting_for_ok     (DBusAuth         *aut
 static dbus_bool_t handle_client_state_waiting_for_reject (DBusAuth         *auth,
                                                            DBusAuthCommand   command,
                                                            const DBusString *args);
+static dbus_bool_t handle_client_state_waiting_for_agree_unix_fd (DBusAuth         *auth,
+                                                           DBusAuthCommand   command,
+                                                           const DBusString *args);
 
 static const DBusAuthStateData client_state_need_send_auth = {
   "NeedSendAuth", NULL
@@ -277,7 +289,10 @@ static const DBusAuthStateData client_state_waiting_for_ok = {
 static const DBusAuthStateData client_state_waiting_for_reject = {
   "WaitingForReject", handle_client_state_waiting_for_reject
 };
-  
+static const DBusAuthStateData client_state_waiting_for_agree_unix_fd = {
+  "WaitingForAgreeUnixFD", handle_client_state_waiting_for_agree_unix_fd
+};
+
 /**
  * Common terminal states.  Terminal states have handler == NULL.
  */
@@ -1039,6 +1054,7 @@ handle_server_data_external_mech (DBusAuth         *auth,
           _dbus_verbose ("%s: sending empty challenge asking client for auth identity\n",
                          DBUS_AUTH_NAME (auth));
           auth->already_asked_for_initial_response = TRUE;
+          goto_state (auth, &server_state_waiting_for_data);
           return TRUE;
         }
       else
@@ -1093,6 +1109,13 @@ handle_server_data_external_mech (DBusAuth         *auth,
                                              DBUS_CREDENTIAL_UNIX_PROCESS_ID,
                                              auth->credentials))
         return FALSE;
+
+      /* also copy audit data from the socket credentials
+       */
+      if (!_dbus_credentials_add_credential (auth->authorized_identity,
+                                             DBUS_CREDENTIAL_ADT_AUDIT_DATA_ID,
+                                             auth->credentials))
+        return FALSE;
       
       if (!send_ok (auth))
         return FALSE;
@@ -1180,18 +1203,6 @@ handle_server_data_anonymous_mech (DBusAuth         *auth,
         {
           _dbus_verbose ("%s: Received invalid UTF-8 trace data from ANONYMOUS client\n",
                          DBUS_AUTH_NAME (auth));
-
-          {
-            DBusString plaintext;
-            DBusString encoded;
-            _dbus_string_init_const (&plaintext, "D-Bus " VERSION);
-            _dbus_string_init (&encoded);
-            _dbus_string_hex_encode (&plaintext, 0,
-                                     &encoded,
-                                     0);
-              _dbus_verbose ("%s: try '%s'\n",
-                             DBUS_AUTH_NAME (auth), _dbus_string_get_const_data (&encoded));
-          }
           return send_rejected (auth);
         }
       
@@ -1242,7 +1253,7 @@ handle_client_initial_response_anonymous_mech (DBusAuth         *auth,
     return FALSE;
 
   if (!_dbus_string_append (&plaintext,
-                            "libdbus " VERSION))
+                            "libdbus " DBUS_VERSION_STRING))
     goto failed;
 
   if (!_dbus_string_hex_encode (&plaintext, 0,
@@ -1514,9 +1525,21 @@ send_ok (DBusAuth *auth)
 }
 
 static dbus_bool_t
-send_begin (DBusAuth         *auth,
-            const DBusString *args_from_ok)
+send_begin (DBusAuth         *auth)
 {
+
+  if (!_dbus_string_append (&auth->outgoing,
+                            "BEGIN\r\n"))
+    return FALSE;
+
+  goto_state (auth, &common_state_authenticated);
+  return TRUE;
+}
+
+static dbus_bool_t
+process_ok(DBusAuth *auth,
+          const DBusString *args_from_ok) {
+
   int end_of_hex;
   
   /* "args_from_ok" should be the GUID, whitespace already pulled off the front */
@@ -1541,20 +1564,19 @@ send_begin (DBusAuth         *auth,
       return TRUE;
     }
 
-  if (_dbus_string_copy (args_from_ok, 0, &DBUS_AUTH_CLIENT (auth)->guid_from_server, 0) &&
-      _dbus_string_append (&auth->outgoing, "BEGIN\r\n"))
-    {
-      _dbus_verbose ("Got GUID '%s' from the server\n",
-                     _dbus_string_get_const_data (& DBUS_AUTH_CLIENT (auth)->guid_from_server));
-      
-      goto_state (auth, &common_state_authenticated);
-      return TRUE;
-    }
-  else
-    {
+  if (!_dbus_string_copy (args_from_ok, 0, &DBUS_AUTH_CLIENT (auth)->guid_from_server, 0)) {
       _dbus_string_set_length (& DBUS_AUTH_CLIENT (auth)->guid_from_server, 0);
       return FALSE;
-    }
+  }
+
+  _dbus_verbose ("Got GUID '%s' from the server\n",
+                 _dbus_string_get_const_data (& DBUS_AUTH_CLIENT (auth)->guid_from_server));
+
+  if (auth->unix_fd_possible)
+    return send_negotiate_unix_fd(auth);
+
+  _dbus_verbose("Not negotiating unix fd passing, since not possible\n");
+  return send_begin (auth);
 }
 
 static dbus_bool_t
@@ -1614,6 +1636,33 @@ process_data (DBusAuth             *auth,
 }
 
 static dbus_bool_t
+send_negotiate_unix_fd (DBusAuth *auth)
+{
+  if (!_dbus_string_append (&auth->outgoing,
+                            "NEGOTIATE_UNIX_FD\r\n"))
+    return FALSE;
+
+  goto_state (auth, &client_state_waiting_for_agree_unix_fd);
+  return TRUE;
+}
+
+static dbus_bool_t
+send_agree_unix_fd (DBusAuth *auth)
+{
+  _dbus_assert(auth->unix_fd_possible);
+
+  auth->unix_fd_negotiated = TRUE;
+  _dbus_verbose("Agreed to UNIX FD passing\n");
+
+  if (!_dbus_string_append (&auth->outgoing,
+                            "AGREE_UNIX_FD\r\n"))
+    return FALSE;
+
+  goto_state (auth, &server_state_waiting_for_begin);
+  return TRUE;
+}
+
+static dbus_bool_t
 handle_auth (DBusAuth *auth, const DBusString *args)
 {
   if (_dbus_string_get_length (args) == 0)
@@ -1704,9 +1753,13 @@ handle_server_state_waiting_for_auth  (DBusAuth         *auth,
     case DBUS_AUTH_COMMAND_ERROR:
       return send_rejected (auth);
 
+    case DBUS_AUTH_COMMAND_NEGOTIATE_UNIX_FD:
+      return send_error (auth, "Need to authenticate first");
+
     case DBUS_AUTH_COMMAND_REJECTED:
     case DBUS_AUTH_COMMAND_OK:
     case DBUS_AUTH_COMMAND_UNKNOWN:
+    case DBUS_AUTH_COMMAND_AGREE_UNIX_FD:
     default:
       return send_error (auth, "Unknown command");
     }
@@ -1733,9 +1786,13 @@ handle_server_state_waiting_for_data  (DBusAuth         *auth,
       goto_state (auth, &common_state_need_disconnect);
       return TRUE;
 
+    case DBUS_AUTH_COMMAND_NEGOTIATE_UNIX_FD:
+      return send_error (auth, "Need to authenticate first");
+
     case DBUS_AUTH_COMMAND_REJECTED:
     case DBUS_AUTH_COMMAND_OK:
     case DBUS_AUTH_COMMAND_UNKNOWN:
+    case DBUS_AUTH_COMMAND_AGREE_UNIX_FD:
     default:
       return send_error (auth, "Unknown command");
     }
@@ -1758,9 +1815,16 @@ handle_server_state_waiting_for_begin (DBusAuth         *auth,
       goto_state (auth, &common_state_authenticated);
       return TRUE;
 
+    case DBUS_AUTH_COMMAND_NEGOTIATE_UNIX_FD:
+      if (auth->unix_fd_possible)
+        return send_agree_unix_fd(auth);
+      else
+        return send_error(auth, "Unix FD passing not supported, not authenticated or otherwise not possible");
+
     case DBUS_AUTH_COMMAND_REJECTED:
     case DBUS_AUTH_COMMAND_OK:
     case DBUS_AUTH_COMMAND_UNKNOWN:
+    case DBUS_AUTH_COMMAND_AGREE_UNIX_FD:
     default:
       return send_error (auth, "Unknown command");
 
@@ -1925,7 +1989,7 @@ handle_client_state_waiting_for_data (DBusAuth         *auth,
       return process_rejected (auth, args);
 
     case DBUS_AUTH_COMMAND_OK:
-      return send_begin (auth, args);
+      return process_ok(auth, args);
 
     case DBUS_AUTH_COMMAND_ERROR:
       return send_cancel (auth);
@@ -1934,6 +1998,8 @@ handle_client_state_waiting_for_data (DBusAuth         *auth,
     case DBUS_AUTH_COMMAND_CANCEL:
     case DBUS_AUTH_COMMAND_BEGIN:
     case DBUS_AUTH_COMMAND_UNKNOWN:
+    case DBUS_AUTH_COMMAND_NEGOTIATE_UNIX_FD:
+    case DBUS_AUTH_COMMAND_AGREE_UNIX_FD:
     default:
       return send_error (auth, "Unknown command");
     }
@@ -1950,7 +2016,7 @@ handle_client_state_waiting_for_ok (DBusAuth         *auth,
       return process_rejected (auth, args);
 
     case DBUS_AUTH_COMMAND_OK:
-      return send_begin (auth, args);
+      return process_ok(auth, args);
 
     case DBUS_AUTH_COMMAND_DATA:
     case DBUS_AUTH_COMMAND_ERROR:
@@ -1960,6 +2026,8 @@ handle_client_state_waiting_for_ok (DBusAuth         *auth,
     case DBUS_AUTH_COMMAND_CANCEL:
     case DBUS_AUTH_COMMAND_BEGIN:
     case DBUS_AUTH_COMMAND_UNKNOWN:
+    case DBUS_AUTH_COMMAND_NEGOTIATE_UNIX_FD:
+    case DBUS_AUTH_COMMAND_AGREE_UNIX_FD:
     default:
       return send_error (auth, "Unknown command");
     }
@@ -1982,12 +2050,46 @@ handle_client_state_waiting_for_reject (DBusAuth         *auth,
     case DBUS_AUTH_COMMAND_OK:
     case DBUS_AUTH_COMMAND_ERROR:
     case DBUS_AUTH_COMMAND_UNKNOWN:
+    case DBUS_AUTH_COMMAND_NEGOTIATE_UNIX_FD:
+    case DBUS_AUTH_COMMAND_AGREE_UNIX_FD:
     default:
       goto_state (auth, &common_state_need_disconnect);
       return TRUE;
     }
 }
 
+static dbus_bool_t
+handle_client_state_waiting_for_agree_unix_fd(DBusAuth         *auth,
+                                              DBusAuthCommand   command,
+                                              const DBusString *args)
+{
+  switch (command)
+    {
+    case DBUS_AUTH_COMMAND_AGREE_UNIX_FD:
+      _dbus_assert(auth->unix_fd_possible);
+      auth->unix_fd_negotiated = TRUE;
+      _dbus_verbose("Successfully negotiated UNIX FD passing\n");
+      return send_begin (auth);
+
+    case DBUS_AUTH_COMMAND_ERROR:
+      _dbus_assert(auth->unix_fd_possible);
+      auth->unix_fd_negotiated = FALSE;
+      _dbus_verbose("Failed to negotiate UNIX FD passing\n");
+      return send_begin (auth);
+
+    case DBUS_AUTH_COMMAND_OK:
+    case DBUS_AUTH_COMMAND_DATA:
+    case DBUS_AUTH_COMMAND_REJECTED:
+    case DBUS_AUTH_COMMAND_AUTH:
+    case DBUS_AUTH_COMMAND_CANCEL:
+    case DBUS_AUTH_COMMAND_BEGIN:
+    case DBUS_AUTH_COMMAND_UNKNOWN:
+    case DBUS_AUTH_COMMAND_NEGOTIATE_UNIX_FD:
+    default:
+      return send_error (auth, "Unknown command");
+    }
+}
+
 /**
  * Mapping from command name to enum
  */
@@ -1997,13 +2099,15 @@ typedef struct {
 } DBusAuthCommandName;
 
 static const 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 }
+  { "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 },
+  { "NEGOTIATE_UNIX_FD", DBUS_AUTH_COMMAND_NEGOTIATE_UNIX_FD },
+  { "AGREE_UNIX_FD",     DBUS_AUTH_COMMAND_AGREE_UNIX_FD }
 };
 
 static DBusAuthCommand
@@ -2135,8 +2239,8 @@ process_command (DBusAuth *auth)
 
 /**
  * Creates a new auth conversation object for the server side.
- * See doc/dbus-sasl-profile.txt for full details on what
- * this object does.
+ * See http://dbus.freedesktop.org/doc/dbus-specification.html#auth-protocol
+ * for full details on what this object does.
  *
  * @returns the new object or #NULL if no memory
  */
@@ -2181,8 +2285,8 @@ _dbus_auth_server_new (const DBusString *guid)
 
 /**
  * Creates a new auth conversation object for the client side.
- * See doc/dbus-sasl-profile.txt for full details on what
- * this object does.
+ * See http://dbus.freedesktop.org/doc/dbus-specification.html#auth-protocol
+ * for full details on what this object does.
  *
  * @returns the new object or #NULL if no memory
  */
@@ -2218,6 +2322,49 @@ _dbus_auth_client_new (void)
   return auth;
 }
 
+#ifdef ENABLE_KDBUS_TRANSPORT
+/**
+ * Creates a new auth conversation object for the client side of kdbus.
+ * In fact it only initialize structures and sets authenticated state
+ * because of different authentication-like mechanism in kdbus - policies
+ * TODO Probably to be checked and modified when kdbus will be documented
+ *
+ * @returns the new object or #NULL if no memory
+ */
+DBusAuth*
+_dbus_auth_client_new_kdbus (void)
+{
+  DBusAuth *auth;
+  DBusString guid_str;
+
+  if (!_dbus_string_init (&guid_str))
+    return NULL;
+
+  auth = _dbus_auth_new (sizeof (DBusAuthClient));
+  if (auth == NULL)
+    {
+      _dbus_string_free (&guid_str);
+      return NULL;
+    }
+
+  DBUS_AUTH_CLIENT (auth)->guid_from_server = guid_str;
+
+  auth->side = auth_side_client;
+  auth->state = &common_state_authenticated;
+  auth->unix_fd_negotiated = TRUE;
+
+  /* Start the auth conversation by sending AUTH for our default
+   * mechanism */
+/*  if (!send_auth (auth, &all_mechanisms[0]))
+    {
+      _dbus_auth_unref (auth);
+      return NULL;
+    }*/
+
+  return auth;
+}
+#endif
+
 /**
  * Increments the refcount of an auth object.
  *
@@ -2677,6 +2824,31 @@ _dbus_auth_set_context (DBusAuth               *auth,
                                    &auth->context, 0, _dbus_string_get_length (context));
 }
 
+/**
+ * Sets whether unix fd passing is potentially on the transport and
+ * hence shall be negotiated.
+ *
+ * @param auth the auth conversation
+ * @param b TRUE when unix fd passing shall be negotiated, otherwise FALSE
+ */
+void
+_dbus_auth_set_unix_fd_possible(DBusAuth *auth, dbus_bool_t b)
+{
+  auth->unix_fd_possible = b;
+}
+
+/**
+ * Queries whether unix fd passing was successfully negotiated.
+ *
+ * @param auth the auth conversion
+ * @returns #TRUE when unix fd passing was negotiated.
+ */
+dbus_bool_t
+_dbus_auth_get_unix_fd_negotiated(DBusAuth *auth)
+{
+  return auth->unix_fd_negotiated;
+}
+
 /** @} */
 
 /* tests in dbus-auth-util.c */