diff --git a/examples/test-video.c b/examples/test-video.c index 05db5f32d8..4a8e2058b0 100644 --- a/examples/test-video.c +++ b/examples/test-video.c @@ -22,7 +22,7 @@ #include /* define this if you want the resource to only be available when using - * user/admin as the password */ + * user/password as the password */ #undef WITH_AUTH /* define this if you want the server to use TLS */ @@ -52,7 +52,10 @@ main (int argc, char *argv[]) GstRTSPMediaFactory *factory; #ifdef WITH_AUTH GstRTSPAuth *auth; + GstRTSPToken *token; + GstStructure *s; gchar *basic; + GstRTSPPermissions *permissions; #endif #ifdef WITH_TLS GTlsCertificate *cert; @@ -64,6 +67,11 @@ main (int argc, char *argv[]) /* create a server instance */ server = gst_rtsp_server_new (); + +#ifdef WITH_AUTH + /* make a new authentication manager. it can be added to control access to all + * the factories on the server or on individual factories. */ + auth = gst_rtsp_auth_new (); #ifdef WITH_TLS cert = g_tls_certificate_new_from_pem ("-----BEGIN CERTIFICATE-----" "MIICJjCCAY+gAwIBAgIBBzANBgkqhkiG9w0BAQUFADCBhjETMBEGCgmSJomT8ixk" @@ -88,25 +96,27 @@ main (int argc, char *argv[]) "DwIga8PqH5Sf5sHedy2+CiK0V4MRfoU4c3zQ6kArI+bEgSkCIQCLA1vXBiE31B5s" "bdHoYa1BXebfZVd+1Hd95IfEM5mbRwIgSkDuQwV55BBlvWph3U8wVIMIb4GStaH8" "W535W8UBbEg=" "-----END PRIVATE KEY-----", -1, NULL); - gst_rtsp_server_set_tls_certificate (server, cert); + gst_rtsp_auth_set_tls_certificate (auth, cert); g_object_unref (cert); #endif + /* make user token */ + token = gst_rtsp_token_new (); + s = gst_rtsp_token_writable_structure (token); + gst_structure_set (s, "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); + + /* configure in the server */ + gst_rtsp_server_set_auth (server, auth); +#endif + /* 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); -#ifdef WITH_AUTH - /* make a new authentication manager. it can be added to control access to all - * the factories on the server or on individual factories. */ - auth = gst_rtsp_auth_new (); - basic = gst_rtsp_auth_make_basic ("user", "admin"); - gst_rtsp_auth_set_basic (auth, basic); - g_free (basic); - /* configure in the server */ - gst_rtsp_server_set_auth (server, auth); -#endif - /* 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 pay%d. Each @@ -117,6 +127,16 @@ main (int argc, char *argv[]) "x264enc ! rtph264pay name=pay0 pt=96 " "audiotestsrc ! audio/x-raw,rate=8000 ! " "alawenc ! rtppcmapay name=pay1 pt=97 " ")"); +#ifdef WITH_AUTH + /* add permissions for the user media role */ + permissions = gst_rtsp_permissions_new (); + gst_rtsp_permissions_add_role (permissions, "user", + gst_structure_new ("user", + "media.factory.access", G_TYPE_BOOLEAN, TRUE, + "media.factory.construct", G_TYPE_BOOLEAN, TRUE, NULL)); + gst_rtsp_media_factory_set_permissions (factory, permissions); + gst_rtsp_permissions_unref (permissions); +#endif /* attach the test factory to the /test url */ gst_rtsp_mount_points_add_factory (mounts, "/test", factory); diff --git a/gst/rtsp-server/rtsp-auth.c b/gst/rtsp-server/rtsp-auth.c index dc0b2e04a7..f5afb973b0 100644 --- a/gst/rtsp-server/rtsp-auth.c +++ b/gst/rtsp-server/rtsp-auth.c @@ -34,6 +34,9 @@ struct _GstRTSPAuthPrivate { GMutex lock; + + /* the TLS certificate */ + GTlsCertificate *certificate; GHashTable *basic; /* protected by lock */ GstRTSPMethod methods; }; @@ -109,6 +112,9 @@ gst_rtsp_auth_finalize (GObject * obj) GstRTSPAuthPrivate *priv = auth->priv; GST_INFO ("finalize auth %p", auth); + + if (priv->certificate) + g_object_unref (priv->certificate); g_hash_table_unref (priv->basic); g_mutex_clear (&priv->lock); @@ -152,6 +158,64 @@ gst_rtsp_auth_new (void) return result; } +/** + * gst_rtsp_auth_set_tls_certificate: + * @auth: a #GstRTSPAuth + * @cert: (allow none): a #GTlsCertificate + * + * Set the TLS certificate for the auth. Client connections will only + * be accepted when TLS is negotiated. + */ +void +gst_rtsp_auth_set_tls_certificate (GstRTSPAuth * auth, GTlsCertificate * cert) +{ + GstRTSPAuthPrivate *priv; + GTlsCertificate *old; + + g_return_if_fail (GST_IS_RTSP_AUTH (auth)); + + priv = auth->priv; + + if (cert) + g_object_ref (cert); + + g_mutex_lock (&priv->lock); + old = priv->certificate; + priv->certificate = cert; + g_mutex_unlock (&priv->lock); + + if (old) + g_object_unref (old); +} + +/** + * gst_rtsp_auth_get_tls_certificate: + * @auth: a #GstRTSPAuth + * + * Get the #GTlsCertificate used for negotiating TLS @auth. + * + * Returns: (transfer full): the #GTlsCertificate of @auth. g_object_unref() after + * usage. + */ +GTlsCertificate * +gst_rtsp_auth_get_tls_certificate (GstRTSPAuth * auth) +{ + GstRTSPAuthPrivate *priv; + GTlsCertificate *result; + + g_return_val_if_fail (GST_IS_RTSP_AUTH (auth), NULL); + + priv = auth->priv; + + g_mutex_lock (&priv->lock); + if ((result = priv->certificate)) + g_object_ref (result); + g_mutex_unlock (&priv->lock); + + return result; +} + + /** * gst_rtsp_auth_add_basic: * @auth: a #GstRTSPAuth @@ -321,12 +385,24 @@ default_check (GstRTSPAuth * auth, GstRTSPClientState * state, GstRTSPAuthPrivate *priv = auth->priv; gboolean res = FALSE; - if (g_str_equal (check, GST_RTSP_AUTH_CHECK_URL)) { + if (g_str_equal (check, GST_RTSP_AUTH_CHECK_CONNECT)) { + /* new connection */ + if (priv->certificate) { + GTlsConnection *tls; + + /* configure the connection */ + tls = gst_rtsp_connection_get_tls (state->conn, NULL); + g_tls_connection_set_certificate (tls, priv->certificate); + } + res = TRUE; + } else if (g_str_equal (check, GST_RTSP_AUTH_CHECK_URL)) { + /* check url and methods */ if ((state->method & priv->methods) != 0) res = ensure_authenticated (auth, state); else res = TRUE; } else if (g_str_has_prefix (check, "auth.check.media.factory.")) { + /* check access to media factory */ const gchar *role; GstRTSPPermissions *perms; diff --git a/gst/rtsp-server/rtsp-auth.h b/gst/rtsp-server/rtsp-auth.h index cb8579fae1..29044de0f1 100644 --- a/gst/rtsp-server/rtsp-auth.h +++ b/gst/rtsp-server/rtsp-auth.h @@ -80,6 +80,9 @@ GType gst_rtsp_auth_get_type (void); GstRTSPAuth * gst_rtsp_auth_new (void); +void gst_rtsp_auth_set_tls_certificate (GstRTSPAuth *auth, GTlsCertificate *cert); +GTlsCertificate * gst_rtsp_auth_get_tls_certificate (GstRTSPAuth *auth); + void gst_rtsp_auth_add_basic (GstRTSPAuth *auth, const gchar * basic, GstRTSPToken *token); void gst_rtsp_auth_remove_basic (GstRTSPAuth *auth, const gchar * basic); @@ -93,6 +96,12 @@ gboolean gst_rtsp_auth_check (const gchar *check); gchar * gst_rtsp_auth_make_basic (const gchar * user, const gchar * pass); /* checks */ +/** + * GST_RTSP_AUTH_CHECK_CONNECT: + * + * Check a new connection + */ +#define GST_RTSP_AUTH_CHECK_CONNECT "auth.check.connect" /** * GST_RTSP_AUTH_CHECK_URL: * diff --git a/gst/rtsp-server/rtsp-server.c b/gst/rtsp-server/rtsp-server.c index 631826aef9..49d6d514c2 100644 --- a/gst/rtsp-server/rtsp-server.c +++ b/gst/rtsp-server/rtsp-server.c @@ -31,7 +31,7 @@ * network (0.0.0.0) and port 8554. * * The server will require an SSL connection when a TLS certificate has been - * set with gst_rtsp_server_set_tls_certificate(). + * set in the auth object with gst_rtsp_auth_set_tls_certificate(). * * To start the server, use gst_rtsp_server_attach() to attach it to a * #GMainContext. For more control, gst_rtsp_server_create_source() and @@ -89,9 +89,6 @@ struct _GstRTSPServerPrivate /* resource manager */ GstRTSPThreadPool *thread_pool; - /* the TLS certificate */ - GTlsCertificate *certificate; - /* the clients that are connected */ GList *clients; }; @@ -144,8 +141,6 @@ static void gst_rtsp_server_set_property (GObject * object, guint propid, static void gst_rtsp_server_finalize (GObject * object); static GstRTSPClient *default_create_client (GstRTSPServer * server); -static gboolean default_setup_connection (GstRTSPServer * server, - GstRTSPClient * client, GstRTSPConnection * conn); static void gst_rtsp_server_class_init (GstRTSPServerClass * klass) @@ -248,7 +243,6 @@ gst_rtsp_server_class_init (GstRTSPServerClass * klass) gst_rtsp_client_get_type ()); klass->create_client = default_create_client; - klass->setup_connection = default_setup_connection; GST_DEBUG_CATEGORY_INIT (rtsp_server_debug, "rtspserver", 0, "GstRTSPServer"); } @@ -295,9 +289,6 @@ gst_rtsp_server_finalize (GObject * object) if (priv->auth) g_object_unref (priv->auth); - if (priv->certificate) - g_object_unref (priv->certificate); - g_mutex_clear (&priv->lock); G_OBJECT_CLASS (gst_rtsp_server_parent_class)->finalize (object); @@ -784,64 +775,6 @@ gst_rtsp_server_get_use_client_settings (GstRTSPServer * server) return res; } -/** - * gst_rtsp_server_set_tls_certificate: - * @server: a #GstRTSPServer - * @cert: (allow none): a #GTlsCertificate - * - * Set the TLS certificate for the server. Client connections will only - * be accepted when TLS is negotiated. - */ -void -gst_rtsp_server_set_tls_certificate (GstRTSPServer * server, - GTlsCertificate * cert) -{ - GstRTSPServerPrivate *priv; - GTlsCertificate *old; - - g_return_if_fail (GST_IS_RTSP_SERVER (server)); - - priv = server->priv; - - if (cert) - g_object_ref (cert); - - GST_RTSP_SERVER_LOCK (server); - old = priv->certificate; - priv->certificate = cert; - GST_RTSP_SERVER_UNLOCK (server); - - if (old) - g_object_unref (old); -} - -/** - * gst_rtsp_server_get_tls_certificate: - * @server: a #GstRTSPServer - * - * Get the #GTlsCertificate used for negotiating TLS @server. - * - * Returns: (transfer full): the #GTlsCertificate of @server. g_object_unref() after - * usage. - */ -GTlsCertificate * -gst_rtsp_server_get_tls_certificate (GstRTSPServer * server) -{ - GstRTSPServerPrivate *priv; - GTlsCertificate *result; - - g_return_val_if_fail (GST_IS_RTSP_SERVER (server), NULL); - - priv = server->priv; - - GST_RTSP_SERVER_LOCK (server); - if ((result = priv->certificate)) - g_object_ref (result); - GST_RTSP_SERVER_UNLOCK (server); - - return result; -} - static void gst_rtsp_server_get_property (GObject * object, guint propid, GValue * value, GParamSpec * pspec) @@ -1188,25 +1121,6 @@ default_create_client (GstRTSPServer * server) return client; } -static gboolean -default_setup_connection (GstRTSPServer * server, GstRTSPClient * client, - GstRTSPConnection * conn) -{ - GstRTSPServerPrivate *priv = server->priv; - - GST_RTSP_SERVER_LOCK (server); - if (priv->certificate) { - GTlsConnection *tls; - - /* configure the connection */ - tls = gst_rtsp_connection_get_tls (conn, NULL); - g_tls_connection_set_certificate (tls, priv->certificate); - } - GST_RTSP_SERVER_UNLOCK (server); - - return TRUE; -} - /** * gst_rtsp_server_transfer_connection: * @server: a #GstRTSPServer @@ -1282,29 +1196,33 @@ gboolean gst_rtsp_server_io_func (GSocket * socket, GIOCondition condition, GstRTSPServer * server) { + GstRTSPServerPrivate *priv = server->priv; GstRTSPClient *client = NULL; GstRTSPServerClass *klass; GstRTSPResult res; GstRTSPConnection *conn = NULL; + GstRTSPClientState state = { NULL }; if (condition & G_IO_IN) { + /* a new client connected. */ + GST_RTSP_CHECK (gst_rtsp_connection_accept (socket, &conn, NULL), + accept_failed); + + state.server = server; + state.conn = conn; + state.auth = priv->auth; + gst_rtsp_client_state_push_current (&state); + + if (!gst_rtsp_auth_check (GST_RTSP_AUTH_CHECK_CONNECT)) + goto connection_refused; klass = GST_RTSP_SERVER_GET_CLASS (server); - /* a new client connected, create a client object to handle the client. */ if (klass->create_client) client = klass->create_client (server); if (client == NULL) goto client_failed; - /* a new client connected. */ - GST_RTSP_CHECK (gst_rtsp_connection_accept (socket, &conn, NULL), - accept_failed); - - if (klass->setup_connection) - if (!klass->setup_connection (server, client, conn)) - goto setup_failed; - /* set connection on the client now */ gst_rtsp_client_set_connection (client, conn); @@ -1316,29 +1234,31 @@ gst_rtsp_server_io_func (GSocket * socket, GIOCondition condition, } else { GST_WARNING_OBJECT (server, "received unknown event %08x", condition); } +exit: + gst_rtsp_client_state_pop_current (&state); + return G_SOURCE_CONTINUE; /* ERRORS */ -client_failed: - { - GST_ERROR_OBJECT (server, "failed to create a client"); - return G_SOURCE_CONTINUE; - } accept_failed: { gchar *str = gst_rtsp_strresult (res); GST_ERROR_OBJECT (server, "Could not accept client on socket %p: %s", socket, str); g_free (str); - g_object_unref (client); - return G_SOURCE_CONTINUE; + goto exit; } -setup_failed: +connection_refused: { - GST_ERROR_OBJECT (server, "failed to setup client connection"); + GST_ERROR_OBJECT (server, "connection refused"); gst_rtsp_connection_free (conn); - g_object_unref (client); - return G_SOURCE_CONTINUE; + goto exit; + } +client_failed: + { + GST_ERROR_OBJECT (server, "failed to create a client"); + gst_rtsp_connection_free (conn); + goto exit; } } diff --git a/gst/rtsp-server/rtsp-server.h b/gst/rtsp-server/rtsp-server.h index 7140bff2c4..b59482e631 100644 --- a/gst/rtsp-server/rtsp-server.h +++ b/gst/rtsp-server/rtsp-server.h @@ -70,8 +70,7 @@ struct _GstRTSPServerClass { GObjectClass parent_class; GstRTSPClient * (*create_client) (GstRTSPServer *server); - gboolean (*setup_connection) (GstRTSPServer *server, GstRTSPClient *client, - GstRTSPConnection *conn); + /* signals */ void (*client_connected) (GstRTSPServer *server, GstRTSPClient *client); };