Esempio n. 1
0
/**
 * See dbus_connection_get_unix_process_id().
 *
 * @param transport the transport
 * @param pid return location for the process ID
 * @returns #TRUE if uid is filled in with a valid process ID
 */
dbus_bool_t
_dbus_transport_get_unix_process_id (DBusTransport *transport,
				     unsigned long *pid)
{
  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,
			  * just to root out possible bugs in bad callers.
			  */
  
  if (!transport->authenticated)
    return FALSE;
  
  auth_identity = _dbus_auth_get_identity (transport->auth);

  if (_dbus_credentials_include (auth_identity,
                                 DBUS_CREDENTIAL_UNIX_PROCESS_ID))
    {
      *pid = _dbus_credentials_get_unix_pid (auth_identity);
      return TRUE;
    }
  else
    return FALSE;
}
Esempio n. 2
0
/**
 * See dbus_connection_get_adt_audit_session_data().
 *
 * @param transport the transport
 * @param data return location for the ADT audit data 
 * @param data_size return length of audit data
 * @returns #TRUE if audit data is filled in with a valid ucred
 */
dbus_bool_t
_dbus_transport_get_adt_audit_session_data (DBusTransport      *transport,
                                            void              **data,
                                            int                *data_size)
{
  DBusCredentials *auth_identity;

  *data = NULL;
  *data_size = 0;
  
  if (!transport->authenticated)
    return FALSE;
  
  auth_identity = _dbus_auth_get_identity (transport->auth);

  if (_dbus_credentials_include (auth_identity,
                                 DBUS_CREDENTIAL_ADT_AUDIT_DATA_ID))
    {
      *data = (void *) _dbus_credentials_get_adt_audit_data (auth_identity);
      *data_size = _dbus_credentials_get_adt_audit_data_size (auth_identity);
      return TRUE;
    }
  else
    return FALSE;
}
Esempio n. 3
0
/**
 * See dbus_connection_get_unix_user().
 *
 * @param transport the transport
 * @param uid return location for the user ID
 * @returns #TRUE if uid is filled in with a valid user ID
 */
dbus_bool_t
_dbus_transport_get_unix_user (DBusTransport *transport,
                               unsigned long *uid)
{
  DBusCredentials *auth_identity;

  *uid = _DBUS_INT32_MAX; /* better than some root or system user in
                           * case of bugs in the caller. Caller should
                           * never use this value on purpose, however.
                           */
  
  if (!transport->authenticated)
    return FALSE;
  
  auth_identity = _dbus_auth_get_identity (transport->auth);

  if (_dbus_credentials_include (auth_identity,
                                 DBUS_CREDENTIAL_UNIX_USER_ID))
    {
      *uid = _dbus_credentials_get_unix_uid (auth_identity);
      return TRUE;
    }
  else
    return FALSE;
}
Esempio n. 4
0
static dbus_bool_t
auth_via_default_rules (DBusTransport *transport)
{
  DBusCredentials *auth_identity;
  DBusCredentials *our_identity;
  dbus_bool_t allow;
  
  auth_identity = _dbus_auth_get_identity (transport->auth);
  _dbus_assert (auth_identity != NULL);

  /* By default, connection is allowed if the client is 1) root or 2)
   * has the same UID as us or 3) anonymous is allowed.
   */
  
  our_identity = _dbus_credentials_new_from_current_process ();
  if (our_identity == NULL)
    {
      /* OOM */
      return FALSE;
    }
              
  if (transport->allow_anonymous ||
      _dbus_credentials_get_unix_uid (auth_identity) == 0 ||
      _dbus_credentials_same_user (our_identity,
                                   auth_identity))
    {
      if (_dbus_credentials_include(our_identity,DBUS_CREDENTIAL_WINDOWS_SID))
          _dbus_verbose ("Client authorized as SID '%s'"
                         "matching our SID '%s'\n",
                         _dbus_credentials_get_windows_sid(auth_identity),
                         _dbus_credentials_get_windows_sid(our_identity));
      else
          _dbus_verbose ("Client authorized as UID "DBUS_UID_FORMAT
                         " matching our UID "DBUS_UID_FORMAT"\n",
                         _dbus_credentials_get_unix_uid(auth_identity),
                         _dbus_credentials_get_unix_uid(our_identity));
      /* We have authenticated! */
      allow = TRUE;
    }
  else
    {
      if (_dbus_credentials_include(our_identity,DBUS_CREDENTIAL_WINDOWS_SID))
          _dbus_verbose ("Client authorized as SID '%s'"
                         " but our SID is '%s', disconnecting\n",
                         _dbus_credentials_get_windows_sid(auth_identity),
                         _dbus_credentials_get_windows_sid(our_identity));
      else
          _dbus_verbose ("Client authorized as UID "DBUS_UID_FORMAT
                         " but our UID is "DBUS_UID_FORMAT", disconnecting\n",
                         _dbus_credentials_get_unix_uid(auth_identity),
                         _dbus_credentials_get_unix_uid(our_identity));
      _dbus_transport_disconnect (transport);
      allow = FALSE;
    }  

  _dbus_credentials_unref (our_identity);
  
  return allow;
}
Esempio n. 5
0
static dbus_bool_t
auth_via_windows_user_function (DBusTransport *transport)
{
  DBusCredentials *auth_identity;  
  dbus_bool_t allow;
  DBusConnection *connection;
  DBusAllowWindowsUserFunction windows_user_function;
  void *windows_user_data;
  char *windows_sid;

  /* Dropping the lock here probably isn't that safe. */
  
  auth_identity = _dbus_auth_get_identity (transport->auth);
  _dbus_assert (auth_identity != NULL);

  connection = transport->connection;
  windows_user_function = transport->windows_user_function;
  windows_user_data = transport->unix_user_data;
  windows_sid = _dbus_strdup (_dbus_credentials_get_windows_sid (auth_identity));

  if (windows_sid == NULL)
    {
      /* OOM */
      return FALSE;
    }
                
  _dbus_verbose ("unlock %s\n", _DBUS_FUNCTION_NAME);
  _dbus_connection_unlock (connection);

  allow = (* windows_user_function) (connection,
                                     windows_sid,
                                     windows_user_data);
              
  _dbus_verbose ("lock %s post windows user function\n", _DBUS_FUNCTION_NAME);
  _dbus_connection_lock (connection);

  if (allow)
    {
      _dbus_verbose ("Client SID '%s' authorized\n", windows_sid);
    }
  else
    {
      _dbus_verbose ("Client SID '%s' was rejected, disconnecting\n",
                     _dbus_credentials_get_windows_sid (auth_identity));
      _dbus_transport_disconnect (transport);
    }

  return allow;
}
Esempio n. 6
0
/**
 * See dbus_connection_get_is_anonymous().
 *
 * @param transport the transport
 * @returns #TRUE if not authenticated or authenticated as anonymous
 */
dbus_bool_t
_dbus_transport_get_is_anonymous (DBusTransport *transport)
{
  DBusCredentials *auth_identity;
  
  if (!transport->authenticated)
    return TRUE;
  
  auth_identity = _dbus_auth_get_identity (transport->auth);

  if (_dbus_credentials_are_anonymous (auth_identity))
    return TRUE;
  else
    return FALSE;
}
Esempio n. 7
0
static dbus_bool_t
auth_via_unix_user_function (DBusTransport *transport)
{
  DBusCredentials *auth_identity;
  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. */
  
  auth_identity = _dbus_auth_get_identity (transport->auth);
  _dbus_assert (auth_identity != NULL);

  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,
                                  uid,
                                  unix_user_data);
              
  _dbus_verbose ("lock %s post unix user function\n", _DBUS_FUNCTION_NAME);
  _dbus_connection_lock (connection);

  if (allow)
    {
      _dbus_verbose ("Client UID "DBUS_UID_FORMAT" authorized\n", uid);
    }
  else
    {
      _dbus_verbose ("Client UID "DBUS_UID_FORMAT
                     " was rejected, disconnecting\n",
                     _dbus_credentials_get_unix_uid (auth_identity));
      _dbus_transport_disconnect (transport);
    }

  return allow;
}
Esempio n. 8
0
/**
 * See dbus_connection_get_windows_user().
 *
 * @param transport the transport
 * @param windows_sid_p return location for the user ID
 * @returns #TRUE if user is available; the returned value may still be #NULL if no memory to copy it
 */
dbus_bool_t
_dbus_transport_get_windows_user (DBusTransport              *transport,
                                  char                      **windows_sid_p)
{
  DBusCredentials *auth_identity;

  *windows_sid_p = NULL;
  
  if (!transport->authenticated)
    return FALSE;
  
  auth_identity = _dbus_auth_get_identity (transport->auth);

  if (_dbus_credentials_include (auth_identity,
                                 DBUS_CREDENTIAL_WINDOWS_SID))
    {
      /* If no memory, we are supposed to return TRUE and set NULL */
      *windows_sid_p = _dbus_strdup (_dbus_credentials_get_windows_sid (auth_identity));

      return TRUE;
    }
  else
    return FALSE;
}
/**
 * See dbus_connection_get_unix_process_id().
 *
 * @param transport the transport
 * @param pid return location for the process ID
 * @returns #TRUE if uid is filled in with a valid process ID
 */
dbus_bool_t
_dbus_transport_get_unix_process_id (DBusTransport *transport,
				     unsigned long *pid)
{
  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,
			  * just to root out possible bugs in bad callers.
			  */
  
  if (!transport->authenticated)
    return FALSE;
  
  _dbus_auth_get_identity (transport->auth, &auth_identity);

  if (auth_identity.pid != DBUS_PID_UNSET)
    {
      *pid = auth_identity.pid;
      return TRUE;
    }
  else
    return FALSE;
}
/**
 * See dbus_connection_get_unix_user().
 *
 * @param transport the transport
 * @param uid return location for the user ID
 * @returns #TRUE if uid is filled in with a valid user ID
 */
dbus_bool_t
_dbus_transport_get_unix_user (DBusTransport *transport,
                               unsigned long *uid)
{
  DBusCredentials auth_identity;

  *uid = _DBUS_INT32_MAX; /* better than some root or system user in
                           * case of bugs in the caller. Caller should
                           * never use this value on purpose, however.
                           */
  
  if (!transport->authenticated)
    return FALSE;
  
  _dbus_auth_get_identity (transport->auth, &auth_identity);

  if (auth_identity.uid != DBUS_UID_UNSET)
    {
      *uid = auth_identity.uid;
      return TRUE;
    }
  else
    return FALSE;
}
Esempio n. 11
0
/**
 * Returns #TRUE if we have been authenticated.  Will return #TRUE
 * even if the transport is disconnected.
 *
 * @todo we drop connection->mutex when calling the unix_user_function,
 * and windows_user_function, which may not be safe really.
 *
 * @param transport the transport
 * @returns whether we're authenticated
 */
dbus_bool_t
_dbus_transport_get_is_authenticated (DBusTransport *transport)
{  
  if (transport->authenticated)
    return TRUE;
  else
    {
      dbus_bool_t maybe_authenticated;
      
      if (transport->disconnected)
        return FALSE;

      /* paranoia ref since we call user callbacks sometimes */
      _dbus_connection_ref_unlocked (transport->connection);
      
      maybe_authenticated =
        (!(transport->send_credentials_pending ||
           transport->receive_credentials_pending));

      if (maybe_authenticated)
        {
          switch (_dbus_auth_do_work (transport->auth))
            {
            case DBUS_AUTH_STATE_AUTHENTICATED:
              /* leave as maybe_authenticated */
              break;
            default:
              maybe_authenticated = FALSE;
            }
        }

      /* If we're the client, verify the GUID
       */
      if (maybe_authenticated && !transport->is_server)
        {
          const char *server_guid;

          server_guid = _dbus_auth_get_guid_from_server (transport->auth);
          _dbus_assert (server_guid != NULL);

          if (transport->expected_guid &&
              strcmp (transport->expected_guid, server_guid) != 0)
            {
              _dbus_verbose ("Client expected GUID '%s' and we got '%s' from the server\n",
                             transport->expected_guid, server_guid);
              _dbus_transport_disconnect (transport);
              _dbus_connection_unref_unlocked (transport->connection);
              return FALSE;
            }

          if (transport->expected_guid == NULL)
            {
              transport->expected_guid = _dbus_strdup (server_guid);

              if (transport->expected_guid == NULL)
                {
                  _dbus_verbose ("No memory to complete auth in %s\n", _DBUS_FUNCTION_NAME);
                  return FALSE;
                }
            }
        }

      /* If we're the server, see if we want to allow this identity to proceed.
       */
      if (maybe_authenticated && transport->is_server)
        {
          dbus_bool_t allow;
          DBusCredentials *auth_identity;
          
          auth_identity = _dbus_auth_get_identity (transport->auth);
          _dbus_assert (auth_identity != NULL);
          
          /* If we have an auth'd user and a 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))
            {
              allow = auth_via_unix_user_function (transport);
            }
          else if (transport->windows_user_function != NULL &&
                   _dbus_credentials_include (auth_identity, DBUS_CREDENTIAL_WINDOWS_SID))
            {
              allow = auth_via_windows_user_function (transport);
            }      
          else
            {
              allow = auth_via_default_rules (transport);
            }
          
          if (!allow)
            maybe_authenticated = FALSE;
        }

      transport->authenticated = maybe_authenticated;

      _dbus_connection_unref_unlocked (transport->connection);
      return maybe_authenticated;
    }
}
/**
 * Returns #TRUE if we have been authenticated.  Will return #TRUE
 * even if the transport is disconnected.
 *
 * @todo we drop connection->mutex when calling the unix_user_function,
 * which may not be safe really.
 *
 * @param transport the transport
 * @returns whether we're authenticated
 */
dbus_bool_t
_dbus_transport_get_is_authenticated (DBusTransport *transport)
{  
  if (transport->authenticated)
    return TRUE;
  else
    {
      dbus_bool_t maybe_authenticated;
      
      if (transport->disconnected)
        return FALSE;

      /* paranoia ref since we call user callbacks sometimes */
      _dbus_connection_ref_unlocked (transport->connection);
      
      maybe_authenticated =
        (!(transport->send_credentials_pending ||
           transport->receive_credentials_pending));

      if (maybe_authenticated)
        {
          switch (_dbus_auth_do_work (transport->auth))
            {
            case DBUS_AUTH_STATE_AUTHENTICATED:
              /* leave as maybe_authenticated */
              break;
            default:
              maybe_authenticated = FALSE;
            }
        }

      if (maybe_authenticated && !transport->is_server)
        {
          const char *server_guid;

          server_guid = _dbus_auth_get_guid_from_server (transport->auth);
          _dbus_assert (server_guid != NULL);

          if (transport->expected_guid &&
              strcmp (transport->expected_guid, server_guid) != 0)
            {
              _dbus_verbose ("Client expected GUID '%s' and we got '%s' from the server\n",
                             transport->expected_guid, server_guid);
              _dbus_transport_disconnect (transport);
              _dbus_connection_unref_unlocked (transport->connection);
              return FALSE;
            }

          if (transport->expected_guid == NULL)
            {
              transport->expected_guid = _dbus_strdup (server_guid);

              if (transport->expected_guid == NULL)
                {
                  _dbus_verbose ("No memory to complete auth in %s\n", _DBUS_FUNCTION_NAME);
                  return FALSE;
                }
            }
        }
      
      /* If we've authenticated as some identity, check that the auth
       * identity is the same as our own identity.  In the future, we
       * may have API allowing applications to specify how this is
       * done, for example they may allow connection as any identity,
       * but then impose restrictions on certain identities.
       * Or they may give certain identities extra privileges.
       */
      
      if (maybe_authenticated && transport->is_server)
        {
          DBusCredentials auth_identity;

          _dbus_auth_get_identity (transport->auth, &auth_identity);

          if (transport->unix_user_function != NULL)
            {
              dbus_bool_t allow;
              DBusConnection *connection;
              DBusAllowUnixUserFunction unix_user_function;
              void *unix_user_data;
              
              /* 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;

              _dbus_verbose ("unlock %s\n", _DBUS_FUNCTION_NAME);
              _dbus_connection_unlock (connection);
              
              allow = (* unix_user_function) (connection,
                                              auth_identity.uid,
                                              unix_user_data);

              _dbus_verbose ("lock %s post unix user function\n", _DBUS_FUNCTION_NAME);
              _dbus_connection_lock (connection);

              if (allow)
                {
                  _dbus_verbose ("Client UID "DBUS_UID_FORMAT" authorized\n", auth_identity.uid);
                }
              else
                {
                  _dbus_verbose ("Client UID "DBUS_UID_FORMAT
                                 " was rejected, disconnecting\n",
                                 auth_identity.uid);
                  _dbus_transport_disconnect (transport);
                  _dbus_connection_unref_unlocked (connection);
                  return FALSE;
                }
            }
          else
            {
              DBusCredentials our_identity;
              
              _dbus_credentials_from_current_process (&our_identity);
              
              if (!_dbus_credentials_match (&our_identity,
                                            &auth_identity))
                {
                  _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_transport_disconnect (transport);
                  _dbus_connection_unref_unlocked (transport->connection);
                  return FALSE;
                }
              else
                {
                  _dbus_verbose ("Client authorized as UID "DBUS_UID_FORMAT
                                 " matching our UID "DBUS_UID_FORMAT"\n",
                                 auth_identity.uid, our_identity.uid);
                }
            }
        }
      
      transport->authenticated = maybe_authenticated;

      _dbus_connection_unref_unlocked (transport->connection);
      return maybe_authenticated;
    }
}
/**
 * Runs an "auth script" which is a script for testing the
 * authentication protocol. Scripts send and receive data, and then
 * include assertions about the state of both ends of the connection
 * after processing the data. A script succeeds if these assertions
 * hold.
 *
 * @param filename the file containing the script to run
 * @returns #TRUE if the script succeeds, #FALSE otherwise
 */
dbus_bool_t
_dbus_auth_script_run (const DBusString *filename)
{
  DBusString file;
  DBusError error = DBUS_ERROR_INIT;
  DBusString line;
  dbus_bool_t retval;
  int line_no;
  DBusAuth *auth;
  DBusString from_auth;
  DBusAuthState state;
  DBusString context;
  DBusString guid;
  
  retval = FALSE;
  auth = NULL;

  _dbus_string_init_const (&guid, "5fa01f4202cd837709a3274ca0df9d00");
  _dbus_string_init_const (&context, "org_freedesktop_test");
  
  if (!_dbus_string_init (&file))
    return FALSE;

  if (!_dbus_string_init (&line))
    {
      _dbus_string_free (&file);
      return FALSE;
    }

  if (!_dbus_string_init (&from_auth))
    {
      _dbus_string_free (&file);
      _dbus_string_free (&line);
      return FALSE;
    }

  if (!_dbus_file_get_contents (&file, filename, &error))    {
      _dbus_warn ("Getting contents of %s failed: %s\n",
                  _dbus_string_get_const_data (filename), error.message);
      dbus_error_free (&error);
      goto out;
    }

  state = DBUS_AUTH_STATE_NEED_DISCONNECT;
  line_no = 0;

 next_iteration:
  while (_dbus_string_pop_line (&file, &line))
    {      
      line_no += 1;

      /* _dbus_warn ("%s\n", _dbus_string_get_const_data (&line)); */
      
      _dbus_string_delete_leading_blanks (&line);

      if (auth != NULL)
        {
          while ((state = _dbus_auth_do_work (auth)) ==
                 DBUS_AUTH_STATE_HAVE_BYTES_TO_SEND)
            {
              const DBusString *tmp;
              if (_dbus_auth_get_bytes_to_send (auth, &tmp))
                {
                  int count = _dbus_string_get_length (tmp);

                  if (_dbus_string_copy (tmp, 0, &from_auth,
                                         _dbus_string_get_length (&from_auth)))
                    _dbus_auth_bytes_sent (auth, count);
                }
            }
        }
      
      if (_dbus_string_get_length (&line) == 0)
        {
          /* empty line */
          goto next_iteration;
        }
      else if (_dbus_string_starts_with_c_str (&line,
                                               "#"))
        {
          /* Ignore this comment */
          goto next_iteration;
        }
#ifdef DBUS_WIN
      else if (_dbus_string_starts_with_c_str (&line,
                                               "WIN_ONLY"))
        {
          /* Ignore this line */
          goto next_iteration;
        }
      else if (_dbus_string_starts_with_c_str (&line,
                                               "UNIX_ONLY"))
        {
          /* skip this file */
          _dbus_warn ("skipping unix only auth script\n");
          retval = TRUE;
          goto out;
        }
#endif
#ifdef DBUS_UNIX
      else if (_dbus_string_starts_with_c_str (&line,
                                               "UNIX_ONLY"))
        {
          /* Ignore this line */
          goto next_iteration;
        }
      else if (_dbus_string_starts_with_c_str (&line,
                                               "WIN_ONLY"))
        {
          /* skip this file */
          _dbus_warn ("skipping windows only auth script\n");
          retval = TRUE;
          goto out;
        }
#endif
      else if (_dbus_string_starts_with_c_str (&line,
                                               "CLIENT"))
        {
          DBusCredentials *creds;
          
          if (auth != NULL)
            {
              _dbus_warn ("already created a DBusAuth (CLIENT or SERVER given twice)\n");
              goto out;
            }

          auth = _dbus_auth_client_new ();
          if (auth == NULL)
            {
              _dbus_warn ("no memory to create DBusAuth\n");
              goto out;
            }

          /* 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_unref (creds);
        }
      else if (_dbus_string_starts_with_c_str (&line,
                                               "SERVER"))
        {
          DBusCredentials *creds;
          
          if (auth != NULL)
            {
              _dbus_warn ("already created a DBusAuth (CLIENT or SERVER given twice)\n");
              goto out;
            }

          auth = _dbus_auth_server_new (&guid);
          if (auth == NULL)
            {
              _dbus_warn ("no memory to create DBusAuth\n");
              goto out;
            }

          /* 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_unref (creds);

          _dbus_auth_set_context (auth, &context);
        }
      else if (auth == NULL)
        {
          _dbus_warn ("must specify CLIENT or SERVER\n");
          goto out;

        }
      else if (_dbus_string_starts_with_c_str (&line,
                                               "NO_CREDENTIALS"))
        {
          auth_set_unix_credentials (auth, DBUS_UID_UNSET, DBUS_PID_UNSET);
        }
      else if (_dbus_string_starts_with_c_str (&line,
                                               "ROOT_CREDENTIALS"))
        {
          auth_set_unix_credentials (auth, 0, DBUS_PID_UNSET);
        }
      else if (_dbus_string_starts_with_c_str (&line,
                                               "SILLY_CREDENTIALS"))
        {
          auth_set_unix_credentials (auth, 4312, DBUS_PID_UNSET);
        }
      else if (_dbus_string_starts_with_c_str (&line,
                                               "ALLOWED_MECHS"))
        {
          char **mechs;

          _dbus_string_delete_first_word (&line);
          mechs = split_string (&line);
          _dbus_auth_set_mechanisms (auth, (const char **) mechs);
          dbus_free_string_array (mechs);
        }
      else if (_dbus_string_starts_with_c_str (&line,
                                               "SEND"))
        {
          DBusString to_send;
          
          _dbus_string_delete_first_word (&line);

          if (!_dbus_string_init (&to_send))
            {
              _dbus_warn ("no memory to allocate string\n");
              goto out;
            }

          if (!append_quoted_string (&to_send, &line))
            {
              _dbus_warn ("failed to append quoted string line %d\n",
                          line_no);
              _dbus_string_free (&to_send);
              goto out;
            }

          _dbus_verbose ("Sending '%s'\n", _dbus_string_get_const_data (&to_send));
          
          if (!_dbus_string_append (&to_send, "\r\n"))
            {
              _dbus_warn ("failed to append \r\n from line %d\n",
                          line_no);
              _dbus_string_free (&to_send);
              goto out;
            }

          /* Replace USERID_HEX with our username in hex */
          {
            int where;
            
            if (_dbus_string_find (&to_send, 0,
                                   "USERID_HEX", &where))
              {
                DBusString username;

                if (!_dbus_string_init (&username))
                  {
                    _dbus_warn ("no memory for userid\n");
                    _dbus_string_free (&to_send);
                    goto out;
                  }

                if (!_dbus_append_user_from_current_process (&username))
                  {
                    _dbus_warn ("no memory for userid\n");
                    _dbus_string_free (&username);
                    _dbus_string_free (&to_send);
                    goto out;
                  }

                _dbus_string_delete (&to_send, where, (int) strlen ("USERID_HEX"));
                
                if (!_dbus_string_hex_encode (&username, 0,
					      &to_send, where))
                  {
                    _dbus_warn ("no memory to subst USERID_HEX\n");
                    _dbus_string_free (&username);
                    _dbus_string_free (&to_send);
                    goto out;
                  }

                _dbus_string_free (&username);
              }
            else if (_dbus_string_find (&to_send, 0,
                                        "USERNAME_HEX", &where))
              {
                DBusString username;
                
                if (!_dbus_string_init (&username))
                  {
                    _dbus_warn ("no memory for username\n");
                    _dbus_string_free (&to_send);
                    goto out;
                  }

                if (!_dbus_append_user_from_current_process (&username))
                  {
                    _dbus_warn ("no memory for username\n");
                    _dbus_string_free (&username);
                    _dbus_string_free (&to_send);
                    goto out;
                  }

                _dbus_string_delete (&to_send, where, (int) strlen ("USERNAME_HEX"));
                
                if (!_dbus_string_hex_encode (&username, 0,
					      &to_send, where))
                  {
                    _dbus_warn ("no memory to subst USERNAME_HEX\n");
                    _dbus_string_free (&username);
                    _dbus_string_free (&to_send);
                    goto out;
                  }

                _dbus_string_free (&username);
              }
          }

          {
            DBusString *buffer;

            _dbus_auth_get_buffer (auth, &buffer);
            if (!_dbus_string_copy (&to_send, 0,
                                    buffer, _dbus_string_get_length (buffer)))
              {
                _dbus_warn ("not enough memory to call bytes_received, or can't add bytes to auth object already in end state\n");
                _dbus_string_free (&to_send);
                _dbus_auth_return_buffer (auth, buffer);
                goto out;
              }

            _dbus_auth_return_buffer (auth, buffer);
          }
          
          _dbus_string_free (&to_send);
        }
      else if (_dbus_string_starts_with_c_str (&line,
                                               "EXPECT_STATE"))
        {
          DBusAuthState expected;
          
          _dbus_string_delete_first_word (&line);

          expected = auth_state_from_string (&line);
          if (expected < 0)
            {
              _dbus_warn ("bad auth state given to EXPECT_STATE\n");
              goto parse_failed;
            }

          if (expected != state)
            {
              _dbus_warn ("expected auth state %s but got %s on line %d\n",
                          auth_state_to_string (expected),
                          auth_state_to_string (state),
                          line_no);
              goto out;
            }
        }
      else if (_dbus_string_starts_with_c_str (&line,
                                               "EXPECT_COMMAND"))
        {
          DBusString received;
          
          _dbus_string_delete_first_word (&line);

          if (!_dbus_string_init (&received))
            {
              _dbus_warn ("no mem to allocate string received\n");
              goto out;
            }

          if (!_dbus_string_pop_line (&from_auth, &received))
            {
              _dbus_warn ("no line popped from the DBusAuth being tested, expected command %s on line %d\n",
                          _dbus_string_get_const_data (&line), line_no);
              _dbus_string_free (&received);
              goto out;
            }

          if (!same_first_word (&received, &line))
            {
              _dbus_warn ("line %d expected command '%s' and got '%s'\n",
                          line_no,
                          _dbus_string_get_const_data (&line),
                          _dbus_string_get_const_data (&received));
              _dbus_string_free (&received);
              goto out;
            }
          
          _dbus_string_free (&received);
        }
      else if (_dbus_string_starts_with_c_str (&line,
                                               "EXPECT_UNUSED"))
        {
          DBusString expected;
          const DBusString *unused;
          
          _dbus_string_delete_first_word (&line);

          if (!_dbus_string_init (&expected))
            {
              _dbus_warn ("no mem to allocate string expected\n");
              goto out;
            }

          if (!append_quoted_string (&expected, &line))
            {
              _dbus_warn ("failed to append quoted string line %d\n",
                          line_no);
              _dbus_string_free (&expected);
              goto out;
            }

          _dbus_auth_get_unused_bytes (auth, &unused);
          
          if (_dbus_string_equal (&expected, unused))
            {
              _dbus_auth_delete_unused_bytes (auth);
              _dbus_string_free (&expected);
            }
          else
            {
              _dbus_warn ("Expected unused bytes '%s' and have '%s'\n",
                          _dbus_string_get_const_data (&expected),
                          _dbus_string_get_const_data (unused));
              _dbus_string_free (&expected);
              goto out;
            }
        }
      else if (_dbus_string_starts_with_c_str (&line,
                                               "EXPECT_HAVE_NO_CREDENTIALS"))
        {
          DBusCredentials *authorized_identity;
          
          authorized_identity = _dbus_auth_get_identity (auth);
          if (!_dbus_credentials_are_anonymous (authorized_identity))
            {
              _dbus_warn ("Expected anonymous login or failed login, but some credentials were authorized\n");
              goto out;
            }
        }
      else if (_dbus_string_starts_with_c_str (&line,
                                               "EXPECT_HAVE_SOME_CREDENTIALS"))
        {
          DBusCredentials *authorized_identity;
          
          authorized_identity = _dbus_auth_get_identity (auth);
          if (_dbus_credentials_are_anonymous (authorized_identity))
            {
              _dbus_warn ("Expected to have some credentials, but we don't\n");
              goto out;
            }
        }
      else if (_dbus_string_starts_with_c_str (&line,
                                               "EXPECT"))
        {
          DBusString expected;
          
          _dbus_string_delete_first_word (&line);

          if (!_dbus_string_init (&expected))
            {
              _dbus_warn ("no mem to allocate string expected\n");
              goto out;
            }

          if (!append_quoted_string (&expected, &line))
            {
              _dbus_warn ("failed to append quoted string line %d\n",
                          line_no);
              _dbus_string_free (&expected);
              goto out;
            }

          if (_dbus_string_equal_len (&expected, &from_auth,
                                      _dbus_string_get_length (&expected)))
            {
              _dbus_string_delete (&from_auth, 0,
                                   _dbus_string_get_length (&expected));
              _dbus_string_free (&expected);
            }
          else
            {
              _dbus_warn ("Expected exact string '%s' and have '%s'\n",
                          _dbus_string_get_const_data (&expected),
                          _dbus_string_get_const_data (&from_auth));
              _dbus_string_free (&expected);
              goto out;
            }
        }
      else
        goto parse_failed;

      goto next_iteration; /* skip parse_failed */
      
    parse_failed:
      {
        _dbus_warn ("couldn't process line %d \"%s\"\n",
                    line_no, _dbus_string_get_const_data (&line));
        goto out;
      }
    }

  if (auth == NULL)
    {
      _dbus_warn ("Auth script is bogus, did not even have CLIENT or SERVER\n");
      goto out;
    }
  else if (state == DBUS_AUTH_STATE_AUTHENTICATED)
    {
      const DBusString *unused;

      _dbus_auth_get_unused_bytes (auth, &unused);

      if (_dbus_string_get_length (unused) > 0)
        {
          _dbus_warn ("did not expect unused bytes (scripts must specify explicitly if they are expected)\n");
          goto out;
        }
    }

  if (_dbus_string_get_length (&from_auth) > 0)
    {
      _dbus_warn ("script did not have EXPECT_ statements for all the data received from the DBusAuth\n");
      _dbus_warn ("Leftover data: %s\n", _dbus_string_get_const_data (&from_auth));
      goto out;
    }
  
  retval = TRUE;
  
 out:
  if (auth)
    _dbus_auth_unref (auth);

  _dbus_string_free (&file);
  _dbus_string_free (&line);
  _dbus_string_free (&from_auth);
  
  return retval;
}