Пример #1
0
static GBytes *
check_utf8_and_force_if_necessary (GBytes *input)
{
  const gchar *data;
  const gchar *end;
  gsize length;
  GString *string;

  data = g_bytes_get_data (input, &length);
  if (g_utf8_validate (data, length, &end))
    return g_bytes_ref (input);

  string = g_string_sized_new (length + 16);
  do
    {
      /* Valid part of the string */
      g_string_append_len (string, data, end - data);

      /* Replacement character */
      g_string_append (string, "\xef\xbf\xbd");

      length -= (end - data) + 1;
      data = end + 1;
    }
  while (!g_utf8_validate (data, length, &end));

  if (length)
    g_string_append_len (string, data, length);

  return g_string_free_to_bytes (string);
}
Пример #2
0
gboolean
ostree_bootconfig_parser_write (OstreeBootconfigParser   *self,
                                GFile            *output,
                                GCancellable     *cancellable,
                                GError          **error)
{
  gboolean ret = FALSE;
  GHashTableIter hashiter;
  gpointer hashkey, hashvalue;
  GString *buf = g_string_new ("");
  gs_unref_bytes GBytes *bytes = NULL;
  guint i;
  gs_unref_hashtable GHashTable *written_overrides = NULL;

  written_overrides = g_hash_table_new (g_str_hash, g_str_equal);

  for (i = 0; i < self->lines->len; i++)
    {
      GVariant *linedata = self->lines->pdata[i];
      const char *key;
      const char *value;
      const char *line;

      g_variant_get (linedata, "(&s&s)", &key, &line);

      value = g_hash_table_lookup (self->options, key);
      if (value == NULL)
        {
          g_string_append (buf, line);
          g_string_append_c (buf, '\n');
        }
      else
        {
          write_key (self, buf, key, value);
          g_hash_table_insert (written_overrides, (gpointer)key, (gpointer)key);
        }
    }

  g_hash_table_iter_init (&hashiter, self->options);
  while (g_hash_table_iter_next (&hashiter, &hashkey, &hashvalue))
    {
      if (g_hash_table_lookup (written_overrides, hashkey))
        continue;
      write_key (self, buf, hashkey, hashvalue);
    }

  bytes = g_string_free_to_bytes (buf);
  buf = NULL;

  if (!ot_gfile_replace_contents_fsync (output, bytes,
                                        cancellable, error))
    goto out;

  ret = TRUE;
 out:
  if (buf) g_string_free (buf, TRUE);
  return ret;
}
Пример #3
0
static GBytes *
finish_headers (CockpitWebResponse *self,
                GString *string,
                gssize length,
                gboolean success,
                guint seen)
{
  gint i;

  static const struct {
    const gchar *extension;
    const gchar *content_type;
  } content_types[] = {
    { ".css", "text/css" },
    { ".gif", "image/gif" },
    { ".eot", "application/vnd.ms-fontobject" },
    { ".html", "text/html" },
    { ".ico", "image/vnd.microsoft.icon" },
    { ".jpg", "image/jpg" },
    { ".js", "application/javascript" },
    { ".otf", "font/opentype" },
    { ".png", "image/png" },
    { ".svg", "image/svg+xml" },
    { ".ttf", "application/octet-stream" }, /* unassigned */
    { ".woff", "application/font-woff" },
    { ".xml", "text/xml" },
  };

  /* Automatically figure out content type */
  if ((seen & HEADER_CONTENT_TYPE) == 0 &&
      self->path != NULL && success)
    {
      for (i = 0; i < G_N_ELEMENTS (content_types); i++)
        {
          if (g_str_has_suffix (self->path, content_types[i].extension))
            {
              g_string_append_printf (string, "Content-Type: %s\r\n", content_types[i].content_type);
              break;
            }
        }
    }

  if (length >= 0)
    {
      self->chunked = FALSE;
      g_string_append_printf (string, "Content-Length: %" G_GSSIZE_FORMAT "\r\n", length);
    }
  else
    {
      self->chunked = TRUE;
      g_string_append_printf (string, "Transfer-Encoding: chunked\r\n");
    }
  if (!self->keep_alive)
    g_string_append (string, "Connection: close\r\n");
  g_string_append (string, "\r\n");

  return g_string_free_to_bytes (string);
}
Пример #4
0
static GBytes *
finish_headers (CockpitWebResponse *self,
                GString *string,
                gssize length,
                gint status,
                guint seen)
{
  const gchar *content_type;

  /* Automatically figure out content type */
  if ((seen & HEADER_CONTENT_TYPE) == 0 &&
      self->full_path != NULL && status >= 200 && status <= 299)
    {
      content_type = cockpit_web_response_content_type (self->full_path);
      if (content_type)
        g_string_append_printf (string, "Content-Type: %s\r\n", content_type);
    }

  if (status != 304)
    {
      if (length >= 0 && !self->filters)
        g_string_append_printf (string, "Content-Length: %" G_GSSIZE_FORMAT "\r\n", length);

      if (length < 0 || seen & HEADER_CONTENT_ENCODING || self->filters)
        {
          self->chunked = TRUE;
          g_string_append_printf (string, "Transfer-Encoding: chunked\r\n");
        }
      else
        {
          self->chunked = FALSE;
        }
    }

  if ((seen & HEADER_CACHE_CONTROL) == 0 && status >= 200 && status <= 299)
    {
      if (self->cache_type == COCKPIT_WEB_RESPONSE_CACHE_FOREVER)
        g_string_append (string, "Cache-Control: max-age=31556926, public\r\n");
      else if (self->cache_type == COCKPIT_WEB_RESPONSE_NO_CACHE)
        g_string_append (string, "Cache-Control: no-cache, no-store\r\n");
      else if (self->cache_type == COCKPIT_WEB_RESPONSE_CACHE_PRIVATE)
        g_string_append (string, "Cache-Control: max-age=86400, private\r\n");
    }

  if ((seen & HEADER_VARY) == 0 && status >= 200 && status <= 299 &&
      self->cache_type == COCKPIT_WEB_RESPONSE_CACHE_PRIVATE)
    {
      g_string_append (string, "Vary: Cookie\r\n");
    }

  if (!self->keep_alive)
    g_string_append (string, "Connection: close\r\n");
  g_string_append (string, "\r\n");

  return g_string_free_to_bytes (string);
}
Пример #5
0
static GBytes *
_encode_wanted_services (const char *type, GSList *list)
{
	GString *encoded = g_string_new(type);
	g_string_append_c (encoded, '\0');
	g_string_append_c (encoded, '[');
	for (GSList *l=list; l ;l=l->next) {
		if (!l->data) continue;
		if (l != list) g_string_append_c (encoded, ',');
		service_info_encode_json (encoded, l->data, FALSE);
	}
	g_string_append_c (encoded, ']');
	return g_string_free_to_bytes(encoded);
}
Пример #6
0
static void
cockpit_channel_inject_perform (CockpitChannelInject *inject,
                                CockpitWebResponse *response,
                                CockpitTransport *transport)
{
  static const gchar *marker = "<head>";
  CockpitWebFilter *filter;
  CockpitCreds *creds;
  const gchar *application;
  const gchar *checksum;
  const gchar *host;
  GString *str;
  GBytes *base;

  str = g_string_new ("");

  if (!inject->service)
    return;

  creds = cockpit_web_service_get_creds (inject->service);
  application = cockpit_creds_get_application (creds);

  checksum = cockpit_web_service_get_checksum (inject->service, transport);
  if (checksum)
    {
      g_string_printf (str, "\n    <base href=\"/%s/$%s%s\">", application, checksum, inject->base_path);
    }
  else
    {
      host = cockpit_web_service_get_host (inject->service, transport);
      g_string_printf (str, "\n    <base href=\"/%s/@%s%s\">", application, host, inject->base_path);
    }

  base = g_string_free_to_bytes (str);
  filter = cockpit_web_inject_new (marker, base, 1);
  g_bytes_unref (base);

  cockpit_web_response_add_filter (response, filter);
  g_object_unref (filter);
}
Пример #7
0
	void set_body_gstr(GString *gstr) {
		return set_body_bytes (g_string_free_to_bytes (gstr));
	}
Пример #8
0
static void
send_http_request (CockpitHttpStream *self)
{
  CockpitChannel *channel = COCKPIT_CHANNEL (self);
  JsonObject *options;
  gboolean had_host;
  gboolean had_encoding;
  const gchar *method;
  const gchar *path;
  GString *string = NULL;
  JsonNode *node;
  JsonObject *headers;
  const gchar *header;
  const gchar *value;
  GList *request = NULL;
  GList *names = NULL;
  GBytes *bytes;
  GList *l;
  gsize total;

  options = cockpit_channel_get_options (channel);

  /*
   * The checks we do here for token validity are just enough to be able
   * to format an HTTP response, without leaking across lines etc.
   */

  if (!cockpit_json_get_string (options, "path", NULL, &path))
    {
      cockpit_channel_fail (channel, "protocol-error",
                            "%s: bad \"path\" field in HTTP stream request", self->name);
      goto out;
    }
  else if (path == NULL)
    {
      cockpit_channel_fail (channel, "protocol-error",
                            "%s: missing \"path\" field in HTTP stream request", self->name);
      goto out;
    }
  else if (!cockpit_web_response_is_simple_token (path))
    {
      cockpit_channel_fail (channel, "protocol-error",
                            "%s: invalid \"path\" field in HTTP stream request", self->name);
      goto out;
    }

  if (!cockpit_json_get_string (options, "method", NULL, &method))
    {
      cockpit_channel_fail (channel, "protocol-error",
                            "%s: bad \"method\" field in HTTP stream request", self->name);
      goto out;
    }
  else if (method == NULL)
    {
      cockpit_channel_fail (channel, "protocol-error",
                            "%s: missing \"method\" field in HTTP stream request", self->name);
      goto out;
    }
  else if (!cockpit_web_response_is_simple_token (method))
    {
      cockpit_channel_fail (channel, "protocol-error",
                            "%s: invalid \"method\" field in HTTP stream request", self->name);
      goto out;
    }

  g_debug ("%s: sending %s request", self->name, method);

  string = g_string_sized_new (128);
  g_string_printf (string, "%s %s HTTP/1.1\r\n", method, path);

  had_encoding = had_host = FALSE;

  node = json_object_get_member (options, "headers");
  if (node)
    {
      if (!JSON_NODE_HOLDS_OBJECT (node))
        {
          cockpit_channel_fail (channel, "protocol-error",
                                "%s: invalid \"headers\" field in HTTP stream request", self->name);
          goto out;
        }

      headers = json_node_get_object (node);
      names = json_object_get_members (headers);
      for (l = names; l != NULL; l = g_list_next (l))
        {
          header = l->data;
          if (!cockpit_web_response_is_simple_token (header))
            {
              cockpit_channel_fail (channel, "protocol-error",
                                    "%s: invalid header in HTTP stream request: %s", self->name, header);
              goto out;
            }
          node = json_object_get_member (headers, header);
          if (!node || !JSON_NODE_HOLDS_VALUE (node) || json_node_get_value_type (node) != G_TYPE_STRING)
            {
              cockpit_channel_fail (channel, "protocol-error",
                                    "%s: invalid header value in HTTP stream request: %s", self->name, header);
              goto out;
            }
          value = json_node_get_string (node);
          if (disallowed_header (header, value, self->binary))
            {
              cockpit_channel_fail (channel, "protocol-error",
                                    "%s: disallowed header in HTTP stream request: %s", self->name, header);
              goto out;
            }
          if (!cockpit_web_response_is_header_value (value))
            {
              cockpit_channel_fail (channel, "protocol-error",
                                    "%s: invalid header value in HTTP stream request: %s", self->name, header);
              goto out;
            }

          g_string_append_printf (string, "%s: %s\r\n", (gchar *)l->data, value);
          g_debug ("%s: sending header: %s %s", self->name, (gchar *)l->data, value);

          if (g_ascii_strcasecmp (l->data, "Host") == 0)
            had_host = TRUE;
          if (g_ascii_strcasecmp (l->data, "Accept-Encoding") == 0)
            had_encoding = TRUE;
        }
    }

  if (!had_host)
    {
      g_string_append (string, "Host: ");
      g_string_append_uri_escaped (string, self->client->connectable->name, "[]!%$&()*+,-.:;=\\_~", FALSE);
      g_string_append (string, "\r\n");
    }
  if (!had_encoding)
    g_string_append (string, "Accept-Encoding: identity\r\n");

  if (!self->binary)
    g_string_append (string, "Accept-Charset: UTF-8\r\n");

  request = g_list_reverse (self->request);
  self->request = NULL;

  /* Calculate how much data we have to send */
  total = 0;
  for (l = request; l != NULL; l = g_list_next (l))
    total += g_bytes_get_size (l->data);

  if (request || g_ascii_strcasecmp (method, "POST") == 0)
    g_string_append_printf (string, "Content-Length: %" G_GSIZE_FORMAT "\r\n", total);
  g_string_append (string, "\r\n");

  bytes = g_string_free_to_bytes (string);
  string = NULL;

  cockpit_stream_write (self->stream, bytes);
  g_bytes_unref (bytes);

  /* Now send all the data */
  for (l = request; l != NULL; l = g_list_next (l))
    cockpit_stream_write (self->stream, l->data);

out:
  g_list_free (names);
  g_list_free_full (request, (GDestroyNotify)g_bytes_unref);
  if (string)
    g_string_free (string, TRUE);
}
Пример #9
0
static void
setup_commit_passwd1 (GVariant *parameters,
                     GDBusMethodInvocation *invocation)
{
  const gchar *mechanism;
  GVariant *transferred = NULL;
  const gchar **lines;
  GHashTable *users = NULL;
  GHashTable *groups = NULL;
  GString *chpasswd = NULL;
  GString *newusers = NULL;
  CommitAdmin1 *context;
  CockpitPipe *pipe;
  gsize length, i, j;
  gchar **parts;
  GBytes *bytes;
  GVariant *pwdata = NULL;
  GVariant *grdata = NULL;
  GHashTable *usermod;
  gchar **memlist;
  GString *string;
  gboolean user_exists;

  /* We are getting crypted passwords so we need to use
   * --crypt-method=NONE with newusers and chpasswd so that the string
   * is installed unchanged.  Unfortunately, newusers might or might
   * not support the --crypt-method option, depending on whether it
   * was compiled with or without PAM.  When the option is missing, we
   * fix up the password afterwards via chpasswd.
   *
   * However, newusers needs some valid password to create new users.
   * Thus, we need a good random string that passes all password
   * quality criteria, and we just use the crpyted password for that.
   */

  const gchar *argv[] = { cockpit_bridge_path_newusers, "--crypt-method=NONE", NULL };
  if (!cockpit_bridge_have_newusers_crypt_method)
    argv[1] = NULL;

  g_variant_get (parameters, "(&sv)", &mechanism, &transferred);

  if (!g_str_equal (mechanism, "passwd1"))
    {
      g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR, G_DBUS_ERROR_NOT_SUPPORTED,
                                             "Unsupported setup mechanism: %s", mechanism);
      goto out;
    }
  if (!g_variant_is_of_type (transferred, G_VARIANT_TYPE ("(asas)")))
    {
      g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR, G_DBUS_ERROR_INVALID_ARGS,
                                             "Bad data passed for passwd1 mechanism");
      goto out;
    }

  users = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
  groups = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);

  if (!fgetpwent_callback (add_name_to_hashtable, users) ||
      !fgetgrent_callback (add_group_to_hashtable, groups))
    {
      g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR, G_DBUS_ERROR_FAILED,
                                             _("Couldn't list local users"));
      goto out;
    }

  g_debug ("starting setup synchronization");

  g_variant_get (transferred, "(@as@as)", &pwdata, &grdata);

  chpasswd = g_string_new ("");
  newusers = g_string_new ("");
  usermod = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, string_free);

  lines = g_variant_get_strv (pwdata, &length);
  for (i = 0; i < length; i++)
    {
      parts = g_strsplit(lines[i], ":", 3);

      user_exists = (g_hash_table_lookup (users, parts[0]) != NULL);

      if (!user_exists)
        {
          g_string_append (newusers, lines[i]);
          g_string_append_c (newusers, '\n');
        }

      if (user_exists || !cockpit_bridge_have_newusers_crypt_method)
        {
          g_string_append_printf (chpasswd, "%s:%s\n", parts[0], parts[1]);
        }

      g_strfreev (parts);
    }

  g_free (lines);

  lines = g_variant_get_strv (grdata, &length);
  for (i = 0; i < length; i++)
    {
      parts = g_strsplit(lines[i], ":", 4);
      if (g_hash_table_lookup (groups, parts[0]))
        {
          memlist = g_strsplit (parts[3], ",", -1);
          for (j = 0; memlist[j] != NULL; j++)
            {
              string = g_hash_table_lookup (usermod, memlist[j]);
              if (!string)
                {
                  string = g_string_new ("");
                  g_hash_table_insert (usermod, g_strdup (memlist[j]), string);
                }
              if (string->len > 0)
                g_string_append_c (string, ',');
              g_string_append (string, parts[0]);
            }
          g_strfreev (memlist);
        }
      g_strfreev (parts);
    }
  g_free (lines);

  context = g_new0 (CommitAdmin1, 1);
  context->invocation = g_object_ref (invocation);
  context->chpasswd = g_string_free_to_bytes (chpasswd);
  context->usermod = usermod;

  g_debug ("batch creating new users");

  bytes = g_string_free_to_bytes (newusers);
  pipe = cockpit_pipe_spawn (argv, NULL, NULL, COCKPIT_PIPE_FLAGS_NONE);
  g_signal_connect (pipe, "close", G_CALLBACK (on_newusers_close), context);
  cockpit_pipe_write (pipe, bytes);
  cockpit_pipe_close (pipe, NULL);
  g_bytes_unref (bytes);

out:
  if (users)
    g_hash_table_unref (users);
  if (groups)
    g_hash_table_unref (groups);
  if (pwdata)
    g_variant_unref (pwdata);
  if (grdata)
    g_variant_unref (grdata);
  g_variant_unref (transferred);
}