Bug 15740: Solaris/ADT auditing support (simon zheng)
authorColin Walters <walters@verbum.org>
Thu, 5 Jun 2008 21:24:34 +0000 (17:24 -0400)
committerColin Walters <walters@verbum.org>
Thu, 5 Jun 2008 21:24:34 +0000 (17:24 -0400)
* bus/driver.c: Add GetAdtAuditSessionData method
which returns audit data for a connection.
* configure.in: Detect ADT auditing support
* dbus/dbus-auth.c: Read ADT auditing creds.
* dbus/dbus-connection.c: Implement
dbus_connection_get_adt_audit_session_data.
* dbus/dbus-connection.h: Export it.
* dbus/dbus-credentials.c: Add support for
gathering adt_audit_data and retrieving it
via _dbus_credentials_get_adt_audit_data.
* dbus/dbus-credentials.h: Add
DBUS_CREDENTIAL_ADT_AUDIT_DATA_ID.
* dbus/dbus-protocol.h: New error
DBUS_ERROR_ADT_AUDIT_DATA_UNKNOWN.
* dbus/dbus-sysdeps.c: Support for reading
audit credentials via ADT API.
* dbus/dbus-transport.c: New function
_dbus_transport_get_adt_audit_session_data
to retrieve credentials.
* dbus/dbus-transport.h: Export it.

bus/driver.c
configure.in
dbus/dbus-auth.c
dbus/dbus-connection.c
dbus/dbus-connection.h
dbus/dbus-credentials.c
dbus/dbus-credentials.h
dbus/dbus-protocol.h
dbus/dbus-sysdeps-unix.c
dbus/dbus-transport.c
dbus/dbus-transport.h

index 2519626..bdf5afb 100644 (file)
@@ -1273,6 +1273,81 @@ bus_driver_handle_get_connection_unix_process_id (DBusConnection *connection,
 }
 
 static dbus_bool_t
+bus_driver_handle_get_adt_audit_session_data (DBusConnection *connection,
+                                             BusTransaction *transaction,
+                                             DBusMessage    *message,
+                                             DBusError      *error)
+{
+  const char *service;
+  DBusString str;
+  BusRegistry *registry;
+  BusService *serv;
+  DBusConnection *conn;
+  DBusMessage *reply;
+  char *data = NULL;
+  dbus_uint32_t data_size;
+
+  _DBUS_ASSERT_ERROR_IS_CLEAR (error);
+
+  registry = bus_connection_get_registry (connection);
+
+  service = NULL;
+  reply = NULL;
+
+  if (! dbus_message_get_args (message, error,
+                              DBUS_TYPE_STRING, &service,
+                              DBUS_TYPE_INVALID))
+      goto failed;
+
+  _dbus_verbose ("asked for audit session data for connection %s\n", service);
+
+  _dbus_string_init_const (&str, service);
+  serv = bus_registry_lookup (registry, &str);
+  if (serv == NULL)
+    {
+      dbus_set_error (error, 
+                     DBUS_ERROR_NAME_HAS_NO_OWNER,
+                     "Could not get audit session data for name '%s': no such name", service);
+      goto failed;
+    }
+
+  conn = bus_service_get_primary_owners_connection (serv);
+
+  reply = dbus_message_new_method_return (message);
+  if (reply == NULL)
+    goto oom;
+
+  if (!dbus_connection_get_adt_audit_session_data (conn, &data, &data_size) || data == NULL)
+    {
+      dbus_set_error (error,
+                      DBUS_ERROR_ADT_AUDIT_DATA_UNKNOWN,
+                      "Could not determine audit session data for '%s'", service);
+      goto failed;
+    }
+
+  if (! dbus_message_append_args (reply,
+                                  DBUS_TYPE_ARRAY, DBUS_TYPE_BYTE, &data, data_size,
+                                  DBUS_TYPE_INVALID))
+    goto oom;
+
+  if (! bus_transaction_send_from_driver (transaction, connection, reply))
+    goto oom;
+
+  dbus_message_unref (reply);
+
+  return TRUE;
+
+ oom:
+  BUS_SET_OOM (error);
+
+ failed:
+  _DBUS_ASSERT_ERROR_IS_SET (error);
+  if (reply)
+    dbus_message_unref (reply);
+  return FALSE;
+}
+
+static dbus_bool_t
 bus_driver_handle_get_connection_selinux_security_context (DBusConnection *connection,
                                                           BusTransaction *transaction,
                                                           DBusMessage    *message,
@@ -1503,6 +1578,10 @@ struct
     DBUS_TYPE_STRING_AS_STRING,
     DBUS_TYPE_UINT32_AS_STRING,
     bus_driver_handle_get_connection_unix_process_id },
+  { "GetAdtAuditSessionData",
+    DBUS_TYPE_STRING_AS_STRING,
+    DBUS_TYPE_ARRAY_AS_STRING DBUS_TYPE_BYTE_AS_STRING,
+    bus_driver_handle_get_adt_audit_session_data },
   { "GetConnectionSELinuxSecurityContext",
     DBUS_TYPE_STRING_AS_STRING,
     DBUS_TYPE_ARRAY_AS_STRING DBUS_TYPE_BYTE_AS_STRING,
index 7130a8c..b833840 100644 (file)
@@ -1028,6 +1028,24 @@ if test x$have_libaudit = xyes ; then
     AC_DEFINE(HAVE_LIBAUDIT,1,[audit daemon SELinux support])
 fi
 
+# Check for ADT API
+AC_MSG_CHECKING(for ADT API)
+AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
+#include <bsm/adt.h>
+adt_user_context = ADT_USER;
+]], [[]])], [ check_adt_audit=yes ], [ check_adt_audit=no ])
+
+if test ${check_adt_audit} = yes
+then
+   AC_DEFINE([HAVE_ADT], [], [Adt audit API])
+   ADT_LIBS="-lbsm"
+   LIBS="-lbsm $LIBS"
+   AC_MSG_RESULT(yes)
+else
+   AC_MSG_RESULT(no)
+fi
+
+
 #### Set up final flags
 DBUS_CLIENT_CFLAGS=
 DBUS_CLIENT_LIBS="$THREAD_LIBS"
@@ -1035,7 +1053,7 @@ AC_SUBST(DBUS_CLIENT_CFLAGS)
 AC_SUBST(DBUS_CLIENT_LIBS)
 
 DBUS_BUS_CFLAGS="$XML_CFLAGS"
-DBUS_BUS_LIBS="$XML_LIBS $SELINUX_LIBS $INTLLIBS $THREAD_LIBS"
+DBUS_BUS_LIBS="$XML_LIBS $SELINUX_LIBS $INTLLIBS $THREAD_LIBS $ADT_LIBS"
 AC_SUBST(DBUS_BUS_CFLAGS)
 AC_SUBST(DBUS_BUS_LIBS)
 
index 7e424af..ec7cf31 100644 (file)
@@ -1094,6 +1094,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;
index f2902ed..804af82 100644 (file)
@@ -4986,6 +4986,40 @@ dbus_connection_get_unix_process_id (DBusConnection *connection,
 }
 
 /**
+ * Gets the ADT audit data of the connection if any.
+ * Returns #TRUE if the structure pointer is returned.
+ * Always returns #FALSE prior to authenticating the
+ * connection.
+ *
+ * @param connection the connection
+ * @param data return location for audit data 
+ * @returns #TRUE if audit data is filled in with a valid ucred pointer
+ */
+dbus_bool_t
+dbus_connection_get_adt_audit_session_data (DBusConnection *connection,
+                                           void          **data,
+                                           dbus_int32_t   *data_size)
+{
+  dbus_bool_t result;
+
+  _dbus_return_val_if_fail (connection != NULL, FALSE);
+  _dbus_return_val_if_fail (data != NULL, FALSE);
+  _dbus_return_val_if_fail (data_size != NULL, FALSE);
+  
+  CONNECTION_LOCK (connection);
+
+  if (!_dbus_transport_get_is_authenticated (connection->transport))
+    result = FALSE;
+  else
+    result = _dbus_transport_get_adt_audit_session_data (connection->transport,
+                                                        data,
+                                                        data_size);
+  CONNECTION_UNLOCK (connection);
+
+  return result;
+}
+
+/**
  * Sets a predicate function used to determine whether a given user ID
  * is allowed to connect. When an incoming connection has
  * authenticated with a particular user ID, this function is called;
index 5d7e493..b8fd35f 100644 (file)
@@ -231,6 +231,9 @@ dbus_bool_t        dbus_connection_get_unix_user                (DBusConnection
                                                                  unsigned long              *uid);
 dbus_bool_t        dbus_connection_get_unix_process_id          (DBusConnection             *connection,
                                                                  unsigned long              *pid);
+dbus_bool_t        dbus_connection_get_adt_audit_session_data   (DBusConnection             *connection,
+                                                                 void                      **data,
+                                                                 dbus_int32_t               *data_size);
 void               dbus_connection_set_unix_user_function       (DBusConnection             *connection,
                                                                  DBusAllowUnixUserFunction   function,
                                                                  void                       *data,
index 790ca06..f21ecb2 100644 (file)
@@ -50,6 +50,8 @@ struct DBusCredentials {
   dbus_uid_t unix_uid;
   dbus_pid_t unix_pid;
   char *windows_sid;
+  void *adt_audit_data;
+  dbus_int32_t adt_audit_data_size;
 };
 
 /** @} */
@@ -77,6 +79,8 @@ _dbus_credentials_new (void)
   creds->unix_uid = DBUS_UID_UNSET;
   creds->unix_pid = DBUS_PID_UNSET;
   creds->windows_sid = NULL;
+  creds->adt_audit_data = NULL;
+  creds->adt_audit_data_size = 0;
 
   return creds;
 }
@@ -129,6 +133,7 @@ _dbus_credentials_unref (DBusCredentials    *credentials)
   if (credentials->refcount == 0)
     {
       dbus_free (credentials->windows_sid);
+      dbus_free (credentials->adt_audit_data);
       dbus_free (credentials);
     }
 }
@@ -188,6 +193,31 @@ _dbus_credentials_add_windows_sid (DBusCredentials    *credentials,
 }
 
 /**
+ * Add ADT audit data to the credentials.
+ *
+ * @param credentials the object
+ * @param audit_data the audit data
+ * @param size the length of audit data
+ * @returns #FALSE if no memory
+ */
+dbus_bool_t
+_dbus_credentials_add_adt_audit_data (DBusCredentials    *credentials,
+                                      void               *audit_data,
+                                      dbus_int32_t        size)
+{
+  void *copy;
+  copy = _dbus_memdup (audit_data, size);
+  if (copy == NULL)
+    return FALSE;
+
+  dbus_free (credentials->adt_audit_data);
+  credentials->adt_audit_data = copy;
+  credentials->adt_audit_data_size = size;
+
+  return TRUE;
+}
+
+/**
  * Checks whether the given credential is present.
  *
  * @param credentials the object
@@ -206,6 +236,8 @@ _dbus_credentials_include (DBusCredentials    *credentials,
       return credentials->unix_uid != DBUS_UID_UNSET;
     case DBUS_CREDENTIAL_WINDOWS_SID:
       return credentials->windows_sid != NULL;
+    case DBUS_CREDENTIAL_ADT_AUDIT_DATA_ID:
+      return credentials->adt_audit_data != NULL;
     }
 
   _dbus_assert_not_reached ("Unknown credential enum value");
@@ -252,6 +284,32 @@ _dbus_credentials_get_windows_sid (DBusCredentials    *credentials)
 }
 
 /**
+ * Gets the ADT audit data in the credentials, or #NULL if
+ * the credentials object doesn't contain ADT audit data.
+ *
+ * @param credentials the object
+ * @returns Solaris ADT audit data 
+ */
+void *
+_dbus_credentials_get_adt_audit_data (DBusCredentials    *credentials)
+{
+  return credentials->adt_audit_data;
+}
+
+/**
+ * Gets the ADT audit data size in the credentials, or 0 if
+ * the credentials object doesn't contain ADT audit data.
+ *
+ * @param credentials the object
+ * @returns Solaris ADT audit data size
+ */
+dbus_int32_t 
+_dbus_credentials_get_adt_audit_data_size (DBusCredentials    *credentials)
+{
+  return credentials->adt_audit_data_size;
+}
+
+/**
  * Checks whether the first credentials object contains
  * all the credentials found in the second credentials object.
  *
@@ -270,7 +328,11 @@ _dbus_credentials_are_superset (DBusCredentials    *credentials,
      possible_subset->unix_uid == credentials->unix_uid) &&
     (possible_subset->windows_sid == NULL ||
      (credentials->windows_sid && strcmp (possible_subset->windows_sid,
-                                          credentials->windows_sid) == 0));
+                                          credentials->windows_sid) == 0)) &&
+    (possible_subset->adt_audit_data == NULL ||
+     (credentials->adt_audit_data && memcmp (possible_subset->adt_audit_data,
+                                             credentials->adt_audit_data,
+                                             credentials->adt_audit_data_size) == 0));
 }
 
 /**
@@ -285,7 +347,8 @@ _dbus_credentials_are_empty (DBusCredentials    *credentials)
   return
     credentials->unix_pid == DBUS_PID_UNSET &&
     credentials->unix_uid == DBUS_UID_UNSET &&
-    credentials->windows_sid == NULL;
+    credentials->windows_sid == NULL &&
+    credentials->adt_audit_data == NULL;
 }
 
 /**
@@ -322,6 +385,9 @@ _dbus_credentials_add_credentials (DBusCredentials    *credentials,
                                       DBUS_CREDENTIAL_UNIX_USER_ID,
                                       other_credentials) &&
     _dbus_credentials_add_credential (credentials,
+                                      DBUS_CREDENTIAL_ADT_AUDIT_DATA_ID,
+                                      other_credentials) &&
+    _dbus_credentials_add_credential (credentials,
                                       DBUS_CREDENTIAL_WINDOWS_SID,
                                       other_credentials);
 }
@@ -360,6 +426,12 @@ _dbus_credentials_add_credential (DBusCredentials    *credentials,
     {
       if (!_dbus_credentials_add_windows_sid (credentials, other_credentials->windows_sid))
         return FALSE;
+    } 
+  else if (which == DBUS_CREDENTIAL_ADT_AUDIT_DATA_ID &&
+           other_credentials->adt_audit_data != NULL) 
+    {
+      if (!_dbus_credentials_add_adt_audit_data (credentials, other_credentials->adt_audit_data, other_credentials->adt_audit_data_size))
+        return FALSE;
     }
 
   return TRUE;
@@ -377,6 +449,9 @@ _dbus_credentials_clear (DBusCredentials    *credentials)
   credentials->unix_uid = DBUS_UID_UNSET;
   dbus_free (credentials->windows_sid);
   credentials->windows_sid = NULL;
+  dbus_free (credentials->adt_audit_data);
+  credentials->adt_audit_data = NULL;
+  credentials->adt_audit_data_size = 0;
 }
 
 /**
index b8d7dd7..d4c8d16 100644 (file)
@@ -33,6 +33,7 @@ DBUS_BEGIN_DECLS
 typedef enum {
   DBUS_CREDENTIAL_UNIX_PROCESS_ID,
   DBUS_CREDENTIAL_UNIX_USER_ID,
+  DBUS_CREDENTIAL_ADT_AUDIT_DATA_ID,
   DBUS_CREDENTIAL_WINDOWS_SID
 } DBusCredentialType;
 
@@ -51,6 +52,8 @@ dbus_bool_t      _dbus_credentials_include                  (DBusCredentials
 dbus_pid_t       _dbus_credentials_get_unix_pid             (DBusCredentials    *credentials);
 dbus_uid_t       _dbus_credentials_get_unix_uid             (DBusCredentials    *credentials);
 const char*      _dbus_credentials_get_windows_sid          (DBusCredentials    *credentials);
+void *           _dbus_credentials_get_adt_audit_data       (DBusCredentials    *credentials);
+dbus_int32_t     _dbus_credentials_get_adt_audit_data_size  (DBusCredentials    *credentials);
 dbus_bool_t      _dbus_credentials_are_superset             (DBusCredentials    *credentials,
                                                              DBusCredentials    *possible_subset);
 dbus_bool_t      _dbus_credentials_are_empty                (DBusCredentials    *credentials);
index 58677dc..814deae 100644 (file)
@@ -411,6 +411,8 @@ extern "C" {
 #define DBUS_ERROR_INVALID_FILE_CONTENT       "org.freedesktop.DBus.Error.InvalidFileContent"
 /** Asked for SELinux security context and it wasn't available. */
 #define DBUS_ERROR_SELINUX_SECURITY_CONTEXT_UNKNOWN    "org.freedesktop.DBus.Error.SELinuxSecurityContextUnknown"
+/** Asked for ADT audit data and it wasn't available. */
+#define DBUS_ERROR_ADT_AUDIT_DATA_UNKNOWN     "org.freedesktop.DBus.Error.AdtAuditDataUnknown"
 /** There's already an object with the requested object path. */
 #define DBUS_ERROR_OBJECT_PATH_IN_USE         "org.freedesktop.DBus.Error.ObjectPathInUse"
 
index a66d071..64d925d 100644 (file)
 #include <ucred.h>
 #endif
 
+#ifdef HAVE_ADT
+#include <bsm/adt.h>
+#endif
+
 #ifndef O_BINARY
 #define O_BINARY 0
 #endif
@@ -1260,6 +1264,37 @@ _dbus_read_credentials_socket  (int              client_fd,
       {
         pid_read = ucred_getpid (ucred);
         uid_read = ucred_geteuid (ucred);
+#ifdef HAVE_ADT
+        /* generate audit session data based on socket ucred */
+        adt_session_data_t *adth = NULL;
+        adt_export_data_t *data = NULL;
+        size_t size = 0;
+        if (adt_start_session (&adth, NULL, 0) || (adth == NULL))
+          {
+            _dbus_verbose ("Failed to adt_start_session(): %s\n", _dbus_strerror (errno));
+          }
+        else 
+          {
+            if (adt_set_from_ucred (adth, ucred, ADT_NEW)) 
+              {
+                _dbus_verbose ("Failed to adt_set_from_ucred(): %s\n", _dbus_strerror (errno));
+              }
+            else
+              {
+                size = adt_export_session_data (adth, &data);
+                if (size <= 0)
+                  {
+                    _dbus_verbose ("Failed to adt_export_session_data(): %s\n", _dbus_strerror (errno));
+                  }
+                else
+                  {
+                    _dbus_credentials_add_adt_audit_data (credentials, data, size);
+                    free (data);
+                  }
+              }
+            (void) adt_end_session (adth);
+          }
+#endif /* HAVE_ADT */
       }
     else
       {
index 1e1fc97..9029198 100644 (file)
@@ -1262,6 +1262,40 @@ _dbus_transport_get_unix_process_id (DBusTransport *transport,
 }
 
 /**
+ * See dbus_connection_get_adt_audit_session_data().
+ *
+ * @param transport the transport
+ * @param data return location for the ADT audit data 
+ * @param data_size return length of audit data
+ * @returns #TRUE if audit data is filled in with a valid ucred
+ */
+dbus_bool_t
+_dbus_transport_get_adt_audit_session_data (DBusTransport      *transport,
+                                            void              **data,
+                                            int                *data_size)
+{
+  DBusCredentials *auth_identity;
+
+  *data = NULL;
+  *data_size = 0;
+  
+  if (!transport->authenticated)
+    return FALSE;
+  
+  auth_identity = _dbus_auth_get_identity (transport->auth);
+
+  if (_dbus_credentials_include (auth_identity,
+                                 DBUS_CREDENTIAL_ADT_AUDIT_DATA_ID))
+    {
+      *data = (void *) _dbus_credentials_get_adt_audit_data (auth_identity);
+      *data_size = _dbus_credentials_get_adt_audit_data_size (auth_identity);
+      return TRUE;
+    }
+  else
+    return FALSE;
+}
+
+/**
  * See dbus_connection_set_unix_user_function().
  *
  * @param transport the transport
index 9a9e553..691763c 100644 (file)
@@ -64,6 +64,9 @@ dbus_bool_t        _dbus_transport_get_unix_user          (DBusTransport
                                                            unsigned long              *uid);
 dbus_bool_t        _dbus_transport_get_unix_process_id     (DBusTransport              *transport,
                                                            unsigned long              *pid);
+dbus_bool_t        _dbus_transport_get_adt_audit_session_data (DBusTransport              *transport,
+                                                               void                      **data,
+                                                               int                        *data_size);
 void               _dbus_transport_set_unix_user_function (DBusTransport              *transport,
                                                            DBusAllowUnixUserFunction   function,
                                                            void                       *data,