diff options
| author | Havoc Pennington <hp@redhat.com> | 2003-04-17 23:17:04 +0000 | 
|---|---|---|
| committer | Havoc Pennington <hp@redhat.com> | 2003-04-17 23:17:04 +0000 | 
| commit | 88cd5da3c0ec86fed29942b062c2f7bf0f8fda44 (patch) | |
| tree | 9ca9236af208046ed5d6edae99cf62d13237f1d0 | |
| parent | 4219b08bfa318443419c7a3acde28f0b237b05fe (diff) | |
2003-04-17  Havoc Pennington  <hp@redhat.com>
	* dbus/dbus-userdb.c, dbus/dbus-sysdeps.c: redo all the passwd
	database usage so it all goes via the DBusUserDatabase cache.
| -rw-r--r-- | ChangeLog | 5 | ||||
| -rw-r--r-- | dbus/dbus-auth-script.c | 6 | ||||
| -rw-r--r-- | dbus/dbus-auth.c | 11 | ||||
| -rw-r--r-- | dbus/dbus-internals.h | 2 | ||||
| -rw-r--r-- | dbus/dbus-keyring.c | 8 | ||||
| -rw-r--r-- | dbus/dbus-sysdeps.c | 678 | ||||
| -rw-r--r-- | dbus/dbus-sysdeps.h | 56 | ||||
| -rw-r--r-- | dbus/dbus-threads.c | 4 | ||||
| -rw-r--r-- | dbus/dbus-userdb.c | 656 | ||||
| -rw-r--r-- | dbus/dbus-userdb.h | 54 | 
10 files changed, 983 insertions, 497 deletions
| @@ -1,5 +1,10 @@  2003-04-17  Havoc Pennington  <hp@redhat.com> +	* dbus/dbus-userdb.c, dbus/dbus-sysdeps.c: redo all the passwd +	database usage so it all goes via the DBusUserDatabase cache. + +2003-04-17  Havoc Pennington  <hp@redhat.com> +  	* dbus/dbus-mainloop.c (_dbus_loop_iterate): fix logic so that if  	there was an OOM watch we skipped, we always return TRUE so we  	iterate again to have a look at it again. Fixes test suite hang. diff --git a/dbus/dbus-auth-script.c b/dbus/dbus-auth-script.c index b8015c2d..d61ecb59 100644 --- a/dbus/dbus-auth-script.c +++ b/dbus/dbus-auth-script.c @@ -30,6 +30,7 @@  #include "dbus-hash.h"  #include "dbus-internals.h"  #include "dbus-marshal.h" +#include "dbus-userdb.h"  /**   * @defgroup DBusAuthScript code for running unit test scripts for DBusAuth @@ -373,7 +374,8 @@ _dbus_auth_script_run (const DBusString *filename)                      goto out;                    } -                if (!_dbus_string_append_our_uid (&username)) +                if (!_dbus_string_append_uint (&username, +                                               _dbus_getuid ()))                    {                      _dbus_warn ("no memory for userid\n");                      _dbus_string_free (&username); @@ -407,7 +409,7 @@ _dbus_auth_script_run (const DBusString *filename)                      goto out;                    } -                if (!_dbus_user_info_from_current_process (&u, NULL, NULL) || +                if (!_dbus_username_from_current_process (&u) ||                      !_dbus_string_copy (u, 0, &username,                                          _dbus_string_get_length (&username)))                    { diff --git a/dbus/dbus-auth.c b/dbus/dbus-auth.c index 5ee31e52..c585bd08 100644 --- a/dbus/dbus-auth.c +++ b/dbus/dbus-auth.c @@ -26,6 +26,7 @@  #include "dbus-internals.h"  #include "dbus-keyring.h"  #include "dbus-sha.h" +#include "dbus-userdb.h"  /* See doc/dbus-sasl-profile.txt */ @@ -712,8 +713,7 @@ handle_client_initial_response_cookie_sha1_mech (DBusAuth   *auth,    retval = FALSE; -  if (!_dbus_user_info_from_current_process (&username, -                                             NULL, NULL)) +  if (!_dbus_username_from_current_process (&username))      goto out_0;    if (!_dbus_string_base64_encode (username, 0, @@ -1000,8 +1000,8 @@ handle_server_data_external_mech (DBusAuth         *auth,      }    else      { -      if (!_dbus_credentials_from_uid_string (&auth->identity, -                                              &auth->desired_identity)) +      if (!_dbus_uid_from_string (&auth->identity, +                                  &auth->desired_identity.uid))          {            _dbus_verbose ("could not get credentials from uid string\n");            return send_rejected (auth); @@ -1066,7 +1066,8 @@ handle_client_initial_response_external_mech (DBusAuth         *auth,    if (!_dbus_string_init (&plaintext))      return FALSE; -  if (!_dbus_string_append_our_uid (&plaintext)) +  if (!_dbus_string_append_uint (&plaintext, +                                 _dbus_getuid ()))      goto failed;    if (!_dbus_string_base64_encode (&plaintext, 0, diff --git a/dbus/dbus-internals.h b/dbus/dbus-internals.h index 3ffecbda..9eac19c9 100644 --- a/dbus/dbus-internals.h +++ b/dbus/dbus-internals.h @@ -195,9 +195,9 @@ _DBUS_DECLARE_GLOBAL_LOCK (connection_slots);  _DBUS_DECLARE_GLOBAL_LOCK (server_slots);  _DBUS_DECLARE_GLOBAL_LOCK (atomic);  _DBUS_DECLARE_GLOBAL_LOCK (message_handler); -_DBUS_DECLARE_GLOBAL_LOCK (user_info);  _DBUS_DECLARE_GLOBAL_LOCK (bus);  _DBUS_DECLARE_GLOBAL_LOCK (shutdown_funcs); +_DBUS_DECLARE_GLOBAL_LOCK (system_users);  #define _DBUS_N_GLOBAL_LOCKS (8)  dbus_bool_t _dbus_threads_init_debug (void); diff --git a/dbus/dbus-keyring.c b/dbus/dbus-keyring.c index b9203404..85f0a015 100644 --- a/dbus/dbus-keyring.c +++ b/dbus/dbus-keyring.c @@ -22,6 +22,7 @@   */  #include "dbus-keyring.h" +#include "dbus-userdb.h"  #include <dbus/dbus-string.h>  #include <dbus/dbus-list.h>  #include <dbus/dbus-sysdeps.h> @@ -699,10 +700,9 @@ _dbus_keyring_new_homedir (const DBusString *username,    if (username == NULL)      {        const DBusString *const_homedir; -       -      if (!_dbus_user_info_from_current_process (&username, -                                                 &const_homedir, -                                                 NULL)) + +      if (!_dbus_username_from_current_process (&username) || +          !_dbus_homedir_from_current_process (&const_homedir))          goto failed;        if (!_dbus_string_copy (const_homedir, 0, diff --git a/dbus/dbus-sysdeps.c b/dbus/dbus-sysdeps.c index 0877a293..6ff18415 100644 --- a/dbus/dbus-sysdeps.c +++ b/dbus/dbus-sysdeps.c @@ -1310,85 +1310,52 @@ _dbus_string_parse_double (const DBusString *str,   * @addtogroup DBusInternalsUtils   * @{   */ -  static dbus_bool_t -store_user_info (struct passwd    *p, -                 DBusCredentials  *credentials, -                 DBusString       *homedir, -                 DBusString       *username_out, -                 DBusError        *error) +fill_user_info_from_passwd (struct passwd *p, +                            DBusUserInfo  *info, +                            DBusError     *error)  { -  int old_homedir_len; +  _dbus_assert (p->pw_name != NULL); +  _dbus_assert (p->pw_dir != NULL); -  if (credentials != NULL) -    { -      credentials->uid = p->pw_uid; -      credentials->gid = p->pw_gid; -    } - -  old_homedir_len = 0; -  if (homedir != NULL) -    { -      old_homedir_len = _dbus_string_get_length (homedir); -       -      if (!_dbus_string_append (homedir, p->pw_dir)) -        { -          dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); -          return FALSE; -        } -    } +  info->uid = p->pw_uid; +  info->primary_gid = p->pw_gid; +  info->username = _dbus_strdup (p->pw_name); +  info->homedir = _dbus_strdup (p->pw_dir); -  if (username_out && -      !_dbus_string_append (username_out, p->pw_name)) +  if (info->username == NULL || +      info->homedir == NULL)      { -      if (homedir) -        _dbus_string_set_length (homedir, old_homedir_len);        dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);        return FALSE;      } -       -  _dbus_verbose ("Username %s has uid %d gid %d homedir %s\n", -                 p->pw_name, (int) p->pw_uid, (int) p->pw_gid, -                 p->pw_dir);    return TRUE;  } -   -/** - * Gets user info using either username or uid. Only - * one of these may be passed in, either username - * must be #NULL or uid must be < 0. - * - * @param username the username - * @param uid the user ID - * @param credentials to fill in or #NULL - * @param homedir string to append homedir to or #NULL - * @param username_out string to append username to or #NULL - * @param error return location for reason for failure - * - * @returns #TRUE on success - */ +  static dbus_bool_t -get_user_info (const DBusString *username, -               dbus_uid_t        uid, -               DBusCredentials  *credentials, -               DBusString       *homedir, -               DBusString       *username_out, -               DBusError        *error) -{ -  const char *username_c_str; -       +fill_user_info (DBusUserInfo       *info, +                dbus_uid_t          uid, +                const DBusString   *username, +                DBusError          *error) +{ +  const char *username_c; +      /* exactly one of username/uid provided */ -  _dbus_assert (username != NULL || uid >= 0); +  _dbus_assert (username != NULL || uid != DBUS_UID_UNSET);    _dbus_assert (username == NULL || uid == DBUS_UID_UNSET); -  if (credentials) -    _dbus_credentials_clear (credentials); +  info->uid = DBUS_UID_UNSET; +  info->primary_gid = DBUS_GID_UNSET; +  info->group_ids = NULL; +  info->n_group_ids = 0; +  info->username = NULL; +  info->homedir = NULL;    if (username != NULL) -    username_c_str = _dbus_string_get_const_data (username); +    username_c = _dbus_string_get_const_data (username);    else -    username_c_str = NULL; +    username_c = NULL;    /* For now assuming that the getpwnam() and getpwuid() flavors     * are always symmetrical, if not we have to add more configure @@ -1408,26 +1375,26 @@ get_user_info (const DBusString *username,        result = getpwuid_r (uid, &p_str, buf, sizeof (buf),                             &p);      else -      result = getpwnam_r (username_c_str, &p_str, buf, sizeof (buf), +      result = getpwnam_r (username_c, &p_str, buf, sizeof (buf),                             &p);  #else      if (uid >= 0)        p = getpwuid_r (uid, &p_str, buf, sizeof (buf));      else -      p = getpwnam_r (username_c_str, &p_str, buf, sizeof (buf)); +      p = getpwnam_r (username_c, &p_str, buf, sizeof (buf));      result = 0;  #endif /* !HAVE_POSIX_GETPWNAME_R */      if (result == 0 && p == &p_str)        { -        return store_user_info (p, credentials, homedir, -                                username_out, error); +        if (!fill_user_info_from_passwd (p, info, error)) +          return FALSE;        }      else        { -        dbus_set_error (error, DBUS_ERROR_FAILED, +        dbus_set_error (error, _dbus_error_from_errno (errno),                          "User \"%s\" unknown or no memory to allocate password entry\n", -                        username_c_str); -        _dbus_verbose ("User %s unknown\n", username_c_str); +                        username_c ? username_c : "???"); +        _dbus_verbose ("User %s unknown\n", username_c ? username_c : "???");          return FALSE;        }    } @@ -1439,292 +1406,182 @@ get_user_info (const DBusString *username,      if (uid >= 0)        p = getpwuid (uid);      else -      p = getpwnam (username_c_str); +      p = getpwnam (username_c);      if (p != NULL)        { -        return store_user_info (p, credentials, homedir, -                                username_out, error); +        if (!fill_user_info_from_passwd (p, info, error)) +          return FALSE;        }      else        { -        dbus_set_error (error, DBUS_ERROR_FAILED, +        dbus_set_error (error, _dbus_error_from_errno (errno),                          "User \"%s\" unknown or no memory to allocate password entry\n", -                        username_c_str); -        _dbus_verbose ("User %s unknown\n", username_c_str); +                        username_c ? username_c : "???"); +        _dbus_verbose ("User %s unknown\n", username_c ? username_c : "???");          return FALSE;        }    }  #endif  /* ! HAVE_GETPWNAM_R */ -} -/** - * Sets fields in DBusCredentials to DBUS_PID_UNSET, - * DBUS_UID_UNSET, DBUS_GID_UNSET. - * - * @param credentials the credentials object to fill in - */ -void -_dbus_credentials_clear (DBusCredentials *credentials) -{ -  credentials->pid = DBUS_PID_UNSET; -  credentials->uid = DBUS_UID_UNSET; -  credentials->gid = DBUS_GID_UNSET; -} +  /* Fill this in so we can use it to get groups */ +  username_c = info->username; +   +#ifdef HAVE_GETGROUPLIST +  { +    gid_t *buf; +    int buf_count; +    int i; +     +    buf_count = 17; +    buf = dbus_new (gid_t, buf_count); +    if (buf == NULL) +      { +        dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); +        goto failed; +      } +     +    if (getgrouplist (username_c, +                      info->primary_gid, +                      buf, &buf_count) < 0) +      { +        gid_t *new = dbus_realloc (buf, buf_count * sizeof (buf[0])); +        if (new == NULL) +          { +            dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); +            dbus_free (buf); +            goto failed; +          } +         +        buf = new; -/** - * Gets the credentials corresponding to the given username. - * - * @param username the username - * @param credentials credentials to fill in - * @returns #TRUE if the username existed and we got some credentials - */ -dbus_bool_t -_dbus_credentials_from_username (const DBusString *username, -                                 DBusCredentials  *credentials) -{ -  return get_user_info (username, -1, credentials, NULL, NULL, NULL); -} +        getgrouplist (username_c, info->primary_gid, buf, &buf_count); +      } -/** - * 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) -{ -  DBusCredentials creds; +    info->group_ids = dbus_new (dbus_gid_t, buf_count); +    if (info->group_ids == NULL) +      { +        dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); +        dbus_free (buf); +        goto failed; +      } +     +    for (i = 0; i < buf_count; ++i) +      info->group_ids[i] = buf[i]; -  if (!_dbus_credentials_from_username (username, &creds)) -    return FALSE; +    info->n_group_ids = buf_count; +     +    dbus_free (buf); +  } +#else  /* HAVE_GETGROUPLIST */ +  { +    /* We just get the one group ID */ +    info->group_ids = dbus_new (dbus_gid_t, 1); +    if (info->group_ids == NULL) +      { +        dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); +        goto out; +      } -  if (creds.uid == DBUS_UID_UNSET) -    return FALSE; +    info->n_group_ids = 1; -  *uid = creds.uid; +    (info->group_ids)[0] = info->primary_gid; +  } +#endif /* HAVE_GETGROUPLIST */ +  _DBUS_ASSERT_ERROR_IS_CLEAR (error); +      return TRUE; +   + failed: +  _DBUS_ASSERT_ERROR_IS_SET (error); +  _dbus_user_info_free (info); +  return FALSE;  }  /** - * Gets the credentials corresponding to the given user ID. + * Gets user info for the given username.   * - * @param user_id the user ID - * @param credentials credentials to fill in - * @returns #TRUE if the username existed and we got some credentials + * @param info user info object to initialize + * @param username the username + * @param error error return + * @returns #TRUE on success   */  dbus_bool_t -_dbus_credentials_from_user_id (unsigned long     user_id, -                                DBusCredentials  *credentials) -{ -  return get_user_info (NULL, user_id, credentials, NULL, NULL, NULL); -} - -_DBUS_DEFINE_GLOBAL_LOCK (user_info); - -typedef struct -{ -  DBusString name; -  DBusString dir; -  DBusCredentials creds; -} UserInfo; - -static void -shutdown_user_info (void *data) +_dbus_user_info_fill (DBusUserInfo     *info, +                      const DBusString *username, +                      DBusError        *error)  { -  UserInfo *u = data; - -  _dbus_string_free (&u->name); -  _dbus_string_free (&u->dir); +  return fill_user_info (info, DBUS_UID_UNSET, +                         username, error);  }  /** - * Gets information about the user running this process. + * Gets user info for the given user ID.   * - * @param username return location for username or #NULL - * @param homedir return location for home directory or #NULL - * @param credentials return location for credentials or #NULL + * @param info user info object to initialize + * @param username the username + * @param error error return   * @returns #TRUE on success   */  dbus_bool_t -_dbus_user_info_from_current_process (const DBusString      **username, -                                      const DBusString      **homedir, -                                      const DBusCredentials **credentials) +_dbus_user_info_fill_uid (DBusUserInfo *info, +                          dbus_uid_t    uid, +                          DBusError    *error)  { -  static UserInfo u; -  static int initialized_generation = 0; -   -  if (!_DBUS_LOCK (user_info)) -    return FALSE; - -  if (initialized_generation != _dbus_current_generation) -    { -      if (!_dbus_string_init (&u.name)) -        { -          _DBUS_UNLOCK (user_info); -          return FALSE; -        } - -      if (!_dbus_string_init (&u.dir)) -        { -          _dbus_string_free (&u.name); -          _DBUS_UNLOCK (user_info); -          return FALSE; -        } - -      _dbus_credentials_clear (&u.creds); - -      if (!get_user_info (NULL, getuid (), -                          &u.creds, &u.dir, &u.name, NULL)) -        goto fail_init; -       -      if (!_dbus_register_shutdown_func (shutdown_user_info, -                                         &u)) -        goto fail_init; -       -      initialized_generation = _dbus_current_generation; -    fail_init: -      if (initialized_generation != _dbus_current_generation) -        { -          _dbus_string_free (&u.name); -          _dbus_string_free (&u.dir); -          _DBUS_UNLOCK (user_info); -          return FALSE; -        } -    } - -  if (username) -    *username = &u.name; -  if (homedir) -    *homedir = &u.dir; -  if (credentials) -    *credentials = &u.creds; -   -  _DBUS_UNLOCK (user_info); - -  return TRUE; +  return fill_user_info (info, uid, +                         NULL, error);  }  /** - * Gets the home directory for the given user. - * - * @param username the username - * @param homedir string to append home directory to - * @returns #TRUE if user existed and we appended their homedir + * Frees the members of info + * (but not info itself) + * @param info the user info struct   */ -dbus_bool_t -_dbus_homedir_from_username (const DBusString *username, -                             DBusString       *homedir) +void +_dbus_user_info_free (DBusUserInfo *info)  { -  return get_user_info (username, -1, NULL, homedir, NULL, NULL); +  dbus_free (info->group_ids); +  dbus_free (info->username); +  dbus_free (info->homedir);  } -/** - * Gets credentials from a UID string. (Parses a string to a UID - * and converts to a DBusCredentials.) - * - * @param uid_str the UID in string form - * @param credentials credentials to fill in - * @returns #TRUE if successfully filled in some credentials - */ -dbus_bool_t -_dbus_credentials_from_uid_string (const DBusString      *uid_str, -                                   DBusCredentials       *credentials) +static dbus_bool_t +fill_user_info_from_group (struct group  *g, +                           DBusGroupInfo *info, +                           DBusError     *error)  { -  int end; -  long uid; - -  _dbus_credentials_clear (credentials); +  _dbus_assert (g->gr_name != NULL); -  if (_dbus_string_get_length (uid_str) == 0) -    { -      _dbus_verbose ("UID string was zero length\n"); -      return FALSE; -    } +  info->gid = g->gr_gid; +  info->groupname = _dbus_strdup (g->gr_name); -  uid = -1; -  end = 0; -  if (!_dbus_string_parse_int (uid_str, 0, &uid, -                               &end)) -    { -      _dbus_verbose ("could not parse string as a UID\n"); -      return FALSE; -    } +  /* info->members = dbus_strdupv (g->gr_mem) */ -  if (end != _dbus_string_get_length (uid_str)) +  if (info->groupname == NULL)      { -      _dbus_verbose ("string contained trailing stuff after UID\n"); +      dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);        return FALSE;      } -  credentials->uid = uid; -    return TRUE;  } -/** - * Gets the credentials of the current process. - * - * @param credentials credentials to fill in. - */ -void -_dbus_credentials_from_current_process (DBusCredentials *credentials) +static dbus_bool_t +fill_group_info (DBusGroupInfo    *info, +                 dbus_gid_t        gid, +                 const DBusString *groupname, +                 DBusError        *error)  { -  /* The POSIX spec certainly doesn't promise this, but -   * we need these assertions to fail as soon as we're wrong about -   * it so we can do the porting fixups -   */ -  _dbus_assert (sizeof (pid_t) <= sizeof (credentials->pid)); -  _dbus_assert (sizeof (uid_t) <= sizeof (credentials->uid)); -  _dbus_assert (sizeof (gid_t) <= sizeof (credentials->gid)); -   -  credentials->pid = getpid (); -  credentials->uid = getuid (); -  credentials->gid = getgid (); -} +  const char *group_c_str; -/** - * Checks whether the provided_credentials are allowed to log in - * as the expected_credentials. - * - * @param expected_credentials credentials we're trying to log in as - * @param provided_credentials credentials we have - * @returns #TRUE if we can log in - */ -dbus_bool_t -_dbus_credentials_match (const DBusCredentials *expected_credentials, -                         const DBusCredentials *provided_credentials) -{ -  if (provided_credentials->uid == DBUS_UID_UNSET) -    return FALSE; -  else if (expected_credentials->uid == DBUS_UID_UNSET) -    return FALSE; -  else if (provided_credentials->uid == 0) -    return TRUE; -  else if (provided_credentials->uid == expected_credentials->uid) -    return TRUE; -  else -    return FALSE; -} +  _dbus_assert (groupname != NULL || gid != DBUS_GID_UNSET); +  _dbus_assert (groupname == NULL || gid == DBUS_GID_UNSET); -/** - * Gets group ID from group name. - * - * @param group_name name of the group - * @param gid location to store group ID - * @returns #TRUE if group was known - */ -dbus_bool_t -_dbus_get_group_id (const DBusString *group_name, -                    unsigned long    *gid) -{ -  const char *group_c_str; -   -  group_c_str = _dbus_string_get_const_data (group_name); +  if (groupname) +    group_c_str = _dbus_string_get_const_data (groupname); +  else +    group_c_str = NULL;    /* For now assuming that the getgrnam() and getgrgid() flavors     * always correspond to the pwnam flavors, if not we have @@ -1741,20 +1598,25 @@ _dbus_get_group_id (const DBusString *group_name,      g = NULL;  #ifdef HAVE_POSIX_GETPWNAME_R -    result = getgrnam_r (group_c_str, &g_str, buf, sizeof (buf), -                         &g); +    if (group_c_str) +      result = getgrnam_r (group_c_str, &g_str, buf, sizeof (buf), +                           &g); +    else +      result = getgrgid_r (gid, &g_str, buf, sizeof (buf), +                           &g);  #else      p = getgrnam_r (group_c_str, &g_str, buf, sizeof (buf));      result = 0;  #endif /* !HAVE_POSIX_GETPWNAME_R */      if (result == 0 && g == &g_str)        { -        *gid = g->gr_gid; -        return TRUE; +        return fill_user_info_from_group (g, info, error);        }      else        { -        _dbus_verbose ("Group %s unknown\n", group_c_str); +        dbus_set_error (error, _dbus_error_from_errno (errno), +                        "Group %s unknown or failed to look it up\n", +                        group_c_str ? group_c_str : "???");          return FALSE;        }    } @@ -1767,144 +1629,105 @@ _dbus_get_group_id (const DBusString *group_name,      if (g != NULL)        { -        *gid = g->gr_gid; -        return TRUE; +        return fill_user_info_from_group (g, info, error);        }      else        { -        _dbus_verbose ("Group %s unknown\n", group_c_str); +        dbus_set_error (error, _dbus_error_from_errno (errno), +                        "Group %s unknown or failed to look it up\n", +                        group_c_str ? group_c_str : "???");          return FALSE;        }    }  #endif  /* ! HAVE_GETPWNAM_R */  } -/** - * Gets all groups for a particular user. 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. - * - * @param uid the user ID - * @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 - */  dbus_bool_t -_dbus_get_groups (unsigned long   uid, -                  unsigned long **group_ids, -                  int            *n_group_ids, -                  DBusError      *error) +_dbus_group_info_fill (DBusGroupInfo    *info, +                       const DBusString *groupname, +                       DBusError        *error)  { -  DBusCredentials creds; -  DBusString username; -  const char *username_c; -  dbus_bool_t retval; -   -  *group_ids = NULL; -  *n_group_ids = 0; - -  retval = FALSE; - -  if (!_dbus_string_init (&username)) -    { -      dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); -      return FALSE; -    } - -  if (!get_user_info (NULL, uid, &creds, -                      NULL, &username, error) || -      creds.gid == DBUS_GID_UNSET) -    goto out; - -  username_c = _dbus_string_get_const_data (&username); -   -#ifdef HAVE_GETGROUPLIST -  { -    gid_t *buf; -    int buf_count; -    int i; -     -    buf_count = 17; -    buf = dbus_new (gid_t, buf_count); -    if (buf == NULL) -      { -        dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); -        goto out; -      } -     -    if (getgrouplist (username_c, -                      creds.gid, -                      buf, &buf_count) < 0) -      { -        gid_t *new = dbus_realloc (buf, buf_count * sizeof (buf[0])); -        if (new == NULL) -          { -            dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); -            dbus_free (buf); -            goto out; -          } -         -        buf = new; +  return fill_group_info (info, DBUS_GID_UNSET, +                          groupname, error); -        getgrouplist (username_c, creds.gid, buf, &buf_count); -      } - -    *group_ids = dbus_new (unsigned long, buf_count); -    if (*group_ids == NULL) -      { -        dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); -        dbus_free (buf); -        goto out; -      } -     -    for (i = 0; i < buf_count; ++i) -      (*group_ids)[i] = buf[i]; +} -    *n_group_ids = buf_count; -     -    dbus_free (buf); -  } -#else  /* HAVE_GETGROUPLIST */ -  { -    /* We just get the one group ID */ -    *group_ids = dbus_new (unsigned long, 1); -    if (*group_ids == NULL) -      { -        dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); -        goto out; -      } +dbus_bool_t +_dbus_group_info_fill_gid (DBusGroupInfo *info, +                           dbus_gid_t     gid, +                           DBusError     *error) +{ +  return fill_group_info (info, gid, NULL, error); +} -    *n_group_ids = 1; +/** + * Frees the members of info (but not info itself). + * + * @param info the group info + */ +void +_dbus_group_info_free (DBusGroupInfo    *info) +{ +  dbus_free (info->groupname); +} -    (*group_ids)[0] = creds.gid; -  } -#endif /* HAVE_GETGROUPLIST */ -   -  retval = TRUE; -   - out: -  _dbus_string_free (&username); +/** + * Sets fields in DBusCredentials to DBUS_PID_UNSET, + * DBUS_UID_UNSET, DBUS_GID_UNSET. + * + * @param credentials the credentials object to fill in + */ +void +_dbus_credentials_clear (DBusCredentials *credentials) +{ +  credentials->pid = DBUS_PID_UNSET; +  credentials->uid = DBUS_UID_UNSET; +  credentials->gid = DBUS_GID_UNSET; +} -  if (retval) -    _DBUS_ASSERT_ERROR_IS_CLEAR (error); -  else -    _DBUS_ASSERT_ERROR_IS_SET (error); +/** + * Gets the credentials of the current process. + * + * @param credentials credentials to fill in. + */ +void +_dbus_credentials_from_current_process (DBusCredentials *credentials) +{ +  /* The POSIX spec certainly doesn't promise this, but +   * we need these assertions to fail as soon as we're wrong about +   * it so we can do the porting fixups +   */ +  _dbus_assert (sizeof (pid_t) <= sizeof (credentials->pid)); +  _dbus_assert (sizeof (uid_t) <= sizeof (credentials->uid)); +  _dbus_assert (sizeof (gid_t) <= sizeof (credentials->gid)); -  return retval; +  credentials->pid = getpid (); +  credentials->uid = getuid (); +  credentials->gid = getgid ();  }  /** - * Appends the uid of the current process to the given string. + * Checks whether the provided_credentials are allowed to log in + * as the expected_credentials.   * - * @param str the string to append to - * @returns #TRUE on success + * @param expected_credentials credentials we're trying to log in as + * @param provided_credentials credentials we have + * @returns #TRUE if we can log in   */  dbus_bool_t -_dbus_string_append_our_uid (DBusString *str) +_dbus_credentials_match (const DBusCredentials *expected_credentials, +                         const DBusCredentials *provided_credentials)  { -  return _dbus_string_append_uint (str, getuid ()); +  if (provided_credentials->uid == DBUS_UID_UNSET) +    return FALSE; +  else if (expected_credentials->uid == DBUS_UID_UNSET) +    return FALSE; +  else if (provided_credentials->uid == 0) +    return TRUE; +  else if (provided_credentials->uid == expected_credentials->uid) +    return TRUE; +  else +    return FALSE;  }  /** @@ -1917,6 +1740,25 @@ _dbus_getpid (void)    return getpid ();  } +/** Gets our UID + * @returns process UID + */ +dbus_uid_t +_dbus_getuid (void) +{ +  return getuid (); +} + +/** Gets our GID + * @returns process GID + */ +dbus_gid_t +_dbus_getgid (void) +{ +  return getgid (); +} + +  _DBUS_DEFINE_GLOBAL_LOCK (atomic);  /** diff --git a/dbus/dbus-sysdeps.h b/dbus/dbus-sysdeps.h index 27f27b58..593496c0 100644 --- a/dbus/dbus-sysdeps.h +++ b/dbus/dbus-sysdeps.h @@ -124,34 +124,50 @@ dbus_bool_t _dbus_send_credentials_unix_socket (int              server_fd,  void        _dbus_credentials_clear                (DBusCredentials       *credentials); -dbus_bool_t _dbus_credentials_from_username        (const DBusString      *username, -                                                    DBusCredentials       *credentials); -dbus_bool_t _dbus_credentials_from_user_id         (dbus_uid_t             user_id, -                                                    DBusCredentials       *credentials); -dbus_bool_t _dbus_credentials_from_uid_string      (const DBusString      *uid_str, -                                                    DBusCredentials       *credentials);  void        _dbus_credentials_from_current_process (DBusCredentials       *credentials);  dbus_bool_t _dbus_credentials_match                (const DBusCredentials *expected_credentials,                                                      const DBusCredentials *provided_credentials); -dbus_bool_t _dbus_get_user_id                    (const DBusString  *username, -                                                  dbus_uid_t        *uid); -dbus_bool_t _dbus_string_append_our_uid (DBusString *str); -dbus_bool_t _dbus_homedir_from_username          (const DBusString       *username, -                                                  DBusString             *homedir); -dbus_bool_t _dbus_user_info_from_current_process (const DBusString      **username, -                                                  const DBusString      **homedir, -                                                  const DBusCredentials **credentials); +typedef struct DBusUserInfo  DBusUserInfo; +typedef struct DBusGroupInfo DBusGroupInfo; + +struct DBusUserInfo +{ +  dbus_uid_t  uid;            /**< UID */ +  dbus_gid_t  primary_gid;    /**< GID */ +  dbus_gid_t *group_ids;      /**< Groups IDs, *including* above primary group */ +  int         n_group_ids;    /**< Size of group IDs array */ +  char       *username;       /**< Username */ +  char       *homedir;        /**< Home directory */ +}; + +struct DBusGroupInfo +{ +  dbus_gid_t  gid;            /**< GID */ +  char       *groupname;      /**< Group name */ +}; + +dbus_bool_t _dbus_user_info_fill     (DBusUserInfo     *info, +                                      const DBusString *username, +                                      DBusError        *error); +dbus_bool_t _dbus_user_info_fill_uid (DBusUserInfo     *info, +                                      dbus_uid_t        uid, +                                      DBusError        *error); +void        _dbus_user_info_free     (DBusUserInfo     *info); + +dbus_bool_t _dbus_group_info_fill     (DBusGroupInfo    *info, +                                       const DBusString *groupname, +                                       DBusError        *error); +dbus_bool_t _dbus_group_info_fill_gid (DBusGroupInfo    *info, +                                       dbus_gid_t        gid, +                                       DBusError        *error); +void        _dbus_group_info_free     (DBusGroupInfo    *info); -dbus_bool_t _dbus_get_group_id (const DBusString  *group_name, -                                dbus_gid_t        *gid); -dbus_bool_t _dbus_get_groups   (dbus_uid_t         uid, -                                dbus_gid_t       **group_ids, -                                int               *n_group_ids, -                                DBusError         *error);  unsigned long _dbus_getpid (void); +dbus_uid_t    _dbus_getuid (void); +dbus_gid_t    _dbus_getgid (void);  typedef int dbus_atomic_t; diff --git a/dbus/dbus-threads.c b/dbus/dbus-threads.c index a573a1ec..07c98973 100644 --- a/dbus/dbus-threads.c +++ b/dbus/dbus-threads.c @@ -226,9 +226,9 @@ init_global_locks (void)      LOCK_ADDR (server_slots),      LOCK_ADDR (atomic),      LOCK_ADDR (message_handler), -    LOCK_ADDR (user_info),      LOCK_ADDR (bus), -    LOCK_ADDR (shutdown_funcs) +    LOCK_ADDR (shutdown_funcs), +    LOCK_ADDR (system_users)  #undef LOCK_ADDR    }; diff --git a/dbus/dbus-userdb.c b/dbus/dbus-userdb.c index 871fa5bd..ad691c57 100644 --- a/dbus/dbus-userdb.c +++ b/dbus/dbus-userdb.c @@ -26,81 +26,547 @@  #include "dbus-internals.h"  #include <string.h> -typedef struct DBusUserEntry DBusUserEntry; - -struct DBusUserEntry -{ -  dbus_uid_t  uid; - -  dbus_gid_t *group_ids; -  int         n_group_ids; -}; -  struct DBusUserDatabase  {    int refcount;    DBusHashTable *users; +  DBusHashTable *groups; +  DBusHashTable *users_by_name; +  DBusHashTable *groups_by_name;  };  static void -free_user_entry (void *data) +free_user_info (void *data)  { -  DBusUserEntry *entry = data; +  DBusUserInfo *info = data; -  if (entry == NULL) /* hash table will pass NULL */ +  if (info == NULL) /* hash table will pass NULL */      return; -  dbus_free (entry->group_ids); -   -  dbus_free (entry); +  _dbus_user_info_free (info); +  dbus_free (info);  } -static DBusUserEntry* +static void +free_group_info (void *data) +{ +  DBusGroupInfo *info = data; + +  if (info == NULL) /* hash table will pass NULL */ +    return; + +  _dbus_group_info_free (info); +  dbus_free (info); +} + +static DBusUserInfo*  _dbus_user_database_lookup (DBusUserDatabase *db,                              dbus_uid_t        uid, +                            const DBusString *username,                              DBusError        *error)  { -  DBusUserEntry *entry; +  DBusUserInfo *info;    _DBUS_ASSERT_ERROR_IS_CLEAR (error); + +  if (uid != DBUS_UID_UNSET) +    info = _dbus_hash_table_lookup_ulong (db->users, uid); +  else +    info = _dbus_hash_table_lookup_string (db->users_by_name, _dbus_string_get_const_data (username)); -  entry = _dbus_hash_table_lookup_ulong (db->users, uid); -  if (entry) -    return entry; +  if (info) +    { +      _dbus_verbose ("Using cache for UID "DBUS_UID_FORMAT" information\n", +                     uid); +      return info; +    } +  else +    { +      _dbus_verbose ("No cache for UID "DBUS_UID_FORMAT"\n", +                     uid); +       +      info = dbus_new0 (DBusUserInfo, 1); +      if (info == NULL) +        { +          dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); +          return NULL; +        } + +      if (!_dbus_user_info_fill_uid (info, uid, error)) +        { +          _DBUS_ASSERT_ERROR_IS_SET (error); +          free_user_info (info); +          return NULL; +        } + +      if (!_dbus_hash_table_insert_ulong (db->users, info->uid, info)) +        { +          dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); +          free_user_info (info); +          return NULL; +        } + +      if (!_dbus_hash_table_insert_string (db->users_by_name, +                                           info->username, +                                           info)) +        { +          _dbus_hash_table_remove_ulong (db->users, info->uid); +          dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); +          return NULL; +        } +       +      return info; +    } +} + +static DBusGroupInfo* +_dbus_user_database_lookup_group (DBusUserDatabase *db, +                                  dbus_gid_t        gid, +                                  const DBusString *groupname, +                                  DBusError        *error) +{ +  DBusGroupInfo *info; + +  _DBUS_ASSERT_ERROR_IS_CLEAR (error); + +  if (gid != DBUS_GID_UNSET) +    info = _dbus_hash_table_lookup_ulong (db->groups, gid);    else +    info = _dbus_hash_table_lookup_string (db->groups_by_name, +                                           _dbus_string_get_const_data (groupname)); +  if (info)      { -      entry = dbus_new0 (DBusUserEntry, 1); -      if (entry == NULL) +      _dbus_verbose ("Using cache for GID "DBUS_GID_FORMAT" information\n", +                     gid); +      return info; +    } +  else +    { +      _dbus_verbose ("No cache for GID "DBUS_GID_FORMAT"\n", +                     gid); +       +      info = dbus_new0 (DBusGroupInfo, 1); +      if (info == NULL)          {            dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);            return NULL;          } -      if (!_dbus_get_groups (uid, &entry->group_ids, &entry->n_group_ids, error)) +      if (!_dbus_group_info_fill_gid (info, gid, error))          {            _DBUS_ASSERT_ERROR_IS_SET (error); -          free_user_entry (entry); +          free_group_info (info);            return NULL;          } -      if (!_dbus_hash_table_insert_ulong (db->users, entry->uid, entry)) +      if (!_dbus_hash_table_insert_ulong (db->groups, info->gid, info))          {            dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); -          free_user_entry (entry); +          free_group_info (info);            return NULL;          } -      return entry; + +      if (!_dbus_hash_table_insert_string (db->groups_by_name, +                                           info->groupname, +                                           info)) +        { +          _dbus_hash_table_remove_ulong (db->groups, info->gid); +          dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); +          return NULL; +        } +       +      return info;      }  } +_DBUS_DEFINE_GLOBAL_LOCK(system_users); +static dbus_bool_t database_locked = FALSE; +static DBusUserDatabase *system_db = NULL; +static DBusString process_username; +static DBusString process_homedir; +       +static void +shutdown_system_db (void *data) +{ +  _dbus_user_database_unref (system_db); +  system_db = NULL; +  _dbus_string_free (&process_username); +  _dbus_string_free (&process_homedir); +} + +static dbus_bool_t +init_system_db (void) +{ +  _dbus_assert (database_locked); +     +  if (system_db == NULL) +    { +      DBusError error; +      const DBusUserInfo *info; +       +      system_db = _dbus_user_database_new (); +      if (system_db == NULL) +        return FALSE; + +      dbus_error_init (&error); + +      if (!_dbus_user_database_get_uid (system_db, +                                        _dbus_getuid (), +                                        &info, +                                        &error)) +        { +          _dbus_user_database_unref (system_db); +          system_db = NULL; +           +          if (dbus_error_has_name (&error, DBUS_ERROR_NO_MEMORY)) +            { +              dbus_error_free (&error); +              return FALSE; +            } +          else +            { +              /* This really should not happen. */ +              _dbus_warn ("Could not get password database information for UID of current process: %s\n", +                          error.message); +              dbus_error_free (&error); +              return FALSE; +            } +        } + +      if (!_dbus_string_init (&process_username)) +        { +          _dbus_user_database_unref (system_db); +          system_db = NULL; +          return FALSE; +        } + +      if (!_dbus_string_init (&process_homedir)) +        { +          _dbus_string_free (&process_username); +          _dbus_user_database_unref (system_db); +          system_db = NULL; +          return FALSE; +        } + +      if (!_dbus_string_append (&process_username, +                                info->username) || +          !_dbus_string_append (&process_homedir, +                                info->homedir) || +          !_dbus_register_shutdown_func (shutdown_system_db, NULL)) +        { +          _dbus_string_free (&process_username); +          _dbus_string_free (&process_homedir); +          _dbus_user_database_unref (system_db); +          system_db = NULL; +          return FALSE; +        } +    } + +  return TRUE; +} +  /**   * @addtogroup DBusInternalsUtils   * @{   */  /** + * Locks global system user database. + */ +void +_dbus_user_database_lock_system (void) +{ +  _DBUS_LOCK (system_users); +  database_locked = TRUE; +} + +/** + * Unlocks global system user database. + */ +void +_dbus_user_database_unlock_system (void) +{ +  database_locked = FALSE; +  _DBUS_UNLOCK (system_users); +} + +/** + * Gets the system global user database; + * must be called with lock held (_dbus_user_database_lock_system()). + * + * @returns the database or #NULL if no memory + */ +DBusUserDatabase* +_dbus_user_database_get_system (void) +{ +  _dbus_assert (database_locked); + +  init_system_db (); +   +  return system_db; +} + +/** + * Gets username of user owning current process.  The returned string + * is valid until dbus_shutdown() is called. + * + * @param username place to store pointer to username + * @returns #FALSE if no memory + */ +dbus_bool_t +_dbus_username_from_current_process (const DBusString **username) +{ +  _dbus_user_database_lock_system (); +  if (!init_system_db ()) +    { +      _dbus_user_database_unlock_system (); +      return FALSE; +    } +  *username = &process_username; +  _dbus_user_database_unlock_system ();   + +  return TRUE; +} + +/** + * Gets homedir of user owning current process.  The returned string + * is valid until dbus_shutdown() is called. + * + * @param homedir place to store pointer to homedir + * @returns #FALSE if no memory + */ +dbus_bool_t +_dbus_homedir_from_current_process (const DBusString  **homedir) +{ +  _dbus_user_database_lock_system (); +  if (!init_system_db ()) +    { +      _dbus_user_database_unlock_system (); +      return FALSE; +    } +  *homedir = &process_homedir; +  _dbus_user_database_unlock_system (); + +  return TRUE; +} + +/** + * 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) +{ +  DBusCredentials creds; + +  if (!_dbus_credentials_from_username (username, &creds)) +    return FALSE; + +  if (creds.uid == DBUS_UID_UNSET) +    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) +    { +      _dbus_user_database_unlock_system (); +      return FALSE; +    } + +  if (!_dbus_user_database_get_groupname (db, groupname, +                                          &info, NULL)) +    { +      _dbus_user_database_unlock_system (); +      return FALSE; +    } + +  *gid = info->gid; +   +  _dbus_user_database_unlock_system (); +  return TRUE; +} + +/** + * Gets the home directory for the given user. + * + * @param username the username + * @param homedir string to append home directory to + * @returns #TRUE if user existed and we appended their homedir + */ +dbus_bool_t +_dbus_homedir_from_username (const DBusString *username, +                             DBusString       *homedir) +{ +  DBusUserDatabase *db; +  const DBusUserInfo *info; +  _dbus_user_database_lock_system (); + +  db = _dbus_user_database_get_system (); +  if (db == NULL) +    { +      _dbus_user_database_unlock_system (); +      return FALSE; +    } + +  if (!_dbus_user_database_get_username (db, username, +                                         &info, NULL)) +    { +      _dbus_user_database_unlock_system (); +      return FALSE; +    } + +  if (!_dbus_string_append (homedir, info->homedir)) +    { +      _dbus_user_database_unlock_system (); +      return FALSE; +    } +   +  _dbus_user_database_unlock_system (); +  return TRUE; +} + +/** + * Gets a UID from a UID string. + * + * @param uid_str the UID in string form + * @param uid UID to fill in + * @returns #TRUE if successfully filled in UID + */ +dbus_bool_t +_dbus_uid_from_string (const DBusString      *uid_str, +                       dbus_uid_t            *uid) +{ +  int end; +  long val; +   +  if (_dbus_string_get_length (uid_str) == 0) +    { +      _dbus_verbose ("UID string was zero length\n"); +      return FALSE; +    } + +  val = -1; +  end = 0; +  if (!_dbus_string_parse_int (uid_str, 0, &val, +                               &end)) +    { +      _dbus_verbose ("could not parse string as a UID\n"); +      return FALSE; +    } +   +  if (end != _dbus_string_get_length (uid_str)) +    { +      _dbus_verbose ("string contained trailing stuff after UID\n"); +      return FALSE; +    } + +  *uid = val; + +  return TRUE; +} + +/** + * Gets the credentials corresponding to the given username. + * + * @param username the username + * @param credentials credentials to fill in + * @returns #TRUE if the username existed and we got some credentials + */ +dbus_bool_t +_dbus_credentials_from_username (const DBusString *username, +                                 DBusCredentials  *credentials) +{ +  DBusUserDatabase *db; +  const DBusUserInfo *info; +  _dbus_user_database_lock_system (); + +  db = _dbus_user_database_get_system (); +  if (db == NULL) +    { +      _dbus_user_database_unlock_system (); +      return FALSE; +    } + +  if (!_dbus_user_database_get_username (db, username, +                                         &info, NULL)) +    { +      _dbus_user_database_unlock_system (); +      return FALSE; +    } + +  credentials->pid = DBUS_PID_UNSET; +  credentials->uid = info->uid; +  credentials->gid = info->primary_gid; +   +  _dbus_user_database_unlock_system (); +  return TRUE; +} + +/** + * Gets the credentials corresponding to the given UID. + * + * @param uid the UID + * @param credentials credentials to fill in + * @returns #TRUE if the UID existed and we got some credentials + */ +dbus_bool_t +_dbus_credentials_from_uid (dbus_uid_t        uid, +                            DBusCredentials  *credentials) +{ +  DBusUserDatabase *db; +  const DBusUserInfo *info; +  _dbus_user_database_lock_system (); + +  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_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; +   +  _dbus_user_database_unlock_system (); +  return TRUE; +} + +/**   * Creates a new user database object used to look up and   * cache user information.   * @returns new database, or #NULL on out of memory @@ -117,10 +583,26 @@ _dbus_user_database_new (void)    db->refcount = 1;    db->users = _dbus_hash_table_new (DBUS_HASH_ULONG, -                                    NULL, free_user_entry); - +                                    NULL, free_user_info); +      if (db->users == NULL)      goto failed; + +  db->groups = _dbus_hash_table_new (DBUS_HASH_ULONG, +                                     NULL, free_group_info); +   +  if (db->groups == NULL) +    goto failed; + +  db->users_by_name = _dbus_hash_table_new (DBUS_HASH_STRING, +                                            NULL, NULL); +  if (db->users_by_name == NULL) +    goto failed; +   +  db->groups_by_name = _dbus_hash_table_new (DBUS_HASH_STRING, +                                             NULL, NULL); +  if (db->groups_by_name == NULL) +    goto failed;    return db; @@ -155,6 +637,15 @@ _dbus_user_database_unref (DBusUserDatabase  *db)      {        if (db->users)          _dbus_hash_table_unref (db->users); + +      if (db->groups) +        _dbus_hash_table_unref (db->groups); + +      if (db->users_by_name) +        _dbus_hash_table_unref (db->users_by_name); + +      if (db->groups_by_name) +        _dbus_hash_table_unref (db->groups_by_name);        dbus_free (db);      } @@ -180,37 +671,116 @@ _dbus_user_database_get_groups (DBusUserDatabase  *db,                                  int               *n_group_ids,                                  DBusError         *error)  { -  DBusUserEntry *entry; +  DBusUserInfo *info;    _DBUS_ASSERT_ERROR_IS_CLEAR (error);    *group_ids = NULL;    *n_group_ids = 0; -  entry = _dbus_user_database_lookup (db, uid, error); -  if (entry == NULL) +  info = _dbus_user_database_lookup (db, uid, NULL, error); +  if (info == NULL)      {        _DBUS_ASSERT_ERROR_IS_SET (error);        return FALSE;      } -  if (entry->n_group_ids > 0) +  if (info->n_group_ids > 0)      { -      *group_ids = dbus_new (dbus_gid_t, entry->n_group_ids); +      *group_ids = dbus_new (dbus_gid_t, info->n_group_ids);        if (*group_ids == NULL)          {            dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);            return FALSE;          } -      *n_group_ids = entry->n_group_ids; +      *n_group_ids = info->n_group_ids; -      memcpy (*group_ids, entry->group_ids, entry->n_group_ids * sizeof (dbus_gid_t)); +      memcpy (*group_ids, info->group_ids, info->n_group_ids * sizeof (dbus_gid_t));      }    return TRUE;  } +/** + * Gets the user information for the given UID, + * returned user info should not be freed.  + * + * @param db user database + * @param uid the user ID + * @param info return location for const ref to user info + * @param error error location + * @returns #FALSE if error is set + */ +dbus_bool_t +_dbus_user_database_get_uid (DBusUserDatabase    *db, +                             dbus_uid_t           uid, +                             const DBusUserInfo **info, +                             DBusError           *error) +{ +  *info = _dbus_user_database_lookup (db, uid, NULL, error); +  return *info != NULL; +} + +/** + * Gets the user information for the given GID, + * returned group info should not be freed.  + * + * @param db user database + * @param gid the group ID + * @param info return location for const ref to group info + * @param error error location + * @returns #FALSE if error is set + */ +dbus_bool_t +_dbus_user_database_get_gid (DBusUserDatabase     *db, +                             dbus_gid_t            gid, +                             const DBusGroupInfo **info, +                             DBusError            *error) +{ +  *info = _dbus_user_database_lookup_group (db, gid, NULL, error); +  return *info != NULL; +} + +/** + * Gets the user information for the given username. + * + * @param db user database + * @param username the user name + * @param info return location for const ref to user info + * @param error error location + * @returns #FALSE if error is set + */ +dbus_bool_t +_dbus_user_database_get_username  (DBusUserDatabase     *db, +                                   const DBusString     *username, +                                   const DBusUserInfo  **info, +                                   DBusError            *error) +{ +  *info = _dbus_user_database_lookup (db, DBUS_UID_UNSET, username, error); +  return *info != NULL; +} + +/** + * Gets the user information for the given group name, + * returned group info should not be freed.  + * + * @param db user database + * @param groupname the group name + * @param info return location for const ref to group info + * @param error error location + * @returns #FALSE if error is set + */ +dbus_bool_t +_dbus_user_database_get_groupname (DBusUserDatabase     *db, +                                   const DBusString     *groupname, +                                   const DBusGroupInfo **info, +                                   DBusError            *error) +{ +  *info = _dbus_user_database_lookup_group (db, DBUS_GID_UNSET, groupname, error); +  return *info != NULL; +} +  /** @} */  #ifdef DBUS_BUILD_TESTS @@ -222,7 +792,19 @@ _dbus_user_database_get_groups (DBusUserDatabase  *db,  dbus_bool_t  _dbus_userdb_test (const char *test_data_dir)  { +  const DBusString *username; +  const DBusString *homedir; + +  if (!_dbus_username_from_current_process (&username)) +    _dbus_assert_not_reached ("didn't get username"); +  if (!_dbus_homedir_from_current_process (&homedir)) +    _dbus_assert_not_reached ("didn't get homedir");   + +  printf ("    Current user: %s homedir: %s\n", +          _dbus_string_get_const_data (username), +          _dbus_string_get_const_data (homedir)); +      return TRUE;  }  #endif /* DBUS_BUILD_TESTS */ diff --git a/dbus/dbus-userdb.h b/dbus/dbus-userdb.h index b1df4588..e277979e 100644 --- a/dbus/dbus-userdb.h +++ b/dbus/dbus-userdb.h @@ -30,14 +30,52 @@ DBUS_BEGIN_DECLS;  typedef struct DBusUserDatabase DBusUserDatabase; -DBusUserDatabase* _dbus_user_database_new        (void); -void              _dbus_user_database_ref        (DBusUserDatabase  *db); -void              _dbus_user_database_unref      (DBusUserDatabase  *db); -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); +DBusUserDatabase* _dbus_user_database_new           (void); +void              _dbus_user_database_ref           (DBusUserDatabase     *db); +void              _dbus_user_database_unref         (DBusUserDatabase     *db); +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_bool_t       _dbus_user_database_get_uid       (DBusUserDatabase     *db, +                                                     dbus_uid_t            uid, +                                                     const DBusUserInfo  **info, +                                                     DBusError            *error); +dbus_bool_t       _dbus_user_database_get_gid       (DBusUserDatabase     *db, +                                                     dbus_gid_t            gid, +                                                     const DBusGroupInfo **info, +                                                     DBusError            *error); +dbus_bool_t       _dbus_user_database_get_username  (DBusUserDatabase     *db, +                                                     const DBusString     *username, +                                                     const DBusUserInfo  **info, +                                                     DBusError            *error); +dbus_bool_t       _dbus_user_database_get_groupname (DBusUserDatabase     *db, +                                                     const DBusString     *groupname, +                                                     const DBusGroupInfo **info, +                                                     DBusError            *error); + + + +DBusUserDatabase* _dbus_user_database_get_system    (void); +void              _dbus_user_database_lock_system   (void); +void              _dbus_user_database_unlock_system (void); + +dbus_bool_t _dbus_username_from_current_process (const DBusString **username); +dbus_bool_t _dbus_homedir_from_current_process  (const DBusString **homedir); +dbus_bool_t _dbus_homedir_from_username         (const DBusString  *username, +                                                 DBusString        *homedir); +dbus_bool_t _dbus_get_user_id                   (const DBusString  *username, +                                                 dbus_uid_t        *uid); +dbus_bool_t _dbus_get_group_id                  (const DBusString  *group_name, +                                                 dbus_gid_t        *gid); +dbus_bool_t _dbus_uid_from_string               (const DBusString  *uid_str, +                                                 dbus_uid_t        *uid); +dbus_bool_t _dbus_credentials_from_username     (const DBusString  *username, +                                                 DBusCredentials   *credentials); +dbus_bool_t _dbus_credentials_from_uid          (dbus_uid_t         user_id, +                                                 DBusCredentials   *credentials); +  DBUS_END_DECLS; | 
