[daemon-fix] Fixed sending daemon match rules for kdbus broadcasts
[platform/upstream/dbus.git] / dbus / dbus-userdb-util.c
index 81564ad..62495d8 100644 (file)
@@ -1,4 +1,4 @@
-/* -*- mode: C; c-file-style: "gnu" -*- */
+/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
 /* dbus-userdb-util.c Would be in dbus-userdb.c, but not used in libdbus
  * 
  * Copyright (C) 2003, 2004, 2005  Red Hat, Inc.
  * 
  * 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 <unistd.h>
 #define DBUS_USERDB_INCLUDES_PRIVATE 1
 #include "dbus-userdb.h"
 #include "dbus-test.h"
 #include "dbus-protocol.h"
 #include <string.h>
 
+#if HAVE_SYSTEMD
+#include <systemd/sd-login.h>
+#endif
+
 /**
  * @addtogroup DBusInternalsUtils
  * @{
@@ -46,7 +52,29 @@ _dbus_is_console_user (dbus_uid_t uid,
 
   DBusUserDatabase *db;
   const DBusUserInfo *info;
-  dbus_bool_t result = FALSE; 
+  dbus_bool_t result = FALSE;
+
+#ifdef HAVE_SYSTEMD
+  /* check if we have logind */
+  if (access ("/run/systemd/seats/", F_OK) >= 0)
+    {
+      int r;
+
+      /* Check whether this user is logged in on at least one physical
+         seat */
+      r = sd_uid_get_seats (uid, 0, NULL);
+      if (r < 0)
+        {
+          dbus_set_error (error, _dbus_error_from_errno (-r),
+                          "Failed to determine seats of user \"" DBUS_UID_FORMAT "\": %s",
+                          uid,
+                          _dbus_strerror (-r));
+          return FALSE;
+        }
+
+      return (r > 0);
+    }
+#endif
 
 #ifdef HAVE_CONSOLE_OWNER_FILE
 
@@ -76,7 +104,11 @@ _dbus_is_console_user (dbus_uid_t uid,
 
 #endif /* HAVE_CONSOLE_OWNER_FILE */
 
-  _dbus_user_database_lock_system ();
+  if (!_dbus_user_database_lock_system ())
+    {
+      _DBUS_SET_OOM (error);
+      return FALSE;
+    }
 
   db = _dbus_user_database_get_system ();
   if (db == NULL)
@@ -86,6 +118,8 @@ _dbus_is_console_user (dbus_uid_t uid,
       return FALSE;
     }
 
+  /* TPTD: this should be cache-safe, we've locked the DB and
+    _dbus_user_at_console doesn't pass it on. */
   info = _dbus_user_database_lookup (db, uid, NULL, error);
 
   if (info == NULL)
@@ -101,21 +135,37 @@ _dbus_is_console_user (dbus_uid_t uid,
   return result;
 }
 
+/**
+ * Gets user ID given username
+ *
+ * @param username the username
+ * @param uid return location for UID
+ * @returns #TRUE if username existed and we got the UID
+ */
+dbus_bool_t
+_dbus_get_user_id (const DBusString  *username,
+                   dbus_uid_t        *uid)
+{
+  return _dbus_get_user_id_and_primary_group (username, uid, NULL);
+}
 
 /**
- * Gets the credentials corresponding to the given UID.
+ * Gets group ID given groupname
  *
- * @param uid the UID
- * @param credentials credentials to fill in
- * @returns #TRUE if the UID existed and we got some credentials
+ * @param groupname the groupname
+ * @param gid return location for GID
+ * @returns #TRUE if group name existed and we got the GID
  */
 dbus_bool_t
-_dbus_credentials_from_uid (dbus_uid_t        uid,
-                            DBusCredentials  *credentials)
+_dbus_get_group_id (const DBusString  *groupname,
+                    dbus_gid_t        *gid)
 {
   DBusUserDatabase *db;
-  const DBusUserInfo *info;
-  _dbus_user_database_lock_system ();
+  const DBusGroupInfo *info;
+
+  /* FIXME: this can't distinguish ENOMEM from other errors */
+  if (!_dbus_user_database_lock_system ())
+    return FALSE;
 
   db = _dbus_user_database_get_system ();
   if (db == NULL)
@@ -124,63 +174,39 @@ _dbus_credentials_from_uid (dbus_uid_t        uid,
       return FALSE;
     }
 
-  if (!_dbus_user_database_get_uid (db, uid,
-                                    &info, NULL))
+  if (!_dbus_user_database_get_groupname (db, groupname,
+                                          &info, NULL))
     {
       _dbus_user_database_unlock_system ();
       return FALSE;
     }
 
-  _dbus_assert (info->uid == uid);
-  
-  credentials->pid = DBUS_PID_UNSET;
-  credentials->uid = info->uid;
-  credentials->gid = info->primary_gid;
+  *gid = info->gid;
   
   _dbus_user_database_unlock_system ();
   return TRUE;
 }
 
-
 /**
- * Gets user ID given username
+ * Gets user ID and primary group given username
  *
  * @param username the username
- * @param uid return location for UID
- * @returns #TRUE if username existed and we got the UID
+ * @param uid_p return location for UID
+ * @param gid_p return location for GID
+ * @returns #TRUE if username existed and we got the UID and GID
  */
 dbus_bool_t
-_dbus_get_user_id (const DBusString  *username,
-                   dbus_uid_t        *uid)
+_dbus_get_user_id_and_primary_group (const DBusString  *username,
+                                     dbus_uid_t        *uid_p,
+                                     dbus_gid_t        *gid_p)
 {
-  DBusCredentials creds;
-
-  if (!_dbus_credentials_from_username (username, &creds))
-    return FALSE;
+  DBusUserDatabase *db;
+  const DBusUserInfo *info;
 
-  if (creds.uid == DBUS_UID_UNSET)
+  /* FIXME: this can't distinguish ENOMEM from other errors */
+  if (!_dbus_user_database_lock_system ())
     return FALSE;
 
-  *uid = creds.uid;
-
-  return TRUE;
-}
-
-/**
- * Gets group ID given groupname
- *
- * @param groupname the groupname
- * @param gid return location for GID
- * @returns #TRUE if group name existed and we got the GID
- */
-dbus_bool_t
-_dbus_get_group_id (const DBusString  *groupname,
-                    dbus_gid_t        *gid)
-{
-  DBusUserDatabase *db;
-  const DBusGroupInfo *info;
-  _dbus_user_database_lock_system ();
-
   db = _dbus_user_database_get_system ();
   if (db == NULL)
     {
@@ -188,14 +214,17 @@ _dbus_get_group_id (const DBusString  *groupname,
       return FALSE;
     }
 
-  if (!_dbus_user_database_get_groupname (db, groupname,
-                                          &info, NULL))
+  if (!_dbus_user_database_get_username (db, username,
+                                         &info, NULL))
     {
       _dbus_user_database_unlock_system ();
       return FALSE;
     }
 
-  *gid = info->gid;
+  if (uid_p)
+    *uid_p = info->uid;
+  if (gid_p)
+    *gid_p = info->primary_gid;
   
   _dbus_user_database_unlock_system ();
   return TRUE;
@@ -232,9 +261,9 @@ _dbus_user_database_lookup_group (DBusUserDatabase *db,
         gid = n;
     }
 
-
+#ifdef DBUS_ENABLE_USERDB_CACHE
   if (gid != DBUS_GID_UNSET)
-    info = _dbus_hash_table_lookup_ulong (db->groups, gid);
+    info = _dbus_hash_table_lookup_uintptr (db->groups, gid);
   else
     info = _dbus_hash_table_lookup_string (db->groups_by_name,
                                            _dbus_string_get_const_data (groupname));
@@ -245,6 +274,9 @@ _dbus_user_database_lookup_group (DBusUserDatabase *db,
       return info;
     }
   else
+#else
+  if (1)
+#endif
     {
       if (gid != DBUS_GID_UNSET)
        _dbus_verbose ("No cache for GID "DBUS_GID_FORMAT"\n",
@@ -283,7 +315,7 @@ _dbus_user_database_lookup_group (DBusUserDatabase *db,
       gid = DBUS_GID_UNSET;
       groupname = NULL;
 
-      if (!_dbus_hash_table_insert_ulong (db->groups, info->gid, info))
+      if (!_dbus_hash_table_insert_uintptr (db->groups, info->gid, info))
         {
           dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
           _dbus_group_info_free_allocated (info);
@@ -295,7 +327,7 @@ _dbus_user_database_lookup_group (DBusUserDatabase *db,
                                            info->groupname,
                                            info))
         {
-          _dbus_hash_table_remove_ulong (db->groups, info->gid);
+          _dbus_hash_table_remove_uintptr (db->groups, info->gid);
           dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
           return NULL;
         }
@@ -347,45 +379,51 @@ _dbus_user_database_get_gid (DBusUserDatabase     *db,
 
 
 /**
- * Gets all groups for a particular user. Returns #FALSE
+ * Gets all groups  corresponding to the given UID. Returns #FALSE
  * if no memory, or user isn't known, but always initializes
- * group_ids to a NULL array. Sets error to the reason
- * for returning #FALSE.
+ * group_ids to a NULL array. 
  *
- * @param db the user database object
- * @param uid the user ID
+ * @param uid the UID
  * @param group_ids return location for array of group IDs
  * @param n_group_ids return location for length of returned array
- * @param error return location for error
- * @returns #TRUE on success
+ * @returns #TRUE if the UID existed and we got some credentials
  */
 dbus_bool_t
-_dbus_user_database_get_groups (DBusUserDatabase  *db,
-                                dbus_uid_t         uid,
-                                dbus_gid_t       **group_ids,
-                                int               *n_group_ids,
-                                DBusError         *error)
+_dbus_groups_from_uid (dbus_uid_t         uid,
+                       dbus_gid_t       **group_ids,
+                       int               *n_group_ids)
 {
-  DBusUserInfo *info;
-  
-  _DBUS_ASSERT_ERROR_IS_CLEAR (error);
-
+  DBusUserDatabase *db;
+  const DBusUserInfo *info;
   *group_ids = NULL;
   *n_group_ids = 0;
-  
-  info = _dbus_user_database_lookup (db, uid, NULL, error);
-  if (info == NULL)
+
+  /* FIXME: this can't distinguish ENOMEM from other errors */
+  if (!_dbus_user_database_lock_system ())
+    return FALSE;
+
+  db = _dbus_user_database_get_system ();
+  if (db == NULL)
+    {
+      _dbus_user_database_unlock_system ();
+      return FALSE;
+    }
+
+  if (!_dbus_user_database_get_uid (db, uid,
+                                    &info, NULL))
     {
-      _DBUS_ASSERT_ERROR_IS_SET (error);
+      _dbus_user_database_unlock_system ();
       return FALSE;
     }
 
+  _dbus_assert (info->uid == uid);
+  
   if (info->n_group_ids > 0)
     {
       *group_ids = dbus_new (dbus_gid_t, info->n_group_ids);
       if (*group_ids == NULL)
         {
-          dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
+         _dbus_user_database_unlock_system ();
           return FALSE;
         }
 
@@ -394,12 +432,12 @@ _dbus_user_database_get_groups (DBusUserDatabase  *db,
       memcpy (*group_ids, info->group_ids, info->n_group_ids * sizeof (dbus_gid_t));
     }
 
+  _dbus_user_database_unlock_system ();
   return TRUE;
 }
-
 /** @} */
 
-#ifdef DBUS_BUILD_TESTS
+#ifdef DBUS_ENABLE_EMBEDDED_TESTS
 #include <stdio.h>
 
 /**
@@ -412,6 +450,10 @@ _dbus_userdb_test (const char *test_data_dir)
 {
   const DBusString *username;
   const DBusString *homedir;
+  dbus_uid_t uid;
+  unsigned long *group_ids;
+  int n_group_ids, i;
+  DBusError error;
 
   if (!_dbus_username_from_current_process (&username))
     _dbus_assert_not_reached ("didn't get username");
@@ -419,10 +461,33 @@ _dbus_userdb_test (const char *test_data_dir)
   if (!_dbus_homedir_from_current_process (&homedir))
     _dbus_assert_not_reached ("didn't get homedir");  
 
-  printf ("    Current user: %s homedir: %s\n",
+  if (!_dbus_get_user_id (username, &uid))
+    _dbus_assert_not_reached ("didn't get uid");
+
+  if (!_dbus_groups_from_uid (uid, &group_ids, &n_group_ids))
+    _dbus_assert_not_reached ("didn't get groups");
+
+  printf ("    Current user: %s homedir: %s gids:",
           _dbus_string_get_const_data (username),
           _dbus_string_get_const_data (homedir));
-  
+
+  for (i=0; i<n_group_ids; i++)
+      printf(" %ld", group_ids[i]);
+
+  printf ("\n");
+
+  dbus_error_init (&error);
+  printf ("Is Console user: %i\n",
+          _dbus_is_console_user (uid, &error));
+  printf ("Invocation was OK: %s\n", error.message ? error.message : "yes");
+  dbus_error_free (&error);
+  printf ("Is Console user 4711: %i\n",
+          _dbus_is_console_user (4711, &error));
+  printf ("Invocation was OK: %s\n", error.message ? error.message : "yes");
+  dbus_error_free (&error);
+
+  dbus_free (group_ids);
+
   return TRUE;
 }
-#endif /* DBUS_BUILD_TESTS */
+#endif /* DBUS_ENABLE_EMBEDDED_TESTS */