Ejemplo n.º 1
0
static void client_start_tls(struct client *client)
{
	int fd_ssl;

	client_ref(client);
	if (!client_unref(&client) || client->destroyed)
		return;

	fd_ssl = ssl_proxy_alloc(client->fd, &client->ip, client->pool,
				 client->set, client->ssl_set,
				 &client->ssl_proxy);
	if (fd_ssl == -1) {
		client_notify_disconnect(client,
			CLIENT_DISCONNECT_INTERNAL_ERROR,
			"TLS initialization failed.");
		client_destroy(client,
			"Disconnected: TLS initialization failed.");
		return;
	}
	ssl_proxy_set_client(client->ssl_proxy, client);
	ssl_proxy_start(client->ssl_proxy);

	client->starttls = TRUE;
	client->tls = TRUE;
	client->secured = TRUE;
	login_refresh_proctitle();

	client->fd = fd_ssl;
	client->io = io_add(client->fd, IO_READ, client_input, client);
	i_stream_unref(&client->input);
	o_stream_unref(&client->output);
	client_open_streams(client);

	client->v.starttls(client);
}
Ejemplo n.º 2
0
static int32_t
rtp_sinker_consumable(network_sinker *ns, proto_watch *pw,
                      int32_t stm_i, uint32_t size)
{
    int32_t err = -EINVAL;
    media_sinker *sinker = (media_sinker*)ns;
    rtp_sinker *rs = (rtp_sinker*)ns;
    network_client *nc = (network_client*)rs->interleaved;

    if (rs->trans_mode == RTP_OVER_RTSP && nc)
    {   //@{Interleaved rtp mode}
        client_ref((client*)nc);
        RELEASE_LOCK(sinker->lock);

        err = network_client_consumable(nc, size);
        client_unref((client*)nc);

        AQUIRE_LOCK(sinker->lock);
        return err;
    }

    if (pw)
    {
        return proto_watch_writeable(pw, size);
    }

    return err;
}
Ejemplo n.º 3
0
/* Could be called from any thread, so it could be called after client_unref()
 * has started finalising the #Client. Avoid that by looking up the #Client
 * atomically. */
static void
on_connection_disconnected (GDBusConnection *connection,
                            gboolean         remote_peer_vanished,
                            GError          *error,
                            gpointer         user_data)
{
  guint watcher_id = GPOINTER_TO_UINT (user_data);
  Client *client = NULL;

  client = dup_client (watcher_id);
  if (client == NULL)
    return;

  if (client->name_owner_changed_subscription_id > 0)
    g_dbus_connection_signal_unsubscribe (client->connection, client->name_owner_changed_subscription_id);
  if (client->disconnected_signal_handler_id > 0)
    g_signal_handler_disconnect (client->connection, client->disconnected_signal_handler_id);
  g_object_unref (client->connection);
  client->disconnected_signal_handler_id = 0;
  client->name_owner_changed_subscription_id = 0;
  client->connection = NULL;

  call_vanished_handler (client, FALSE);

  client_unref (client);
}
Ejemplo n.º 4
0
static void
connection_get_cb (GObject      *source_object,
                   GAsyncResult *res,
                   gpointer      user_data)
{
  Client *client = user_data;

  client->connection = g_bus_get_finish (res, NULL);
  if (client->connection == NULL)
    {
      call_lost_handler (client);
      goto out;
    }

  /* No need to schedule this in idle as we're already in the thread
   * that the user called g_bus_own_name() from. This is because
   * g_bus_get() guarantees that.
   *
   * Also, we need to ensure that the handler is invoked *before*
   * we call RequestName(). Otherwise there is a race.
   */
  if (client->bus_acquired_handler != NULL)
    {
      client->bus_acquired_handler (client->connection,
                                    client->name,
                                    client->user_data);
    }

  has_connection (client);

 out:
  client_unref (client);
}
Ejemplo n.º 5
0
/**
 * g_bus_unwatch_name:
 * @watcher_id: An identifier obtained from g_bus_watch_name()
 *
 * Stops watching a name.
 *
 * Since: 2.26
 */
void
g_bus_unwatch_name (guint watcher_id)
{
  Client *client;

  g_return_if_fail (watcher_id > 0);

  client = NULL;

  G_LOCK (lock);
  if (watcher_id == 0 ||
      map_id_to_client == NULL ||
      (client = g_hash_table_lookup (map_id_to_client, GUINT_TO_POINTER (watcher_id))) == NULL)
    {
      g_warning ("Invalid id %d passed to g_bus_unwatch_name()", watcher_id);
      goto out;
    }

  client->cancelled = TRUE;
  g_warn_if_fail (g_hash_table_remove (map_id_to_client, GUINT_TO_POINTER (watcher_id)));

 out:
  G_UNLOCK (lock);

  /* do callback without holding lock */
  if (client != NULL)
    {
      client_unref (client);
    }
}
Ejemplo n.º 6
0
static void
call_handler_data_free (CallHandlerData *data)
{
  if (data->connection != NULL)
    g_object_unref (data->connection);
  client_unref (data->client);
  g_free (data);
}
Ejemplo n.º 7
0
int hi_talk_cli_close(hi_talk_cli_t *hdl)
{
	if (!hdl)
	{
		return (-1);
	}
	client_unref((talk_client_t *)hdl);
	return 0;
}
Ejemplo n.º 8
0
/* Will always be called from the thread which acquired client->main_context. */
static void
on_name_owner_changed (GDBusConnection *connection,
                       const gchar      *sender_name,
                       const gchar      *object_path,
                       const gchar      *interface_name,
                       const gchar      *signal_name,
                       GVariant         *parameters,
                       gpointer          user_data)
{
  guint watcher_id = GPOINTER_TO_UINT (user_data);
  Client *client = NULL;
  const gchar *name;
  const gchar *old_owner;
  const gchar *new_owner;

  client = dup_client (watcher_id);
  if (client == NULL)
    return;

  if (!client->initialized)
    goto out;

  if (g_strcmp0 (object_path, "/org/freedesktop/DBus") != 0 ||
      g_strcmp0 (interface_name, "org.freedesktop.DBus") != 0 ||
      g_strcmp0 (sender_name, "org.freedesktop.DBus") != 0)
    goto out;

  g_variant_get (parameters,
                 "(&s&s&s)",
                 &name,
                 &old_owner,
                 &new_owner);

  /* we only care about a specific name */
  if (g_strcmp0 (name, client->name) != 0)
    goto out;

  if ((old_owner != NULL && strlen (old_owner) > 0) && client->name_owner != NULL)
    {
      g_free (client->name_owner);
      client->name_owner = NULL;
      call_vanished_handler (client, FALSE);
    }

  if (new_owner != NULL && strlen (new_owner) > 0)
    {
      g_warn_if_fail (client->name_owner == NULL);
      g_free (client->name_owner);
      client->name_owner = g_strdup (new_owner);
      call_appeared_handler (client);
    }

 out:
  client_unref (client);
}
Ejemplo n.º 9
0
login_proxy_free_full(struct login_proxy **_proxy, const char *reason,
		      bool delayed)
{
	struct login_proxy *proxy = *_proxy;
	struct client *client = proxy->client;
	const char *ipstr;
	unsigned int delay_ms = 0;

	*_proxy = NULL;

	if (proxy->destroying)
		return;
	proxy->destroying = TRUE;

	/* we'll disconnect server side in any case. */
	login_proxy_disconnect(proxy);

	if (proxy->client_fd != -1) {
		/* detached proxy */
		DLLIST_REMOVE(&login_proxies, proxy);

		if (delayed)
			delay_ms = login_proxy_delay_disconnect(proxy);

		ipstr = net_ip2addr(&proxy->client->ip);
		client_log(proxy->client, t_strdup_printf(
			"proxy(%s): disconnecting %s%s%s",
			proxy->client->virtual_user,
			ipstr != NULL ? ipstr : "",
			reason == NULL ? "" : t_strdup_printf(" (%s)", reason),
			delay_ms == 0 ? "" : t_strdup_printf(" - disconnecting client in %ums", delay_ms)));

		if (proxy->client_io != NULL)
			io_remove(&proxy->client_io);
	} else {
		i_assert(proxy->client_io == NULL);
		i_assert(proxy->client_input == NULL);
		i_assert(proxy->client_output == NULL);
		i_assert(proxy->client_fd == -1);

		DLLIST_REMOVE(&login_proxies_pending, proxy);

		if (proxy->callback != NULL)
			proxy->callback(proxy->client);
	}
	if (delay_ms == 0)
		login_proxy_free_final(proxy);
	else {
		proxy->client_io = io_add_istream(proxy->client_input,
			proxy_client_disconnected_input, proxy);
	}

	client->login_proxy = NULL;
	client_unref(&client);
}
Ejemplo n.º 10
0
static void
rtp_sinker_fin(network_sinker *ns)
{
    rtp_sinker *rs = (rtp_sinker*)ns;

    if (rs->interleaved)
    {
        client_unref((client*)rs->interleaved);
        rs->interleaved = NULL;
    }
}
Ejemplo n.º 11
0
void client_set_del(client_set *cs, client *c)
{
	int32_t err;

	AQUIRE_LOCK(cs->lock);
	err = __client_set_del(cs, c);
	RELEASE_LOCK(cs->lock);

	if (!err)
	{
		client_unref(c);
	}
}
Ejemplo n.º 12
0
static void
start_service_by_name_cb (GObject      *source_object,
                          GAsyncResult *res,
                          gpointer      user_data)
{
  Client *client = user_data;
  GVariant *result;

  result = NULL;

  result = g_dbus_connection_call_finish (client->connection,
                                          res,
                                          NULL);
  if (result != NULL)
    {
      guint32 start_service_result;
      g_variant_get (result, "(u)", &start_service_result);

      if (start_service_result == 1) /* DBUS_START_REPLY_SUCCESS */
        {
          invoke_get_name_owner (client);
        }
      else if (start_service_result == 2) /* DBUS_START_REPLY_ALREADY_RUNNING */
        {
          invoke_get_name_owner (client);
        }
      else
        {
          g_warning ("Unexpected reply %d from StartServiceByName() method", start_service_result);
          call_vanished_handler (client, FALSE);
          client->initialized = TRUE;
        }
    }
  else
    {
      /* Errors are not unexpected; the bus will reply e.g.
       *
       *   org.freedesktop.DBus.Error.ServiceUnknown: The name org.gnome.Epiphany2
       *   was not provided by any .service files
       *
       * This doesn't mean that the name doesn't have an owner, just
       * that it's not provided by a .service file. So proceed to
       * invoke GetNameOwner().
       */
      invoke_get_name_owner (client);
    }

  if (result != NULL)
    g_variant_unref (result);
  client_unref (client);
}
Ejemplo n.º 13
0
static void
connection_get_cb (GObject      *source_object,
                   GAsyncResult *res,
                   gpointer      user_data)
{
  Client *client = user_data;

  client->connection = g_bus_get_finish (res, NULL);
  if (client->connection == NULL)
    {
      call_vanished_handler (client, FALSE);
      goto out;
    }

  has_connection (client);

 out:
  client_unref (client);
}
Ejemplo n.º 14
0
static void
get_name_owner_cb (GObject      *source_object,
                   GAsyncResult *res,
                   gpointer      user_data)
{
  Client *client = user_data;
  GVariant *result;
  const char *name_owner;

  name_owner = NULL;
  result = NULL;

  result = g_dbus_connection_call_finish (client->connection,
                                          res,
                                          NULL);
  if (result != NULL)
    {
      g_variant_get (result, "(&s)", &name_owner);
    }

  if (name_owner != NULL)
    {
      g_warn_if_fail (client->name_owner == NULL);
      client->name_owner = g_strdup (name_owner);
      call_appeared_handler (client);
    }
  else
    {
      call_vanished_handler (client, FALSE);
    }

  client->initialized = TRUE;

  if (result != NULL)
    g_variant_unref (result);
  client_unref (client);
}
Ejemplo n.º 15
0
void client_destroy(struct client *client, const char *reason)
{
	if (client->destroyed)
		return;
	client->destroyed = TRUE;

	if (!client->login_success && reason != NULL) {
		reason = t_strconcat(reason, " ",
			client_get_extra_disconnect_reason(client), NULL);
	}
	if (reason != NULL)
		client_log(client, reason);

	if (last_client == client)
		last_client = client->prev;
	DLLIST_REMOVE(&clients, client);

	if (client->input != NULL)
		i_stream_close(client->input);
	if (client->output != NULL)
		o_stream_close(client->output);

	if (client->master_tag != 0) {
		i_assert(client->auth_request == NULL);
		i_assert(client->authenticating);
		i_assert(client->refcount > 1);
		client->authenticating = FALSE;
		master_auth_request_abort(master_auth, client->master_tag);
		client->refcount--;
	} else if (client->auth_request != NULL) {
		i_assert(client->authenticating);
		sasl_server_auth_abort(client);
	} else {
		i_assert(!client->authenticating);
	}

	if (client->io != NULL)
		io_remove(&client->io);
	if (client->to_disconnect != NULL)
		timeout_remove(&client->to_disconnect);
	if (client->to_auth_waiting != NULL)
		timeout_remove(&client->to_auth_waiting);
	if (client->auth_response != NULL)
		str_free(&client->auth_response);

	if (client->fd != -1) {
		net_disconnect(client->fd);
		client->fd = -1;
	}

	if (client->proxy_password != NULL) {
		safe_memset(client->proxy_password, 0,
			    strlen(client->proxy_password));
		i_free_and_null(client->proxy_password);
	}

	if (client->proxy_sasl_client != NULL)
		dsasl_client_free(&client->proxy_sasl_client);
	if (client->login_proxy != NULL)
		login_proxy_free(&client->login_proxy);
	if (client->v.destroy != NULL)
		client->v.destroy(client);
	if (client_unref(&client) && initial_service_count == 1) {
		/* as soon as this connection is done with proxying
		   (or whatever), the process will die. there's no need for
		   authentication anymore, so close the connection.
		   do this only with initial service_count=1, in case there
		   are other clients with pending authentications */
		auth_client_disconnect(auth_client, "unnecessary connection");
	}
	login_client_destroyed();
	login_refresh_proctitle();
}
Ejemplo n.º 16
0
static void
request_name_cb (GObject      *source_object,
                 GAsyncResult *res,
                 gpointer      user_data)
{
  Client *client = user_data;
  GVariant *result;
  guint32 request_name_reply;
  gboolean subscribe;

  request_name_reply = 0;
  result = NULL;

  result = g_dbus_connection_call_finish (client->connection,
                                          res,
                                          NULL);
  if (result != NULL)
    {
      g_variant_get (result, "(u)", &request_name_reply);
      g_variant_unref (result);
    }

  subscribe = FALSE;

  switch (request_name_reply)
    {
    case 1: /* DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER */
      /* We got the name - now listen for NameLost and NameAcquired */
      call_acquired_handler (client);
      subscribe = TRUE;
      client->needs_release = TRUE;
      break;

    case 2: /* DBUS_REQUEST_NAME_REPLY_IN_QUEUE */
      /* Waiting in line - listen for NameLost and NameAcquired */
      call_lost_handler (client);
      subscribe = TRUE;
      client->needs_release = TRUE;
      break;

    default:
      /* assume we couldn't get the name - explicit fallthrough */
    case 3: /* DBUS_REQUEST_NAME_REPLY_EXISTS */
    case 4: /* DBUS_REQUEST_NAME_REPLY_ALREADY_OWNER */
      /* Some other part of the process is already owning the name */
      call_lost_handler (client);
      break;
    }

  if (subscribe)
    {
      /* start listening to NameLost and NameAcquired messages */
      client->name_lost_subscription_id =
        g_dbus_connection_signal_subscribe (client->connection,
                                            "org.freedesktop.DBus",
                                            "org.freedesktop.DBus",
                                            "NameLost",
                                            "/org/freedesktop/DBus",
                                            client->name,
                                            on_name_lost_or_acquired,
                                            client,
                                            NULL);
      client->name_acquired_subscription_id =
        g_dbus_connection_signal_subscribe (client->connection,
                                            "org.freedesktop.DBus",
                                            "org.freedesktop.DBus",
                                            "NameAcquired",
                                            "/org/freedesktop/DBus",
                                            client->name,
                                            on_name_lost_or_acquired,
                                            client,
                                            NULL);
    }

  client_unref (client);
}
Ejemplo n.º 17
0
login_proxy_free_reason(struct login_proxy **_proxy, const char *reason)
{
	struct login_proxy *proxy = *_proxy;
	struct client *client = proxy->client;
	const char *ipstr;

	*_proxy = NULL;

	if (proxy->destroying)
		return;
	proxy->destroying = TRUE;

	if (proxy->to != NULL)
		timeout_remove(&proxy->to);
	if (proxy->to_notify != NULL)
		timeout_remove(&proxy->to_notify);

	if (proxy->state_rec != NULL)
		proxy->state_rec->num_waiting_connections--;
	if (proxy->to != NULL)
		timeout_remove(&proxy->to);

	if (proxy->server_io != NULL)
		io_remove(&proxy->server_io);
	if (proxy->server_input != NULL)
		i_stream_destroy(&proxy->server_input);
	if (proxy->server_output != NULL)
		o_stream_destroy(&proxy->server_output);

	if (proxy->client_fd != -1) {
		/* detached proxy */
		DLLIST_REMOVE(&login_proxies, proxy);

		ipstr = net_ip2addr(&proxy->client->ip);
		client_log(proxy->client, t_strdup_printf(
			"proxy(%s): disconnecting %s%s",
			proxy->client->virtual_user,
			ipstr != NULL ? ipstr : "",
			reason == NULL ? "" : t_strdup_printf(" (%s)", reason)));

		if (proxy->client_io != NULL)
			io_remove(&proxy->client_io);
		if (proxy->client_output != NULL)
			o_stream_destroy(&proxy->client_output);
		net_disconnect(proxy->client_fd);
	} else {
		i_assert(proxy->client_io == NULL);
		i_assert(proxy->client_output == NULL);

		DLLIST_REMOVE(&login_proxies_pending, proxy);

		if (proxy->callback != NULL)
			proxy->callback(proxy->client);
	}

	if (proxy->server_fd != -1)
		net_disconnect(proxy->server_fd);

	if (proxy->ssl_server_proxy != NULL)
		ssl_proxy_free(&proxy->ssl_server_proxy);
	i_free(proxy->host);
	i_free(proxy);

	client->login_proxy = NULL;
	client_unref(&client);
}
Ejemplo n.º 18
0
static void
request_name_cb (GObject      *source_object,
                 GAsyncResult *res,
                 gpointer      user_data)
{
  Client *client = user_data;
  GVariant *result;
  guint32 request_name_reply;
  gboolean subscribe;

  request_name_reply = 0;
  result = NULL;

  /* don't use client->connection - it may be NULL already */
  result = g_dbus_connection_call_finish (G_DBUS_CONNECTION (source_object),
                                          res,
                                          NULL);
  if (result != NULL)
    {
      g_variant_get (result, "(u)", &request_name_reply);
      g_variant_unref (result);
    }

  subscribe = FALSE;

  switch (request_name_reply)
    {
    case 1: /* DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER */
      /* We got the name - now listen for NameLost and NameAcquired */
      call_acquired_handler (client);
      subscribe = TRUE;
      client->needs_release = TRUE;
      break;

    case 2: /* DBUS_REQUEST_NAME_REPLY_IN_QUEUE */
      /* Waiting in line - listen for NameLost and NameAcquired */
      call_lost_handler (client);
      subscribe = TRUE;
      client->needs_release = TRUE;
      break;

    default:
      /* assume we couldn't get the name - explicit fallthrough */
    case 3: /* DBUS_REQUEST_NAME_REPLY_EXISTS */
    case 4: /* DBUS_REQUEST_NAME_REPLY_ALREADY_OWNER */
      /* Some other part of the process is already owning the name */
      call_lost_handler (client);
      break;
    }


  if (subscribe)
    {
      GDBusConnection *connection = NULL;

      /* if cancelled, there is no point in subscribing to signals - if not, make sure
       * we use a known good Connection object since it may be set to NULL at any point
       * after being cancelled
       */
      G_LOCK (lock);
      if (!client->cancelled)
        connection = g_object_ref (client->connection);
      G_UNLOCK (lock);

      /* start listening to NameLost and NameAcquired messages */
      if (connection != NULL)
        {
          client->name_lost_subscription_id =
            g_dbus_connection_signal_subscribe (connection,
                                                "org.freedesktop.DBus",
                                                "org.freedesktop.DBus",
                                                "NameLost",
                                                "/org/freedesktop/DBus",
                                                client->name,
                                                G_DBUS_SIGNAL_FLAGS_NONE,
                                                on_name_lost_or_acquired,
                                                client,
                                                NULL);
          client->name_acquired_subscription_id =
            g_dbus_connection_signal_subscribe (connection,
                                                "org.freedesktop.DBus",
                                                "org.freedesktop.DBus",
                                                "NameAcquired",
                                                "/org/freedesktop/DBus",
                                                client->name,
                                                G_DBUS_SIGNAL_FLAGS_NONE,
                                                on_name_lost_or_acquired,
                                                client,
                                                NULL);
          g_object_unref (connection);
        }
    }

  client_unref (client);
}
Ejemplo n.º 19
0
/**
 * g_bus_unown_name:
 * @owner_id: An identifier obtained from g_bus_own_name()
 *
 * Stops owning a name.
 *
 * Since: 2.26
 */
void
g_bus_unown_name (guint owner_id)
{
  Client *client;

  g_return_if_fail (owner_id > 0);

  client = NULL;

  G_LOCK (lock);
  if (owner_id == 0 || map_id_to_client == NULL ||
      (client = g_hash_table_lookup (map_id_to_client, GUINT_TO_POINTER (owner_id))) == NULL)
    {
      g_warning ("Invalid id %d passed to g_bus_unown_name()", owner_id);
      goto out;
    }

  client->cancelled = TRUE;
  g_warn_if_fail (g_hash_table_remove (map_id_to_client, GUINT_TO_POINTER (owner_id)));

 out:
  G_UNLOCK (lock);

  /* do callback without holding lock */
  if (client != NULL)
    {
      /* Release the name if needed */
      if (client->needs_release && client->connection != NULL)
        {
          GVariant *result;
          GError *error;
          guint32 release_name_reply;

          /* TODO: it kinda sucks having to do a sync call to release the name - but if
           * we don't, then a subsequent grab of the name will make the bus daemon return
           * IN_QUEUE which will trigger name_lost().
           *
           * I believe this is a bug in the bus daemon.
           */
          error = NULL;
          result = g_dbus_connection_call_sync (client->connection,
                                                "org.freedesktop.DBus",  /* bus name */
                                                "/org/freedesktop/DBus", /* object path */
                                                "org.freedesktop.DBus",  /* interface name */
                                                "ReleaseName",           /* method name */
                                                g_variant_new ("(s)", client->name),
                                                G_VARIANT_TYPE ("(u)"),
                                                G_DBUS_CALL_FLAGS_NONE,
                                                -1,
                                                NULL,
                                                &error);
          if (result == NULL)
            {
              g_warning ("Error releasing name %s: %s", client->name, error->message);
              g_error_free (error);
            }
          else
            {
              g_variant_get (result, "(u)", &release_name_reply);
              if (release_name_reply != 1 /* DBUS_RELEASE_NAME_REPLY_RELEASED */)
                {
                  g_warning ("Unexpected reply %d when releasing name %s", release_name_reply, client->name);
                }
              g_variant_unref (result);
            }
        }

      if (client->disconnected_signal_handler_id > 0)
        g_signal_handler_disconnect (client->connection, client->disconnected_signal_handler_id);
      if (client->name_acquired_subscription_id > 0)
        g_dbus_connection_signal_unsubscribe (client->connection, client->name_acquired_subscription_id);
      if (client->name_lost_subscription_id > 0)
        g_dbus_connection_signal_unsubscribe (client->connection, client->name_lost_subscription_id);
      client->disconnected_signal_handler_id = 0;
      client->name_acquired_subscription_id = 0;
      client->name_lost_subscription_id = 0;
      if (client->connection != NULL)
        {
          g_object_unref (client->connection);
          client->connection = NULL;
        }

      client_unref (client);
    }
}
Ejemplo n.º 20
0
static void
sasl_callback(struct client *client, enum sasl_server_reply sasl_reply,
	      const char *data, const char *const *args)
{
	struct client_auth_reply reply;

	i_assert(!client->destroyed ||
		 sasl_reply == SASL_SERVER_REPLY_AUTH_ABORTED ||
		 sasl_reply == SASL_SERVER_REPLY_MASTER_FAILED);

	switch (sasl_reply) {
	case SASL_SERVER_REPLY_SUCCESS:
		if (client->to_auth_waiting != NULL)
			timeout_remove(&client->to_auth_waiting);
		if (args != NULL) {
			client_auth_parse_args(client, args, &reply);
			if (client_auth_handle_reply(client, &reply, TRUE))
				break;
		}
		client_auth_result(client, CLIENT_AUTH_RESULT_SUCCESS,
				   NULL, NULL);
		client_destroy_success(client, "Login");
		break;
	case SASL_SERVER_REPLY_AUTH_FAILED:
	case SASL_SERVER_REPLY_AUTH_ABORTED:
		if (client->to_auth_waiting != NULL)
			timeout_remove(&client->to_auth_waiting);
		if (args != NULL) {
			client_auth_parse_args(client, args, &reply);
			reply.nologin = TRUE;
			if (client_auth_handle_reply(client, &reply, FALSE))
				break;
		}

		if (sasl_reply == SASL_SERVER_REPLY_AUTH_ABORTED) {
			client_auth_result(client, CLIENT_AUTH_RESULT_ABORTED,
				NULL, "Authentication aborted by client.");
		} else if (data == NULL) {
			client_auth_result(client,
				CLIENT_AUTH_RESULT_AUTHFAILED, NULL,
				AUTH_FAILED_MSG);
		} else {
			client_auth_result(client,
				CLIENT_AUTH_RESULT_AUTHFAILED_REASON, NULL,
				data);
		}

		if (!client->destroyed)
			client_auth_failed(client);
		break;
	case SASL_SERVER_REPLY_MASTER_FAILED:
		if (data != NULL) {
			/* authentication itself succeeded, we just hit some
			   internal failure. */
			client_auth_result(client, CLIENT_AUTH_RESULT_TEMPFAIL,
					   NULL, data);
		}

		/* the fd may still be hanging somewhere in kernel or another
		   process. make sure the client gets disconnected. */
		if (shutdown(client->fd, SHUT_RDWR) < 0 && errno != ENOTCONN)
			i_error("shutdown() failed: %m");

		if (data == NULL)
			client_destroy_internal_failure(client);
		else
			client_destroy_success(client, data);
		break;
	case SASL_SERVER_REPLY_CONTINUE:
		i_assert(client->v.auth_send_challenge != NULL);
		client->v.auth_send_challenge(client, data);

		if (client->to_auth_waiting != NULL)
			timeout_remove(&client->to_auth_waiting);

		if (client->auth_response != NULL)
			str_truncate(client->auth_response, 0);

		i_assert(client->io == NULL);
		client->auth_waiting = TRUE;
		client->io = io_add(client->fd, IO_READ,
				    client_auth_input, client);
		client_auth_input(client);
		return;
	}

	client_unref(&client);
}
Ejemplo n.º 21
0
static void
client_close(struct context *ctx, struct conn *conn)
{
    rstatus_t status;
    struct msg *msg, *nmsg; /* current and next message */

    ASSERT(conn->type == CONN_CLIENT);

    client_close_stats(ctx, conn->owner, conn->err, conn->eof);

    if (conn->sd < 0) {
        client_unref(conn);
        return;
    }

    msg = conn->rmsg;
    if (msg != NULL) {
        conn->rmsg = NULL;

        ASSERT(msg->peer == NULL);
        ASSERT(msg->request && !msg->done);

        log_debug(LOG_INFO, "close c %d discarding pending req %"PRIu64" len "
                  "%"PRIu32" type %d", conn->sd, msg->id, msg->mlen,
                  msg->type);

        req_put(msg);
    }

    ASSERT(conn->smsg == NULL);
    ASSERT(TAILQ_EMPTY(&conn->imsg_q));

    for (msg = TAILQ_FIRST(&conn->omsg_q); msg != NULL; msg = nmsg) {
        nmsg = TAILQ_NEXT(msg, c_tqe);

        /* dequeue the message (request) from client outq */
        conn_dequeue_outq(ctx, conn, msg);

        if (msg->done) {
            log_debug(LOG_INFO, "close c %d discarding %s req %"PRIu64" len "
                      "%"PRIu32" type %d", conn->sd,
                      msg->error ? "error": "completed", msg->id, msg->mlen,
                      msg->type);
            req_put(msg);
        } else {
            msg->swallow = 1;

            ASSERT(msg->request);
            ASSERT(msg->peer == NULL);

            log_debug(LOG_INFO, "close c %d schedule swallow of req %"PRIu64" "
                      "len %"PRIu32" type %d", conn->sd, msg->id, msg->mlen,
                      msg->type);
        }

        stats_pool_incr(ctx, client_dropped_requests);
    }
    ASSERT(TAILQ_EMPTY(&conn->omsg_q));

    status = close(conn->sd);
    if (status < 0) {
        log_error("close c %d failed, ignored: %s", conn->sd, strerror(errno));
    }
    conn->sd = -1;
    client_unref(conn);
}