Пример #1
0
gboolean
cockpit_handler_logout (CockpitWebServer *server,
                        CockpitWebServerRequestType reqtype,
                        const gchar *path,
                        GHashTable *headers,
                        GBytes *input,
                        CockpitWebResponse *response,
                        CockpitHandlerData *ws)
{
  GIOStream *io_stream;
  GHashTable *out_headers;
  const gchar *body;
  gboolean secure;
  GBytes *content;

  io_stream = cockpit_web_response_get_stream (response);
  secure = !G_IS_SOCKET_CONNECTION (io_stream);

  out_headers = cockpit_web_server_new_table ();
  cockpit_auth_logout (ws->auth, headers, secure, out_headers);

  body ="<html><head><title>Logged out</title></head>"
    "<body>Logged out</body></html>";

  content = g_bytes_new_static (body, strlen (body));
  cockpit_web_response_content (response, out_headers, content, NULL);
  g_bytes_unref (content);
  g_hash_table_unref (out_headers);

  return TRUE;
}
Пример #2
0
gboolean
cockpit_handler_ping (CockpitWebServer *server,
                      const gchar *path,
                      GHashTable *headers,
                      CockpitWebResponse *response,
                      CockpitHandlerData *ws)
{
  GHashTable *out_headers;
  const gchar *body;
  GBytes *content;

  out_headers = cockpit_web_server_new_table ();

  /*
   * The /ping request has unrestricted CORS enabled on it. This allows javascript
   * in the browser on embedding websites to check if Cockpit is available. These
   * websites could do this in another way (such as loading an image from Cockpit)
   * but this does it in the correct manner.
   *
   * See: http://www.w3.org/TR/cors/
   */
  g_hash_table_insert (out_headers, g_strdup ("Access-Control-Allow-Origin"), g_strdup ("*"));

  g_hash_table_insert (out_headers, g_strdup ("Content-Type"), g_strdup ("application/json"));
  body ="{ \"service\": \"cockpit\" }";
  content = g_bytes_new_static (body, strlen (body));

  cockpit_web_response_content (response, out_headers, content, NULL);

  g_bytes_unref (content);
  g_hash_table_unref (out_headers);

  return TRUE;
}
Пример #3
0
static void
on_login_complete (GObject *object,
                   GAsyncResult *result,
                   gpointer user_data)
{
  CockpitWebResponse *response = user_data;
  GError *error = NULL;
  CockpitWebService *service;
  CockpitAuthFlags flags = 0;
  CockpitCreds *creds;
  GHashTable *headers;
  GIOStream *io_stream;

  io_stream = cockpit_web_response_get_stream (response);
  if (G_IS_SOCKET_CONNECTION (io_stream))
    flags |= COCKPIT_AUTH_COOKIE_INSECURE;

  headers = cockpit_web_server_new_table ();
  service = cockpit_auth_login_finish (COCKPIT_AUTH (object), result, flags, headers, &error);

  if (error)
    {
      cockpit_web_response_gerror (response, headers, error);
      g_error_free (error);
    }
  else
    {
      creds = cockpit_web_service_get_creds (service);
      send_login_response (response, creds, headers);
      g_object_unref (service);
    }

  g_hash_table_unref (headers);
  g_object_unref (response);
}
Пример #4
0
static void
handle_login (CockpitHandlerData *data,
              CockpitWebService *service,
              const gchar *path,
              GHashTable *headers,
              CockpitWebResponse *response)
{
  GHashTable *out_headers;
  GIOStream *io_stream;
  CockpitCreds *creds;
  JsonObject *creds_json = NULL;

  if (service)
    {
      out_headers = cockpit_web_server_new_table ();
      creds = cockpit_web_service_get_creds (service);
      creds_json = cockpit_creds_to_json (creds);
      send_login_response (response, creds_json, out_headers);
      g_hash_table_unref (out_headers);
      json_object_unref (creds_json);
      return;
    }

  io_stream = cockpit_web_response_get_stream (response);
  cockpit_auth_login_async (data->auth, path,io_stream, headers,
                            on_login_complete, g_object_ref (response));
}
Пример #5
0
gboolean
cockpit_handler_login (CockpitWebServer *server,
                       const gchar *path,
                       GHashTable *headers,
                       CockpitWebResponse *response,
                       CockpitHandlerData *ws)
{
  CockpitWebService *service;
  CockpitCreds *creds;
  gchar *remote_peer = NULL;
  GHashTable *out_headers;
  GIOStream *io_stream;

  service = cockpit_auth_check_cookie (ws->auth, headers);
  if (service == NULL)
    {
      io_stream = cockpit_web_response_get_stream (response);
      remote_peer = get_remote_address (io_stream);
      cockpit_auth_login_async (ws->auth, headers, remote_peer, on_login_complete,
                                g_object_ref (response));
      g_free (remote_peer);
    }
  else
    {
      out_headers = cockpit_web_server_new_table ();
      creds = cockpit_web_service_get_creds (service);
      send_login_response (response, creds, out_headers);
      g_hash_table_unref (out_headers);
      g_object_unref (service);
    }

  /* no response yet */
  return TRUE;
}
Пример #6
0
static gboolean
mock_http_headers (CockpitWebResponse *response,
                   GHashTable *in_headers)
{
  GHashTableIter iter;
  GHashTable *headers;
  gpointer name, value;

  headers = cockpit_web_server_new_table();
  g_hash_table_iter_init (&iter, in_headers);
  while (g_hash_table_iter_next (&iter, &name, &value))
    {
      if (g_str_has_prefix (name, "Header"))
        g_hash_table_insert (headers, g_strdup (name), g_strdup (value));
    }
  g_hash_table_replace (headers, g_strdup ("Header3"), g_strdup ("three"));
  g_hash_table_replace (headers, g_strdup ("Header4"), g_strdup ("marmalade"));

  cockpit_web_response_headers_full (response, 201, "Yoo Hoo", -1, headers);
  cockpit_web_response_complete (response);

  g_hash_table_unref (headers);

  return TRUE;
}
Пример #7
0
static void
handle_login (CockpitHandlerData *data,
              CockpitWebService *service,
              const gchar *path,
              GHashTable *headers,
              CockpitWebResponse *response)
{
  GHashTable *out_headers;
  gchar *remote_peer = NULL;
  GIOStream *io_stream;
  CockpitCreds *creds;

  if (service)
    {
      out_headers = cockpit_web_server_new_table ();
      creds = cockpit_web_service_get_creds (service);
      send_login_response (response, creds, out_headers);
      g_hash_table_unref (out_headers);
    }
  else
    {
      io_stream = cockpit_web_response_get_stream (response);
      remote_peer = get_remote_address (io_stream);
      cockpit_auth_login_async (data->auth, path, headers, remote_peer,
                                on_login_complete, g_object_ref (response));
      g_free (remote_peer);
    }
}
Пример #8
0
static void
send_login_html (CockpitWebResponse *response,
                 CockpitHandlerData *ws)
{
  GHashTable *headers = NULL;
  GList *l, *output = NULL;
  gchar *login_html;
  GMappedFile *file;
  GError *error = NULL;
  GBytes *body = NULL;
  gsize length;

  login_html = g_build_filename (ws->static_roots[0], "login.html", NULL);
  file = g_mapped_file_new (login_html, FALSE, &error);
  if (file == NULL)
    {
      g_warning ("%s: %s", login_html, error->message);
      cockpit_web_response_error (response, 500, NULL, NULL);
      g_clear_error (&error);
      goto out;
    }

  body = g_mapped_file_get_bytes (file);
  output = cockpit_template_expand (body, substitute_environment, ws->os_release);

  length = 0;
  for (l = output; l != NULL; l = g_list_next (l))
    length += g_bytes_get_size (l->data);

  headers = cockpit_web_server_new_table ();
  g_hash_table_insert (headers, g_strdup ("Content-Type"), g_strdup ("text/html; charset=utf8"));

  cockpit_web_response_headers_full (response, 200, "OK", length, headers);

  for (l = output; l != NULL; l = g_list_next (l))
    {
      if (!cockpit_web_response_queue (response, l->data))
        break;
    }
  if (l == NULL)
    cockpit_web_response_complete (response);

out:
  g_list_free_full (output, (GDestroyNotify)g_bytes_unref);
  if (headers)
    g_hash_table_unref (headers);
  g_free (login_html);
  if (body)
    g_bytes_unref (body);
  if (file)
    g_mapped_file_unref (file);
}
Пример #9
0
void
cockpit_channel_response_open (CockpitWebService *service,
                               GHashTable *in_headers,
                               CockpitWebResponse *response,
                               JsonObject *open)
{
  CockpitTransport *transport;
  WebSocketDataType data_type;
  GHashTable *headers;
  const gchar *content_type;
  const gchar *content_disposition;

  /* Parse the external */
  if (!cockpit_web_service_parse_external (open, &content_type, &content_disposition, NULL))
    {
      cockpit_web_response_error (response, 400, NULL, "Bad channel request");
      return;
    }

  transport = cockpit_web_service_ensure_transport (service, open);
  if (!transport)
    {
      cockpit_web_response_error (response, 502, NULL, "Failed to open channel transport");
      return;
    }

  headers = cockpit_web_server_new_table ();

  if (content_disposition)
    g_hash_table_insert (headers, g_strdup ("Content-Disposition"), g_strdup (content_disposition));

  if (!json_object_has_member (open, "binary"))
    json_object_set_string_member (open, "binary", "raw");

  if (!content_type)
    {
      if (!cockpit_web_service_parse_binary (open, &data_type))
        g_return_if_reached ();
      if (data_type == WEB_SOCKET_DATA_TEXT)
        content_type = "text/plain";
      else
        content_type = "application/octet-stream";
    }
  g_hash_table_insert (headers, g_strdup ("Content-Type"), g_strdup (content_type));

  /* We shouldn't need to send this part further */
  json_object_remove_member (open, "external");

  cockpit_channel_response_create (service, response, transport, NULL, headers, open);
  g_hash_table_unref (headers);
}
Пример #10
0
static gboolean
mock_http_host (CockpitWebResponse *response,
                GHashTable *in_headers)
{
  GHashTable *headers;

  headers = cockpit_web_server_new_table();
  g_hash_table_insert (headers, g_strdup ("Host"), g_strdup (g_hash_table_lookup (in_headers, "Host")));
  cockpit_web_response_headers_full (response, 201, "Yoo Hoo", -1, headers);
  cockpit_web_response_complete (response);

  g_hash_table_unref (headers);

  return TRUE;
}
Пример #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
gboolean
cockpit_handler_login (CockpitWebServer *server,
                       CockpitWebServerRequestType reqtype,
                       const gchar *path,
                       GHashTable *headers,
                       GBytes *input,
                       CockpitWebResponse *response,
                       CockpitHandlerData *ws)
{
  CockpitWebService *service;
  gchar *remote_peer = NULL;
  GIOStream *io_stream;
  LoginResponse *lr;

  lr = g_new0 (LoginResponse, 1);
  lr->response = g_object_ref (response);
  lr->headers = cockpit_web_server_new_table ();

  if (reqtype == COCKPIT_WEB_SERVER_REQUEST_GET)
    {
      service = cockpit_auth_check_cookie (ws->auth, headers);
      if (service == NULL)
        {
          cockpit_web_response_error (response, 401, NULL, NULL);
          login_response_free (lr);
        }
      else
        {
          cockpit_web_service_modules (service, "localhost", on_login_modules, lr);
          g_object_unref (service);
          /* no response yet */
        }
    }
  else if (reqtype == COCKPIT_WEB_SERVER_REQUEST_POST)
    {
      io_stream = cockpit_web_response_get_stream (response);
      remote_peer = get_remote_address (io_stream);
      cockpit_auth_login_async (ws->auth, headers, input, remote_peer,
                                on_login_complete, lr);
      g_free (remote_peer);
      /* no response yet */
    }

  return TRUE;
}
Пример #13
0
gboolean
cockpit_web_server_parse_cookies (GHashTable *headers,
                                  GHashTable **out_cookies,
                                  GError **error)
{
  gboolean ret = FALSE;
  GHashTableIter hash_iter;
  const gchar *key;
  const gchar *value;
  gs_unref_hashtable GHashTable *ret_cookies = NULL;

  ret_cookies = cockpit_web_server_new_table ();

  g_hash_table_iter_init (&hash_iter, headers);
  while (g_hash_table_iter_next (&hash_iter, (gpointer)&key, (gpointer)&value))
    {
      if (g_ascii_strcasecmp (key, "Cookie") == 0)
        {
          gs_strfreev gchar** elements = NULL;
          guint n;
          elements = g_strsplit (value, ";", 0);
          for (n = 0; elements[n] != NULL; n++)
            {
              gchar *cookie_name;
              gchar *cookie_value;
              g_strstrip(elements[n]);
              if (!parse_cookie_pair (elements[n], &cookie_name, &cookie_value, error))
		goto out;
              /* adopt strings */
              g_hash_table_replace (ret_cookies, cookie_name, cookie_value);
            }
        }
    }

  ret = TRUE;
  *out_cookies = ret_cookies;
  ret_cookies = NULL;
out:
  return ret;
}
Пример #14
0
void
cockpit_channel_response_serve (CockpitWebService *service,
                                GHashTable *in_headers,
                                CockpitWebResponse *response,
                                const gchar *where,
                                const gchar *path)
{
  CockpitChannelResponse *chesp = NULL;
  CockpitTransport *transport = NULL;
  CockpitCacheType cache_type = COCKPIT_WEB_RESPONSE_CACHE_PRIVATE;
  const gchar *host = NULL;
  const gchar *pragma;
  gchar *quoted_etag = NULL;
  GHashTable *out_headers = NULL;
  gchar *val = NULL;
  gboolean handled = FALSE;
  GHashTableIter iter;
  const gchar *checksum;
  JsonObject *object = NULL;
  JsonObject *heads;
  gchar *channel = NULL;
  gchar *language = NULL;
  gpointer key;
  gpointer value;

  g_return_if_fail (COCKPIT_IS_WEB_SERVICE (service));
  g_return_if_fail (in_headers != NULL);
  g_return_if_fail (COCKPIT_IS_WEB_RESPONSE (response));
  g_return_if_fail (path != NULL);

  if (where == NULL)
    {
      host = "localhost";
    }
  else if (where[0] == '@')
    {
      host = where + 1;
    }
  else if (where[0] == '$')
    {
      quoted_etag = g_strdup_printf ("\"%s\"", where);
      cache_type = COCKPIT_WEB_RESPONSE_CACHE_FOREVER;
      pragma = g_hash_table_lookup (in_headers, "Pragma");

      if ((!pragma || !strstr (pragma, "no-cache")) &&
          (g_strcmp0 (g_hash_table_lookup (in_headers, "If-None-Match"), where) == 0 ||
           g_strcmp0 (g_hash_table_lookup (in_headers, "If-None-Match"), quoted_etag) == 0))
        {
          cockpit_web_response_headers (response, 304, "Not Modified", 0, "ETag", quoted_etag, NULL);
          cockpit_web_response_complete (response);
          handled = TRUE;
          goto out;
        }

      transport = cockpit_web_service_find_transport (service, where + 1);
      if (!transport)
        goto out;

      host = cockpit_web_service_get_host (service, transport);
      if (!host)
        {
          g_warn_if_reached ();
          goto out;
        }
    }
  else
    {
      goto out;
    }

  cockpit_web_response_set_cache_type (response, cache_type);
  object = cockpit_transport_build_json ("command", "open",
                                         "payload", "http-stream1",
                                         "internal", "packages",
                                         "method", "GET",
                                         "host", host,
                                         "path", path,
                                         "binary", "raw",
                                         NULL);

  if (!transport)
    {
      transport = cockpit_web_service_ensure_transport (service, object);
      if (!transport)
        goto out;
    }

  if (where)
    {
      /*
       * Maybe send back a redirect to the checksum url. We only do this if actually
       * accessing a file, and not a some sort of data like '/checksum', or a root path
       * like '/'
       */
      if (where[0] == '@' && strchr (path, '.'))
        {
          checksum = cockpit_web_service_get_checksum (service, transport);
          if (checksum)
            {
              handled = redirect_to_checksum_path (service, response, checksum, path);
              goto out;
            }
        }
    }

  out_headers = cockpit_web_server_new_table ();

  channel = cockpit_web_service_unique_channel (service);
  json_object_set_string_member (object, "channel", channel);

  if (quoted_etag)
    {
      /*
       * If we have a checksum, then use it as an ETag. It is intentional that
       * a cockpit-bridge version could (in the future) override this.
       */
      g_hash_table_insert (out_headers, g_strdup ("ETag"), quoted_etag);
      quoted_etag = NULL;
    }

  heads = json_object_new ();

  g_hash_table_iter_init (&iter, in_headers);
  while (g_hash_table_iter_next (&iter, &key, &value))
    {
      val = NULL;

      if (g_ascii_strcasecmp (key, "Host") == 0 ||
          g_ascii_strcasecmp (key, "Cookie") == 0 ||
          g_ascii_strcasecmp (key, "Referer") == 0 ||
          g_ascii_strcasecmp (key, "Connection") == 0 ||
          g_ascii_strcasecmp (key, "Pragma") == 0 ||
          g_ascii_strcasecmp (key, "Cache-Control") == 0 ||
          g_ascii_strcasecmp (key, "User-Agent") == 0 ||
          g_ascii_strcasecmp (key, "Accept-Charset") == 0 ||
          g_ascii_strcasecmp (key, "Accept-Ranges") == 0 ||
          g_ascii_strcasecmp (key, "Content-Length") == 0 ||
          g_ascii_strcasecmp (key, "Content-MD5") == 0 ||
          g_ascii_strcasecmp (key, "Content-Range") == 0 ||
          g_ascii_strcasecmp (key, "Range") == 0 ||
          g_ascii_strcasecmp (key, "TE") == 0 ||
          g_ascii_strcasecmp (key, "Trailer") == 0 ||
          g_ascii_strcasecmp (key, "Upgrade") == 0 ||
          g_ascii_strcasecmp (key, "Transfer-Encoding") == 0)
        continue;

      json_object_set_string_member (heads, key, value);
      g_free (val);
    }

  /* Parse the language out of the CockpitLang cookie */
  language = cockpit_web_server_parse_cookie (in_headers, "CockpitLang");
  if (language)
    json_object_set_string_member (heads, "Accept-Language", language);

  json_object_set_string_member (heads, "Host", host);
  json_object_set_object_member (object, "headers", heads);

  chesp = cockpit_channel_response_create (service, response, transport,
                                           cockpit_web_response_get_path (response),
                                           out_headers, object);

  if (!where)
    chesp->inject = cockpit_channel_inject_new (service, path);

  handled = TRUE;

out:
  g_free (language);
  if (object)
    json_object_unref (object);
  g_free (quoted_etag);
  if (out_headers)
    g_hash_table_unref (out_headers);
  g_free (channel);

  if (!handled)
    cockpit_web_response_error (response, 404, NULL, NULL);
}
Пример #15
0
static void
send_index_response (CockpitWebResponse *response,
                     CockpitWebService *service,
                     JsonObject *modules)
{
  GHashTable *out_headers;
  GError *error = NULL;
  GMappedFile *file = NULL;
  GBytes *body = NULL;
  GBytes *prefix = NULL;
  GBytes *environ = NULL;
  GBytes *suffix = NULL;
  gchar *index_html;
  const gchar *needle;
  const gchar *data;
  const gchar *pos;
  gsize needle_len;
  gsize length;
  gsize offset;

  /*
   * Since the index file cannot be properly cached, it can change on
   * each request, so we include full environment information directly
   * rather than making the client do another round trip later.
   *
   * If the caller is already logged in, then this is included in the
   * environment.
   */

  index_html = g_build_filename (cockpit_ws_static_directory, "index.html", NULL);
  file = g_mapped_file_new (index_html, FALSE, &error);
  if (file == NULL)
    {
      g_warning ("%s: %s", index_html, error->message);
      cockpit_web_response_error (response, 500, NULL, NULL);
      g_clear_error (&error);
      goto out;
    }

  body = g_mapped_file_get_bytes (file);
  data = g_bytes_get_data (body, &length);

  needle = "cockpit_environment_info";
  pos = g_strstr_len (data, length, needle);
  if (!pos)
    {
      g_warning ("couldn't find 'cockpit_environment_info' string in index.html");
      cockpit_web_response_error (response, 500, NULL, NULL);
      goto out;
    }

  environ = build_environment (service, modules);

  offset = (pos - data);
  prefix = g_bytes_new_from_bytes (body, 0, offset);

  needle_len = strlen (needle);
  suffix = g_bytes_new_from_bytes (body, offset + needle_len,
                                   length - (offset + needle_len));

  out_headers = cockpit_web_server_new_table ();
  g_hash_table_insert (out_headers, g_strdup ("Content-Type"), g_strdup ("text/html; charset=utf8"));
  cockpit_web_response_content (response, out_headers, prefix, environ, suffix, NULL);
  g_hash_table_unref (out_headers);

out:
  g_free (index_html);
  if (prefix)
    g_bytes_unref (prefix);
  if (body)
    g_bytes_unref (body);
  if (environ)
    g_bytes_unref (environ);
  if (suffix)
    g_bytes_unref (suffix);
  if (file)
    g_mapped_file_unref (file);
}