Exemple #1
0
xr_server* xr_server_new(const char* cert, const char* privkey, int threads, GError** err)
{
  xr_trace(XR_DEBUG_SERVER_TRACE, "(cert=%s, threads=%d, err=%p)", cert, threads, err);
  GError* local_err = NULL;

  g_return_val_if_fail(threads > 0 && threads < 1000, NULL);
  g_return_val_if_fail (err == NULL || *err == NULL, NULL);

  xr_init();

  xr_server* server = g_new0(xr_server, 1);
  server->secure = !!cert;
  server->service = g_threaded_socket_service_new(threads);
  g_signal_connect(server->service, "run", (GCallback)_xr_server_service_run, server);

  if (cert)
  {
    gchar *cert_and_privkey = g_strconcat(cert, privkey, NULL);
    server->cert = g_tls_certificate_new_from_pem(cert_and_privkey, -1, &local_err);
    g_free(cert_and_privkey);

    if (local_err)
    {
      g_propagate_prefixed_error(err, local_err, "Certificate load failed: ");
      goto err0;
    }
  }

  server->sessions = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, (GDestroyNotify)xr_servlet_free_fini);
  g_static_rw_lock_init(&server->sessions_lock);
  server->sessions_cleaner = g_thread_create((GThreadFunc)sessions_cleaner_func, server, TRUE, NULL);
  if (server->sessions_cleaner == NULL)
    goto err1;

  return server;

err1:
  g_hash_table_destroy(server->sessions);
  g_static_rw_lock_free(&server->sessions_lock);
  if (server->cert)
    g_object_unref(server->cert);
err0:
  g_object_unref(server->service);
  g_free(server);
  return NULL;
}
Exemple #2
0
/**
 * e_trust_prompt_run_for_source:
 * @parent: A #GtkWindow to use as a parent for the trust prompt dialog
 * @source: an #ESource, with %E_SOURCE_EXTENSION_AUTHENTICATION
 * @certificate_pem: a PEM-encoded certificate for which to show the trust prompt
 * @certificate_errors: errors of the @certificate_pem
 * @error_text: (allow-none): an optional error text to show in the dialog; can be %NULL
 * @allow_source_save: whether can also save any @source changes
 * @cancellable: (allow-none): a #GCancellable, or %NULL
 * @callback: a callback to call, when the prompt (an @source save) is done
 * @user_data: user data passed into @callback
 *
 * Similar to e_trust_prompt_run_modal(), except it also manages all the necessary things
 * around the @source<!-- -->'s SSL/TLS trust properties when it also contains %E_SOURCE_EXTENSION_WEBDAV,
 * thus the SSL/TLS trust on the WebDAV @source is properly updated based on the user's choice.
 * The call is finished with e_trust_prompt_run_for_source_finish(),
 * which also returns the user's choice. The finish happens in the @callback.
 * This is necessary, because the @source can be also saved.
 *
 * The function fails, if the @source doesn't contain the %E_SOURCE_EXTENSION_AUTHENTICATION.
 *
 * Note: The dialog is not shown when the stored certificate trust in the WebDAV @source
 *    matches the @certificate_pem and the stored result is #E_TRUST_PROMPT_RESPONSE_REJECT.
 *
 * Since: 3.16
 **/
void
e_trust_prompt_run_for_source (GtkWindow *parent,
			       ESource *source,
			       const gchar *certificate_pem,
			       GTlsCertificateFlags certificate_errors,
			       const gchar *error_text,
			       gboolean allow_source_save,
			       GCancellable *cancellable,
			       GAsyncReadyCallback callback,
			       gpointer user_data)
{
	ESourceAuthentication *extension_authentication = NULL;
	ESourceWebdav *extension_webdav = NULL;
	SaveSourceData *save_data;
	GTlsCertificate *certificate;
	gchar *host;
	GTask *task;

	if (parent)
		g_return_if_fail (GTK_IS_WINDOW (parent));
	g_return_if_fail (E_IS_SOURCE (source));
	g_return_if_fail (certificate_pem != NULL);

	if (e_source_has_extension (source, E_SOURCE_EXTENSION_GOA) ||
	    e_source_has_extension (source, E_SOURCE_EXTENSION_UOA)) {
		/* Make sure that GOA/UOA collection sources contain these extensions too */
		g_warn_if_fail (e_source_get_extension (source, E_SOURCE_EXTENSION_AUTHENTICATION));
		g_warn_if_fail (e_source_get_extension (source, E_SOURCE_EXTENSION_WEBDAV_BACKEND));
	}

	if (e_source_has_extension (source, E_SOURCE_EXTENSION_AUTHENTICATION))
		extension_authentication = e_source_get_extension (source, E_SOURCE_EXTENSION_AUTHENTICATION);
	if (e_source_has_extension (source, E_SOURCE_EXTENSION_WEBDAV_BACKEND))
		extension_webdav = e_source_get_extension (source, E_SOURCE_EXTENSION_WEBDAV_BACKEND);

	save_data = g_new0 (SaveSourceData, 1);
	save_data->response = E_TRUST_PROMPT_RESPONSE_UNKNOWN;
	save_data->call_save = FALSE;

	/* Lookup used host name */
	if (extension_authentication)
		host = e_source_authentication_dup_host (extension_authentication);
	else
		host = NULL;

	if (!host || !*host) {
		g_free (host);
		host = NULL;

		if (e_source_has_extension (source, E_SOURCE_EXTENSION_GOA)) {
			ESourceGoa *goa_extension;
			gchar *url;

			goa_extension = e_source_get_extension (source, E_SOURCE_EXTENSION_GOA);

			url = e_source_goa_dup_calendar_url (goa_extension);
			host = trust_prompt_get_host_from_url (url);
			g_free (url);

			if (!host) {
				url = e_source_goa_dup_contacts_url (goa_extension);
				host = trust_prompt_get_host_from_url (url);
				g_free (url);
			}
		}
	}

	certificate = g_tls_certificate_new_from_pem (certificate_pem, -1, &save_data->error);
	if (certificate) {
		if (extension_webdav && host)
			save_data->response = e_source_webdav_verify_ssl_trust (extension_webdav, host, certificate, 0);
		else
			save_data->response = E_TRUST_PROMPT_RESPONSE_REJECT_TEMPORARILY;

		if (save_data->response != E_TRUST_PROMPT_RESPONSE_REJECT) {
			const gchar *source_extension = NULL;

			if (e_source_has_extension (source, E_SOURCE_EXTENSION_ADDRESS_BOOK))
				source_extension = E_SOURCE_EXTENSION_ADDRESS_BOOK;

			if (e_source_has_extension (source, E_SOURCE_EXTENSION_CALENDAR)) {
				if (!source_extension)
					source_extension = E_SOURCE_EXTENSION_CALENDAR;
				else
					source_extension = E_SOURCE_EXTENSION_COLLECTION;
			}

			if (e_source_has_extension (source, E_SOURCE_EXTENSION_MEMO_LIST)) {
				if (!source_extension)
					source_extension = E_SOURCE_EXTENSION_MEMO_LIST;
				else
					source_extension = E_SOURCE_EXTENSION_COLLECTION;
			}

			if (e_source_has_extension (source, E_SOURCE_EXTENSION_TASK_LIST)) {
				if (!source_extension)
					source_extension = E_SOURCE_EXTENSION_TASK_LIST;
				else
					source_extension = E_SOURCE_EXTENSION_COLLECTION;
			}

			if (e_source_has_extension (source, E_SOURCE_EXTENSION_MAIL_ACCOUNT)) {
				if (!source_extension)
					source_extension = E_SOURCE_EXTENSION_MAIL_ACCOUNT;
				else
					source_extension = E_SOURCE_EXTENSION_COLLECTION;
			}

			if (e_source_has_extension (source, E_SOURCE_EXTENSION_MAIL_TRANSPORT)) {
				if (!source_extension)
					source_extension = E_SOURCE_EXTENSION_MAIL_TRANSPORT;
				else
					source_extension = E_SOURCE_EXTENSION_COLLECTION;
			}

			save_data->response = e_trust_prompt_run_with_dialog_ready_callback (parent,
				source_extension, e_source_get_display_name (source), host,
				certificate_pem, certificate_errors, error_text,
				trust_prompt_listen_for_source_changes_cb, source);
		}
	}

	g_signal_handlers_disconnect_matched (source, G_SIGNAL_MATCH_FUNC, 0, 0, NULL,
		source_connection_status_changed_cb, NULL);

	if (save_data->response != E_TRUST_PROMPT_RESPONSE_UNKNOWN) {
		if (certificate && extension_webdav) {
			e_source_webdav_update_ssl_trust (extension_webdav, host, certificate, save_data->response);
			save_data->call_save = allow_source_save;
		}
	}

	g_clear_object (&certificate);
	g_free (host);

	task = g_task_new (source, cancellable, callback, user_data);
	g_task_set_source_tag (task, e_trust_prompt_run_for_source);
	g_task_set_task_data (task, save_data, save_source_data_free);

	g_task_run_in_thread (task, save_source_thread);

	g_object_unref (task);
}
int
main (int argc, char *argv[])
{
  GMainLoop *loop;
  GstRTSPServer *server;
  GstRTSPMountPoints *mounts;
  GstRTSPMediaFactory *factory;
  GOptionContext *optctx;
  GError *error = NULL;
  GstRTSPAuth *auth;
  GstRTSPToken *token;
  gchar *basic;
#ifdef WITH_TLS
  GTlsCertificate *cert;
#endif

  optctx = g_option_context_new ("<launch line> - Test RTSP Server, Launch\n\n"
      "Example: \"( decodebin name=depay0 ! autovideosink )\"");
  g_option_context_add_main_entries (optctx, entries, NULL);
  g_option_context_add_group (optctx, gst_init_get_option_group ());
  if (!g_option_context_parse (optctx, &argc, &argv, &error)) {
    g_printerr ("Error parsing options: %s\n", error->message);
    return -1;
  }

  if (argc < 2) {
    g_print ("%s\n", g_option_context_get_help (optctx, TRUE, NULL));
    return 1;
  }
  g_option_context_free (optctx);

  loop = g_main_loop_new (NULL, FALSE);

  /* create a server instance */
  server = gst_rtsp_server_new ();
  g_object_set (server, "service", port, NULL);

  /* get the mount points for this server, every server has a default object
   * that be used to map uri mount points to media factories */
  mounts = gst_rtsp_server_get_mount_points (server);

  /* make a media factory for a test stream. The default media factory can use
   * gst-launch syntax to create pipelines.
   * any launch line works as long as it contains elements named depay%d. Each
   * element with depay%d names will be a stream */
  factory = gst_rtsp_media_factory_new ();
  gst_rtsp_media_factory_set_transport_mode (factory,
      GST_RTSP_TRANSPORT_MODE_RECORD);
  gst_rtsp_media_factory_set_launch (factory, argv[1]);
  gst_rtsp_media_factory_set_latency (factory, 2000);
#ifdef WITH_TLS
  gst_rtsp_media_factory_set_profiles (factory,
      GST_RTSP_PROFILE_SAVP | GST_RTSP_PROFILE_SAVPF);
#else
  gst_rtsp_media_factory_set_profiles (factory,
      GST_RTSP_PROFILE_AVP | GST_RTSP_PROFILE_AVPF);
#endif

  /* allow user to access this resource */
  gst_rtsp_media_factory_add_role (factory, "user",
      GST_RTSP_PERM_MEDIA_FACTORY_ACCESS, G_TYPE_BOOLEAN, TRUE,
      GST_RTSP_PERM_MEDIA_FACTORY_CONSTRUCT, G_TYPE_BOOLEAN, TRUE, NULL);
  /* Anonymous users can see but not construct, so get UNAUTHORIZED */
  gst_rtsp_media_factory_add_role (factory, "anonymous",
      GST_RTSP_PERM_MEDIA_FACTORY_ACCESS, G_TYPE_BOOLEAN, TRUE,
      GST_RTSP_PERM_MEDIA_FACTORY_CONSTRUCT, G_TYPE_BOOLEAN, FALSE, NULL);

  /* attach the test factory to the /test url */
  gst_rtsp_mount_points_add_factory (mounts, "/test", factory);

  /* don't need the ref to the mapper anymore */
  g_object_unref (mounts);

  /* Set up the auth for user account */
  /* make a new authentication manager */
  auth = gst_rtsp_auth_new ();
#ifdef WITH_TLS
  cert = g_tls_certificate_new_from_pem ("-----BEGIN CERTIFICATE-----"
      "MIICJjCCAY+gAwIBAgIBBzANBgkqhkiG9w0BAQUFADCBhjETMBEGCgmSJomT8ixk"
      "ARkWA0NPTTEXMBUGCgmSJomT8ixkARkWB0VYQU1QTEUxHjAcBgNVBAsTFUNlcnRp"
      "ZmljYXRlIEF1dGhvcml0eTEXMBUGA1UEAxMOY2EuZXhhbXBsZS5jb20xHTAbBgkq"
      "hkiG9w0BCQEWDmNhQGV4YW1wbGUuY29tMB4XDTExMDExNzE5NDcxN1oXDTIxMDEx"
      "NDE5NDcxN1owSzETMBEGCgmSJomT8ixkARkWA0NPTTEXMBUGCgmSJomT8ixkARkW"
      "B0VYQU1QTEUxGzAZBgNVBAMTEnNlcnZlci5leGFtcGxlLmNvbTBcMA0GCSqGSIb3"
      "DQEBAQUAA0sAMEgCQQDYScTxk55XBmbDM9zzwO+grVySE4rudWuzH2PpObIonqbf"
      "hRoAalKVluG9jvbHI81eXxCdSObv1KBP1sbN5RzpAgMBAAGjIjAgMAkGA1UdEwQC"
      "MAAwEwYDVR0lBAwwCgYIKwYBBQUHAwEwDQYJKoZIhvcNAQEFBQADgYEAYx6fMqT1"
      "Gvo0jq88E8mc+bmp4LfXD4wJ7KxYeadQxt75HFRpj4FhFO3DOpVRFgzHlOEo3Fwk"
      "PZOKjvkT0cbcoEq5whLH25dHoQxGoVQgFyAP5s+7Vp5AlHh8Y/vAoXeEVyy/RCIH"
      "QkhUlAflfDMcrrYjsmwoOPSjhx6Mm/AopX4="
      "-----END CERTIFICATE-----"
      "-----BEGIN PRIVATE KEY-----"
      "MIIBVAIBADANBgkqhkiG9w0BAQEFAASCAT4wggE6AgEAAkEA2EnE8ZOeVwZmwzPc"
      "88DvoK1ckhOK7nVrsx9j6TmyKJ6m34UaAGpSlZbhvY72xyPNXl8QnUjm79SgT9bG"
      "zeUc6QIDAQABAkBRFJZ32VbqWMP9OVwDJLiwC01AlYLnka0mIQZbT/2xq9dUc9GW"
      "U3kiVw4lL8v/+sPjtTPCYYdzHHOyDen6znVhAiEA9qJT7BtQvRxCvGrAhr9MS022"
      "tTdPbW829BoUtIeH64cCIQDggG5i48v7HPacPBIH1RaSVhXl8qHCpQD3qrIw3FMw"
      "DwIga8PqH5Sf5sHedy2+CiK0V4MRfoU4c3zQ6kArI+bEgSkCIQCLA1vXBiE31B5s"
      "bdHoYa1BXebfZVd+1Hd95IfEM5mbRwIgSkDuQwV55BBlvWph3U8wVIMIb4GStaH8"
      "W535W8UBbEg=" "-----END PRIVATE KEY-----", -1, &error);
  if (cert == NULL) {
    g_printerr ("failed to parse PEM: %s\n", error->message);
    return -1;
  }
  gst_rtsp_auth_set_tls_certificate (auth, cert);
  g_object_unref (cert);
#endif

  /* make default token - anonymous unauthenticated access */
  token =
      gst_rtsp_token_new (GST_RTSP_TOKEN_MEDIA_FACTORY_ROLE, G_TYPE_STRING,
      "anonymous", NULL);
  gst_rtsp_auth_set_default_token (auth, token);
  gst_rtsp_token_unref (token);

  /* make user token */
  token =
      gst_rtsp_token_new (GST_RTSP_TOKEN_MEDIA_FACTORY_ROLE, G_TYPE_STRING,
      "user", NULL);
  basic = gst_rtsp_auth_make_basic ("user", "password");
  gst_rtsp_auth_add_basic (auth, basic, token);
  g_free (basic);
  gst_rtsp_token_unref (token);

  /* set as the server authentication manager */
  gst_rtsp_server_set_auth (server, auth);
  g_object_unref (auth);

  /* attach the server to the default maincontext */
  gst_rtsp_server_attach (server, NULL);

  /* start serving */
#ifdef WITH_TLS
  g_print ("stream ready at rtsps://127.0.0.1:%s/test\n", port);
#else
  g_print ("stream ready at rtsp://127.0.0.1:%s/test\n", port);
#endif
  g_main_loop_run (loop);

  return 0;
}
Exemple #4
0
CockpitStreamOptions *
cockpit_channel_parse_stream (CockpitChannel *self)
{
  const gchar *problem = "protocol-error";
  GTlsCertificate *cert = NULL;
  GTlsDatabase *database = NULL;
  CockpitStreamOptions *ret;
  gboolean use_tls = FALSE;
  GError *error = NULL;
  GString *pem = NULL;
  JsonObject *options;
  JsonNode *node;

  node = json_object_get_member (self->priv->open_options, "tls");
  if (node && !JSON_NODE_HOLDS_OBJECT (node))
    {
      g_warning ("invalid \"tls\" option for channel");
      goto out;
    }
  else if (node)
    {
      options = json_node_get_object (node);
      use_tls = TRUE;

      /*
       * The only function in GLib to parse private keys takes
       * them in PEM concatenated form. This is a limitation of GLib,
       * rather than concatenated form being a decent standard for
       * certificates and keys. So build a combined PEM as expected by
       * GLib here.
       */

      pem = g_string_sized_new (8192);

      problem = parse_cert_option_as_pem (options, "certificate", pem);
      if (problem)
        goto out;

      if (pem->len)
        {
          problem = parse_cert_option_as_pem (options, "key", pem);
          if (problem)
            goto out;

          cert = g_tls_certificate_new_from_pem (pem->str, pem->len, &error);
          if (error != NULL)
            {
              g_warning ("invalid \"certificate\" or \"key\" content: %s", error->message);
              g_error_free (error);
              problem = "internal-error";
              goto out;
            }
        }

      problem = parse_cert_option_as_database (options, "authority", &database);
      if (problem)
        goto out;
    }

  problem = NULL;

out:
  if (problem)
    {
      cockpit_channel_close (self, problem);
      ret = NULL;
    }
  else
    {
      ret = g_new0 (CockpitStreamOptions, 1);
      ret->refs = 1;
      ret->tls_client = use_tls;
      ret->tls_cert = cert;
      cert = NULL;

      if (database)
        {
          ret->tls_database = database;
          ret->tls_client_flags = G_TLS_CERTIFICATE_VALIDATE_ALL &
              ~(G_TLS_CERTIFICATE_INSECURE | G_TLS_CERTIFICATE_BAD_IDENTITY);
          database = NULL;
        }
      else
        {
          /* No validation for local servers by default */
          ret->tls_client_flags = G_TLS_CERTIFICATE_GENERIC_ERROR;
        }
    }

  if (pem)
    g_string_free (pem, TRUE);
  if (cert)
    g_object_unref (cert);
  if (database)
    g_object_unref (database);

  return ret;
}
Exemple #5
0
static gboolean
parse_stream_options (CockpitChannel *self,
                      CockpitConnectable *connectable)
{
  gboolean ret = FALSE;
  GTlsCertificate *cert = NULL;
  GTlsDatabase *database = NULL;
  gboolean use_tls = FALSE;
  GError *error = NULL;
  GString *pem = NULL;
  JsonObject *options;
  JsonNode *node;

  /* No validation for local servers by default */
  gboolean validate = !connectable->local;

  node = json_object_get_member (self->priv->open_options, "tls");
  if (node && !JSON_NODE_HOLDS_OBJECT (node))
    {
      cockpit_channel_fail (self, "protocol-error", "invalid \"tls\" option for channel");
      goto out;
    }
  else if (node)
    {
      options = json_node_get_object (node);
      use_tls = TRUE;

      /*
       * The only function in GLib to parse private keys takes
       * them in PEM concatenated form. This is a limitation of GLib,
       * rather than concatenated form being a decent standard for
       * certificates and keys. So build a combined PEM as expected by
       * GLib here.
       */

      pem = g_string_sized_new (8192);

      if (!parse_cert_option_as_pem (self, options, "certificate", pem))
        goto out;

      if (pem->len)
        {
          if (!parse_cert_option_as_pem (self, options, "key", pem))
            goto out;

          cert = g_tls_certificate_new_from_pem (pem->str, pem->len, &error);
          if (error != NULL)
            {
              cockpit_channel_fail (self, "internal-error",
                                    "invalid \"certificate\" or \"key\" content: %s", error->message);
              g_error_free (error);
              goto out;
            }
        }

      if (!parse_cert_option_as_database (self, options, "authority", &database))
        goto out;

      if (!cockpit_json_get_bool (options, "validate", validate, &validate))
        {
          cockpit_channel_fail (self, "protocol-error", "invalid \"validate\" option");
          goto out;
        }
    }

  ret = TRUE;

out:
  if (ret)
    {
      connectable->tls = use_tls;
      connectable->tls_cert = cert;
      cert = NULL;

      if (database)
        {
          connectable->tls_database = database;
          connectable->tls_flags = G_TLS_CERTIFICATE_VALIDATE_ALL;
          if (!validate)
              connectable->tls_flags &= ~(G_TLS_CERTIFICATE_INSECURE | G_TLS_CERTIFICATE_BAD_IDENTITY);
          database = NULL;
        }
      else
        {
          if (validate)
            connectable->tls_flags = G_TLS_CERTIFICATE_VALIDATE_ALL;
          else
            connectable->tls_flags = G_TLS_CERTIFICATE_GENERIC_ERROR;
        }
    }

  if (pem)
    g_string_free (pem, TRUE);
  if (cert)
    g_object_unref (cert);
  if (database)
    g_object_unref (database);

  return ret;
}