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; }
/** * 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; }
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; }
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; }