예제 #1
0
static void
process_request (CockpitRequest *request,
                 const gchar *path,
                 GHashTable *headers)
{
  gboolean claimed = FALSE;
  const gchar *actual_path;

  if (request->web_server->url_root->len &&
      !path_has_prefix (path, request->web_server->url_root))
    {
      request->delayed_reply = 404;
    }

  /*
   * If redirecting to TLS, check the path. Certain paths
   * don't require us to redirect.
   */
  if (request->delayed_reply == 301 &&
      path_has_prefix (path, request->web_server->ssl_exception_prefix))
    {
      request->delayed_reply = 0;
    }

  if (request->delayed_reply)
    {
      process_delayed_reply (request, path, headers);
      return;
    }

  actual_path = path + request->web_server->url_root->len;

  /* See if we have any takers... */
  g_signal_emit (request->web_server,
                 sig_handle_stream, 0,
                 path,
                 actual_path,
                 request->io,
                 headers,
                 request->buffer,
                 &claimed);

  if (!claimed)
    g_critical ("no handler responded to request: %s", actual_path);
}
예제 #2
0
파일: gmountspec.c 프로젝트: Alustriel/gvfs
gboolean
g_mount_spec_match_with_path (GMountSpec      *mount,
			      GMountSpec      *spec,
			      const char      *path)
{
  if (items_equal (mount->items, spec->items) &&
      path_has_prefix (path, mount->mount_prefix))
    return TRUE;
  return FALSE;
}
예제 #3
0
/**
 * cockpit_web_response_file:
 * @response: the response
 * @path: escaped path, or NULL to get from response
 * @roots: directories to look for file in
 *
 * Serve a file from disk as an HTTP response.
 */
void
cockpit_web_response_file (CockpitWebResponse *response,
                           const gchar *escaped,
                           const gchar **roots)
{
  const gchar *csp_header;
  GError *error = NULL;
  gchar *unescaped = NULL;
  gchar *path = NULL;
  GMappedFile *file = NULL;
  const gchar *root;
  GBytes *body;

  g_return_if_fail (COCKPIT_IS_WEB_RESPONSE (response));

  if (!escaped)
    escaped = cockpit_web_response_get_path (response);

  g_return_if_fail (escaped != NULL);

  /* Someone is trying to escape the root directory, or access hidden files? */
  unescaped = g_uri_unescape_string (escaped, NULL);
  if (strstr (unescaped, "/.") || strstr (unescaped, "../") || strstr (unescaped, "//"))
    {
      g_debug ("%s: invalid path request", escaped);
      cockpit_web_response_error (response, 404, NULL, "Not Found");
      goto out;
    }

again:
  root = *(roots++);
  if (root == NULL)
    {
      cockpit_web_response_error (response, 404, NULL, "Not Found");
      goto out;
    }

  g_free (path);
  path = g_build_filename (root, unescaped, NULL);

  if (g_file_test (path, G_FILE_TEST_IS_DIR))
    {
      cockpit_web_response_error (response, 403, NULL, "Directory Listing Denied");
      goto out;
    }

  /* As a double check of above behavior */
  g_assert (path_has_prefix (path, root));

  g_clear_error (&error);
  file = g_mapped_file_new (path, FALSE, &error);
  if (file == NULL)
    {
      if (g_error_matches (error, G_FILE_ERROR, G_FILE_ERROR_NOENT) ||
          g_error_matches (error, G_FILE_ERROR, G_FILE_ERROR_NAMETOOLONG))
        {
          g_debug ("%s: file not found in root: %s", escaped, root);
          goto again;
        }
      else if (g_error_matches (error, G_FILE_ERROR, G_FILE_ERROR_PERM) ||
               g_error_matches (error, G_FILE_ERROR, G_FILE_ERROR_ACCES) ||
               g_error_matches (error, G_FILE_ERROR, G_FILE_ERROR_ISDIR))
        {
          cockpit_web_response_error (response, 403, NULL, "Access denied");
          goto out;
        }
      else
        {
          g_warning ("%s: %s", path, error->message);
          cockpit_web_response_error (response, 500, NULL, "Internal server error");
          goto out;
        }
    }

  body = g_mapped_file_get_bytes (file);

  /*
   * The default Content-Security-Policy for .html files allows
   * the site to have inline <script> and <style> tags. This code
   * is not used when serving resources once logged in, only for
   * static resources when we don't yet have a session.
   */

  csp_header = NULL;
  if (g_str_has_suffix (unescaped, ".html"))
    csp_header = "Content-Security-Policy";

  cockpit_web_response_headers (response, 200, "OK", g_bytes_get_size (body),
                                csp_header, "default-src 'self' 'unsafe-inline'; connect-src 'self' ws: wss:",
                                NULL);

  if (cockpit_web_response_queue (response, body))
    cockpit_web_response_complete (response);

  g_bytes_unref (body);

out:
  g_free (unescaped);
  g_clear_error (&error);
  g_free (path);
  if (file)
    g_mapped_file_unref (file);
}
예제 #4
0
/**
 * cockpit_web_response_file:
 * @response: the response
 * @path: escaped path, or NULL to get from response
 * @roots: directories to look for file in
 *
 * Serve a file from disk as an HTTP response.
 */
void
cockpit_web_response_file (CockpitWebResponse *response,
                           const gchar *escaped,
                           gboolean cache_forever,
                           const gchar **roots)
{
  const gchar *cache_control;
  GError *error = NULL;
  gchar *unescaped;
  char *path = NULL;
  gchar *built = NULL;
  GMappedFile *file = NULL;
  const gchar *root;
  GBytes *body;

  g_return_if_fail (COCKPIT_IS_WEB_RESPONSE (response));

  if (!escaped)
    escaped = cockpit_web_response_get_path (response);

  g_return_if_fail (escaped != NULL);

again:
  root = *(roots++);
  if (root == NULL)
    {
      cockpit_web_response_error (response, 404, NULL, "Not Found");
      goto out;
    }

  unescaped = g_uri_unescape_string (escaped, NULL);
  built = g_build_filename (root, unescaped, NULL);
  g_free (unescaped);

  path = realpath (built, NULL);
  g_free (built);

  if (path == NULL)
    {
      if (errno == ENOENT || errno == ENOTDIR || errno == ELOOP || errno == ENAMETOOLONG)
        {
          g_debug ("%s: file not found in root: %s", escaped, root);
          goto again;
        }
      else if (errno == EACCES)
        {
          cockpit_web_response_error (response, 403, NULL, "Access Denied");
          goto out;
        }
      else
        {
          g_warning ("%s: resolving path failed: %m", escaped);
          cockpit_web_response_error (response, 500, NULL, "Internal Server Error");
          goto out;
        }
    }

  /* Double check that realpath() did the right thing */
  g_return_if_fail (strstr (path, "../") == NULL);
  g_return_if_fail (!g_str_has_suffix (path, "/.."));

  /* Someone is trying to escape the root directory */
  if (!path_has_prefix (path, root) &&
      !path_has_prefix (path, cockpit_web_exception_escape_root))
    {
      g_debug ("%s: request tried to escape the root directory: %s: %s", escaped, root, path);
      cockpit_web_response_error (response, 404, NULL, "Not Found");
      goto out;
    }

  if (g_file_test (path, G_FILE_TEST_IS_DIR))
    {
      cockpit_web_response_error (response, 403, NULL, "Directory Listing Denied");
      goto out;
    }

  file = g_mapped_file_new (path, FALSE, &error);
  if (file == NULL)
    {
      if (g_error_matches (error, G_FILE_ERROR, G_FILE_ERROR_PERM) ||
          g_error_matches (error, G_FILE_ERROR, G_FILE_ERROR_ACCES) ||
          g_error_matches (error, G_FILE_ERROR, G_FILE_ERROR_ISDIR))
        {
          cockpit_web_response_error (response, 403, NULL, "Access denied");
          g_clear_error (&error);
          goto out;
        }
      else
        {
          g_warning ("%s: %s", path, error->message);
          cockpit_web_response_error (response, 500, NULL, "Internal server error");
          g_clear_error (&error);
          goto out;
        }
    }

  body = g_mapped_file_get_bytes (file);

  cache_control = cache_forever ? "max-age=31556926, public" : NULL;
  cockpit_web_response_headers (response, 200, "OK", g_bytes_get_size (body),
                                "Cache-Control", cache_control,
                                NULL);

  if (cockpit_web_response_queue (response, body))
    cockpit_web_response_complete (response);

  g_bytes_unref (body);

out:
  free (path);
  if (file)
    g_mapped_file_unref (file);
}
예제 #5
0
/**
 * cockpit_web_response_file:
 * @response: the response
 * @path: escaped path, or NULL to get from response
 * @roots: directories to look for file in
 *
 * Serve a file from disk as an HTTP response.
 */
void
cockpit_web_response_file (CockpitWebResponse *response,
                           const gchar *escaped,
                           gboolean cache_forever,
                           const gchar **roots)
{
  const gchar *cache_control;
  GError *error = NULL;
  gchar *unescaped = NULL;
  gchar *path = NULL;
  GMappedFile *file = NULL;
  const gchar *root;
  GBytes *body;

  g_return_if_fail (COCKPIT_IS_WEB_RESPONSE (response));

  if (!escaped)
    escaped = cockpit_web_response_get_path (response);

  g_return_if_fail (escaped != NULL);

  /* Someone is trying to escape the root directory, or access hidden files? */
  unescaped = g_uri_unescape_string (escaped, NULL);
  if (strstr (unescaped, "/.") || strstr (unescaped, "../") || strstr (unescaped, "//"))
    {
      g_debug ("%s: invalid path request", escaped);
      cockpit_web_response_error (response, 404, NULL, "Not Found");
      goto out;
    }

again:
  root = *(roots++);
  if (root == NULL)
    {
      cockpit_web_response_error (response, 404, NULL, "Not Found");
      goto out;
    }

  g_free (path);
  path = g_build_filename (root, unescaped, NULL);

  if (g_file_test (path, G_FILE_TEST_IS_DIR))
    {
      cockpit_web_response_error (response, 403, NULL, "Directory Listing Denied");
      goto out;
    }

  /* As a double check of above behavior */
  g_assert (path_has_prefix (path, root));

  g_clear_error (&error);
  file = g_mapped_file_new (path, FALSE, &error);
  if (file == NULL)
    {
      if (g_error_matches (error, G_FILE_ERROR, G_FILE_ERROR_NOENT) ||
          g_error_matches (error, G_FILE_ERROR, G_FILE_ERROR_NAMETOOLONG))
        {
          g_debug ("%s: file not found in root: %s", escaped, root);
          goto again;
        }
      else if (g_error_matches (error, G_FILE_ERROR, G_FILE_ERROR_PERM) ||
               g_error_matches (error, G_FILE_ERROR, G_FILE_ERROR_ACCES) ||
               g_error_matches (error, G_FILE_ERROR, G_FILE_ERROR_ISDIR))
        {
          cockpit_web_response_error (response, 403, NULL, "Access denied");
          goto out;
        }
      else
        {
          g_warning ("%s: %s", path, error->message);
          cockpit_web_response_error (response, 500, NULL, "Internal server error");
          goto out;
        }
    }

  body = g_mapped_file_get_bytes (file);

  cache_control = cache_forever ? "max-age=31556926, public" : NULL;
  cockpit_web_response_headers (response, 200, "OK", g_bytes_get_size (body),
                                "Cache-Control", cache_control,
                                NULL);

  if (cockpit_web_response_queue (response, body))
    cockpit_web_response_complete (response);

  g_bytes_unref (body);

out:
  g_free (unescaped);
  g_clear_error (&error);
  g_free (path);
  if (file)
    g_mapped_file_unref (file);
}