diff options
31 files changed, 1360 insertions, 434 deletions
@@ -1,3 +1,22 @@ +2007-06-09  Havoc Pennington  <hp@redhat.com> + +	* bus/dispatch.c (check_get_connection_unix_process_id): adapt +	since sysdeps-unix.h stuff isn't included anymore + +	* bus/bus.c (bus_context_new): use more abstract functions to +	change user, so they can be no-ops on Windows + +	* dbus/dbus-credentials.c, dbus/dbus-credentials.h, +	dbus/dbus-credentials-util.c: new files containing a fully opaque +	DBusCredentials data type to replace the old not opaque one. + +	* configure.in (DBUS_UNIX): define DBUS_UNIX to match DBUS_WIN on +	windows + +	* dbus/dbus-userdb.h: prohibit on Windows, next step is to clean +	up the uses of it in bus/*.c and factor out the parts of  +	cookie auth that depend on it +	  2007-06-07  Havoc Pennington  <hp@redhat.com>  	* dbus/dbus-message.c: improve some docs related to reading values @@ -533,7 +533,6 @@ bus_context_new (const DBusString *config_file,  {    BusContext *context;    BusConfigParser *parser; -  DBusCredentials creds;    _DBUS_ASSERT_ERROR_IS_CLEAR (error); @@ -660,13 +659,7 @@ bus_context_new (const DBusString *config_file,    /* check user before we fork */    if (context->user != NULL)      { -      DBusString u; - -      _dbus_string_init_const (&u, context->user); - -      if (!_dbus_credentials_from_username (&u, &creds) || -          creds.uid < 0 || -          creds.gid < 0) +      if (!_dbus_verify_daemon_user (context->user))          {            dbus_set_error (error, DBUS_ERROR_FAILED,                            "Could not get UID and GID for username \"%s\"", @@ -769,7 +762,7 @@ bus_context_new (const DBusString *config_file,     */    if (context->user != NULL)      { -      if (!_dbus_change_identity (creds.uid, creds.gid, error)) +      if (!_dbus_change_to_daemon_user (context->user, error))  	{  	  _DBUS_ASSERT_ERROR_IS_SET (error);  	  goto failed; diff --git a/bus/dispatch.c b/bus/dispatch.c index f491ef44..ef75933f 100644 --- a/bus/dispatch.c +++ b/bus/dispatch.c @@ -399,6 +399,10 @@ bus_dispatch_remove_connection (DBusConnection *connection)  #ifdef DBUS_BUILD_TESTS  #include <stdio.h> +#ifdef DBUS_UNIX +#include <sys/types.h> +#include <unistd.h> +#endif  /* This is used to know whether we need to block in order to finish   * sending a message, or whether the initial dbus_connection_send() @@ -1313,7 +1317,7 @@ check_get_connection_unix_process_id (BusContext     *context,             *       cause then we can test that the pid returned matches             *       getppid()             */ -          if (pid != (dbus_uint32_t) _dbus_getpid ()) +          if (pid != (dbus_uint32_t) getpid ())              {                _dbus_assert (dbus_error_is_set (&error));                _dbus_warn ("Result from GetConnectionUnixProcessID is not our own pid\n"); diff --git a/bus/policy.c b/bus/policy.c index 52ae72a4..7782563b 100644 --- a/bus/policy.c +++ b/bus/policy.c @@ -324,13 +324,9 @@ bus_policy_create_client_policy (BusPolicy      *policy,    if (!dbus_connection_get_unix_user (connection, &uid))      { -#ifdef DBUS_WIN_FIXME -      _dbus_verbose ("policy.c: dbus_connection_get_unix_user check disabled under windows\n"); -#else        dbus_set_error (error, DBUS_ERROR_FAILED,                        "No user ID known for connection, cannot determine security policy\n");        goto failed; -#endif      }    if (_dbus_hash_table_get_n_entries (policy->rules_by_uid) > 0) diff --git a/configure.in b/configure.in index 6cbcb9b3..4836342f 100644 --- a/configure.in +++ b/configure.in @@ -1169,6 +1169,8 @@ fi  AC_DEFINE_UNQUOTED(DBUS_SESSION_SOCKET_DIR, "$DBUS_SESSION_SOCKET_DIR", [Where per-session bus puts its sockets])  AC_SUBST(DBUS_SESSION_SOCKET_DIR) +AC_DEFINE_UNQUOTED(DBUS_UNIX, "1", [Defined on UNIX and Linux systems and not on Windows]) +  AC_OUTPUT([  Doxyfile  dbus/dbus-arch-deps.h diff --git a/dbus/Makefile.am b/dbus/Makefile.am index 70d5b371..d27ca6f4 100644 --- a/dbus/Makefile.am +++ b/dbus/Makefile.am @@ -41,6 +41,8 @@ DBUS_LIB_SOURCES=				\  	dbus-bus.c				\  	dbus-connection.c			\  	dbus-connection-internal.h		\ +	dbus-credentials.c			\ +	dbus-credentials.h			\  	dbus-errors.c				\  	dbus-keyring.c				\  	dbus-keyring.h				\ @@ -128,6 +130,7 @@ DBUS_SHARED_SOURCES=				\  ### to be unless they move to DBUS_SHARED_SOURCES later)  DBUS_UTIL_SOURCES=				\  	dbus-auth-util.c			\ +	dbus-credentials-util.c			\  	dbus-mainloop.c				\  	dbus-mainloop.h				\  	dbus-marshal-byteswap-util.c		\ diff --git a/dbus/dbus-auth-script.c b/dbus/dbus-auth-script.c index 3cb86d0f..5aa17d4b 100644 --- a/dbus/dbus-auth-script.c +++ b/dbus/dbus-auth-script.c @@ -28,8 +28,8 @@  #include "dbus-auth.h"  #include "dbus-string.h"  #include "dbus-hash.h" +#include "dbus-credentials.h"  #include "dbus-internals.h" -#include "dbus-userdb.h"  /**   * @defgroup DBusAuthScript code for running unit test scripts for DBusAuth @@ -209,6 +209,29 @@ split_string (DBusString *str)    return array;  } +static void +auth_set_unix_credentials(DBusAuth  *auth, +                          dbus_uid_t uid, +                          dbus_pid_t pid) +{ +  DBusCredentials *credentials; + +  credentials = _dbus_credentials_new (); +  if (credentials == NULL) +    { +      _dbus_warn ("no memory\n"); +      return; +    } +  if (uid != DBUS_UID_UNSET) +    _dbus_credentials_add_unix_uid (credentials, uid); +  if (pid != DBUS_PID_UNSET) +    _dbus_credentials_add_unix_pid (credentials, pid); + +  _dbus_auth_set_credentials (auth, credentials); + +  _dbus_credentials_unref (credentials); +} +  /**   * Runs an "auth script" which is a script for testing the   * authentication protocol. Scripts send and receive data, and then @@ -303,7 +326,7 @@ _dbus_auth_script_run (const DBusString *filename)        else if (_dbus_string_starts_with_c_str (&line,                                                 "CLIENT"))          { -          DBusCredentials creds; +          DBusCredentials *creds;            if (auth != NULL)              { @@ -321,14 +344,31 @@ _dbus_auth_script_run (const DBusString *filename)            /* test ref/unref */            _dbus_auth_ref (auth);            _dbus_auth_unref (auth); + +          creds = _dbus_credentials_new_from_current_process (); +          if (creds == NULL) +            { +              _dbus_warn ("no memory for credentials\n"); +              _dbus_auth_unref (auth); +              auth = NULL; +              goto out; +            } +               +          if (!_dbus_auth_set_credentials (auth, creds)) +            { +              _dbus_warn ("no memory for setting credentials\n"); +              _dbus_auth_unref (auth); +              auth = NULL; +              _dbus_credentials_unref (creds); +              goto out; +            } -          _dbus_credentials_from_current_process (&creds); -          _dbus_auth_set_credentials (auth, &creds); +          _dbus_credentials_unref (creds);          }        else if (_dbus_string_starts_with_c_str (&line,                                                 "SERVER"))          { -          DBusCredentials creds; +          DBusCredentials *creds;            if (auth != NULL)              { @@ -346,9 +386,27 @@ _dbus_auth_script_run (const DBusString *filename)            /* test ref/unref */            _dbus_auth_ref (auth);            _dbus_auth_unref (auth); + +          creds = _dbus_credentials_new_from_current_process (); +          if (creds == NULL) +            { +              _dbus_warn ("no memory for credentials\n"); +              _dbus_auth_unref (auth); +              auth = NULL; +              goto out; +            } +               +          if (!_dbus_auth_set_credentials (auth, creds)) +            { +              _dbus_warn ("no memory for setting credentials\n"); +              _dbus_auth_unref (auth); +              auth = NULL; +              _dbus_credentials_unref (creds); +              goto out; +            } -          _dbus_credentials_from_current_process (&creds); -          _dbus_auth_set_credentials (auth, &creds); +          _dbus_credentials_unref (creds); +            _dbus_auth_set_context (auth, &context);          }        else if (auth == NULL) @@ -360,20 +418,17 @@ _dbus_auth_script_run (const DBusString *filename)        else if (_dbus_string_starts_with_c_str (&line,                                                 "NO_CREDENTIALS"))          { -          DBusCredentials creds = { -1, -1, -1 }; -          _dbus_auth_set_credentials (auth, &creds); +          auth_set_unix_credentials (auth, DBUS_UID_UNSET, DBUS_PID_UNSET);          }        else if (_dbus_string_starts_with_c_str (&line,                                                 "ROOT_CREDENTIALS"))          { -          DBusCredentials creds = { -1, 0, 0 }; -          _dbus_auth_set_credentials (auth, &creds);           +          auth_set_unix_credentials (auth, 0, DBUS_PID_UNSET);          }        else if (_dbus_string_starts_with_c_str (&line,                                                 "SILLY_CREDENTIALS"))          { -          DBusCredentials creds = { -1, 4312, 1232 }; -          _dbus_auth_set_credentials (auth, &creds);           +          auth_set_unix_credentials (auth, 4312, DBUS_PID_UNSET);          }        else if (_dbus_string_starts_with_c_str (&line,                                                 "ALLOWED_MECHS")) @@ -432,8 +487,7 @@ _dbus_auth_script_run (const DBusString *filename)                      goto out;                    } -                if (!_dbus_string_append_uint (&username, -                                               _dbus_getuid ())) +                if (!_dbus_append_desired_identity (&username))                    {                      _dbus_warn ("no memory for userid\n");                      _dbus_string_free (&username); diff --git a/dbus/dbus-auth.c b/dbus/dbus-auth.c index 7ece76e4..b1d57a49 100644 --- a/dbus/dbus-auth.c +++ b/dbus/dbus-auth.c @@ -27,7 +27,7 @@  #include "dbus-keyring.h"  #include "dbus-sha.h"  #include "dbus-protocol.h" -#include "dbus-userdb.h" +#include "dbus-credentials.h"  /**   * @defgroup DBusAuth Authentication @@ -162,13 +162,12 @@ struct DBusAuth                                            *   as.                                            */ -  DBusCredentials credentials;      /**< Credentials read from socket, -                                     * fields may be -1 -                                     */ +  DBusCredentials *credentials;          /**< Credentials read from socket +                                          */ -  DBusCredentials authorized_identity; /**< Credentials that are authorized */ +  DBusCredentials *authorized_identity; /**< Credentials that are authorized */ -  DBusCredentials desired_identity;    /**< Identity client has requested */ +  DBusCredentials *desired_identity;    /**< Identity client has requested */    DBusString context;               /**< Cookie scope */    DBusKeyring *keyring;             /**< Keyring for cookie mechanism. */ @@ -331,10 +330,6 @@ _dbus_auth_new (int size)      return NULL;    auth->refcount = 1; - -  _dbus_credentials_clear (&auth->credentials); -  _dbus_credentials_clear (&auth->authorized_identity); -  _dbus_credentials_clear (&auth->desired_identity);    auth->keyring = NULL;    auth->cookie_id = -1; @@ -365,9 +360,31 @@ _dbus_auth_new (int size)    /* default context if none is specified */    if (!_dbus_string_append (&auth->context, "org_freedesktop_general"))      goto enomem_5; + +  auth->credentials = _dbus_credentials_new (); +  if (auth->credentials == NULL) +    goto enomem_6; +   +  auth->authorized_identity = _dbus_credentials_new (); +  if (auth->authorized_identity == NULL) +    goto enomem_7; + +  auth->desired_identity = _dbus_credentials_new (); +  if (auth->desired_identity == NULL) +    goto enomem_8;    return auth; +#if 0 + enomem_9: +  _dbus_credentials_unref (auth->desired_identity); +#endif + enomem_8: +  _dbus_credentials_unref (auth->authorized_identity); + enomem_7: +  _dbus_credentials_unref (auth->credentials); + enomem_6: + /* last alloc was an append to context, which is freed already below */ ;   enomem_5:    _dbus_string_free (&auth->challenge);   enomem_4: @@ -390,8 +407,8 @@ shutdown_mech (DBusAuth *auth)    auth->already_asked_for_initial_response = FALSE;    _dbus_string_set_length (&auth->identity, 0); -  _dbus_credentials_clear (&auth->authorized_identity); -  _dbus_credentials_clear (&auth->desired_identity); +  _dbus_credentials_clear (auth->authorized_identity); +  _dbus_credentials_clear (auth->desired_identity);    if (auth->mech != NULL)      { @@ -513,7 +530,7 @@ sha1_handle_first_client_response (DBusAuth         *auth,          }      } -  if (!_dbus_credentials_from_username (data, &auth->desired_identity)) +  if (!_dbus_credentials_add_from_username (auth->desired_identity, data))      {        _dbus_verbose ("%s: Did not get a valid username from client\n",                       DBUS_AUTH_NAME (auth)); @@ -706,14 +723,17 @@ sha1_handle_second_client_response (DBusAuth         *auth,          retval = TRUE;        goto out_3;      } -       + +  if (!_dbus_credentials_add_credentials (auth->authorized_identity, +                                          auth->desired_identity)) +    goto out_3; +      if (!send_ok (auth))      goto out_3; -  _dbus_verbose ("%s: authenticated client with UID "DBUS_UID_FORMAT" using DBUS_COOKIE_SHA1\n", -                 DBUS_AUTH_NAME (auth), auth->desired_identity.uid); +  _dbus_verbose ("%s: authenticated client using DBUS_COOKIE_SHA1\n", +                 DBUS_AUTH_NAME (auth)); -  auth->authorized_identity = auth->desired_identity;    retval = TRUE;   out_3: @@ -966,7 +986,7 @@ static dbus_bool_t  handle_server_data_external_mech (DBusAuth         *auth,                                    const DBusString *data)  { -  if (auth->credentials.uid == DBUS_UID_UNSET) +  if (_dbus_credentials_are_empty (auth->credentials))      {        _dbus_verbose ("%s: no credentials, mechanism EXTERNAL can't authenticate\n",                       DBUS_AUTH_NAME (auth)); @@ -1005,7 +1025,7 @@ handle_server_data_external_mech (DBusAuth         *auth,          return FALSE;      } -  _dbus_credentials_clear (&auth->desired_identity); +  _dbus_credentials_clear (auth->desired_identity);    /* If auth->identity is still empty here, then client     * responded with an empty string after we poked it for @@ -1014,12 +1034,16 @@ handle_server_data_external_mech (DBusAuth         *auth,     */    if (_dbus_string_get_length (&auth->identity) == 0)      { -      auth->desired_identity.uid = auth->credentials.uid; +      if (!_dbus_credentials_add_credentials (auth->desired_identity, +                                              auth->credentials)) +        { +          return FALSE; /* OOM */ +        }      }    else      { -      if (!_dbus_parse_uid (&auth->identity, -                            &auth->desired_identity.uid)) +      if (!_dbus_credentials_parse_and_add_desired(auth->desired_identity, +                                                   &auth->identity))          {            _dbus_verbose ("%s: could not get credentials from uid string\n",                           DBUS_AUTH_NAME (auth)); @@ -1027,7 +1051,7 @@ handle_server_data_external_mech (DBusAuth         *auth,          }      } -  if (auth->desired_identity.uid == DBUS_UID_UNSET) +  if (_dbus_credentials_are_empty(auth->desired_identity))      {        _dbus_verbose ("%s: desired user %s is no good\n",                       DBUS_AUTH_NAME (auth), @@ -1035,32 +1059,34 @@ handle_server_data_external_mech (DBusAuth         *auth,        return send_rejected (auth);      } -  if (_dbus_credentials_match (&auth->desired_identity, -                               &auth->credentials)) +  if (_dbus_credentials_are_superset (auth->credentials, +                                      auth->desired_identity))      { -      /* client has authenticated */       +      /* client has authenticated */ +      if (!_dbus_credentials_add_credentials (auth->authorized_identity, +                                              auth->desired_identity)) +        return FALSE; + +      /* also copy process ID from the socket credentials - FIXME this +       * should be done even if auth EXTERNAL not used +       */ +      if (!_dbus_credentials_add_credential (auth->authorized_identity, +                                             DBUS_CREDENTIAL_UNIX_PROCESS_ID, +                                             auth->credentials)) +        return FALSE; +              if (!send_ok (auth))          return FALSE; -      _dbus_verbose ("%s: authenticated client with UID "DBUS_UID_FORMAT -                     " matching socket credentials UID "DBUS_UID_FORMAT"\n", -                     DBUS_AUTH_NAME (auth), -                     auth->desired_identity.uid, -                     auth->credentials.uid); +      _dbus_verbose ("%s: authenticated client based on socket credentials\n", +                     DBUS_AUTH_NAME (auth)); -      auth->authorized_identity.pid = auth->credentials.pid; -      auth->authorized_identity.uid = auth->desired_identity.uid;        return TRUE;      }    else      { -      _dbus_verbose ("%s: credentials uid="DBUS_UID_FORMAT -                     " gid="DBUS_GID_FORMAT -                     " do not allow uid="DBUS_UID_FORMAT -                     " gid="DBUS_GID_FORMAT"\n", -                     DBUS_AUTH_NAME (auth), -                     auth->credentials.uid, auth->credentials.gid, -                     auth->desired_identity.uid, auth->desired_identity.gid); +      _dbus_verbose ("%s: desired identity not found in socket credentials\n", +                     DBUS_AUTH_NAME (auth));        return send_rejected (auth);      }  } @@ -1084,9 +1110,8 @@ handle_client_initial_response_external_mech (DBusAuth         *auth,    if (!_dbus_string_init (&plaintext))      return FALSE; -   -  if (!_dbus_string_append_uint (&plaintext, -                                 _dbus_getuid ())) + +  if (!_dbus_append_desired_identity (&plaintext))      goto failed;    if (!_dbus_string_hex_encode (&plaintext, 0, @@ -2105,6 +2130,10 @@ _dbus_auth_unref (DBusAuth *auth)        _dbus_string_free (&auth->outgoing);        dbus_free_string_array (auth->allowed_mechs); + +      _dbus_credentials_unref (auth->credentials); +      _dbus_credentials_unref (auth->authorized_identity); +      _dbus_credentials_unref (auth->desired_identity);        dbus_free (auth);      } @@ -2435,29 +2464,42 @@ _dbus_auth_decode_data (DBusAuth         *auth,   *   * @param auth the auth conversation   * @param credentials the credentials received + * @returns #FALSE on OOM   */ -void +dbus_bool_t  _dbus_auth_set_credentials (DBusAuth               *auth, -                            const DBusCredentials  *credentials) +                            DBusCredentials        *credentials)  { -  auth->credentials = *credentials; +  _dbus_credentials_clear (auth->credentials); +  return _dbus_credentials_add_credentials (auth->credentials, +                                            credentials);  }  /**   * Gets the identity we authorized the client as.  Apps may have   * different policies as to what identities they allow.   * + * Returned credentials are not a copy and should not be modified + *   * @param auth the auth conversation - * @param credentials the credentials we've authorized + * @returns the credentials we've authorized BY REFERENCE do not modify   */ -void -_dbus_auth_get_identity (DBusAuth               *auth, -                         DBusCredentials        *credentials) +DBusCredentials* +_dbus_auth_get_identity (DBusAuth               *auth)  {    if (auth->state == &common_state_authenticated) -    *credentials = auth->authorized_identity; +    { +      return auth->authorized_identity; +    }    else -    _dbus_credentials_clear (credentials); +    { +      /* FIXME instead of this, keep an empty credential around that +       * doesn't require allocation or something +       */ +      /* return empty credentials */ +      _dbus_assert (_dbus_credentials_are_empty (auth->authorized_identity)); +      return auth->authorized_identity; +    }  }  /** diff --git a/dbus/dbus-auth.h b/dbus/dbus-auth.h index 9cff8b56..4b6b1065 100644 --- a/dbus/dbus-auth.h +++ b/dbus/dbus-auth.h @@ -68,10 +68,9 @@ dbus_bool_t   _dbus_auth_needs_decoding      (DBusAuth               *auth);  dbus_bool_t   _dbus_auth_decode_data         (DBusAuth               *auth,                                                const DBusString       *encoded,                                                DBusString             *plaintext); -void          _dbus_auth_set_credentials     (DBusAuth               *auth, -                                              const DBusCredentials  *credentials); -void          _dbus_auth_get_identity        (DBusAuth               *auth, +dbus_bool_t   _dbus_auth_set_credentials     (DBusAuth               *auth,                                                DBusCredentials        *credentials); +DBusCredentials* _dbus_auth_get_identity     (DBusAuth               *auth);  dbus_bool_t   _dbus_auth_set_context         (DBusAuth               *auth,                                                const DBusString       *context);  const char*   _dbus_auth_get_guid_from_server(DBusAuth               *auth); diff --git a/dbus/dbus-credentials-util.c b/dbus/dbus-credentials-util.c new file mode 100644 index 00000000..9b81aca4 --- /dev/null +++ b/dbus/dbus-credentials-util.c @@ -0,0 +1,202 @@ +/* -*- mode: C; c-file-style: "gnu" -*- */ +/* dbus-credentials-util.c Would be in dbus-credentials.c, but only used for tests/bus + * + * Copyright (C) 2007 Red Hat Inc. + * + * Licensed under the Academic Free License version 2.1 + *  + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + *  + * 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 + * + */ +#include "dbus-internals.h" +#include "dbus-test.h" +#include "dbus-credentials.h" + +/** + * @addtogroup DBusCredentials + * @{ + */ + +/** @} */ + +#ifdef DBUS_BUILD_TESTS +#include "dbus-test.h" +#include <stdio.h> +#include <string.h> + +static DBusCredentials* +make_credentials(dbus_uid_t  unix_uid, +                 dbus_pid_t  unix_pid, +                 const char *windows_sid) +{ +  DBusCredentials *credentials; + +  credentials = _dbus_credentials_new (); + +  if (unix_uid != DBUS_UID_UNSET) +    { +      if (!_dbus_credentials_add_unix_uid (credentials, unix_uid)) +        { +          _dbus_credentials_unref (credentials); +          return NULL; +        } +    } + +  if (unix_pid != DBUS_PID_UNSET) +    { +      if (!_dbus_credentials_add_unix_pid (credentials, unix_pid)) +        { +          _dbus_credentials_unref (credentials); +          return NULL; +        } +    } + +  if (windows_sid != NULL) +    { +      if (!_dbus_credentials_add_windows_sid (credentials, windows_sid)) +        { +          _dbus_credentials_unref (credentials); +          return NULL; +        } +    } + +  return credentials; +} + +#define SAMPLE_SID "whatever a windows sid looks like" +#define OTHER_SAMPLE_SID "whatever else" + +dbus_bool_t +_dbus_credentials_test (const char *test_data_dir) +{ +  DBusCredentials *creds; +  DBusCredentials *creds2; +   +  if (test_data_dir == NULL) +    return TRUE; + +  creds = make_credentials (12, 511, SAMPLE_SID); +  if (creds == NULL) +    _dbus_assert_not_reached ("oom"); + +  /* test refcounting */ +  _dbus_credentials_ref (creds); +  _dbus_credentials_unref (creds); +   +  _dbus_assert (_dbus_credentials_include (creds, DBUS_CREDENTIAL_UNIX_USER_ID)); +  _dbus_assert (_dbus_credentials_include (creds, DBUS_CREDENTIAL_UNIX_PROCESS_ID)); +  _dbus_assert (_dbus_credentials_include (creds, DBUS_CREDENTIAL_WINDOWS_SID)); + +  _dbus_assert (_dbus_credentials_get_unix_uid (creds) == 12); +  _dbus_assert (_dbus_credentials_get_unix_pid (creds) == 511); +  _dbus_assert (strcmp (_dbus_credentials_get_windows_sid (creds), SAMPLE_SID) == 0); + +  _dbus_assert (!_dbus_credentials_are_empty (creds)); + +  /* Test copy */ +  creds2 = _dbus_credentials_copy (creds); +  if (creds2 == NULL) +    _dbus_assert_not_reached ("oom"); + +  _dbus_assert (_dbus_credentials_include (creds2, DBUS_CREDENTIAL_UNIX_USER_ID)); +  _dbus_assert (_dbus_credentials_include (creds2, DBUS_CREDENTIAL_UNIX_PROCESS_ID)); +  _dbus_assert (_dbus_credentials_include (creds2, DBUS_CREDENTIAL_WINDOWS_SID)); + +  _dbus_assert (_dbus_credentials_get_unix_uid (creds2) == 12); +  _dbus_assert (_dbus_credentials_get_unix_pid (creds2) == 511); +  _dbus_assert (strcmp (_dbus_credentials_get_windows_sid (creds2), SAMPLE_SID) == 0);   + +  _dbus_assert (_dbus_credentials_are_superset (creds, creds2)); +   +  _dbus_credentials_unref (creds2); +   +  /* Same user if both unix and windows are the same */ +  creds2 = make_credentials (12, DBUS_PID_UNSET, SAMPLE_SID); +  if (creds2 == NULL) +    _dbus_assert_not_reached ("oom"); + +  _dbus_assert (_dbus_credentials_same_user (creds, creds2)); + +  _dbus_credentials_unref (creds2); + +  /* Not the same user if Windows is missing */ +  creds2 = make_credentials (12, DBUS_PID_UNSET, NULL); +  if (creds2 == NULL) +    _dbus_assert_not_reached ("oom"); + +  _dbus_assert (!_dbus_credentials_same_user (creds, creds2)); +  _dbus_assert (_dbus_credentials_are_superset (creds, creds2)); +   +  _dbus_credentials_unref (creds2); + +  /* Not the same user if Windows is different */ +  creds2 = make_credentials (12, DBUS_PID_UNSET, OTHER_SAMPLE_SID); +  if (creds2 == NULL) +    _dbus_assert_not_reached ("oom"); + +  _dbus_assert (!_dbus_credentials_same_user (creds, creds2)); +  _dbus_assert (!_dbus_credentials_are_superset (creds, creds2)); +   +  _dbus_credentials_unref (creds2); + +  /* Not the same user if Unix is missing */ +  creds2 = make_credentials (DBUS_UID_UNSET, DBUS_PID_UNSET, SAMPLE_SID); +  if (creds2 == NULL) +    _dbus_assert_not_reached ("oom"); + +  _dbus_assert (!_dbus_credentials_same_user (creds, creds2)); +  _dbus_assert (_dbus_credentials_are_superset (creds, creds2)); +   +  _dbus_credentials_unref (creds2); + +  /* Not the same user if Unix is different */ +  creds2 = make_credentials (15, DBUS_PID_UNSET, SAMPLE_SID); +  if (creds2 == NULL) +    _dbus_assert_not_reached ("oom"); + +  _dbus_assert (!_dbus_credentials_same_user (creds, creds2)); +  _dbus_assert (!_dbus_credentials_are_superset (creds, creds2)); +   +  _dbus_credentials_unref (creds2); + +  /* Not the same user if both are missing */ +  creds2 = make_credentials (DBUS_UID_UNSET, DBUS_PID_UNSET, NULL); +  if (creds2 == NULL) +    _dbus_assert_not_reached ("oom"); + +  _dbus_assert (!_dbus_credentials_same_user (creds, creds2)); +  _dbus_assert (_dbus_credentials_are_superset (creds, creds2)); +   +  _dbus_credentials_unref (creds2); + +  /* Clearing credentials works */ +  _dbus_credentials_clear (creds); + +  _dbus_assert (!_dbus_credentials_include (creds, DBUS_CREDENTIAL_UNIX_USER_ID)); +  _dbus_assert (!_dbus_credentials_include (creds, DBUS_CREDENTIAL_UNIX_PROCESS_ID)); +  _dbus_assert (!_dbus_credentials_include (creds, DBUS_CREDENTIAL_WINDOWS_SID)); + +  _dbus_assert (_dbus_credentials_get_unix_uid (creds) == DBUS_UID_UNSET); +  _dbus_assert (_dbus_credentials_get_unix_pid (creds) == DBUS_PID_UNSET); +  _dbus_assert (_dbus_credentials_get_windows_sid (creds) == NULL); + +  _dbus_assert (_dbus_credentials_are_empty (creds)); + +  _dbus_credentials_unref (creds); +   +  return TRUE; +} + +#endif /* DBUS_BUILD_TESTS */ diff --git a/dbus/dbus-credentials.c b/dbus/dbus-credentials.c new file mode 100644 index 00000000..dde69281 --- /dev/null +++ b/dbus/dbus-credentials.c @@ -0,0 +1,418 @@ +/* -*- mode: C; c-file-style: "gnu" -*- */ +/* dbus-credentials.c Credentials provable through authentication + * + * Copyright (C) 2007 Red Hat Inc. + * + * Licensed under the Academic Free License version 2.1 + *  + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + *  + * 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 + * + */ +#include <config.h> +#include <string.h> +#include "dbus-credentials.h" +#include "dbus-internals.h" + +/** + * @defgroup DBusCredentials Credentials provable through authentication + * @ingroup  DBusInternals + * @brief DBusCredentials object + * + * Credentials are what you have to prove you have in order to + * authenticate.  The main credentials right now are a unix user + * account, a Windows user account, or a UNIX process ID. + */ + +/** + * @defgroup DBusCredentialsInternals Credentials implementation details + * @ingroup  DBusInternals + * @brief DBusCredentials implementation details + * + * Private details of credentials code. + * + * @{ + */ + +struct DBusCredentials { +  int refcount; +  dbus_uid_t unix_uid; +  dbus_pid_t unix_pid; +  char *windows_sid; +}; + +/** @} */ + +/** + * @addtogroup DBusCredentials + * @{ + */ + +/** + * Creates a new credentials object. + * + * @returns the new object or #NULL if no memory + */ +DBusCredentials* +_dbus_credentials_new (void) +{ +  DBusCredentials *creds; + +  creds = dbus_new (DBusCredentials, 1); +  if (creds == NULL) +    return NULL; +   +  creds->refcount = 1; +  creds->unix_uid = DBUS_UID_UNSET; +  creds->unix_pid = DBUS_PID_UNSET; +  creds->windows_sid = NULL; + +  return creds; +} + +/** + * Creates a new object with credentials (user ID and process ID) from the current process. + * @returns the new object or #NULL if no memory + */ +DBusCredentials* +_dbus_credentials_new_from_current_process (void) +{ +  DBusCredentials *creds; + +  creds = _dbus_credentials_new (); +  if (creds == NULL) +    return NULL; + +  if (!_dbus_credentials_add_from_current_process (creds)) +    { +      _dbus_credentials_unref (creds); +      return NULL; +    } +   +  return creds; +} + +/** + * Increment refcount on credentials. + * + * @param credentials the object + */ +void +_dbus_credentials_ref (DBusCredentials *credentials) +{ +  _dbus_assert (credentials->refcount > 0); +  credentials->refcount += 1; +} + +/** + * Decrement refcount on credentials. + * + * @param credentials the object + */ +void +_dbus_credentials_unref (DBusCredentials    *credentials) +{ +  _dbus_assert (credentials->refcount > 0); + +  credentials->refcount -= 1; +  if (credentials->refcount == 0) +    { +      dbus_free (credentials->windows_sid); +      dbus_free (credentials); +    } +} + +/** + * Add a UNIX process ID to the credentials. + * + * @param credentials the object + * @param pid the process ID + * @returns #FALSE if no memory + */ +dbus_bool_t +_dbus_credentials_add_unix_pid (DBusCredentials    *credentials, +                                dbus_pid_t          pid) +{ +  credentials->unix_pid = pid; +  return TRUE; +} + +/** + * Add a UNIX user ID to the credentials. + * + * @param credentials the object + * @param uid the user ID + * @returns #FALSE if no memory + */ +dbus_bool_t +_dbus_credentials_add_unix_uid(DBusCredentials    *credentials, +                               dbus_uid_t          uid) +{ +  credentials->unix_uid = uid; +  return TRUE; + +} + +/** + * Add a Windows user SID to the credentials. + * + * @param credentials the object + * @param windows_sid the user SID + * @returns #FALSE if no memory + */ +dbus_bool_t +_dbus_credentials_add_windows_sid (DBusCredentials    *credentials, +                                   const char         *windows_sid) +{ +  char *copy; + +  copy = _dbus_strdup (windows_sid); +  if (copy == NULL) +    return FALSE; + +  dbus_free (credentials->windows_sid); +  credentials->windows_sid = copy; + +  return TRUE; +} + +/** + * Checks whether the given credential is present. + * + * @param credentials the object + * @param type the credential to check for + * @returns #TRUE if the credential is present + */ +dbus_bool_t +_dbus_credentials_include (DBusCredentials    *credentials, +                           DBusCredentialType  type) +{ +  switch (type) +    { +    case DBUS_CREDENTIAL_UNIX_PROCESS_ID: +      return credentials->unix_pid != DBUS_PID_UNSET; +    case DBUS_CREDENTIAL_UNIX_USER_ID: +      return credentials->unix_uid != DBUS_UID_UNSET; +    case DBUS_CREDENTIAL_WINDOWS_SID: +      return credentials->windows_sid != NULL; +    } + +  _dbus_assert_not_reached ("Unknown credential enum value"); +  return FALSE; +} + +/** + * Gets the UNIX process ID in the credentials, or #DBUS_PID_UNSET if + * the credentials object doesn't contain a process ID. + * + * @param credentials the object + * @returns UNIX process ID + */ +dbus_pid_t +_dbus_credentials_get_unix_pid (DBusCredentials    *credentials) +{ +  return credentials->unix_pid; +} + +/** + * Gets the UNIX user ID in the credentials, or #DBUS_UID_UNSET if + * the credentials object doesn't contain a user ID. + * + * @param credentials the object + * @returns UNIX user ID + */ +dbus_uid_t +_dbus_credentials_get_unix_uid (DBusCredentials    *credentials) +{ +  return credentials->unix_uid; +} + +/** + * Gets the Windows user SID in the credentials, or #NULL if + * the credentials object doesn't contain a Windows user SID. + * + * @param credentials the object + * @returns Windows user SID + */ +const char* +_dbus_credentials_get_windows_sid (DBusCredentials    *credentials) +{ +  return credentials->windows_sid; +} + +/** + * Checks whether the first credentials object contains + * all the credentials found in the second credentials object. + * + * @param credentials the object + * @param possible_subset see if credentials in here are also in the first arg + * @returns #TRUE if second arg is contained in first + */ +dbus_bool_t +_dbus_credentials_are_superset (DBusCredentials    *credentials, +                                DBusCredentials    *possible_subset) +{ +  return +    (possible_subset->unix_pid == DBUS_PID_UNSET || +     possible_subset->unix_pid == credentials->unix_pid) && +    (possible_subset->unix_uid == DBUS_UID_UNSET || +     possible_subset->unix_uid == credentials->unix_uid) && +    (possible_subset->windows_sid == NULL || +     (credentials->windows_sid && strcmp (possible_subset->windows_sid, +                                          credentials->windows_sid) == 0)); +} + +/** + * Checks whether a credentials object contains anything. + *  + * @param credentials the object + * @returns #TRUE if there are no credentials in the object + */ +dbus_bool_t +_dbus_credentials_are_empty (DBusCredentials    *credentials) +{ +  return +    credentials->unix_pid == DBUS_PID_UNSET && +    credentials->unix_uid == DBUS_UID_UNSET && +    credentials->windows_sid == NULL; +} + +/** + * Merge all credentials found in the second object into the first object, + * overwriting the first object if there are any overlaps. + *  + * @param credentials the object + * @param other_credentials credentials to merge + * @returns #FALSE if no memory + */ +dbus_bool_t +_dbus_credentials_add_credentials (DBusCredentials    *credentials, +                                   DBusCredentials    *other_credentials) +{ +  return +    _dbus_credentials_add_credential (credentials, +                                      DBUS_CREDENTIAL_UNIX_PROCESS_ID, +                                      other_credentials) && +    _dbus_credentials_add_credential (credentials, +                                      DBUS_CREDENTIAL_UNIX_USER_ID, +                                      other_credentials) && +    _dbus_credentials_add_credential (credentials, +                                      DBUS_CREDENTIAL_WINDOWS_SID, +                                      other_credentials); +} + +/** + * Merge the given credential found in the second object into the first object, + * overwriting the first object's value for that credential. + * + * Does nothing if the second object does not contain the specified credential. + * i.e., will never delete a credential from the first object. + *  + * @param credentials the object + * @param which the credential to overwrite + * @param other_credentials credentials to merge + * @returns #FALSE if no memory + */ +dbus_bool_t +_dbus_credentials_add_credential (DBusCredentials    *credentials, +                                  DBusCredentialType  which, +                                  DBusCredentials    *other_credentials) +{ +  if (which == DBUS_CREDENTIAL_UNIX_PROCESS_ID && +      other_credentials->unix_pid != DBUS_PID_UNSET) +    { +      if (!_dbus_credentials_add_unix_pid (credentials, other_credentials->unix_pid)) +        return FALSE; +    } +  else if (which == DBUS_CREDENTIAL_UNIX_USER_ID && +           other_credentials->unix_uid != DBUS_UID_UNSET) +    { +      if (!_dbus_credentials_add_unix_uid (credentials, other_credentials->unix_uid)) +        return FALSE; +    } +  else if (which == DBUS_CREDENTIAL_WINDOWS_SID && +           other_credentials->windows_sid != NULL) +    { +      if (!_dbus_credentials_add_windows_sid (credentials, other_credentials->windows_sid)) +        return FALSE; +    } + +  return TRUE; +} + +/** + * Clear all credentials in the object. + *  + * @param credentials the object + */ +void +_dbus_credentials_clear (DBusCredentials    *credentials) +{ +  credentials->unix_pid = DBUS_PID_UNSET; +  credentials->unix_uid = DBUS_UID_UNSET; +  dbus_free (credentials->windows_sid); +  credentials->windows_sid = NULL; +} + +/** + * Copy a credentials object. + *  + * @param credentials the object + * @returns the copy or #NULL + */ +DBusCredentials* +_dbus_credentials_copy (DBusCredentials    *credentials) +{ +  DBusCredentials *copy; + +  copy = _dbus_credentials_new (); +  if (copy == NULL) +    return NULL; + +  if (!_dbus_credentials_add_credentials (copy, credentials)) +    { +      _dbus_credentials_unref (copy); +      return NULL; +    } + +  return copy; +} + +/** + * Check whether the user-identifying credentials in two credentials + * objects are identical. Credentials that are not related to the + * user are ignored, but any kind of user ID credentials must be the + * same (UNIX user ID, Windows user SID, etc.) and present in both + * objects for the function to return #TRUE. + *  + * @param credentials the object + * @param other_credentials credentials to compare + * @returns #TRUE if the two credentials refer to the same user + */ +dbus_bool_t +_dbus_credentials_same_user (DBusCredentials    *credentials, +                             DBusCredentials    *other_credentials) +{ +  /* both windows and unix user must be the same (though pretty much +   * in all conceivable cases, one will be unset) +   */ +  return credentials->unix_uid == other_credentials->unix_uid && +    ((!(credentials->windows_sid || other_credentials->windows_sid)) || +     (credentials->windows_sid && other_credentials->windows_sid && +      strcmp (credentials->windows_sid, other_credentials->windows_sid) == 0)); +} + +/** @} */ + +/* tests in dbus-credentials-util.c */ diff --git a/dbus/dbus-credentials.h b/dbus/dbus-credentials.h new file mode 100644 index 00000000..b47c9c47 --- /dev/null +++ b/dbus/dbus-credentials.h @@ -0,0 +1,71 @@ +/* -*- mode: C; c-file-style: "gnu" -*- */ +/* dbus-credentials.h Credentials provable through authentication + * + * Copyright (C) 2007 Red Hat Inc. + * + * Licensed under the Academic Free License version 2.1 + *  + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + *  + * 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 + * + */ +#ifndef DBUS_CREDENTIALS_H +#define DBUS_CREDENTIALS_H + +#include <dbus/dbus-macros.h> +#include <dbus/dbus-errors.h> +#include <dbus/dbus-string.h> +#include <dbus/dbus-sysdeps.h> + +DBUS_BEGIN_DECLS + +typedef enum { +  DBUS_CREDENTIAL_UNIX_PROCESS_ID, +  DBUS_CREDENTIAL_UNIX_USER_ID, +  DBUS_CREDENTIAL_WINDOWS_SID +} DBusCredentialType; + +DBusCredentials* _dbus_credentials_new_from_current_process (void); +DBusCredentials* _dbus_credentials_new                      (void); +void             _dbus_credentials_ref                      (DBusCredentials    *credentials); +void             _dbus_credentials_unref                    (DBusCredentials    *credentials); +dbus_bool_t      _dbus_credentials_add_unix_pid             (DBusCredentials    *credentials, +                                                             dbus_pid_t          pid); +dbus_bool_t      _dbus_credentials_add_unix_uid             (DBusCredentials    *credentials, +                                                             dbus_uid_t          uid); +dbus_bool_t      _dbus_credentials_add_windows_sid          (DBusCredentials    *credentials, +                                                             const char         *windows_sid); +dbus_bool_t      _dbus_credentials_include                  (DBusCredentials    *credentials, +                                                             DBusCredentialType  type); +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); +dbus_bool_t      _dbus_credentials_are_superset             (DBusCredentials    *credentials, +                                                             DBusCredentials    *possible_subset); +dbus_bool_t      _dbus_credentials_are_empty                (DBusCredentials    *credentials); +dbus_bool_t      _dbus_credentials_add_credentials          (DBusCredentials    *credentials, +                                                             DBusCredentials    *other_credentials); +/* must silently allow 'which' to not exist */ +dbus_bool_t      _dbus_credentials_add_credential           (DBusCredentials    *credentials, +                                                             DBusCredentialType  which, +                                                             DBusCredentials    *other_credentials); +void             _dbus_credentials_clear                    (DBusCredentials    *credentials); +DBusCredentials* _dbus_credentials_copy                     (DBusCredentials    *credentials); +dbus_bool_t      _dbus_credentials_same_user                (DBusCredentials    *credentials, +                                                             DBusCredentials    *other_credentials); + + +DBUS_END_DECLS + +#endif /* DBUS_CREDENTIALS_H */ diff --git a/dbus/dbus-internals.c b/dbus/dbus-internals.c index b0a0f023..86c13324 100644 --- a/dbus/dbus-internals.c +++ b/dbus/dbus-internals.c @@ -271,7 +271,7 @@ _dbus_warn_check_failed(const char *format,    if (!warn_initted)      init_warnings (); -  fprintf (stderr, "process %lu: ", _dbus_getpid ()); +  fprintf (stderr, "process %lu: ", _dbus_pid_for_log ());    va_start (args, format);    vfprintf (stderr, format, args); @@ -349,9 +349,9 @@ _dbus_verbose_real (const char *format,    if (need_pid)      {  #if PTHREAD_IN_VERBOSE -      fprintf (stderr, "%lu: 0x%lx: ", _dbus_getpid (), pthread_self ()); +      fprintf (stderr, "%lu: 0x%lx: ", _dbus_pid_for_log (), pthread_self ());  #else -      fprintf (stderr, "%lu: ", _dbus_getpid ()); +      fprintf (stderr, "%lu: ", _dbus_pid_for_log ());  #endif      } @@ -813,7 +813,7 @@ _dbus_real_assert (dbus_bool_t  condition,    if (_DBUS_UNLIKELY (!condition))      {        _dbus_warn ("%lu: assertion failed \"%s\" file \"%s\" line %d function %s\n", -                  _dbus_getpid (), condition_text, file, line, func); +                  _dbus_pid_for_log (), condition_text, file, line, func);        _dbus_abort ();      }  } @@ -834,7 +834,7 @@ _dbus_real_assert_not_reached (const char *explanation,                                 int         line)  {    _dbus_warn ("File \"%s\" line %d process %lu should not have been reached: %s\n", -              file, line, _dbus_getpid (), explanation); +              file, line, _dbus_pid_for_log (), explanation);    _dbus_abort ();  }  #endif /* DBUS_DISABLE_ASSERT */ diff --git a/dbus/dbus-keyring.c b/dbus/dbus-keyring.c index 018f45af..17c6b179 100644 --- a/dbus/dbus-keyring.c +++ b/dbus/dbus-keyring.c @@ -22,7 +22,6 @@   */  #include "dbus-keyring.h" -#include "dbus-userdb.h"  #include "dbus-protocol.h"  #include <dbus/dbus-string.h>  #include <dbus/dbus-list.h> diff --git a/dbus/dbus-marshal-recursive-util.c b/dbus/dbus-marshal-recursive-util.c index 3d4320d9..bd9949c0 100644 --- a/dbus/dbus-marshal-recursive-util.c +++ b/dbus/dbus-marshal-recursive-util.c @@ -986,7 +986,7 @@ node_read_value (TestTypeNode   *node,                   DBusTypeReader *reader,                   int             seed)  { -  DBusTypeReader restored; +  /* DBusTypeReader restored; */    if (!(* node->klass->read_value) (node, reader, seed))      return FALSE; diff --git a/dbus/dbus-spawn.c b/dbus/dbus-spawn.c index 07535db9..c3be333c 100644 --- a/dbus/dbus-spawn.c +++ b/dbus/dbus-spawn.c @@ -22,7 +22,7 @@   *   */  #include "dbus-spawn.h" -#include "dbus-sysdeps.h" +#include "dbus-sysdeps-unix.h"  #include "dbus-internals.h"  #include "dbus-test.h"  #include "dbus-protocol.h" @@ -849,7 +849,7 @@ do_exec (int                       child_err_report_fd,  #endif    _dbus_verbose_reset (); -  _dbus_verbose ("Child process has PID %lu\n", +  _dbus_verbose ("Child process has PID " DBUS_PID_FORMAT "\n",                   _dbus_getpid ());    if (child_setup) diff --git a/dbus/dbus-sysdeps-unix.c b/dbus/dbus-sysdeps-unix.c index 80732a79..135f7c9f 100644 --- a/dbus/dbus-sysdeps-unix.c +++ b/dbus/dbus-sysdeps-unix.c @@ -31,6 +31,7 @@  #include "dbus-string.h"  #include "dbus-userdb.h"  #include "dbus-list.h" +#include "dbus-credentials.h"  #include <sys/types.h>  #include <stdlib.h>  #include <string.h> @@ -85,6 +86,7 @@ _dbus_open_socket (int              *fd_p,    *fd_p = socket (domain, type, protocol);    if (*fd_p >= 0)      { +      _dbus_verbose ("socket fd %d opened\n", *fd_p);        return TRUE;      }    else @@ -949,11 +951,14 @@ write_credentials_byte (int             server_fd,  /**   * Reads a single byte which must be nul (an error occurs otherwise), - * and reads unix credentials if available. Fills in pid/uid/gid with - * -1 if no credentials are available. Return value indicates whether - * a byte was read, not whether we got valid credentials. On some - * systems, such as Linux, reading/writing the byte isn't actually - * required, but we do it anyway just to avoid multiple codepaths. + * and reads unix credentials if available. Clears the credentials + * object, then adds pid/uid if available, so any previous credentials + * stored in the object are lost. + * + * Return value indicates whether a byte was read, not whether + * we got valid credentials. On some systems, such as Linux, + * reading/writing the byte isn't actually required, but we do it + * anyway just to avoid multiple codepaths.   *    * Fails if no byte is available, so you must select() first.   * @@ -961,19 +966,24 @@ write_credentials_byte (int             server_fd,   * use sendmsg()/recvmsg() to transmit credentials.   *   * @param client_fd the client file descriptor - * @param credentials struct to fill with credentials of client + * @param credentials object to add client credentials to   * @param error location to store error code   * @returns #TRUE on success   */  dbus_bool_t -_dbus_read_credentials_unix_socket  (int              client_fd, -                                     DBusCredentials *credentials, -                                     DBusError       *error) +_dbus_read_credentials_socket  (int              client_fd, +                                DBusCredentials *credentials, +                                DBusError       *error)  {    struct msghdr msg;    struct iovec iov;    char buf; +  dbus_uid_t uid_read; +  dbus_pid_t pid_read; +  uid_read = DBUS_UID_UNSET; +  pid_read = DBUS_PID_UNSET; +    #ifdef HAVE_CMSGCRED     struct {  	  struct cmsghdr hdr; @@ -993,9 +1003,9 @@ _dbus_read_credentials_unix_socket  (int              client_fd,     * 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)); +  _dbus_assert (sizeof (pid_t) <= sizeof (dbus_pid_t)); +  _dbus_assert (sizeof (uid_t) <= sizeof (dbus_uid_t)); +  _dbus_assert (sizeof (gid_t) <= sizeof (dbus_gid_t));    _dbus_credentials_clear (credentials); @@ -1056,9 +1066,8 @@ _dbus_read_credentials_unix_socket  (int              client_fd,      if (getsockopt (client_fd, SOL_SOCKET, SO_PEERCRED, &cr, &cr_len) == 0 &&  	cr_len == sizeof (cr))        { -	credentials->pid = cr.pid; -	credentials->uid = cr.uid; -	credentials->gid = cr.gid; +	pid_read = cr.pid; +	uid_read = cr.uid;        }      else        { @@ -1066,13 +1075,11 @@ _dbus_read_credentials_unix_socket  (int              client_fd,  		       cr_len, (int) sizeof (cr), _dbus_strerror (errno));        }  #elif defined(HAVE_CMSGCRED) -    credentials->pid = cmsg.cred.cmcred_pid; -    credentials->uid = cmsg.cred.cmcred_euid; -    credentials->gid = cmsg.cred.cmcred_groups[0]; +    pid_read = cmsg.cred.cmcred_pid; +    uid_read = cmsg.cred.cmcred_euid;  #elif defined(LOCAL_CREDS) -    credentials->pid = DBUS_PID_UNSET; -    credentials->uid = cmsg.cred.sc_uid; -    credentials->gid = cmsg.cred.sc_gid; +    pid_read = DBUS_PID_UNSET; +    uid_read = cmsg.cred.sc_uid;      /* Since we have already got the credentials from this socket, we can       * disable its LOCAL_CREDS flag if it was ever set. */      _dbus_set_local_creds (client_fd, FALSE); @@ -1081,8 +1088,7 @@ _dbus_read_credentials_unix_socket  (int              client_fd,      gid_t egid;      if (getpeereid (client_fd, &euid, &egid) == 0)        { -        credentials->uid = euid; -        credentials->gid = egid; +        uid_read = euid;        }      else        { @@ -1092,9 +1098,8 @@ _dbus_read_credentials_unix_socket  (int              client_fd,      ucred_t * ucred = NULL;      if (getpeerucred (client_fd, &ucred) == 0)        { -        credentials->pid = ucred_getpid (ucred); -        credentials->uid = ucred_geteuid (ucred); -        credentials->gid = ucred_getegid (ucred); +        pid_read = ucred_getpid (ucred); +        uid_read = ucred_geteuid (ucred);        }      else        { @@ -1110,11 +1115,28 @@ _dbus_read_credentials_unix_socket  (int              client_fd,    _dbus_verbose ("Credentials:"                   "  pid "DBUS_PID_FORMAT                   "  uid "DBUS_UID_FORMAT -                 "  gid "DBUS_GID_FORMAT"\n", -		 credentials->pid, -		 credentials->uid, -		 credentials->gid); -     +                 "\n", +		 pid_read, +		 uid_read); + +  if (pid_read != DBUS_PID_UNSET) +    { +      if (!_dbus_credentials_add_unix_pid (credentials, pid_read)) +        { +          _DBUS_SET_OOM (error); +          return FALSE; +        } +    } + +  if (uid_read != DBUS_UID_UNSET) +    { +      if (!_dbus_credentials_add_unix_uid (credentials, uid_read)) +        { +          _DBUS_SET_OOM (error); +          return FALSE; +        } +    } +      return TRUE;  } @@ -1136,8 +1158,8 @@ _dbus_read_credentials_unix_socket  (int              client_fd,   * @returns #TRUE if the byte was sent   */  dbus_bool_t -_dbus_send_credentials_unix_socket  (int              server_fd, -                                     DBusError       *error) +_dbus_send_credentials_socket  (int              server_fd, +                                DBusError       *error)  {    _DBUS_ASSERT_ERROR_IS_CLEAR (error); @@ -1171,6 +1193,8 @@ _dbus_accept  (int listen_fd)        if (errno == EINTR)          goto retry;      } + +  _dbus_verbose ("client fd %d accepted\n", client_fd);    return client_fd;  } @@ -1446,31 +1470,77 @@ _dbus_user_info_fill_uid (DBusUserInfo *info,  }  /** - * Gets the credentials of the current process. + * Adds the credentials of the current process to the + * passed-in credentials object.   * - * @param credentials credentials to fill in. + * @param credentials credentials to add to + * @returns #FALSE if no memory; does not properly roll back on failure, so only some credentials may have been added   */ -void -_dbus_credentials_from_current_process (DBusCredentials *credentials) +dbus_bool_t +_dbus_credentials_add_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)); -   -  credentials->pid = getpid (); -  credentials->uid = getuid (); -  credentials->gid = getgid (); +  _dbus_assert (sizeof (pid_t) <= sizeof (dbus_pid_t)); +  _dbus_assert (sizeof (uid_t) <= sizeof (dbus_uid_t)); +  _dbus_assert (sizeof (gid_t) <= sizeof (dbus_gid_t)); + +  if (!_dbus_credentials_add_unix_pid(credentials, _dbus_getpid())) +    return FALSE; +  if (!_dbus_credentials_add_unix_uid(credentials, _dbus_getuid())) +    return FALSE; + +  return TRUE; +} + +/** + * Parses a desired identity provided from a client in the auth protocol. + * On UNIX this means parsing a UID. + * + * @todo this is broken because it treats OOM and parse error + * the same way. Needs a #DBusError. + *  + * @param credentials the credentials to add what we parse to + * @param desired_identity the string to parse + * @returns #TRUE if we successfully parsed something + */ +dbus_bool_t +_dbus_credentials_parse_and_add_desired (DBusCredentials  *credentials, +                                         const DBusString *desired_identity) +{ +  dbus_uid_t uid; + +  if (!_dbus_parse_uid (desired_identity, &uid)) +    return FALSE; + +  if (!_dbus_credentials_add_unix_uid (credentials, uid)) +    return FALSE; + +  return TRUE; +} + +/** + * Append to the string the identity we would like to have when we authenticate, + * on UNIX this is the current process UID and on Windows something else. + * No escaping is required, that is done in dbus-auth.c. + *  + * @param str the string to append to + * @returns #FALSE on no memory + */ +dbus_bool_t +_dbus_append_desired_identity (DBusString *str) +{ +  return _dbus_string_append_uint (str, +                                   _dbus_getuid ());  }  /**   * Gets our process ID   * @returns process ID   */ -unsigned long +dbus_pid_t  _dbus_getpid (void)  {    return getpid (); @@ -1485,6 +1555,59 @@ _dbus_getuid (void)    return getuid ();  } +/** + * The only reason this is separate from _dbus_getpid() is to allow it + * on Windows for logging but not for other purposes. + *  + * @returns process ID to put in log messages + */ +unsigned long +_dbus_pid_for_log (void) +{ +  return getpid (); +} + +/** + * 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_parse_uid (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; +} + +  _DBUS_DEFINE_GLOBAL_LOCK (atomic);  #ifdef DBUS_USE_ATOMIC_INT_486 @@ -1717,6 +1840,8 @@ _dbus_file_get_contents (DBusString       *str,        return FALSE;      } +  _dbus_verbose ("file fd %d opened\n", fd); +      if (fstat (fd, &sb) < 0)      {        dbus_set_error (error, _dbus_error_from_errno (errno), @@ -1858,6 +1983,8 @@ _dbus_string_save_to_file (const DBusString *str,        goto out;      } +  _dbus_verbose ("tmp file fd %d opened\n", fd); +      need_unlink = TRUE;    total = 0; @@ -1983,6 +2110,8 @@ _dbus_create_file_exclusively (const DBusString *filename,        return FALSE;      } +  _dbus_verbose ("exclusive file fd %d opened\n", fd); +      if (!_dbus_close (fd, NULL))      {        dbus_set_error (error, @@ -2181,6 +2310,8 @@ _dbus_generate_random_bytes (DBusString *str,    if (fd < 0)      return _dbus_generate_pseudorandom_bytes (str, n_bytes); +  _dbus_verbose ("/dev/urandom fd %d opened\n", fd); +      if (_dbus_read (fd, str, n_bytes) != n_bytes)      {        _dbus_close (fd, NULL); @@ -2571,6 +2702,8 @@ _dbus_get_autolaunch_address (DBusString *address,          /* huh?! can't open /dev/null? */          _exit (1); +      _dbus_verbose ("/dev/null fd %d opened\n", fd); +              /* set-up stdXXX */        close (address_pipe[READ_END]);        close (errors_pipe[READ_END]); @@ -2757,7 +2890,7 @@ _dbus_get_standard_session_servicedirs (DBusList **dirs)    else      {        const DBusString *homedir; -      const DBusString local_share; +      DBusString local_share;        if (!_dbus_homedir_from_current_process (&homedir))          goto oom; diff --git a/dbus/dbus-sysdeps-unix.h b/dbus/dbus-sysdeps-unix.h index f72493a7..58fce9ce 100644 --- a/dbus/dbus-sysdeps-unix.h +++ b/dbus/dbus-sysdeps-unix.h @@ -71,6 +71,63 @@ int _dbus_listen_unix_socket  (const char     *path,                                 dbus_bool_t     abstract,                                 DBusError      *error); +dbus_bool_t _dbus_read_credentials (int               client_fd, +                                    DBusCredentials  *credentials, +                                    DBusError        *error); +dbus_bool_t _dbus_send_credentials (int              server_fd, +                                    DBusError       *error); + +/** Information about a UNIX user */ +typedef struct DBusUserInfo  DBusUserInfo; +/** Information about a UNIX group */ +typedef struct DBusGroupInfo DBusGroupInfo; + +/** + * Information about a UNIX user + */ +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 */ +}; + +/** + * Information about a UNIX group + */ +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_pid_t    _dbus_getpid (void); +dbus_uid_t    _dbus_getuid (void); +dbus_gid_t    _dbus_getgid (void); + +dbus_bool_t _dbus_parse_uid (const DBusString  *uid_str, +                             dbus_uid_t        *uid); +  /** @} */  DBUS_END_DECLS diff --git a/dbus/dbus-sysdeps-util-unix.c b/dbus/dbus-sysdeps-util-unix.c index 5ffc90d9..9963432b 100644 --- a/dbus/dbus-sysdeps-util-unix.c +++ b/dbus/dbus-sysdeps-util-unix.c @@ -243,20 +243,47 @@ _dbus_write_pid_file (const DBusString *filename,    return TRUE;  } +/** + * Verify that after the fork we can successfully change to this user. + * + * @param user the username given in the daemon configuration + * @returns #TRUE if username is valid + */ +dbus_bool_t +_dbus_verify_daemon_user (const char *user) +{ +  DBusString u; + +  _dbus_string_init_const (&u, user); + +  return _dbus_get_user_id_and_primary_group (&u, NULL, NULL); +}  /**   * Changes the user and group the bus is running as.   * - * @param uid the new user ID - * @param gid the new group ID + * @param user the user to become   * @param error return location for errors   * @returns #FALSE on failure   */  dbus_bool_t -_dbus_change_identity  (dbus_uid_t     uid, -                        dbus_gid_t     gid, -                        DBusError     *error) +_dbus_change_to_daemon_user  (const char    *user, +                              DBusError     *error)  { +  dbus_uid_t uid; +  dbus_gid_t gid; +  DBusString u; + +  _dbus_string_init_const (&u, user); +   +  if (!_dbus_get_user_id_and_primary_group (&u, &uid, &gid)) +    { +      dbus_set_error (error, DBUS_ERROR_FAILED, +                      "User '%s' does not appear to exist?", +                      user); +      return FALSE; +    } +      /* setgroups() only works if we are a privileged process,     * so we don't return error on failure; the only possible     * failure is that we don't have perms to do it. diff --git a/dbus/dbus-sysdeps-win.c b/dbus/dbus-sysdeps-win.c index 3b9c8412..0f26ce71 100644 --- a/dbus/dbus-sysdeps-win.c +++ b/dbus/dbus-sysdeps-win.c @@ -42,7 +42,6 @@  #include "dbus-protocol.h"  #include "dbus-hash.h"  #include "dbus-sockets-win.h" -#include "dbus-userdb.h"  #include "dbus-list.h"  #include <windows.h> diff --git a/dbus/dbus-sysdeps.c b/dbus/dbus-sysdeps.c index 8ccdb3ff..cf689bc0 100644 --- a/dbus/dbus-sysdeps.c +++ b/dbus/dbus-sysdeps.c @@ -78,7 +78,7 @@ _dbus_abort (void)    if (s && *s)      {        /* don't use _dbus_warn here since it can _dbus_abort() */ -      fprintf (stderr, "  Process %lu sleeping for gdb attach\n", (unsigned long) _dbus_getpid()); +      fprintf (stderr, "  Process %lu sleeping for gdb attach\n", _dbus_pid_for_log ());        _dbus_sleep_milliseconds (1000 * 180);      } @@ -236,7 +236,8 @@ _dbus_pipe_invalidate (DBusPipe *pipe)  }  /** - * split pathes into a list of char strings  + * Split paths into a list of char strings + *    * @param dirs string with pathes    * @param suffix string concated to each path in dirs   * @param dir_list contains a list of splitted pathes @@ -251,7 +252,7 @@ _dbus_split_paths_and_append (DBusString *dirs,     int i;     int len;     char *cpath; -   const DBusString file_suffix; +   DBusString file_suffix;     start = 0;     i = 0; @@ -770,68 +771,6 @@ _dbus_string_parse_double (const DBusString *str,   * @{   */ -/** - * Frees the members of info - * (but not info itself) - * @param info the user info struct - */ -void -_dbus_user_info_free (DBusUserInfo *info) -{ -  dbus_free (info->group_ids); -  dbus_free (info->username); -  dbus_free (info->homedir); -} - -/** - * 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); -} - -/** - * 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; -} - -/** - * 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; -} -  void  _dbus_generate_pseudorandom_bytes_buffer (char *buffer,                                            int   n_bytes) @@ -929,46 +868,6 @@ _dbus_generate_random_ascii (DBusString *str,  }  /** - * 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_parse_uid (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; -} - -/**   * Converts a UNIX or Windows errno   * into a #DBusError name.   * diff --git a/dbus/dbus-sysdeps.h b/dbus/dbus-sysdeps.h index c89d35f0..f83c17ca 100644 --- a/dbus/dbus-sysdeps.h +++ b/dbus/dbus-sysdeps.h @@ -55,6 +55,9 @@ typedef struct DBusString DBusString;  /** An opaque list type */  typedef struct DBusList DBusList; +/** Object that contains a list of credentials such as UNIX or Windows user ID */ +typedef struct DBusCredentials DBusCredentials; +  /**   * @addtogroup DBusSysdeps   * @@ -151,79 +154,25 @@ int _dbus_listen_tcp_socket   (const char     *host,                                 DBusError      *error);  int _dbus_accept              (int             listen_fd); -/** - * Struct representing socket credentials - */ -typedef struct -{ -  dbus_pid_t pid; /**< process ID or DBUS_PID_UNSET */ -  dbus_uid_t uid; /**< user ID or DBUS_UID_UNSET */ -  dbus_gid_t gid; /**< group ID or DBUS_GID_UNSET */ -} DBusCredentials; - -/* FIXME these read/send credentials should get moved to sysdeps-unix.h, - * or renamed to reflect what they mean cross-platform - */ -dbus_bool_t _dbus_read_credentials_unix_socket (int              client_fd, -                                                DBusCredentials *credentials, -                                                DBusError       *error); -dbus_bool_t _dbus_send_credentials_unix_socket (int              server_fd, -                                                DBusError       *error); - - -void        _dbus_credentials_clear                (DBusCredentials       *credentials); -void        _dbus_credentials_from_current_process (DBusCredentials       *credentials); -dbus_bool_t _dbus_credentials_match                (const DBusCredentials *expected_credentials, -                                                    const DBusCredentials *provided_credentials); - - -/** Information about a UNIX user */ -typedef struct DBusUserInfo  DBusUserInfo; -/** Information about a UNIX group */ -typedef struct DBusGroupInfo DBusGroupInfo; - -/** - * Information about a UNIX user - */ -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 */ -}; - -/** - * Information about a UNIX group - */ -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_read_credentials_socket (int               client_fd, +                                           DBusCredentials  *credentials, +                                           DBusError        *error); +dbus_bool_t _dbus_send_credentials_socket (int              server_fd, +                                           DBusError       *error); -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_credentials_add_from_username        (DBusCredentials  *credentials, +                                                        const DBusString *username); +dbus_bool_t _dbus_credentials_add_from_current_process (DBusCredentials  *credentials); +dbus_bool_t _dbus_credentials_parse_and_add_desired    (DBusCredentials  *credentials, +                                                        const DBusString *desired_identity); +dbus_bool_t _dbus_username_from_current_process (const DBusString **username); +dbus_bool_t _dbus_append_desired_identity       (DBusString *str); -unsigned long _dbus_getpid (void); -dbus_uid_t    _dbus_getuid (void); -dbus_gid_t    _dbus_getgid (void); +dbus_bool_t _dbus_homedir_from_current_process  (const DBusString **homedir); +dbus_bool_t _dbus_homedir_from_username         (const DBusString  *username, +                                                 DBusString        *homedir);  /** Opaque type representing an atomically-modifiable integer   * that can be used from multiple threads. @@ -398,9 +347,9 @@ dbus_bool_t _dbus_become_daemon   (const DBusString *pidfile,  dbus_bool_t _dbus_write_pid_file  (const DBusString *filename,                                     unsigned long     pid,                                     DBusError        *error); -dbus_bool_t _dbus_change_identity (unsigned long     uid, -                                   unsigned long     gid, -                                   DBusError        *error); +dbus_bool_t _dbus_verify_daemon_user    (const char *user); +dbus_bool_t _dbus_change_to_daemon_user (const char *user, +                                         DBusError  *error);  /** A UNIX signal handler */  typedef void (* DBusSignalHandler) (int sig); @@ -446,9 +395,6 @@ dbus_bool_t _dbus_user_at_console (const char *username,        _DBUS_BYTE_OF_PRIMITIVE (a, 6) == _DBUS_BYTE_OF_PRIMITIVE (b, 6) &&       \        _DBUS_BYTE_OF_PRIMITIVE (a, 7) == _DBUS_BYTE_OF_PRIMITIVE (b, 7)) -dbus_bool_t _dbus_parse_uid (const DBusString  *uid_str, -                             dbus_uid_t        *uid); -  dbus_bool_t _dbus_get_autolaunch_address (DBusString *address,   					  DBusError *error); @@ -472,6 +418,8 @@ dbus_bool_t _dbus_split_paths_and_append (DBusString *dirs,                                            const char *suffix,                                             DBusList **dir_list); +unsigned long _dbus_pid_for_log (void); +  /** @} */  DBUS_END_DECLS diff --git a/dbus/dbus-test.c b/dbus/dbus-test.c index 07544622..a1df3604 100644 --- a/dbus/dbus-test.c +++ b/dbus/dbus-test.c @@ -160,6 +160,8 @@ dbus_internal_do_not_use_run_tests (const char *test_data_dir, const char *speci    run_data_test ("spawn", specific_test, _dbus_spawn_test, test_data_dir);  #endif +  run_data_test ("credentials", specific_test, _dbus_credentials_test, test_data_dir); +      run_data_test ("userdb", specific_test, _dbus_userdb_test, test_data_dir);    run_test ("keyring", specific_test, _dbus_keyring_test); diff --git a/dbus/dbus-test.h b/dbus/dbus-test.h index e7c55d92..8619ae73 100644 --- a/dbus/dbus-test.h +++ b/dbus/dbus-test.h @@ -54,6 +54,7 @@ dbus_bool_t _dbus_userdb_test            (const char *test_data_dir);  dbus_bool_t _dbus_memory_test            (void);  dbus_bool_t _dbus_object_tree_test       (void);  dbus_bool_t _dbus_pending_call_test      (const char *test_data_dir); +dbus_bool_t _dbus_credentials_test       (const char *test_data_dir);  void        dbus_internal_do_not_use_run_tests         (const char          *test_data_dir,  							const char          *specific_test); diff --git a/dbus/dbus-transport-protected.h b/dbus/dbus-transport-protected.h index 2b3a6c68..bfdff0e2 100644 --- a/dbus/dbus-transport-protected.h +++ b/dbus/dbus-transport-protected.h @@ -89,7 +89,7 @@ struct DBusTransport    DBusAuth *auth;                             /**< Authentication conversation */ -  DBusCredentials credentials;                /**< Credentials of other end */   +  DBusCredentials *credentials;               /**< Credentials of other end read from the socket */      long max_live_messages_size;                /**< Max total size of received messages. */ diff --git a/dbus/dbus-transport-socket.c b/dbus/dbus-transport-socket.c index 76a6fcfb..3f8c94d5 100644 --- a/dbus/dbus-transport-socket.c +++ b/dbus/dbus-transport-socket.c @@ -26,6 +26,7 @@  #include "dbus-transport-socket.h"  #include "dbus-transport-protected.h"  #include "dbus-watch.h" +#include "dbus-credentials.h"  /** @@ -332,7 +333,8 @@ write_data_from_auth (DBusTransport *transport)    return FALSE;  } -static void +/* FALSE on OOM */ +static dbus_bool_t  exchange_credentials (DBusTransport *transport,                        dbus_bool_t    do_reading,                        dbus_bool_t    do_writing) @@ -346,8 +348,8 @@ exchange_credentials (DBusTransport *transport,    dbus_error_init (&error);    if (do_writing && transport->send_credentials_pending)      { -      if (_dbus_send_credentials_unix_socket (socket_transport->fd, -                                              &error)) +      if (_dbus_send_credentials_socket (socket_transport->fd, +                                         &error))          {            transport->send_credentials_pending = FALSE;          } @@ -361,9 +363,10 @@ exchange_credentials (DBusTransport *transport,    if (do_reading && transport->receive_credentials_pending)      { -      if (_dbus_read_credentials_unix_socket (socket_transport->fd, -                                              &transport->credentials, -                                              &error)) +      /* FIXME this can fail due to IO error _or_ OOM, broken */ +      if (_dbus_read_credentials_socket (socket_transport->fd, +                                         transport->credentials, +                                         &error))          {            transport->receive_credentials_pending = FALSE;          } @@ -378,9 +381,12 @@ exchange_credentials (DBusTransport *transport,    if (!(transport->send_credentials_pending ||          transport->receive_credentials_pending))      { -      _dbus_auth_set_credentials (transport->auth, -                                  &transport->credentials); +      if (!_dbus_auth_set_credentials (transport->auth, +                                       transport->credentials)) +        return FALSE;      } + +  return TRUE;  }  static dbus_bool_t @@ -412,7 +418,12 @@ do_authentication (DBusTransport *transport,    while (!_dbus_transport_get_is_authenticated (transport) &&           _dbus_transport_get_is_connected (transport))      {       -      exchange_credentials (transport, do_reading, do_writing); +      if (!exchange_credentials (transport, do_reading, do_writing)) +        { +          /* OOM */ +          oom = TRUE; +          goto out; +        }        if (transport->send_credentials_pending ||            transport->receive_credentials_pending) @@ -1161,7 +1172,7 @@ _dbus_transport_new_for_socket (int               fd,                                                  NULL, NULL, NULL);    if (socket_transport->read_watch == NULL)      goto failed_3; -   +    if (!_dbus_transport_init_base (&socket_transport->base,                                    &socket_vtable,                                    server_guid, address)) diff --git a/dbus/dbus-transport.c b/dbus/dbus-transport.c index d8d3bb29..e922eb5d 100644 --- a/dbus/dbus-transport.c +++ b/dbus/dbus-transport.c @@ -28,6 +28,7 @@  #include "dbus-watch.h"  #include "dbus-auth.h"  #include "dbus-address.h" +#include "dbus-credentials.h"  #ifdef DBUS_BUILD_TESTS  #include "dbus-server-debug-pipe.h"  #endif @@ -98,6 +99,7 @@ _dbus_transport_init_base (DBusTransport             *transport,    DBusAuth *auth;    DBusCounter *counter;    char *address_copy; +  DBusCredentials *creds;    loader = _dbus_message_loader_new ();    if (loader == NULL) @@ -120,6 +122,15 @@ _dbus_transport_init_base (DBusTransport             *transport,        _dbus_message_loader_unref (loader);        return FALSE;      }   + +  creds = _dbus_credentials_new (); +  if (creds == NULL) +    { +      _dbus_counter_unref (counter); +      _dbus_auth_unref (auth); +      _dbus_message_loader_unref (loader); +      return FALSE; +    }    if (server_guid)      { @@ -132,6 +143,7 @@ _dbus_transport_init_base (DBusTransport             *transport,        if (!_dbus_string_copy_data (address, &address_copy))          { +          _dbus_credentials_unref (creds);            _dbus_counter_unref (counter);            _dbus_auth_unref (auth);            _dbus_message_loader_unref (loader); @@ -161,11 +173,10 @@ _dbus_transport_init_base (DBusTransport             *transport,     * but doesn't impose too much of a limitation.     */    transport->max_live_messages_size = _DBUS_ONE_MEGABYTE * 63; -   -  transport->credentials.pid = -1; -  transport->credentials.uid = -1; -  transport->credentials.gid = -1; +  /* credentials read from socket if any */ +  transport->credentials = creds; +      _dbus_counter_set_notify (transport->live_messages_size,                              transport->max_live_messages_size,                              live_messages_size_notify, @@ -199,6 +210,8 @@ _dbus_transport_finalize_base (DBusTransport *transport)    _dbus_counter_unref (transport->live_messages_size);    dbus_free (transport->address);    dbus_free (transport->expected_guid); +  if (transport->credentials) +    _dbus_credentials_unref (transport->credentials);  } @@ -490,16 +503,7 @@ _dbus_transport_get_is_connected (DBusTransport *transport)   */  dbus_bool_t  _dbus_transport_get_is_authenticated (DBusTransport *transport) -{ -  /* We don't want to run unix_user_function on Windows, but it -   * can exist, which allows application code to just unconditionally -   * set it and have it only be invoked when appropriate. -   */ -  dbus_bool_t on_windows = FALSE; -#ifdef DBUS_WIN -  on_windows = TRUE; -#endif -   +{      if (transport->authenticated)      return TRUE;    else @@ -567,28 +571,36 @@ _dbus_transport_get_is_authenticated (DBusTransport *transport)        if (maybe_authenticated && transport->is_server)          { -          DBusCredentials auth_identity; +          DBusCredentials *auth_identity; -          _dbus_auth_get_identity (transport->auth, &auth_identity); +          auth_identity = _dbus_auth_get_identity (transport->auth); +          _dbus_assert (auth_identity != NULL); -          if (transport->unix_user_function != NULL && !on_windows) +          /* If we have a UNIX user and a unix user function, delegate +           * deciding whether auth credentials are good enough to the app; +           * otherwise, use our default decision process. +           */ +          if (transport->unix_user_function != NULL && +              _dbus_credentials_include (auth_identity, DBUS_CREDENTIAL_UNIX_USER_ID))              {                dbus_bool_t allow;                DBusConnection *connection;                DBusAllowUnixUserFunction unix_user_function;                void *unix_user_data; +              dbus_uid_t uid;                /* Dropping the lock here probably isn't that safe. */                connection = transport->connection;                unix_user_function = transport->unix_user_function;                unix_user_data = transport->unix_user_data; - +              uid = _dbus_credentials_get_unix_uid (auth_identity), +                              _dbus_verbose ("unlock %s\n", _DBUS_FUNCTION_NAME);                _dbus_connection_unlock (connection);                allow = (* unix_user_function) (connection, -                                              auth_identity.uid, +                                              uid,                                                unix_user_data);                _dbus_verbose ("lock %s post unix user function\n", _DBUS_FUNCTION_NAME); @@ -596,13 +608,13 @@ _dbus_transport_get_is_authenticated (DBusTransport *transport)                if (allow)                  { -                  _dbus_verbose ("Client UID "DBUS_UID_FORMAT" authorized\n", auth_identity.uid); +                  _dbus_verbose ("Client UID "DBUS_UID_FORMAT" authorized\n", uid);                  }                else                  {                    _dbus_verbose ("Client UID "DBUS_UID_FORMAT                                   " was rejected, disconnecting\n", -                                 auth_identity.uid); +                                 _dbus_credentials_get_unix_uid (auth_identity));                    _dbus_transport_disconnect (transport);                    _dbus_connection_unref_unlocked (connection);                    return FALSE; @@ -610,25 +622,40 @@ _dbus_transport_get_is_authenticated (DBusTransport *transport)              }            else              { -              DBusCredentials our_identity; +              DBusCredentials *our_identity; + +              /* By default, connection is allowed if the client is +               * 1) root or 2) has the same UID as us +               */ -              _dbus_credentials_from_current_process (&our_identity); +              our_identity = _dbus_credentials_new_from_current_process (); +              if (our_identity == NULL) +                { +                  /* OOM */ +                  _dbus_connection_unref_unlocked (transport->connection); +                  return FALSE; +                } -              if (!_dbus_credentials_match (&our_identity, -                                            &auth_identity)) +              if (_dbus_credentials_get_unix_uid (auth_identity) == 0 || +                  !_dbus_credentials_same_user (our_identity, +                                                auth_identity))                  { +                  /* FIXME the verbose spam here is unix-specific */                    _dbus_verbose ("Client authorized as UID "DBUS_UID_FORMAT                                   " but our UID is "DBUS_UID_FORMAT", disconnecting\n", -                                 auth_identity.uid, our_identity.uid); +                                 _dbus_credentials_get_unix_uid(our_identity), +                                 _dbus_credentials_get_unix_uid(our_identity));                    _dbus_transport_disconnect (transport);                    _dbus_connection_unref_unlocked (transport->connection);                    return FALSE;                  }                else                  { +                  /* FIXME the verbose spam here is unix-specific */                                      _dbus_verbose ("Client authorized as UID "DBUS_UID_FORMAT                                   " matching our UID "DBUS_UID_FORMAT"\n", -                                 auth_identity.uid, our_identity.uid); +                                 _dbus_credentials_get_unix_uid(auth_identity), +                                 _dbus_credentials_get_unix_uid(our_identity));                  }              }          } @@ -1028,7 +1055,7 @@ dbus_bool_t  _dbus_transport_get_unix_user (DBusTransport *transport,                                 unsigned long *uid)  { -  DBusCredentials auth_identity; +  DBusCredentials *auth_identity;    *uid = _DBUS_INT32_MAX; /* better than some root or system user in                             * case of bugs in the caller. Caller should @@ -1038,11 +1065,12 @@ _dbus_transport_get_unix_user (DBusTransport *transport,    if (!transport->authenticated)      return FALSE; -  _dbus_auth_get_identity (transport->auth, &auth_identity); +  auth_identity = _dbus_auth_get_identity (transport->auth); -  if (auth_identity.uid != DBUS_UID_UNSET) +  if (_dbus_credentials_include (auth_identity, +                                 DBUS_CREDENTIAL_UNIX_USER_ID))      { -      *uid = auth_identity.uid; +      *uid = _dbus_credentials_get_unix_uid (auth_identity);        return TRUE;      }    else @@ -1060,7 +1088,7 @@ dbus_bool_t  _dbus_transport_get_unix_process_id (DBusTransport *transport,  				     unsigned long *pid)  { -  DBusCredentials auth_identity; +  DBusCredentials *auth_identity;    *pid = DBUS_PID_UNSET; /* Caller should never use this value on purpose,  			  * but we set it to a safe number, INT_MAX, @@ -1070,11 +1098,12 @@ _dbus_transport_get_unix_process_id (DBusTransport *transport,    if (!transport->authenticated)      return FALSE; -  _dbus_auth_get_identity (transport->auth, &auth_identity); +  auth_identity = _dbus_auth_get_identity (transport->auth); -  if (auth_identity.pid != DBUS_PID_UNSET) +  if (_dbus_credentials_include (auth_identity, +                                 DBUS_CREDENTIAL_UNIX_PROCESS_ID))      { -      *pid = auth_identity.pid; +      *pid = _dbus_credentials_get_unix_pid (auth_identity);        return TRUE;      }    else diff --git a/dbus/dbus-userdb-util.c b/dbus/dbus-userdb-util.c index 7b12de50..6e1653e6 100644 --- a/dbus/dbus-userdb-util.c +++ b/dbus/dbus-userdb-util.c @@ -103,20 +103,33 @@ _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; +  const DBusGroupInfo *info;    _dbus_user_database_lock_system ();    db = _dbus_user_database_get_system (); @@ -126,61 +139,34 @@ _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) -{ -  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) +_dbus_get_user_id_and_primary_group (const DBusString  *username, +                                     dbus_uid_t        *uid_p, +                                     dbus_gid_t        *gid_p)  {    DBusUserDatabase *db; -  const DBusGroupInfo *info; +  const DBusUserInfo *info;    _dbus_user_database_lock_system ();    db = _dbus_user_database_get_system (); @@ -190,14 +176,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; @@ -434,7 +423,6 @@ _dbus_userdb_test (const char *test_data_dir)    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"); diff --git a/dbus/dbus-userdb.c b/dbus/dbus-userdb.c index 2aa395dc..c3ae8ef4 100644 --- a/dbus/dbus-userdb.c +++ b/dbus/dbus-userdb.c @@ -26,6 +26,7 @@  #include "dbus-test.h"  #include "dbus-internals.h"  #include "dbus-protocol.h" +#include "dbus-credentials.h"  #include <string.h>  /** @@ -66,6 +67,30 @@ _dbus_group_info_free_allocated (DBusGroupInfo *info)  }  /** + * Frees the members of info + * (but not info itself) + * @param info the user info struct + */ +void +_dbus_user_info_free (DBusUserInfo *info) +{ +  dbus_free (info->group_ids); +  dbus_free (info->username); +  dbus_free (info->homedir); +} + +/** + * 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); +} + +/**   * Checks if a given string is actually a number    * and converts it if it is    * @@ -412,18 +437,19 @@ _dbus_homedir_from_username (const DBusString *username,  }  /** - * Gets the credentials corresponding to the given username. + * Adds the credentials corresponding to the given username.   * + * @param credentials credentials to fill in    * @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) +_dbus_credentials_add_from_username (DBusCredentials  *credentials, +                                     const DBusString *username)  {    DBusUserDatabase *db;    const DBusUserInfo *info; +    _dbus_user_database_lock_system ();    db = _dbus_user_database_get_system (); @@ -440,9 +466,11 @@ _dbus_credentials_from_username (const DBusString *username,        return FALSE;      } -  credentials->pid = DBUS_PID_UNSET; -  credentials->uid = info->uid; -  credentials->gid = info->primary_gid; +  if (!_dbus_credentials_add_unix_uid(credentials, info->uid)) +    { +      _dbus_user_database_unlock_system (); +      return FALSE; +    }    _dbus_user_database_unlock_system ();    return TRUE; diff --git a/dbus/dbus-userdb.h b/dbus/dbus-userdb.h index 9e278544..4fae6f02 100644 --- a/dbus/dbus-userdb.h +++ b/dbus/dbus-userdb.h @@ -24,7 +24,11 @@  #ifndef DBUS_USERDB_H  #define DBUS_USERDB_H -#include <dbus/dbus-sysdeps.h> +#include <dbus/dbus-sysdeps-unix.h> + +#ifdef DBUS_WIN +#error "Don't include this on Windows" +#endif  DBUS_BEGIN_DECLS @@ -86,16 +90,13 @@ void              _dbus_user_database_lock_system   (void);  void              _dbus_user_database_unlock_system (void);  void              _dbus_user_database_flush_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_credentials_from_username     (const DBusString  *username, -                                                 DBusCredentials   *credentials); +dbus_bool_t _dbus_get_user_id_and_primary_group (const DBusString  *username, +                                                 dbus_uid_t        *uid_p, +                                                 dbus_gid_t        *gid_p);  dbus_bool_t _dbus_credentials_from_uid          (dbus_uid_t         user_id,                                                   DBusCredentials   *credentials);  dbus_bool_t _dbus_groups_from_uid		(dbus_uid_t            uid, diff --git a/test/Makefile.am b/test/Makefile.am index ddb489d3..b3c9773b 100644 --- a/test/Makefile.am +++ b/test/Makefile.am @@ -88,6 +88,7 @@ TESTDIRS=					\  	data/sha-1				\  	data/valid-config-files			\  	data/valid-config-files/basic.d		\ +	data/valid-config-files/session.d	\  	data/valid-config-files/system.d	\  	data/valid-service-files		\  	data/invalid-config-files		\  | 
