コード例 #1
0
ファイル: dbus-transport.c プロジェクト: zsx/windbus
/**
 * Reports our current dispatch status (whether there's buffered
 * data to be queued as messages, or not, or we need memory).
 *
 * @param transport the transport
 * @returns current status
 */
DBusDispatchStatus
_dbus_transport_get_dispatch_status (DBusTransport *transport)
{
  if (_dbus_counter_get_value (transport->live_messages_size) >= transport->max_live_messages_size)
    return DBUS_DISPATCH_COMPLETE; /* complete for now */

  if (!_dbus_transport_get_is_authenticated (transport))
    {
      if (_dbus_auth_do_work (transport->auth) ==
          DBUS_AUTH_STATE_WAITING_FOR_MEMORY)
        return DBUS_DISPATCH_NEED_MEMORY;
      else if (!_dbus_transport_get_is_authenticated (transport))
        return DBUS_DISPATCH_COMPLETE;
    }

  if (!transport->unused_bytes_recovered &&
      !recover_unused_bytes (transport))
    return DBUS_DISPATCH_NEED_MEMORY;

  transport->unused_bytes_recovered = TRUE;
  
  if (!_dbus_message_loader_queue_messages (transport->loader))
    return DBUS_DISPATCH_NEED_MEMORY;

  if (_dbus_message_loader_peek_message (transport->loader) != NULL)
    return DBUS_DISPATCH_DATA_REMAINS;
  else
    return DBUS_DISPATCH_COMPLETE;
}
コード例 #2
0
static void
check_read_watch (DBusTransport *transport)
{
  DBusTransportSocket *socket_transport = (DBusTransportSocket*) transport;
  dbus_bool_t need_read_watch;

  _dbus_verbose ("fd = %" DBUS_SOCKET_FORMAT "\n",
                 _dbus_socket_printable (socket_transport->fd));
  
  if (transport->connection == NULL)
    return;

  if (transport->disconnected)
    {
      _dbus_assert (socket_transport->read_watch == NULL);
      return;
    }
  
  _dbus_transport_ref (transport);

  if (_dbus_transport_try_to_authenticate (transport))
    need_read_watch =
      (_dbus_counter_get_size_value (transport->live_messages) < transport->max_live_messages_size) &&
      (_dbus_counter_get_unix_fd_value (transport->live_messages) < transport->max_live_messages_unix_fds);
  else
    {
      if (transport->receive_credentials_pending)
        need_read_watch = TRUE;
      else
        {
          /* The reason to disable need_read_watch when not WAITING_FOR_INPUT
           * is to avoid spinning on the file descriptor when we're waiting
           * to write or for some other part of the auth process
           */
          DBusAuthState auth_state;
          
          auth_state = _dbus_auth_do_work (transport->auth);

          /* If we need memory we install the read watch just in case,
           * if there's no need for it, it will get de-installed
           * next time we try reading. If we're authenticated we
           * install it since we normally have it installed while
           * authenticated.
           */
          if (auth_state == DBUS_AUTH_STATE_WAITING_FOR_INPUT ||
              auth_state == DBUS_AUTH_STATE_WAITING_FOR_MEMORY ||
              auth_state == DBUS_AUTH_STATE_AUTHENTICATED)
            need_read_watch = TRUE;
          else
            need_read_watch = FALSE;
        }
    }

  _dbus_verbose ("  setting read watch enabled = %d\n", need_read_watch);
  _dbus_connection_toggle_watch_unlocked (transport->connection,
                                          socket_transport->read_watch,
                                          need_read_watch);

  _dbus_transport_unref (transport);
}
コード例 #3
0
static void
check_write_watch (DBusTransport *transport)
{
  DBusTransportSocket *socket_transport = (DBusTransportSocket*) transport;
  dbus_bool_t needed;

  if (transport->connection == NULL)
    return;

  if (transport->disconnected)
    {
      _dbus_assert (socket_transport->write_watch == NULL);
      return;
    }
  
  _dbus_transport_ref (transport);

  if (_dbus_transport_try_to_authenticate (transport))
    needed = _dbus_connection_has_messages_to_send_unlocked (transport->connection);
  else
    {
      if (transport->send_credentials_pending)
        needed = TRUE;
      else
        {
          DBusAuthState auth_state;
          
          auth_state = _dbus_auth_do_work (transport->auth);
          
          /* If we need memory we install the write watch just in case,
           * if there's no need for it, it will get de-installed
           * next time we try reading.
           */
          if (auth_state == DBUS_AUTH_STATE_HAVE_BYTES_TO_SEND ||
              auth_state == DBUS_AUTH_STATE_WAITING_FOR_MEMORY)
            needed = TRUE;
          else
            needed = FALSE;
        }
    }

  _dbus_verbose ("check_write_watch(): needed = %d on connection %p watch %p fd = %" DBUS_SOCKET_FORMAT " outgoing messages exist %d\n",
                 needed, transport->connection, socket_transport->write_watch,
                 _dbus_socket_printable (socket_transport->fd),
                 _dbus_connection_has_messages_to_send_unlocked (transport->connection));

  _dbus_connection_toggle_watch_unlocked (transport->connection,
                                          socket_transport->write_watch,
                                          needed);

  _dbus_transport_unref (transport);
}
コード例 #4
0
static dbus_bool_t
do_authentication (DBusTransport *transport,
                   dbus_bool_t    do_reading,
                   dbus_bool_t    do_writing,
		   dbus_bool_t   *auth_completed)
{
  dbus_bool_t oom;
  dbus_bool_t orig_auth_state;

  oom = FALSE;
  
  orig_auth_state = _dbus_transport_try_to_authenticate (transport);

  /* This is essential to avoid the check_write_watch() at the end,
   * we don't want to add a write watch in do_iteration before
   * we try writing and get EAGAIN
   */
  if (orig_auth_state)
    {
      if (auth_completed)
        *auth_completed = FALSE;
      return TRUE;
    }
  
  _dbus_transport_ref (transport);
  
  while (!_dbus_transport_try_to_authenticate (transport) &&
         _dbus_transport_get_is_connected (transport))
    {      
      if (!exchange_credentials (transport, do_reading, do_writing))
        {
          /* OOM */
          oom = TRUE;
          goto out;
        }
      
      if (transport->send_credentials_pending ||
          transport->receive_credentials_pending)
        {
          _dbus_verbose ("send_credentials_pending = %d receive_credentials_pending = %d\n",
                         transport->send_credentials_pending,
                         transport->receive_credentials_pending);
          goto out;
        }

#define TRANSPORT_SIDE(t) ((t)->is_server ? "server" : "client")
      switch (_dbus_auth_do_work (transport->auth))
        {
        case DBUS_AUTH_STATE_WAITING_FOR_INPUT:
          _dbus_verbose (" %s auth state: waiting for input\n",
                         TRANSPORT_SIDE (transport));
          if (!do_reading || !read_data_into_auth (transport, &oom))
            goto out;
          break;
      
        case DBUS_AUTH_STATE_WAITING_FOR_MEMORY:
          _dbus_verbose (" %s auth state: waiting for memory\n",
                         TRANSPORT_SIDE (transport));
          oom = TRUE;
          goto out;
          break;
      
        case DBUS_AUTH_STATE_HAVE_BYTES_TO_SEND:
          _dbus_verbose (" %s auth state: bytes to send\n",
                         TRANSPORT_SIDE (transport));
          if (!do_writing || !write_data_from_auth (transport))
            goto out;
          break;
      
        case DBUS_AUTH_STATE_NEED_DISCONNECT:
          _dbus_verbose (" %s auth state: need to disconnect\n",
                         TRANSPORT_SIDE (transport));
          do_io_error (transport);
          break;
      
        case DBUS_AUTH_STATE_AUTHENTICATED:
          _dbus_verbose (" %s auth state: authenticated\n",
                         TRANSPORT_SIDE (transport));
          break;
        }
    }

 out:
  if (auth_completed)
    *auth_completed = (orig_auth_state != _dbus_transport_try_to_authenticate (transport));
  
  check_read_watch (transport);
  check_write_watch (transport);
  _dbus_transport_unref (transport);

  if (oom)
    return FALSE;
  else
    return TRUE;
}
コード例 #5
0
/**
 * @todo We need to have a way to wake up the select sleep if
 * a new iteration request comes in with a flag (read/write) that
 * we're not currently serving. Otherwise a call that just reads
 * could block a write call forever (if there are no incoming
 * messages).
 */
static  void
socket_do_iteration (DBusTransport *transport,
                   unsigned int   flags,
                   int            timeout_milliseconds)
{
  DBusTransportSocket *socket_transport = (DBusTransportSocket*) transport;
  DBusPollFD poll_fd;
  int poll_res;
  int poll_timeout;

  _dbus_verbose (" iteration flags = %s%s timeout = %d read_watch = %p write_watch = %p fd = %" DBUS_SOCKET_FORMAT "\n",
                 flags & DBUS_ITERATION_DO_READING ? "read" : "",
                 flags & DBUS_ITERATION_DO_WRITING ? "write" : "",
                 timeout_milliseconds,
                 socket_transport->read_watch,
                 socket_transport->write_watch,
                 _dbus_socket_printable (socket_transport->fd));
  
  /* the passed in DO_READING/DO_WRITING flags indicate whether to
   * read/write messages, but regardless of those we may need to block
   * for reading/writing to do auth.  But if we do reading for auth,
   * we don't want to read any messages yet if not given DO_READING.
   */

  poll_fd.fd = _dbus_socket_get_pollable (socket_transport->fd);
  poll_fd.events = 0;
  
  if (_dbus_transport_try_to_authenticate (transport))
    {
      /* This is kind of a hack; if we have stuff to write, then try
       * to avoid the poll. This is probably about a 5% speedup on an
       * echo client/server.
       *
       * If both reading and writing were requested, we want to avoid this
       * since it could have funky effects:
       *   - both ends spinning waiting for the other one to read
       *     data so they can finish writing
       *   - prioritizing all writing ahead of reading
       */
      if ((flags & DBUS_ITERATION_DO_WRITING) &&
          !(flags & (DBUS_ITERATION_DO_READING | DBUS_ITERATION_BLOCK)) &&
          !transport->disconnected &&
          _dbus_connection_has_messages_to_send_unlocked (transport->connection))
        {
          do_writing (transport);

          if (transport->disconnected ||
              !_dbus_connection_has_messages_to_send_unlocked (transport->connection))
            goto out;
        }

      /* If we get here, we decided to do the poll() after all */
      _dbus_assert (socket_transport->read_watch);
      if (flags & DBUS_ITERATION_DO_READING)
	poll_fd.events |= _DBUS_POLLIN;

      _dbus_assert (socket_transport->write_watch);
      if (flags & DBUS_ITERATION_DO_WRITING)
        poll_fd.events |= _DBUS_POLLOUT;
    }
  else
    {
      DBusAuthState auth_state;
      
      auth_state = _dbus_auth_do_work (transport->auth);

      if (transport->receive_credentials_pending ||
          auth_state == DBUS_AUTH_STATE_WAITING_FOR_INPUT)
	poll_fd.events |= _DBUS_POLLIN;

      if (transport->send_credentials_pending ||
          auth_state == DBUS_AUTH_STATE_HAVE_BYTES_TO_SEND)
	poll_fd.events |= _DBUS_POLLOUT;
    }

  if (poll_fd.events)
    {
      int saved_errno;

      if (flags & DBUS_ITERATION_BLOCK)
	poll_timeout = timeout_milliseconds;
      else
	poll_timeout = 0;

      /* For blocking selects we drop the connection lock here
       * to avoid blocking out connection access during a potentially
       * indefinite blocking call. The io path is still protected
       * by the io_path_cond condvar, so we won't reenter this.
       */
      if (flags & DBUS_ITERATION_BLOCK)
        {
          _dbus_verbose ("unlock pre poll\n");
          _dbus_connection_unlock (transport->connection);
        }
      
    again:
      poll_res = _dbus_poll (&poll_fd, 1, poll_timeout);
      saved_errno = _dbus_save_socket_errno ();

      if (poll_res < 0 && _dbus_get_is_errno_eintr (saved_errno))
	goto again;

      if (flags & DBUS_ITERATION_BLOCK)
        {
          _dbus_verbose ("lock post poll\n");
          _dbus_connection_lock (transport->connection);
        }
      
      if (poll_res >= 0)
        {
          if (poll_res == 0)
            poll_fd.revents = 0; /* some concern that posix does not guarantee this;
                                  * valgrind flags it as an error. though it probably
                                  * is guaranteed on linux at least.
                                  */
          
          if (poll_fd.revents & _DBUS_POLLERR)
            do_io_error (transport);
          else
            {
              dbus_bool_t need_read = (poll_fd.revents & _DBUS_POLLIN) > 0;
              dbus_bool_t need_write = (poll_fd.revents & _DBUS_POLLOUT) > 0;
	      dbus_bool_t authentication_completed;

              _dbus_verbose ("in iteration, need_read=%d need_write=%d\n",
                             need_read, need_write);
              do_authentication (transport, need_read, need_write,
				 &authentication_completed);

	      /* See comment in socket_handle_watch. */
	      if (authentication_completed)
                goto out;
                                 
              if (need_read && (flags & DBUS_ITERATION_DO_READING))
                do_reading (transport);
              if (need_write && (flags & DBUS_ITERATION_DO_WRITING))
                do_writing (transport);
            }
        }
      else
        {
          _dbus_verbose ("Error from _dbus_poll(): %s\n",
                         _dbus_strerror (saved_errno));
        }
    }


 out:
  /* We need to install the write watch only if we did not
   * successfully write everything. Note we need to be careful that we
   * don't call check_write_watch *before* do_writing, since it's
   * inefficient to add the write watch, and we can avoid it most of
   * the time since we can write immediately.
   * 
   * However, we MUST always call check_write_watch(); DBusConnection code
   * relies on the fact that running an iteration will notice that
   * messages are pending.
   */
  check_write_watch (transport);

  _dbus_verbose (" ... leaving do_iteration()\n");
}
コード例 #6
0
ファイル: dbus-transport.c プロジェクト: zsx/windbus
/**
 * 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;
    }
}
コード例 #7
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,
 * 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;
    }
}
コード例 #8
0
/**
 * 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;
}