예제 #1
0
static CockpitChannelResponse *
cockpit_channel_response_create (CockpitWebService *service,
                                 CockpitWebResponse *response,
                                 CockpitTransport *transport,
                                 const gchar *logname,
                                 GHashTable *headers,
                                 JsonObject *open)
{
  CockpitChannelResponse *chesp;
  const gchar *payload;
  JsonObject *done;
  GBytes *bytes;

  payload = json_object_get_string_member (open, "payload");

  chesp = g_new0 (CockpitChannelResponse, 1);
  chesp->response = g_object_ref (response);
  chesp->transport = g_object_ref (transport);
  chesp->headers = g_hash_table_ref (headers);
  chesp->channel = cockpit_web_service_unique_channel (service);
  chesp->open = json_object_ref (open);

  if (!cockpit_json_get_string (open, "path", chesp->channel, &chesp->logname))
    chesp->logname = chesp->channel;

  json_object_set_string_member (open, "command", "open");
  json_object_set_string_member (open, "channel", chesp->channel);

  /* Special handling for http-stream1, splice in headers, handle injection */
  if (g_strcmp0 (payload, "http-stream1") == 0)
    chesp->transport_recv = g_signal_connect (transport, "recv", G_CALLBACK (on_httpstream_recv), chesp);
  else
    chesp->transport_recv = g_signal_connect (transport, "recv", G_CALLBACK (on_transport_recv), chesp);

  /* Special handling for http-stream2, splice in headers, handle injection */
  if (g_strcmp0 (payload, "http-stream2") == 0)
    chesp->transport_control = g_signal_connect (transport, "control", G_CALLBACK (on_httpstream_control), chesp);
  else
    chesp->transport_control = g_signal_connect (transport, "control", G_CALLBACK (on_transport_control), chesp);

  chesp->transport_closed = g_signal_connect (transport, "closed", G_CALLBACK (on_transport_closed), chesp);

  bytes = cockpit_json_write_bytes (chesp->open);
  cockpit_transport_send (transport, NULL, bytes);
  g_bytes_unref (bytes);

  done = cockpit_transport_build_json ("command", "done", "channel", chesp->channel, NULL);
  bytes = cockpit_json_write_bytes (done);
  json_object_unref (done);
  cockpit_transport_send (transport, NULL, bytes);
  g_bytes_unref (bytes);

  return chesp;
}
예제 #2
0
/**
 * cockpit_channel_control:
 * @self: the channel
 * @command: the control command
 * @options: optional control message or NULL
 *
 * Send a control message to the other side.
 *
 * If @options is not NULL, then it may be modified by this code.
 *
 * With @command of "done" will send an EOF to the other side. This
 * should only be called once. Whether an EOF should be sent or not
 * depends on the payload type.
 */
void
cockpit_channel_control (CockpitChannel *self,
                         const gchar *command,
                         JsonObject *options)
{
  JsonObject *object;
  GBytes *message;

  g_return_if_fail (COCKPIT_IS_CHANNEL (self));
  g_return_if_fail (command != NULL);

  if (g_str_equal (command, "done"))
    {
      g_return_if_fail (self->priv->sent_done == FALSE);
      self->priv->sent_done = TRUE;
    }

  if (options)
    object = json_object_ref (options);
  else
    object = json_object_new ();

  json_object_set_string_member (object, "command", command);
  json_object_set_string_member (object, "channel", self->priv->id);

  message = cockpit_json_write_bytes (object);
  json_object_unref (object);

  cockpit_transport_send (self->priv->transport, NULL, message);
  g_bytes_unref (message);
}
예제 #3
0
파일: bridge.c 프로젝트: xyzkizer/cockpit
static void
send_init_command (CockpitTransport *transport)
{
  const gchar *checksum;
  const gchar *name;
  JsonObject *object;
  GBytes *bytes;

  object = json_object_new ();
  json_object_set_string_member (object, "command", "init");
  json_object_set_int_member (object, "version", 1);

  checksum = cockpit_packages_get_checksum (packages);
  if (checksum)
    json_object_set_string_member (object, "checksum", checksum);

  /* Happens when we're in --interact mode */
  name = cockpit_dbus_internal_name ();
  if (name)
    json_object_set_string_member (object, "bridge-dbus-name", name);

  bytes = cockpit_json_write_bytes (object);
  json_object_unref (object);

  cockpit_transport_send (transport, NULL, bytes);
  g_bytes_unref (bytes);
}
예제 #4
0
static void
on_helper_read (CockpitPipe *pipe,
                GByteArray *buffer,
                gboolean eof,
                gpointer user_data)
{
  ReauthorizeCaller *caller = user_data;
  JsonObject *object;
  GBytes *bytes;
  guint8 *lf;

  lf = memchr (buffer->data, '\n', buffer->len);
  if (!lf)
    return;

  /* Null terminate the challenge */
  *lf = 0;

  g_debug ("got challenge from helper, will send to cockpit-ws: %s", (gchar *)buffer->data);

  /* send an authorize packet here */
  object = json_object_new ();
  json_object_set_string_member (object, "command", "authorize");
  json_object_set_string_member (object, "cookie", caller->cookie);
  json_object_set_string_member (object, "challenge", (gchar *)buffer->data);
  bytes = cockpit_json_write_bytes (object);
  json_object_unref (object);

  /* Consume from buffer, including null termination */
  cockpit_pipe_skip (buffer, lf - buffer->data);

  cockpit_transport_send (caller->self->transport, NULL, bytes);
  g_bytes_unref (bytes);
}
예제 #5
0
static GBytes *
build_environment (GHashTable *os_release)
{
  /*
   * We don't include entirety of os-release into the
   * environment for the login.html page. There could
   * be unexpected things in here.
   *
   * However since we are displaying branding based on
   * the OS name variant flavor and version, including
   * the corresponding information is not a leak.
   */
  static const gchar *release_fields[] = {
    "NAME", "ID", "PRETTY_NAME", "VARIANT", "VARIANT_ID", "CPE_NAME",
  };

  static const gchar *prefix = "\n    <script>\nvar environment = ";
  static const gchar *suffix = ";\n    </script>";

  GByteArray *buffer;
  GBytes *bytes;
  JsonObject *object;
  const gchar *value;
  gchar *hostname;
  JsonObject *osr;
  gint i;

  object = json_object_new ();
  add_page_to_environment (object);

  hostname = g_malloc0 (HOST_NAME_MAX + 1);
  gethostname (hostname, HOST_NAME_MAX);
  hostname[HOST_NAME_MAX] = '\0';
  json_object_set_string_member (object, "hostname", hostname);
  g_free (hostname);

  if (os_release)
    {
      osr = json_object_new ();
      for (i = 0; i < G_N_ELEMENTS (release_fields); i++)
        {
          value = g_hash_table_lookup (os_release, release_fields[i]);
          if (value)
            json_object_set_string_member (osr, release_fields[i], value);
        }
      json_object_set_object_member (object, "os-release", osr);
    }

  add_oauth_to_environment (object);

  bytes = cockpit_json_write_bytes (object);
  json_object_unref (object);

  buffer = g_bytes_unref_to_array (bytes);
  g_byte_array_prepend (buffer, (const guint8 *)prefix, strlen (prefix));
  g_byte_array_append (buffer, (const guint8 *)suffix, strlen (suffix));
  return g_byte_array_free_to_bytes (buffer);
}
예제 #6
0
static void
process_open (CockpitRouter *self,
              CockpitTransport *transport,
              const gchar *channel,
              JsonObject *options,
              GBytes *data)
{
  GList *l;
  GBytes *new_payload = NULL;

  if (!channel)
    {
      g_warning ("Caller tried to open channel with invalid id");
      cockpit_transport_close (transport, "protocol-error");
    }

  /* Check that this isn't a local channel */
  else if (g_hash_table_lookup (self->channels, channel))
    {
      g_warning ("%s: caller tried to reuse a channel that's already in use", channel);
      cockpit_transport_close (self->transport, "protocol-error");
      return;
    }

  /* Request that this channel is frozen, and requeue its open message for later */
  else if (g_hash_table_size (self->fences) > 0 && !g_hash_table_lookup (self->fences, channel))
    {
      if (!self->fenced)
        self->fenced = g_queue_new ();
      g_queue_push_tail (self->fenced, g_strdup (channel));
      cockpit_transport_freeze (self->transport, channel);
      cockpit_transport_emit_control (self->transport, "open", channel, options, data);
    }

  else if (!cockpit_router_normalize_host (self, options))
    {
      g_warning ("%s: caller specified invalid 'host' field in open message", channel);
      process_open_not_supported (self, channel, options, data, NULL);
    }

  /* Now go throgh the rules */
  else
    {
      cockpit_router_normalize_host_params (options);
      new_payload = cockpit_json_write_bytes (options);
      for (l = self->rules; l != NULL; l = g_list_next (l))
        {
          if (router_rule_match (l->data, options) &&
              router_rule_invoke (l->data, self, channel, options, new_payload))
            {
              break;
            }
        }
    }
  if (new_payload)
    g_bytes_unref (new_payload);
}
예제 #7
0
/**
 * cockpit_channel_control:
 * @self: the channel
 * @command: the control command
 * @options: optional control message or NULL
 *
 * Send a control message to the other side.
 *
 * If @options is not NULL, then it may be modified by this code.
 *
 * With @command of "done" will send an EOF to the other side. This
 * should only be called once. Whether an EOF should be sent or not
 * depends on the payload type.
 */
void
cockpit_channel_control (CockpitChannel *self,
                         const gchar *command,
                         JsonObject *options)
{
  JsonObject *object;
  GBytes *message;
  const gchar *problem;
  gchar *problem_copy = NULL;

  g_return_if_fail (COCKPIT_IS_CHANNEL (self));
  g_return_if_fail (command != NULL);

  if (g_str_equal (command, "done"))
    {
      g_return_if_fail (self->priv->sent_done == FALSE);
      self->priv->sent_done = TRUE;
    }

  /* If closing save the close options
   * and let close send the message */
  else if (g_str_equal (command, "close"))
    {
      if (!self->priv->close_options)
        {
          /* Ref for close_options, freed in parent */
          self->priv->close_options = json_object_ref (options);
        }

      if (!cockpit_json_get_string (options, "problem", NULL, &problem))
        problem = NULL;

      /* Use a problem copy so it out lasts the value in close_options */
      problem_copy = g_strdup (problem);
      cockpit_channel_close (self, problem_copy);
      goto out;
    }

  if (options)
    object = json_object_ref (options);
  else
    object = json_object_new ();

  json_object_set_string_member (object, "command", command);
  json_object_set_string_member (object, "channel", self->priv->id);

  message = cockpit_json_write_bytes (object);
  json_object_unref (object);

  cockpit_transport_send (self->priv->transport, NULL, message);
  g_bytes_unref (message);

out:
  g_free (problem_copy);
}
예제 #8
0
static void
send_login_response (CockpitWebResponse *response,
                     JsonObject *object,
                     GHashTable *headers)
{
  GBytes *content;

  content = cockpit_json_write_bytes (object);

  g_hash_table_replace (headers, g_strdup ("Content-Type"), g_strdup ("application/json"));
  cockpit_web_response_content (response, headers, content, NULL);
  g_bytes_unref (content);
}
예제 #9
0
static void
send_init_command (CockpitTransport *transport)
{
  JsonObject *object;
  GBytes *bytes;

  object = json_object_new ();
  json_object_set_string_member (object, "command", "init");
  json_object_set_int_member (object, "version", 1);

  bytes = cockpit_json_write_bytes (object);
  cockpit_transport_send (transport, NULL, bytes);
  g_bytes_unref (bytes);
}
예제 #10
0
void
cockpit_fswatch_emit_event (CockpitChannel    *channel,
                            GFile             *file,
                            GFile             *other_file,
                            GFileMonitorEvent  event_type)
{
  JsonObject *msg;
  GBytes *msg_bytes;

  msg = json_object_new ();
  json_object_set_string_member (msg, "event", event_type_to_string (event_type));
  if (file)
    {
      char *p = g_file_get_path (file);
      char *t = cockpit_get_file_tag (p);
      json_object_set_string_member (msg, "path", p);
      json_object_set_string_member (msg, "tag", t);
      if (event_type == G_FILE_MONITOR_EVENT_CREATED)
        {
          GError *error = NULL;
          GFileInfo *info = g_file_query_info (file,
                                               G_FILE_ATTRIBUTE_STANDARD_TYPE,
                                               G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS,
                                               NULL, &error);
          if (info)
            {
              json_object_set_string_member
                (msg, "type", cockpit_file_type_to_string (g_file_info_get_file_type (info)));
              g_object_unref (info);
            }

          g_clear_error (&error);
      }

      g_free (p);
      g_free (t);
    }
  if (other_file)
    {
      char *p = g_file_get_path (other_file);
      json_object_set_string_member (msg, "other", p);
      g_free (p);
    }
  msg_bytes = cockpit_json_write_bytes (msg);
  json_object_unref (msg);
  cockpit_channel_send (channel, msg_bytes, TRUE);
  g_bytes_unref (msg_bytes);
}
예제 #11
0
static void
on_login_complete (GObject *object,
                   GAsyncResult *result,
                   gpointer user_data)
{
  CockpitWebResponse *response = user_data;
  GError *error = NULL;
  JsonObject *response_data = NULL;
  GHashTable *headers;
  GIOStream *io_stream;
  GBytes *content;

  io_stream = cockpit_web_response_get_stream (response);

  headers = cockpit_web_server_new_table ();
  response_data = cockpit_auth_login_finish (COCKPIT_AUTH (object), result,
                                             io_stream, headers, &error);

  /* Never cache a login response */
  cockpit_web_response_set_cache_type (response, COCKPIT_WEB_RESPONSE_NO_CACHE);
  if (error)
    {
      if (response_data)
        {
          g_hash_table_insert (headers, g_strdup ("Content-Type"), g_strdup ("application/json"));
          content = cockpit_json_write_bytes (response_data);
          cockpit_web_response_headers_full (response, 401, "Authentication required", -1, headers);
          cockpit_web_response_queue (response, content);
          cockpit_web_response_complete (response);
          g_bytes_unref (content);
        }
      else
        {
          cockpit_web_response_gerror (response, headers, error);
        }
      g_error_free (error);
    }
  else
    {
      send_login_response (response, response_data, headers);
    }

  if (response_data)
    json_object_unref (response_data);

  g_hash_table_unref (headers);
  g_object_unref (response);
}
예제 #12
0
static gboolean
process_ping (CockpitWebService *self,
              CockpitSocket *socket,
              JsonObject *options)
{
  GBytes *payload;

  /* Respond to a ping without a channel, by saying "pong" */
  json_object_set_string_member (options, "command", "pong");
  payload = cockpit_json_write_bytes (options);
  if (web_socket_connection_get_ready_state (socket->connection) == WEB_SOCKET_STATE_OPEN)
    web_socket_connection_send (socket->connection, WEB_SOCKET_DATA_TEXT, self->control_prefix, payload);
  g_bytes_unref (payload);

  return TRUE;
}
예제 #13
0
static void
on_socket_open (WebSocketConnection *connection,
                CockpitChannelSocket *chock)
{
  GBytes *payload;

  /*
   * Actually open the channel. We wait until the WebSocket is open
   * before doing this, so we don't receive messages from the bridge
   * before the websocket is open.
   */

  payload = cockpit_json_write_bytes (chock->open);
  cockpit_transport_send (chock->transport, NULL, payload);
  g_bytes_unref (payload);
}
예제 #14
0
static void
on_web_socket_open (WebSocketConnection *connection,
                    CockpitWebService *self)
{
  CockpitSocket *socket;
  JsonArray *capabilities;
  GBytes *command;
  JsonObject *object;
  JsonObject *info;

  g_info ("New connection to session from %s", cockpit_creds_get_rhost (self->creds));

  socket = cockpit_socket_lookup_by_connection (&self->sockets, connection);
  g_return_if_fail (socket != NULL);

  object = json_object_new ();
  json_object_set_string_member (object, "command", "init");
  json_object_set_int_member (object, "version", 1);
  json_object_set_string_member (object, "channel-seed", socket->id);
  json_object_set_string_member (object, "host", "localhost");
  json_object_set_string_member (object, "csrf-token", cockpit_creds_get_csrf_token (self->creds));

  capabilities = json_array_new ();
  json_array_add_string_element (capabilities, "multi");
  json_array_add_string_element (capabilities, "credentials");
  json_array_add_string_element (capabilities, "binary");
  json_object_set_array_member (object, "capabilities", capabilities);

  info = json_object_new ();
  json_object_set_string_member (info, "version", PACKAGE_VERSION);
  json_object_set_string_member (info, "build", COCKPIT_BUILD_INFO);
  json_object_set_object_member (object, "system", info);

  command = cockpit_json_write_bytes (object);
  json_object_unref (object);

  web_socket_connection_send (connection, WEB_SOCKET_DATA_TEXT, self->control_prefix, command);
  g_bytes_unref (command);

  /* Do we have an authorize password? if so tell the frontend */
  if (cockpit_creds_get_password (self->creds))
    send_socket_hints (self, "credential", "password");

  g_signal_connect (connection, "message",
                    G_CALLBACK (on_web_socket_message), self);
}
예제 #15
0
static GBytes *
build_environment (GHashTable *os_release)
{
  static const gchar *prefix = "\n    <script>\nvar environment = ";
  static const gchar *suffix = ";\n    </script>";
  GByteArray *buffer;
  GHashTableIter iter;
  GBytes *bytes;
  JsonObject *object;
  const gchar *title;
  gchar *hostname;
  gpointer key, value;
  JsonObject *osr;

  object = json_object_new ();

  title = cockpit_conf_string ("WebService", "LoginTitle");
  if (title)
    json_object_set_string_member (object, "title", title);

  hostname = g_malloc0 (HOST_NAME_MAX + 1);
  gethostname (hostname, HOST_NAME_MAX);
  hostname[HOST_NAME_MAX] = '\0';
  json_object_set_string_member (object, "hostname", hostname);
  g_free (hostname);

  if (os_release)
    {
      osr = json_object_new ();
      g_hash_table_iter_init (&iter, os_release);
      while (g_hash_table_iter_next (&iter, &key, &value))
        json_object_set_string_member (osr, key, value);
      json_object_set_object_member (object, "os-release", osr);
    }

  add_oauth_to_environment (object);

  bytes = cockpit_json_write_bytes (object);
  json_object_unref (object);

  buffer = g_bytes_unref_to_array (bytes);
  g_byte_array_prepend (buffer, (const guint8 *)prefix, strlen (prefix));
  g_byte_array_append (buffer, (const guint8 *)suffix, strlen (suffix));
  return g_byte_array_free_to_bytes (buffer);
}
예제 #16
0
static void
send_login_response (CockpitWebResponse *response,
                     CockpitCreds *creds,
                     GHashTable *headers)
{
  JsonObject *object;
  GBytes *content;

  object = json_object_new ();
  json_object_set_string_member (object, "user", cockpit_creds_get_user (creds));

  content = cockpit_json_write_bytes (object);
  json_object_unref (object);

  g_hash_table_replace (headers, g_strdup ("Content-Type"), g_strdup ("application/json"));
  cockpit_web_response_content (response, headers, content, NULL);
  g_bytes_unref (content);
}
예제 #17
0
static gboolean
process_and_relay_open (CockpitWebService *self,
                        CockpitSocket *socket,
                        const gchar *channel,
                        JsonObject *options)
{
  WebSocketDataType data_type = WEB_SOCKET_DATA_TEXT;
  GBytes *payload;

  if (self->closing)
    {
      g_debug ("Ignoring open command while web socket is closing");
      return TRUE;
    }

  if (channel == NULL)
    {
      g_warning ("open command is missing the 'channel' field");
      return FALSE;
    }

  if (cockpit_socket_lookup_by_channel (&self->sockets, channel))
    {
      g_warning ("cannot open a channel %s with the same id as another channel", channel);
      return FALSE;
    }

  if (!cockpit_web_service_parse_binary (options, &data_type))
    return FALSE;

  if (socket)
    cockpit_socket_add_channel (&self->sockets, socket, channel, data_type);

  if (!self->sent_done)
    {
      payload = cockpit_json_write_bytes (options);
      cockpit_transport_send (self->transport, NULL, payload);
      g_bytes_unref (payload);
    }

  return TRUE;
}
예제 #18
0
static const gchar *
process_transport_init (CockpitWebService *self,
                        CockpitTransport *transport,
                        JsonObject *options)
{
  JsonObject *object;
  GBytes *payload;
  gint64 version;

  if (!cockpit_json_get_int (options, "version", -1, &version))
    {
      g_warning ("invalid version field in init message");
      return "protocol-error";
    }

  if (version == 1)
    {
      g_debug ("received init message");
      self->init_received = TRUE;
      g_object_set_data_full (G_OBJECT (transport), "init",
                              json_object_ref (options),
                              (GDestroyNotify) json_object_unref);

      /* Always send an init message down the new transport */
      object = cockpit_transport_build_json ("command", "init", NULL);
      json_object_set_int_member (object, "version", 1);
      json_object_set_string_member (object, "host", "localhost");
      payload = cockpit_json_write_bytes (object);
      json_object_unref (object);
      cockpit_transport_send (transport, NULL, payload);
      g_bytes_unref (payload);
    }
  else
    {
      g_message ("unsupported version of cockpit protocol: %" G_GINT64_FORMAT, version);
      return "not-supported";
    }

  g_signal_emit (self, sig_transport_init, 0);
  return NULL;
}
예제 #19
0
파일: stub.c 프로젝트: AmartC/cockpit
static void
send_init_command (CockpitTransport *transport)
{
  const gchar *checksum;
  JsonObject *object;
  GBytes *bytes;

  object = json_object_new ();
  json_object_set_string_member (object, "command", "init");
  json_object_set_int_member (object, "version", 1);

  checksum = cockpit_packages_get_checksum (packages);
  if (checksum)
    json_object_set_string_member (object, "checksum", checksum);

  bytes = cockpit_json_write_bytes (object);
  json_object_unref (object);

  cockpit_transport_send (transport, NULL, bytes);
  g_bytes_unref (bytes);
}
예제 #20
0
/**
 * cockpit_channel_done:
 * @self: the channel
 *
 * Send an EOF to the other side. This should only be called once.
 * Whether an EOF should be sent or not depends on the payload type.
 */
void
cockpit_channel_done (CockpitChannel *self)
{
  JsonObject *object;
  GBytes *message;

  g_return_if_fail (COCKPIT_IS_CHANNEL (self));
  g_return_if_fail (self->priv->sent_done == FALSE);

  self->priv->sent_done = TRUE;

  object = json_object_new ();
  json_object_set_string_member (object, "command", "done");
  json_object_set_string_member (object, "channel", self->priv->id);

  message = cockpit_json_write_bytes (object);
  json_object_unref (object);

  cockpit_transport_send (self->priv->transport, NULL, message);
  g_bytes_unref (message);
}
예제 #21
0
static void
cockpit_channel_real_close (CockpitChannel *self,
                            const gchar *problem)
{
  JsonObject *object;
  GBytes *message;

  if (self->priv->sent_close)
    return;

  self->priv->sent_close = TRUE;

  if (!self->priv->transport_closed)
    {
      flush_buffer (self);

      if (self->priv->close_options)
        {
          object = self->priv->close_options;
          self->priv->close_options = NULL;
        }
      else
        {
          object = json_object_new ();
        }

      json_object_set_string_member (object, "command", "close");
      json_object_set_string_member (object, "channel", self->priv->id);
      if (problem)
        json_object_set_string_member (object, "problem", problem);

      message = cockpit_json_write_bytes (object);
      json_object_unref (object);

      cockpit_transport_send (self->priv->transport, NULL, message);
      g_bytes_unref (message);
    }

  g_signal_emit (self, cockpit_channel_sig_closed, 0, problem);
}
예제 #22
0
static gboolean
process_ping (CockpitChannel *self,
              JsonObject *ping)
{
  GBytes *payload;

  if (self->priv->throttled)
    {
      g_debug ("%s: received ping while throttled", self->priv->id);
      g_queue_push_tail (self->priv->throttled, json_object_ref (ping));
      return FALSE;
    }
  else
    {
      g_debug ("%s: replying to ping with pong", self->priv->id);
      json_object_set_string_member (ping, "command", "pong");
      payload = cockpit_json_write_bytes (ping);
      cockpit_transport_send (self->priv->transport, NULL, payload);
      g_bytes_unref (payload);
      return TRUE;
    }
}
예제 #23
0
static void
send_close_channel (CockpitPortal *self,
                    const gchar *channel_id,
                    const gchar *problem)
{
  JsonObject *object;
  GBytes *bytes;

  g_debug ("sending close for portal channel: %s: %s", channel_id, problem);

  object = json_object_new ();
  json_object_set_string_member (object, "command", "close");
  json_object_set_string_member (object, "channel", channel_id);
  json_object_set_string_member (object, "problem", problem);

  bytes = cockpit_json_write_bytes (object);
  json_object_unref (object);

  if (self->transport)
    cockpit_transport_send (self->transport, NULL, bytes);
  g_bytes_unref (bytes);
}
예제 #24
0
static void
cockpit_channel_real_close (CockpitChannel *self,
                            const gchar *problem)
{
  const gchar *reason = problem;
  JsonObject *object;
  GBytes *message;

  if (self->priv->closed)
    return;

  self->priv->closed = TRUE;

  if (reason == NULL)
    reason = "";

  if (self->priv->close_options)
    {
      object = self->priv->close_options;
      self->priv->close_options = NULL;
    }
  else
    {
      object = json_object_new ();
    }

  json_object_set_string_member (object, "command", "close");
  json_object_set_string_member (object, "channel", self->priv->id);
  json_object_set_string_member (object, "reason", reason);

  message = cockpit_json_write_bytes (object);
  json_object_unref (object);

  cockpit_transport_send (self->priv->transport, 0, message);
  g_bytes_unref (message);

  g_signal_emit (self, cockpit_channel_sig_closed, 0, problem);
}
예제 #25
0
static GBytes *
substitute_environment (const gchar *variable,
                        gpointer user_data)
{
  GHashTable *os_release = user_data;
  GHashTableIter iter;
  GBytes *ret = NULL;
  JsonObject *object;
  gchar *hostname;
  gpointer key, value;
  JsonObject *osr;

  if (g_str_equal (variable, "environment"))
    {
      object = json_object_new ();
      hostname = g_malloc0 (HOST_NAME_MAX + 1);
      gethostname (hostname, HOST_NAME_MAX);
      hostname[HOST_NAME_MAX] = '\0';
      json_object_set_string_member (object, "hostname", hostname);
      g_free (hostname);

      if (os_release)
        {
          osr = json_object_new ();
          g_hash_table_iter_init (&iter, os_release);
          while (g_hash_table_iter_next (&iter, &key, &value))
            json_object_set_string_member (osr, key, value);
          json_object_set_object_member (object, "os-release", osr);
        }

      ret = cockpit_json_write_bytes (object);
      json_object_unref (object);
    }

  return ret;
}
예제 #26
0
파일: stub.c 프로젝트: dperpeet/cockpit
static void
send_init_command (CockpitTransport *transport,
                   gboolean interactive)
{
  const gchar *checksum;
  JsonObject *object;
  GBytes *bytes;

  object = json_object_new ();
  json_object_set_string_member (object, "command", "init");
  json_object_set_int_member (object, "version", 1);

  /*
   * When in interactive mode pretend we received an init
   * message, and don't print one out.
   */
  if (interactive)
    {
      json_object_set_string_member (object, "host", "localhost");
    }
  else
    {
      checksum = cockpit_packages_get_checksum (packages);
      if (checksum)
        json_object_set_string_member (object, "checksum", checksum);
    }

  bytes = cockpit_json_write_bytes (object);
  json_object_unref (object);

  if (interactive)
    cockpit_transport_emit_recv (transport, NULL, bytes);
  else
    cockpit_transport_send (transport, NULL, bytes);
  g_bytes_unref (bytes);
}
예제 #27
0
static void
on_files_listed (GObject *source_object,
                 GAsyncResult *res,
                 gpointer user_data)
{
  GError *error = NULL;
  JsonObject *options;
  GList *files;

  files = g_file_enumerator_next_files_finish (G_FILE_ENUMERATOR (source_object), res, &error);
  if (error)
    {
      if (!g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
        {
          CockpitFslist *self = COCKPIT_FSLIST (user_data);
          g_message ("%s: couldn't process files %s", COCKPIT_FSLIST(user_data)->path, error->message);
          options = cockpit_channel_close_options (COCKPIT_CHANNEL (self));
          json_object_set_string_member (options, "message", error->message);
          cockpit_channel_close (COCKPIT_CHANNEL (self), "internal-error");
        }
      g_clear_error (&error);
      return;
    }

  CockpitFslist *self = COCKPIT_FSLIST (user_data);

  if (files == NULL)
    {
      JsonObject *msg;
      GBytes *msg_bytes;

      msg = json_object_new ();
      json_object_set_string_member (msg, "event", "present-done");
      msg_bytes = cockpit_json_write_bytes (msg);
      json_object_unref (msg);
      cockpit_channel_send (COCKPIT_CHANNEL(self), msg_bytes, FALSE);
      g_bytes_unref (msg_bytes);

      g_clear_object (&self->cancellable);
      g_object_unref (source_object);

      if (self->monitor == NULL)
        {
          cockpit_channel_done (COCKPIT_CHANNEL (self));
          cockpit_channel_close (COCKPIT_CHANNEL (self), NULL);
        }
      return;
    }

  for (GList *l = files; l; l = l->next)
    {
      GFileInfo *info = G_FILE_INFO (l->data);
      JsonObject *msg;
      GBytes *msg_bytes;

      msg = json_object_new ();
      json_object_set_string_member (msg, "event", "present");
      json_object_set_string_member
        (msg, "path", g_file_info_get_attribute_byte_string (info, G_FILE_ATTRIBUTE_STANDARD_NAME));
      json_object_set_string_member
        (msg, "type", cockpit_file_type_to_string (g_file_info_get_file_type (info)));
      msg_bytes = cockpit_json_write_bytes (msg);
      json_object_unref (msg);
      cockpit_channel_send (COCKPIT_CHANNEL(self), msg_bytes, FALSE);
      g_bytes_unref (msg_bytes);
    }

  g_list_free_full (files, g_object_unref);

  g_file_enumerator_next_files_async (G_FILE_ENUMERATOR (source_object),
                                      10,
                                      G_PRIORITY_DEFAULT,
                                      self->cancellable,
                                      on_files_listed,
                                      self);
}
예제 #28
0
static gboolean
relay_headers (CockpitHttpStream *self,
               CockpitChannel *channel,
               GByteArray *buffer)
{
  GHashTable *headers = NULL;
  gchar *version = NULL;
  gchar *reason = NULL;
  JsonObject *object;
  const gchar *data;
  JsonObject *heads;
  GHashTableIter iter;
  GBytes *message;
  gpointer key;
  gpointer value;
  guint status;
  gsize length;
  gssize offset;
  gssize offset2;

  data = (const gchar *)buffer->data;
  length = buffer->len;

  offset = web_socket_util_parse_status_line (data, length, &version, &status, &reason);
  if (offset == 0)
    return FALSE; /* want more data */

  if (offset < 0)
    {
      cockpit_channel_fail (channel, "protocol-error",
                            "%s: received response with bad HTTP status line", self->name);
      goto out;
    }

  offset2 = web_socket_util_parse_headers (data + offset, length - offset, &headers);
  if (offset2 == 0)
    return FALSE; /* want more data */

  if (offset2 < 0)
    {
      cockpit_channel_fail (channel, "protocol-error",
                            "%s: received response with bad HTTP headers", self->name);
      goto out;
    }

  g_debug ("%s: response: %u %s", self->name, status, reason);
  g_hash_table_iter_init (&iter, headers);
  while (g_hash_table_iter_next (&iter, &key, &value))
    g_debug ("%s: header: %s %s", self->name, (gchar *)key, (gchar *)value);

  if (!parse_transfer_encoding (self, channel, headers) ||
      !parse_content_length (self, channel, status, headers) ||
      !parse_keep_alive (self, channel, version, headers))
    goto out;

  cockpit_pipe_skip (buffer, offset + offset2);

  if (!self->binary)
    {
      g_hash_table_remove (headers, "Content-Length");
      g_hash_table_remove (headers, "Range");
    }
  g_hash_table_remove (headers, "Connection");
  g_hash_table_remove (headers, "Transfer-Encoding");

  /* Now serialize all the rest of this into JSON */
  object = json_object_new ();
  json_object_set_int_member (object, "status", status);
  json_object_set_string_member (object, "reason", reason);

  heads = json_object_new();
  g_hash_table_iter_init (&iter, headers);
  while (g_hash_table_iter_next (&iter, &key, &value))
    json_object_set_string_member (heads, key, value);

  json_object_set_object_member (object, "headers", heads);

  if (self->headers_inline)
    {
      message = cockpit_json_write_bytes (object);
      cockpit_channel_send (channel, message, TRUE);
      g_bytes_unref (message);
    }
  else
    {
      cockpit_channel_control (channel, "response", object);
    }

  json_object_unref (object);

out:
  if (headers)
    g_hash_table_unref (headers);
  g_free (version);
  g_free (reason);

  return TRUE;
}
예제 #29
0
static GBytes *
build_environment (CockpitWebService *service,
                   JsonObject *modules)
{
  const gchar *user;
  CockpitCreds *creds;
  JsonObject *env;
  JsonObject *localhost;
  JsonObject *languages;
  JsonObject *language;
  struct passwd *pwd;
  gchar *hostname;
  GBytes *bytes;
  guint n;

  const struct {
    const gchar *name;
    const gchar *code;
  } supported_languages[] = {
    { NC_("display-language", "English"), "" },
    { NC_("display-language", "Danish"),  "da" },
    { NC_("display-language", "German"),  "de" },
  };

  env = json_object_new ();
  if (service)
    {
      creds = cockpit_web_service_get_creds (service);
      user = cockpit_creds_get_user (creds);
      json_object_set_string_member (env, "user", user);
      pwd = cockpit_getpwnam_a (user, NULL);
      if (pwd)
        {
          json_object_set_string_member (env, "name", pwd->pw_gecos);
          free (pwd);
        }
    }

  localhost = json_object_new ();

  /* This awkwardly takes the localhost reference */
  json_object_set_object_member (env, "localhost", localhost);

  hostname = g_malloc0 (HOST_NAME_MAX + 1);
  gethostname (hostname, HOST_NAME_MAX);
  hostname[HOST_NAME_MAX] = '\0';

  json_object_set_string_member (env, "hostname", hostname);

  /* Only include version info if logged in */
  if (service)
    {
      json_object_set_string_member (localhost, "version", PACKAGE_VERSION);
      json_object_set_string_member (localhost, "build_info", COCKPIT_BUILD_INFO);
    }

  languages = json_object_new ();

  /* This awkwardly takes the languages reference */
  json_object_set_object_member (localhost, "languages", languages);

  for (n = 0; n < G_N_ELEMENTS (supported_languages); n++)
    {
      language = json_object_new ();
      json_object_set_object_member (languages, supported_languages[n].code, language);
      json_object_set_string_member (language, "name", supported_languages[n].name);
    }

  if (modules)
    json_object_set_object_member (localhost, "modules", json_object_ref (modules));

  bytes = cockpit_json_write_bytes (env);
  json_object_unref (env);

  return bytes;
}