コード例 #1
0
ファイル: cockpitfswrite.c プロジェクト: zbyufei/cockpit
static void
cockpit_fswrite_prepare (CockpitChannel *channel)
{
  CockpitFswrite *self = COCKPIT_FSWRITE (channel);
  const gchar *problem = "protocol-error";
  JsonObject *options;
  gchar *actual_tag = NULL;

  COCKPIT_CHANNEL_CLASS (cockpit_fswrite_parent_class)->prepare (channel);

  options = cockpit_channel_get_options (channel);
  if (!cockpit_json_get_string (options, "path", NULL, &self->path))
    {
      g_warning ("invalid \"path\" option for fswrite1 channel");
      goto out;
    }
  else if (self->path == NULL || g_str_equal (self->path, ""))
    {
      g_warning ("missing \"path\" option for fswrite1 channel");
      goto out;
    }

  if (!cockpit_json_get_string (options, "tag", NULL, &self->expected_tag))
    {
      g_warning ("%s: invalid \"tag\" option for fswrite1 channel", self->path);
      goto out;
    }

  actual_tag = cockpit_get_file_tag (self->path);
  if (self->expected_tag && g_strcmp0 (self->expected_tag, actual_tag))
    {
      problem = "change-conflict";
      goto out;
    }

  // TODO - delay the opening until the first content message.  That
  // way, we don't create a useless temporary file (which might even
  // fail).

  for (int i = 1; i < 10000; i++)
    {
      self->tmp_path = g_strdup_printf ("%s.%d", self->path, i);
      self->fd = open (self->tmp_path, O_WRONLY | O_CREAT | O_EXCL, 0666);
      if (self->fd >= 0 || errno != EEXIST)
        break;
      g_free (self->tmp_path);
      self->tmp_path = NULL;
    }

  problem = NULL;
  if (self->fd < 0)
    close_with_errno (self, "couldn't open unique file", errno);
  else
    cockpit_channel_ready (channel);

out:
  g_free (actual_tag);
  if (problem)
      cockpit_channel_close (channel, problem);
}
コード例 #2
0
ファイル: cockpitportal.c プロジェクト: haiyangd/cockpit_view
static gboolean
pcp_filter (CockpitPortal *self,
            const gchar *command,
            const gchar *channel,
            JsonObject *options,
            GBytes *payload)
{
  const gchar *type;
  const gchar *source;

  if (g_str_equal (command, "open") && channel)
    {
      if (!cockpit_json_get_string (options, "payload", NULL, &type))
        type = NULL;
      if (!cockpit_json_get_string (options, "source", NULL, &source))
        source = NULL;

      if (g_strcmp0 (type, "metrics1") != 0 ||
          g_strcmp0 (source, "internal") == 0)
        {
          return FALSE;
        }

      g_debug ("pcp portal channel: %s", channel);
      cockpit_portal_add_channel (self, channel, COCKPIT_PORTAL_NORMAL);
      return TRUE;
    }

  return FALSE;
}
コード例 #3
0
ファイル: cockpitrouter.c プロジェクト: harishanand95/cockpit
/*
 * For backwards compatibility we need to normalize some host params
 * so they can be matched against.
 *
 * Some sessions shouldn't be shared by multiple channels, such as those that
 * explicitly specify a host-key or specific user. This changed over time
 * so modify things to make it a simple match.
 *
 * If the given user is the current user, remove it. Preserves the current
 * behavior.
 *
 */
static void
cockpit_router_normalize_host_params (JsonObject *options)
{
  const gchar *sharable = NULL;
  const gchar *user = NULL;
  gboolean needs_private = FALSE;

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

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

  if (!sharable)
    {
      /* Fallback to older ways of indicating this */
      if (user || json_object_has_member (options, "host-key"))
        needs_private = TRUE;

      if (json_object_has_member (options, "temp-session"))
        {
          if (needs_private && !cockpit_json_get_bool (options, "temp-session",
                                                       TRUE, &needs_private))
            needs_private = TRUE;
          json_object_remove_member (options, "temp-session");
        }
    }

  if (g_strcmp0 (user, g_get_user_name ()) == 0)
    json_object_remove_member (options, "user");

  if (needs_private)
    json_object_set_string_member (options, "session", "private");
}
コード例 #4
0
static gboolean
convert_metric_description (CockpitInternalMetrics *self,
                            JsonNode *node,
                            MetricInfo *info,
                            int index)
{
  const gchar *name;
  const gchar *units;

  if (json_node_get_node_type (node) == JSON_NODE_OBJECT)
    {
      if (!cockpit_json_get_string (json_node_get_object (node), "name", NULL, &name)
          || name == NULL)
        {
          g_warning ("invalid \"metrics\" option was specified (no name for metric %d)", index);
          return FALSE;
        }

      if (!cockpit_json_get_string (json_node_get_object (node), "units", NULL, &units))
        {
          g_warning ("invalid units for metric %s (not a string)", name);
          return FALSE;
        }

      if (!cockpit_json_get_string (json_node_get_object (node), "derive", NULL, &info->derive))
        {
          g_warning ("invalid derivation mode for metric %s (not a string)", name);
          return FALSE;
        }
    }
  else
    {
      g_warning ("invalid \"metrics\" option was specified (not an object for metric %d)", index);
      return FALSE;
    }

  MetricDescription *desc = find_metric_description (name);
  if (desc == NULL)
    {
      g_message ("unknown internal metric %s", name);
    }
  else
    {
      if (units && g_strcmp0 (desc->units, units) != 0)
        {
          g_warning ("%s has units %s, not %s", name, desc->units, units);
          return FALSE;
        }

      if (desc->instanced)
        info->instances = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free);

      info->desc = desc;
      self->samplers |= desc->sampler;
    }

  return TRUE;
}
コード例 #5
0
ファイル: cockpitauth.c プロジェクト: cockpituous/cockpit
static CockpitCreds *
parse_ssh_spawn_results (CockpitAuth *self,
                         AuthData *ad,
                         GHashTable *headers,
                         JsonObject **prompt_data,
                         GError **error)
{
  CockpitCreds *creds = NULL;
  JsonObject *results = NULL;
  JsonObject *auth_results = NULL;
  const gchar *pw_result = NULL;
  const gchar *user;
  const gchar *error_str;

  results = cockpit_auth_process_parse_result (ad->auth_process,
                                              ad->response_data,
                                              error);
  if (results)
    {
      user = cockpit_auth_process_get_authenticated_user (ad->auth_process, results,
                                                          prompt_data, error);
      if (user)
        {
          creds = create_creds_for_spawn_authenticated (self, user, ad,
                                                        results,
                                                        ad->response_data);
        }
      else if (cockpit_json_get_string (results, "error", NULL, &error_str))
        {
          if (g_strcmp0 (error_str, "authentication-failed") == 0)
            {
              cockpit_json_get_object (results, "auth-method-results", NULL, &auth_results);
              if (auth_results)
                cockpit_json_get_string (auth_results, "password", NULL, &pw_result);

              if (!pw_result || g_strcmp0 (pw_result, "no-server-support") == 0)
                {
                  g_clear_error (error);
                  g_set_error (error, COCKPIT_ERROR,
                               COCKPIT_ERROR_AUTHENTICATION_FAILED,
                               "Authentication failed: authentication-not-supported");
                }
            }
          else if (g_strcmp0 (error_str, "terminated") == 0)
            {
              g_clear_error (error);
              g_set_error (error, COCKPIT_ERROR,
                           COCKPIT_ERROR_AUTHENTICATION_FAILED,
                           "Authentication failed: terminated");
            }
        }
      json_object_unref (results);
    }

  return creds;
}
コード例 #6
0
static void
on_auth_process_message (CockpitAuthProcess *auth_process,
                         GBytes *bytes,
                         gpointer user_data)
{
  CockpitSshTransport *self = COCKPIT_SSH_TRANSPORT (user_data);
  JsonObject *json = NULL;
  gchar *response = NULL;
  GError *error = NULL;
  gsize len;
  gboolean prompt_claimed;
  gboolean final = TRUE;
  GBytes *blank = NULL;

  const gchar *user;
  const gchar *error_str;
  const gchar *prompt;
  const gchar *message;
  const gchar *host_key = NULL;
  const gchar *host_fp = NULL;
  JsonObject *auth_result = NULL;
  const gchar *problem = "internal-error";

  len = g_bytes_get_size (bytes);
  response = g_strndup (g_bytes_get_data (bytes, NULL), len);
  json = cockpit_auth_process_parse_result (self->auth_process, response, &error);
  if (json)
    {
      if (!cockpit_json_get_string (json, "error", NULL, &error_str) ||
          !cockpit_json_get_string (json, "message", NULL, &message) ||
          !cockpit_json_get_string (json, "prompt", NULL, &prompt) ||
          !cockpit_json_get_string (json, "user", NULL, &user))
        {
          g_warning ("%s: got invalid authentication json", self->logname);
        }
      else if (error_str)
        {
          problem = error_str;
          g_debug ("%s: got authentication error %s: %s", self->logname, error_str, message);
        }
      else if (prompt)
        {
          final = FALSE;
          problem = NULL;
          // Send the signal, if nothing handles it write a blank response.
          g_signal_emit (self, signals[PROMPT], 0, json, &prompt_claimed);
          if (!prompt_claimed)
            {
              blank = g_bytes_new_static ("", 0);
              cockpit_auth_process_write_auth_bytes (self->auth_process, blank);
              g_bytes_unref (blank);
            }
        }
      else if (user)
コード例 #7
0
ファイル: cockpitchannel.c プロジェクト: arilivigni/cockpit
static gboolean
parse_option_file_or_data (CockpitChannel *self,
                           JsonObject *options,
                           const gchar *option,
                           const gchar **file,
                           const gchar **data)
{
  JsonObject *object;
  JsonNode *node;

  g_assert (file != NULL);
  g_assert (data != NULL);

  node = json_object_get_member (options, option);
  if (!node)
    {
      *file = NULL;
      *data = NULL;
      return TRUE;
    }

  if (!JSON_NODE_HOLDS_OBJECT (node))
    {
      cockpit_channel_fail (self, "protocol-error", "invalid \"%s\" tls option for channel", option);
      return FALSE;
    }

  object = json_node_get_object (node);

  if (!cockpit_json_get_string (object, "file", NULL, file))
    {
      cockpit_channel_fail (self, "protocol-error", "invalid \"file\" %s option for channel", option);
    }
  else if (!cockpit_json_get_string (object, "data", NULL, data))
    {
      cockpit_channel_fail (self, "protocol-error", "invalid \"data\" %s option for channel", option);
    }
  else if (!*file && !*data)
    {
      cockpit_channel_fail (self, "not-supported", "missing or unsupported \"%s\" option for channel", option);
    }
  else if (*file && *data)
    {
      cockpit_channel_fail (self, "protocol-error", "cannot specify both \"file\" and \"data\" in \"%s\" option for channel", option);
    }
  else
    {
      return TRUE;
    }

  return FALSE;
}
コード例 #8
0
/**
 * cockpit_transport_parse_command:
 * @payload: command JSON payload to parse
 * @command: a location to return the command
 * @channel: location to return the channel
 * @options: location to return the options
 *
 * Parse a command and return various values from the
 * command. The @options value is transfered with ownership,
 * so you should free it after done. @command and @channel are owned by
 * @options. @channel will be NULL for a missing channel.
 *
 * On failure, message has already been printed.
 *
 * Returns: whether command parsed or not.
 */
gboolean
cockpit_transport_parse_command (GBytes *payload,
                                 const gchar **command,
                                 const gchar **channel,
                                 JsonObject **options)
{
  GError *error = NULL;
  gboolean ret = FALSE;
  JsonObject *object;
  gboolean valid;

  object = cockpit_json_parse_bytes (payload, &error);
  if (!object)
    {
      g_warning ("Received unparseable control message: %s", error->message);
      g_error_free (error);
      goto out;
    }

  /* Parse out the command */
  if (command)
    {
      if (!cockpit_json_get_string (object, "command", NULL, command) ||
          *command == NULL || g_str_equal (*command, ""))
        {
          g_warning ("Received invalid control message: invalid or missing command");
          goto out;
        }
    }

  /* Parse out the channel */
  valid = cockpit_json_get_string (object, "channel", NULL, channel);
  if (valid && *channel)
    {
      valid = (!g_str_equal ("", *channel) &&
               strcspn (*channel, "\n") == strlen (*channel));
    }

  if (!valid)
    {
      g_warning ("Received invalid control message: invalid channel");
      goto out;
    }

  *options = json_object_ref (object);
  ret = TRUE;

out:
  if (object)
    json_object_unref (object);
  return ret;
}
コード例 #9
0
ファイル: cockpitchannel.c プロジェクト: maxamillion/cockpit
static const gchar *
parse_option_file_or_data (JsonObject *options,
                           const gchar *option,
                           const gchar **file,
                           const gchar **data)
{
  JsonObject *object;
  JsonNode *node;

  g_assert (file != NULL);
  g_assert (data != NULL);

  node = json_object_get_member (options, option);
  if (!node)
    {
      *file = NULL;
      *data = NULL;
      return NULL;
    }

  if (!JSON_NODE_HOLDS_OBJECT (node))
    {
      g_warning ("invalid \"%s\" tls option for channel", option);
      return "protocol-error";
    }

  object = json_node_get_object (node);

  if (!cockpit_json_get_string (object, "file", NULL, file))
    {
      g_warning ("invalid \"file\" %s option for channel", option);
      return "protocol-error";
    }
  else if (!cockpit_json_get_string (object, "data", NULL, data))
    {
      g_warning ("invalid \"data\" %s option for channel", option);
      return "protocol-error";
    }
  else if (!*file && !*data)
    {
      g_warning ("missing or unsupported \"%s\" option for channel", option);
      return "not-supported";
    }
  else if (*file && *data)
    {
      g_warning ("cannot specify both \"file\" and \"data\" in \"%s\" option for channel", option);
      return "protocol-error";
    }

  return NULL;
}
コード例 #10
0
ファイル: cockpitchannel.c プロジェクト: maxamillion/cockpit
static void
cockpit_channel_real_prepare (CockpitChannel *channel)
{
  CockpitChannel *self = COCKPIT_CHANNEL (channel);
  JsonObject *options;
  const gchar *binary;
  const gchar *payload;

  options = cockpit_channel_get_options (self);

  if (!cockpit_channel_ensure_capable (self, options))
    return;

  if (G_OBJECT_TYPE (channel) == COCKPIT_TYPE_CHANNEL)
    {
      if (!cockpit_json_get_string (options, "payload", NULL, &payload))
        payload = NULL;

      if (payload)
        {
          g_warning ("bridge doesn't support payloads of type: %s", payload);
          cockpit_channel_close (channel, "not-supported");
        }
      else
        {
          g_warning ("no payload type present in request to open channel");
          cockpit_channel_close (channel, "protocol-error");
        }
      return;
    }

  if (!cockpit_json_get_string (options, "binary", NULL, &binary))
    {
      g_warning ("%s: channel has invalid \"binary\" option", self->priv->id);
      cockpit_channel_close (self, "protocol-error");
    }
  else if (binary != NULL)
    {
      self->priv->binary_ok = TRUE;
      if (g_str_equal (binary, "base64"))
        {
          self->priv->base64_encoding = TRUE;
        }
      else if (!g_str_equal (binary, "raw"))
        {
          g_warning ("%s: channel has invalid \"binary\" option: %s", self->priv->id, binary);
          cockpit_channel_close (self, "protocol-error");
        }
    }
}
コード例 #11
0
ファイル: cockpitrouter.c プロジェクト: harishanand95/cockpit
static gboolean
router_rule_match (RouterRule *rule,
                   JsonObject *object)
{
  RouterMatch *match;
  const gchar *value;
  JsonNode *node;
  guint i;

  for (i = 0; rule->matches && rule->matches[i].name != NULL; i++)
    {
      match = &rule->matches[i];
      if (match->glob)
        {
          if (!cockpit_json_get_string (object, match->name, NULL, &value) || !value ||
              !g_pattern_match (match->glob, strlen (value), value, NULL))
            return FALSE;
        }
      else if (match->node)
        {
          node = json_object_get_member (object, match->name);
          if (!node || !cockpit_json_equal (match->node, node))
            return FALSE;
        }
      else
        {
          if (!json_object_has_member (object, match->name))
            return FALSE;
        }
    }

  return TRUE;
}
コード例 #12
0
ファイル: cockpitchannel.c プロジェクト: arilivigni/cockpit
static void
process_control (CockpitChannel *self,
                 const gchar *command,
                 JsonObject *options)
{
  CockpitChannelClass *klass;
  const gchar *problem;

  if (g_str_equal (command, "close"))
    {
      g_debug ("close channel %s", self->priv->id);
      if (!cockpit_json_get_string (options, "problem", NULL, &problem))
        problem = NULL;
      cockpit_channel_close (self, problem);
      return;
    }

  if (g_str_equal (command, "done"))
    {
      if (self->priv->received_done)
        cockpit_channel_fail (self, "protocol-error", "channel received second done");
      else
        self->priv->received_done = TRUE;
    }

  klass = COCKPIT_CHANNEL_GET_CLASS (self);
  if (klass->control)
    (klass->control) (self, command, options);
}
コード例 #13
0
ファイル: cockpitchannel.c プロジェクト: arilivigni/cockpit
static void
cockpit_channel_real_prepare (CockpitChannel *channel)
{
  CockpitChannel *self = COCKPIT_CHANNEL (channel);
  JsonObject *options;
  const gchar *binary;

  options = cockpit_channel_get_options (self);

  if (!cockpit_channel_ensure_capable (self, options))
    return;

  if (G_OBJECT_TYPE (channel) == COCKPIT_TYPE_CHANNEL)
    {
      cockpit_channel_close (channel, "not-supported");
      return;
    }

  if (!cockpit_json_get_string (options, "binary", NULL, &binary))
    {
      cockpit_channel_fail (self, "protocol-error", "channel has invalid \"binary\" option");
    }
  else if (binary != NULL)
    {
      self->priv->binary_ok = TRUE;
      if (!g_str_equal (binary, "raw"))
        {
          cockpit_channel_fail (self, "protocol-error",
                                "channel has invalid \"binary\" option: %s", binary);
        }
    }
}
コード例 #14
0
static gboolean
on_transport_control (CockpitTransport *transport,
                      const char *command,
                      const gchar *channel,
                      JsonObject *options,
                      GBytes *payload,
                      CockpitChannelSocket *chock)
{
  const gchar *problem;

  if (channel && g_str_equal (channel, chock->channel))
    {
      if (g_str_equal (command, "close"))
        {
          if (!cockpit_json_get_string (options, "problem", NULL, &problem))
            problem = NULL;
          cockpit_channel_socket_close (chock, problem);
        }

      /* Any other control message for this channel is discarded */
      return TRUE;
    }

  return FALSE;
}
コード例 #15
0
static gboolean
parse_httpstream_response (CockpitChannelResponse *chesp,
                           JsonObject *object,
                           gint64 *status,
                           const gchar **reason)
{
  JsonNode *node;

  if (!cockpit_json_get_int (object, "status", 200, status) ||
      !cockpit_json_get_string (object, "reason", NULL, reason))
    {
      g_warning ("%s: received invalid httpstream response", chesp->logname);
      return FALSE;
    }

  node = json_object_get_member (object, "headers");
  if (node)
    {
      if (!JSON_NODE_HOLDS_OBJECT (node))
        {
          g_warning ("%s: received invalid httpstream headers", chesp->logname);
          return FALSE;
        }
      json_object_foreach_member (json_node_get_object (node), object_to_headers, chesp->headers);
    }

  return TRUE;
}
コード例 #16
0
static gboolean
on_transport_control (CockpitTransport *transport,
                      const gchar *command,
                      const gchar *channel,
                      JsonObject *options,
                      GBytes *message,
                      CockpitChannelResponse *chesp)
{
  const gchar *problem = NULL;

  if (!channel || !g_str_equal (channel, chesp->channel))
    return FALSE; /* not handled */

  if (g_str_equal (command, "done"))
    {
      ensure_headers (chesp, 200, "OK");
      cockpit_web_response_complete (chesp->response);
      return TRUE;
    }
  else if (g_str_equal (command, "close"))
    {
      if (!cockpit_json_get_string (options, "problem", NULL, &problem))
        {
          g_message ("%s: received close command with invalid problem", chesp->logname);
          problem = "disconnected";
        }
      cockpit_channel_response_close (chesp, problem);
    }
  else
    {
      /* Ignore other control messages */
    }

  return TRUE; /* handled */
}
コード例 #17
0
ファイル: cockpitrouter.c プロジェクト: harishanand95/cockpit
static gboolean
process_open_channel (CockpitRouter *self,
                      const gchar *channel,
                      JsonObject *options,
                      GBytes *data,
                      gpointer user_data)
{
  GType (* type_function) (void) = user_data;
  GType channel_type = 0;
  const gchar *group;

  if (!cockpit_json_get_string (options, "group", "default", &group))
    g_warning ("%s: caller specified invalid 'group' field in open message", channel);

  g_assert (type_function != NULL);
  channel_type = type_function ();

  if (g_str_equal (group, "fence"))
    g_hash_table_add (self->fences, g_strdup (channel));

  g_hash_table_insert (self->groups, g_strdup (channel), g_strdup (group));

  create_channel (self, channel, options, channel_type);
  return TRUE;
}
コード例 #18
0
static gboolean
on_transport_control (CockpitTransport *transport,
                      const char *command,
                      guint channel,
                      JsonObject *options,
                      GBytes *message,
                      gpointer user_data)
{
  CockpitPolkitAgent *self = COCKPIT_POLKIT_AGENT (user_data);
  ReauthorizeCaller *caller;
  const gchar *response;
  const gchar *cookie;
  GBytes *bytes;

  if (!g_str_equal (command, "authorize"))
    return FALSE;

  if (!cockpit_json_get_string (options, "cookie", NULL, &cookie) ||
      !cockpit_json_get_string (options, "response", NULL, &response) ||
      !cookie || !response)
    {
      g_warning ("got an invalid authorize command from cockpit-ws");
      cockpit_transport_close (transport, "protocol-error");
      return TRUE;
    }

  caller = g_hash_table_lookup (self->callers, cookie);
  if (!caller)
    {
      g_debug ("received authorize response for caller that has gone away");
      return TRUE;
    }

  g_debug ("got \"authorize\" response from cockpit-ws, will send to helper: %s", response);

  bytes = g_bytes_new_with_free_func (response, strlen (response),
                                      (GDestroyNotify)json_object_unref,
                                      json_object_ref (options));
  cockpit_pipe_write (caller->helper, bytes);
  g_bytes_unref (bytes);

  bytes = g_bytes_new_static ("\n", 1);
  cockpit_pipe_write (caller->helper, bytes);
  g_bytes_unref (bytes);

  return TRUE;
}
コード例 #19
0
ファイル: mock-agent-bridge.c プロジェクト: AmartC/cockpit
static void
process_open (CockpitTransport *transport,
              const gchar *channel_id,
              JsonObject *options)
{
  CockpitChannel *channel;
  GType channel_type;
  const gchar *payload;
  const gchar *internal;

  if (!channel_id)
    {
      g_warning ("Caller tried to open channel with invalid id");
      cockpit_transport_close (transport, "protocol-error");
    }
  else if (g_hash_table_lookup (channels, channel_id))
    {
      g_warning ("Caller tried to reuse a channel that's already in use");
      cockpit_transport_close (transport, "protocol-error");
    }
  else
    {
      if (!cockpit_json_get_string (options, "payload", NULL, &payload))
        payload = NULL;

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

      /* This will close with "not-supported" */
      channel_type = COCKPIT_TYPE_CHANNEL;

      if (g_strcmp0 (payload, "stream") == 0 &&
          g_strcmp0 (internal, "ssh-agent") == 0)
        channel_type = COCKPIT_TYPE_PIPE_CHANNEL;

      channel = g_object_new (channel_type,
                              "transport", transport,
                              "id", channel_id,
                              "options", options,
                              NULL);

      g_hash_table_insert (channels, g_strdup (channel_id), channel);
      g_signal_connect (channel, "closed", G_CALLBACK (on_channel_closed), NULL);

  }
}
コード例 #20
0
ファイル: cockpitchannel.c プロジェクト: BillTheBest/cockpit
/**
 * cockpit_channel_get_option:
 * @self: a channel
 * @name: the option name
 *
 * Called by implementations to get a string value from the
 * channel's options.
 *
 * Returns: (transfer none): the option value or NULL
 */
const gchar *
cockpit_channel_get_option (CockpitChannel *self,
                            const gchar *name)
{
  const gchar *value;
  if (!cockpit_json_get_string (self->priv->open_options, name, NULL, &value))
    value = NULL;
  return value;
}
コード例 #21
0
ファイル: cockpitchannel.c プロジェクト: andreasn/cockpit
/**
 * 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);
}
コード例 #22
0
ファイル: cockpitportal.c プロジェクト: haiyangd/cockpit_view
static gboolean
superuser_filter (CockpitPortal *self,
                  const gchar *command,
                  const gchar *channel,
                  JsonObject *options,
                  GBytes *payload)
{
  CockpitPortalFlags flags = COCKPIT_PORTAL_NORMAL;
  gboolean privileged = FALSE;
  const gchar *superuser;

  if (g_str_equal (command, "logout"))
    {
      g_debug ("got logout at super proxy");
      transition_none (self);
      return FALSE;
    }

  if (g_str_equal (command, "open") && channel)
    {
      if (!cockpit_json_get_bool (options, "superuser", FALSE, &privileged))
        {
          if (!cockpit_json_get_string (options, "superuser", NULL, &superuser))
            {
              g_warning ("invalid value for \"superuser\" channel open option");
              send_close_channel (self, channel, "protocol-error");
              return TRUE;
            }
          else if (g_strcmp0 (superuser, "try") == 0)
            {
              privileged = TRUE;
              flags = COCKPIT_PORTAL_FALLBACK;
            }
          else if (g_strcmp0 (superuser, "require") == 0)
            {
              privileged = TRUE;
            }
          else if (superuser)
            {
              g_warning ("invalid value for \"superuser\" channel open option: %s", superuser);
              send_close_channel (self, channel, "protocol-error");
              return TRUE;
            }
        }

      if (!privileged)
        return FALSE;

      g_debug ("superuser channel open: %s", channel);
      cockpit_portal_add_channel (self, channel, flags);
      return TRUE;
    }

  return FALSE;
}
コード例 #23
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;
}
コード例 #24
0
ファイル: cockpitrouter.c プロジェクト: harishanand95/cockpit
static void
process_init (CockpitRouter *self,
              CockpitTransport *transport,
              JsonObject *options)
{
  const gchar *problem = NULL;
  const gchar *host;
  gint64 version = -1;

  if (self->init_host)
    {
      g_warning ("caller already sent another 'init' message");
      problem = "protocol-error";
    }
  else if (!cockpit_json_get_int (options, "version", -1, &version))
    {
      g_warning ("invalid 'version' field in init message");
      problem = "protocol-error";
    }
  else if (version == -1)
    {
      g_warning ("missing 'version' field in init message");
      problem = "protocol-error";
    }
  else if (!cockpit_json_get_string (options, "host", NULL, &host))
    {
      g_warning ("invalid 'host' field in init message");
      problem = "protocol-error";
    }
  else if (host == NULL)
    {
      g_message ("missing 'host' field in init message");
      problem = "protocol-error";
    }
  else if (version != 1)
    {
      g_message ("unsupported 'version' of cockpit protocol: %" G_GINT64_FORMAT, version);
      problem = "not-supported";
    }

  if (problem)
    {
      cockpit_transport_close (transport, problem);
    }
  else
    {
      g_debug ("received init message");
      g_assert (host != NULL);
      self->init_host = g_strdup (host);
      problem = NULL;
    }
}
コード例 #25
0
ファイル: cockpitrouter.c プロジェクト: harishanand95/cockpit
static GBytes *
substitute_json_string (const gchar *variable,
                        gpointer user_data)
{
  const gchar *value;
  JsonObject *options = user_data;
  if (options && cockpit_json_get_string (options, variable, "", &value))
    return g_bytes_new (value, strlen (value));
  else if (options)
    g_message ("Couldn't get argument for bridge: got invalid value for '%s'", variable);

  return g_bytes_new ("", 0);
}
コード例 #26
0
ファイル: cockpitauth.c プロジェクト: reddy520520/cockpit
static CockpitCreds *
create_creds_for_authenticated (const char *user,
                                SessionLoginData *sl,
                                JsonObject *results)
{
  const gchar *fullname = NULL;
  const gchar *password = NULL;
  const gchar *gssapi_creds = NULL;

  /*
   * Dig the password out of the authorization header, rather than having
   * cockpit-session pass it back and forth possibly leaking it.
   */

  if (g_str_equal (sl->auth_type, "basic"))
    password = parse_basic_auth_password (sl->authorization, NULL);

  if (!cockpit_json_get_string (results, "gssapi-creds", NULL, &gssapi_creds))
    {
      g_warning ("received bad gssapi-creds from cockpit-session");
      gssapi_creds = NULL;
    }

  if (!cockpit_json_get_string (results, "full-name", NULL, &fullname))
    {
      g_warning ("received bad full-name from cockpit-session");
      fullname = NULL;
    }

  /* TODO: Try to avoid copying password */
  return cockpit_creds_new (user,
                            sl->application,
                            COCKPIT_CRED_FULLNAME, fullname,
                            COCKPIT_CRED_PASSWORD, password,
                            COCKPIT_CRED_RHOST, sl->remote_peer,
                            COCKPIT_CRED_GSSAPI, gssapi_creds,
                            NULL);
}
コード例 #27
0
ファイル: cockpitchannel.c プロジェクト: maxamillion/cockpit
static gboolean
on_transport_control (CockpitTransport *transport,
                      const char *command,
                      const gchar *channel_id,
                      JsonObject *options,
                      GBytes *payload,
                      gpointer user_data)
{
  CockpitChannel *self = user_data;
  CockpitChannelClass *klass;
  const gchar *problem;

  if (g_strcmp0 (channel_id, self->priv->id) != 0)
    return FALSE;

  klass = COCKPIT_CHANNEL_GET_CLASS (self);
  if (g_str_equal (command, "options"))
    {
      if (klass->options)
        (klass->options) (self, options);
      return TRUE;
    }
  else if (g_str_equal (command, "done"))
    {
      if (self->priv->received_done)
        {
          g_warning ("%s: channel received second done", self->priv->id);
          cockpit_channel_close (self, "protocol-error");
        }
      else
        {
          self->priv->received_done = TRUE;
          if (self->priv->ready)
            {
              if (klass->done)
                (klass->done) (self);
            }
        }
      return TRUE;
    }
  else if (g_str_equal (command, "close"))
    {
      g_debug ("close channel %s", channel_id);
      if (!cockpit_json_get_string (options, "problem", NULL, &problem))
        problem = NULL;
      cockpit_channel_close (self, problem);
    }

  return FALSE;
}
コード例 #28
0
ファイル: cockpitchannel.c プロジェクト: BillTheBest/cockpit
/**
 * cockpit_channel_open:
 * @transport: the transport to send/receive messages on
 * @number: the channel number
 * @options: the options to open the channel.
 *
 * Open a channel for the 'payload' field in @options. Other fields
 * in @options are dependent on the channel type.
 *
 * Guarantee: channel will not close immediately, even on invalid input.
 *
 * Returns: (transfer full): the new channel
 */
CockpitChannel *
cockpit_channel_open (CockpitTransport *transport,
                      const gchar *id,
                      JsonObject *options)
{
  CockpitChannel *channel;
  GType channel_type;
  const gchar *payload;

  if (!cockpit_json_get_string (options, "payload", NULL, &payload))
    payload = NULL;
  /* TODO: We need to migrate away from dbus-json1 */
  if (g_strcmp0 (payload, "dbus-json1") == 0)
    channel_type = COCKPIT_TYPE_DBUS_JSON1;
  else if (g_strcmp0 (payload, "dbus-json2") == 0)
    channel_type = COCKPIT_TYPE_DBUS_JSON;
  else if (g_strcmp0 (payload, "rest-json1") == 0)
    channel_type = COCKPIT_TYPE_REST_JSON;
  else if (g_strcmp0 (payload, "text-stream") == 0)
    channel_type = COCKPIT_TYPE_TEXT_STREAM;
  else if (g_strcmp0 (payload, "resource1") == 0)
    channel_type = COCKPIT_TYPE_RESOURCE;
  else if (g_strcmp0 (payload, "null") == 0)
    channel_type = COCKPIT_TYPE_NULL_CHANNEL;
  else
    channel_type = COCKPIT_TYPE_CHANNEL;

  channel = g_object_new (channel_type,
                          "transport", transport,
                          "id", id,
                          "options", options,
                          NULL);

  if (channel_type == COCKPIT_TYPE_CHANNEL)
    {
      if (payload)
        {
          g_warning ("agent doesn't support payloads of type: %s", payload);
          cockpit_channel_close (channel, "not-supported");
        }
      else
        {
          g_warning ("no payload type present in request to open channel");
          cockpit_channel_close (channel, "protocol-error");
        }
    }

  return channel;
}
コード例 #29
0
ファイル: bridge.c プロジェクト: xyzkizer/cockpit
static void
process_open (CockpitTransport *transport,
              const gchar *channel_id,
              JsonObject *options)
{
  CockpitChannel *channel;
  GType channel_type;
  const gchar *payload;
  gint i;

  if (!channel_id)
    {
      g_warning ("Caller tried to open channel with invalid id");
      cockpit_transport_close (transport, "protocol-error");
    }
  else if (g_hash_table_lookup (channels, channel_id))
    {
      g_warning ("Caller tried to reuse a channel that's already in use");
      cockpit_transport_close (transport, "protocol-error");
    }

  else
    {
      if (!cockpit_json_get_string (options, "payload", NULL, &payload))
        payload = NULL;

      /* This will close with "not-supported" */
      channel_type = COCKPIT_TYPE_CHANNEL;

      for (i = 0; payload_types[i].name != NULL; i++)
        {
          if (g_strcmp0 (payload, payload_types[i].name) == 0)
            {
              channel_type = payload_types[i].function();
              break;
            }
        }

      channel = g_object_new (channel_type,
                              "transport", transport,
                              "id", channel_id,
                              "options", options,
                              NULL);

      g_hash_table_insert (channels, g_strdup (channel_id), channel);
      g_signal_connect (channel, "closed", G_CALLBACK (on_channel_closed), NULL);
    }
}
コード例 #30
0
static void
cockpit_web_socket_stream_prepare (CockpitChannel *channel)
{
  CockpitWebSocketStream *self = COCKPIT_WEB_SOCKET_STREAM (channel);
  CockpitConnectable *connectable = NULL;
  JsonObject *options;
  const gchar *path;
  gboolean started = FALSE;

  COCKPIT_CHANNEL_CLASS (cockpit_web_socket_stream_parent_class)->prepare (channel);

  if (self->closed)
    goto out;

  connectable = cockpit_channel_parse_stream (channel);
  if (!connectable)
    goto out;

  options = cockpit_channel_get_options (channel);
  if (!cockpit_json_get_string (options, "path", NULL, &path))
    {
      g_warning ("%s: bad \"path\" field in WebSocket stream request", self->origin);
      goto out;
    }
  else if (path == NULL || path[0] != '/')
    {
      g_warning ("%s: invalid or missing \"path\" field in WebSocket stream request", self->origin);
      goto out;
    }

  self->url = g_strdup_printf ("%s://%s%s", connectable->tls ? "wss" : "ws", connectable->name, path);
  self->origin = g_strdup_printf ("%s://%s", connectable->tls ? "https" : "http", connectable->name);

  /* Parsed elsewhere */
  self->binary = json_object_has_member (options, "binary");

  cockpit_connect_stream_full (connectable, NULL, on_socket_connect, g_object_ref (self));
  started = TRUE;

out:
  if (connectable)
    {
      cockpit_connectable_unref (connectable);
      if (!started)
        cockpit_channel_close (channel, "protocol-error");
    }
}