diff --git a/examples/.gitignore b/examples/.gitignore index b5dd6b203c..6912d88c0b 100644 --- a/examples/.gitignore +++ b/examples/.gitignore @@ -5,3 +5,4 @@ test-readme test-sdp test-video test-uri +test-auth diff --git a/examples/Makefile.am b/examples/Makefile.am index 1886511a77..92f6cf4ce8 100644 --- a/examples/Makefile.am +++ b/examples/Makefile.am @@ -1,4 +1,4 @@ -noinst_PROGRAMS = test-video test-ogg test-mp4 test-readme test-launch test-sdp test-uri +noinst_PROGRAMS = test-video test-ogg test-mp4 test-readme test-launch test-sdp test-uri test-auth INCLUDES = -I$(top_srcdir) -I$(srcdir) diff --git a/examples/test-auth.c b/examples/test-auth.c new file mode 100644 index 0000000000..915173aa21 --- /dev/null +++ b/examples/test-auth.c @@ -0,0 +1,115 @@ +/* GStreamer + * Copyright (C) 2008 Wim Taymans + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include + +#include + + +static gboolean +timeout (GstRTSPServer * server, gboolean ignored) +{ + GstRTSPSessionPool *pool; + + pool = gst_rtsp_server_get_session_pool (server); + gst_rtsp_session_pool_cleanup (pool); + g_object_unref (pool); + + return TRUE; +} + +int +main (int argc, char *argv[]) +{ + GMainLoop *loop; + GstRTSPServer *server; + GstRTSPMediaMapping *mapping; + GstRTSPMediaFactory *factory; + GstRTSPAuth *auth; + gchar *basic; + + gst_init (&argc, &argv); + + loop = g_main_loop_new (NULL, FALSE); + + /* create a server instance */ + server = gst_rtsp_server_new (); + + /* get the mapping for this server, every server has a default mapper object + * that be used to map uri mount points to media factories */ + mapping = gst_rtsp_server_get_media_mapping (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 pay%d. Each + * element with pay%d names will be a stream */ + factory = gst_rtsp_media_factory_new (); + gst_rtsp_media_factory_set_launch (factory, "( " + "videotestsrc ! video/x-raw-yuv,width=352,height=288,framerate=15/1 ! " + "x264enc ! rtph264pay name=pay0 pt=96 " + "audiotestsrc ! audio/x-raw-int,rate=8000 ! " + "alawenc ! rtppcmapay name=pay1 pt=97 " ")"); + + /* make a new authentication manager */ + auth = gst_rtsp_auth_new (); + basic = gst_rtsp_auth_make_basic ("user", "admin"); + gst_rtsp_auth_set_basic (auth, basic); + g_free (basic); + gst_rtsp_media_factory_set_auth (factory, auth); + g_object_unref (auth); + /* attach the test factory to the /test url */ + gst_rtsp_media_mapping_add_factory (mapping, "/test", factory); + + /* make another factory */ + factory = gst_rtsp_media_factory_new (); + gst_rtsp_media_factory_set_launch (factory, "( " + "videotestsrc ! video/x-raw-yuv,width=352,height=288,framerate=30/1 ! " + "x264enc ! rtph264pay name=pay0 pt=96 )"); + /* make a new authentication manager */ + auth = gst_rtsp_auth_new (); + basic = gst_rtsp_auth_make_basic ("user2", "admin2"); + gst_rtsp_auth_set_basic (auth, basic); + g_free (basic); + gst_rtsp_media_factory_set_auth (factory, auth); + g_object_unref (auth); + /* attach the test factory to the /test url */ + gst_rtsp_media_mapping_add_factory (mapping, "/test2", factory); + + /* don't need the ref to the mapper anymore */ + g_object_unref (mapping); + + /* attach the server to the default maincontext */ + if (gst_rtsp_server_attach (server, NULL) == 0) + goto failed; + + g_timeout_add_seconds (2, (GSourceFunc) timeout, server); + + /* start serving */ + g_main_loop_run (loop); + + return 0; + + /* ERRORS */ +failed: + { + g_print ("failed to attach the server\n"); + return -1; + } +} diff --git a/examples/test-video.c b/examples/test-video.c index 988c1621b4..41194a098e 100644 --- a/examples/test-video.c +++ b/examples/test-video.c @@ -41,8 +41,10 @@ main (int argc, char *argv[]) GstRTSPServer *server; GstRTSPMediaMapping *mapping; GstRTSPMediaFactory *factory; +#if 0 GstRTSPAuth *auth; gchar *basic; +#endif gst_init (&argc, &argv); @@ -55,6 +57,7 @@ main (int argc, char *argv[]) * that be used to map uri mount points to media factories */ mapping = gst_rtsp_server_get_media_mapping (server); +#if 0 /* make a new authentication manager */ auth = gst_rtsp_auth_new (); basic = gst_rtsp_auth_make_basic ("user", "admin"); @@ -62,6 +65,7 @@ main (int argc, char *argv[]) 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. diff --git a/gst/rtsp-server/rtsp-auth.c b/gst/rtsp-server/rtsp-auth.c index 676537b26e..84d5c546a9 100644 --- a/gst/rtsp-server/rtsp-auth.c +++ b/gst/rtsp-server/rtsp-auth.c @@ -37,9 +37,9 @@ static void gst_rtsp_auth_set_property (GObject * object, guint propid, static void gst_rtsp_auth_finalize (GObject * obj); static gboolean default_setup_auth (GstRTSPAuth * auth, GstRTSPClient * client, - GstRTSPClientState * state); + GQuark hint, GstRTSPClientState * state); static gboolean default_check_method (GstRTSPAuth * auth, - GstRTSPClient * client, GstRTSPClientState * state); + GstRTSPClient * client, GQuark hint, GstRTSPClientState * state); G_DEFINE_TYPE (GstRTSPAuth, gst_rtsp_auth, G_TYPE_OBJECT); @@ -140,7 +140,7 @@ gst_rtsp_auth_set_basic (GstRTSPAuth * auth, const gchar * basic) static gboolean default_setup_auth (GstRTSPAuth * auth, GstRTSPClient * client, - GstRTSPClientState * state) + GQuark hint, GstRTSPClientState * state) { if (state->response == NULL) return FALSE; @@ -167,7 +167,7 @@ default_setup_auth (GstRTSPAuth * auth, GstRTSPClient * client, */ gboolean gst_rtsp_auth_setup_auth (GstRTSPAuth * auth, GstRTSPClient * client, - GstRTSPClientState * state) + GQuark hint, GstRTSPClientState * state) { gboolean result = FALSE; GstRTSPAuthClass *klass; @@ -177,14 +177,14 @@ gst_rtsp_auth_setup_auth (GstRTSPAuth * auth, GstRTSPClient * client, GST_DEBUG_OBJECT (auth, "setup auth"); if (klass->setup_auth) - result = klass->setup_auth (auth, client, state); + result = klass->setup_auth (auth, client, hint, state); return result; } static gboolean default_check_method (GstRTSPAuth * auth, GstRTSPClient * client, - GstRTSPClientState * state) + GQuark hint, GstRTSPClientState * state) { gboolean result = TRUE; GstRTSPResult res; @@ -224,6 +224,7 @@ no_auth: * gst_rtsp_auth_check_method: * @auth: a #GstRTSPAuth * @client: the client + * @hint: a hint * @state: client state * * Check if @client is allowed to perform the actions of @state. @@ -232,7 +233,7 @@ no_auth: */ gboolean gst_rtsp_auth_check (GstRTSPAuth * auth, GstRTSPClient * client, - GstRTSPClientState * state) + GQuark hint, GstRTSPClientState * state) { gboolean result = FALSE; GstRTSPAuthClass *klass; @@ -242,7 +243,7 @@ gst_rtsp_auth_check (GstRTSPAuth * auth, GstRTSPClient * client, GST_DEBUG_OBJECT (auth, "check state"); if (klass->check_method) - result = klass->check_method (auth, client, state); + result = klass->check_method (auth, client, hint, state); return result; } diff --git a/gst/rtsp-server/rtsp-auth.h b/gst/rtsp-server/rtsp-auth.h index 4699dea2e5..3aadeffd67 100644 --- a/gst/rtsp-server/rtsp-auth.h +++ b/gst/rtsp-server/rtsp-auth.h @@ -56,8 +56,10 @@ struct _GstRTSPAuth { struct _GstRTSPAuthClass { GObjectClass parent_class; - gboolean (*setup_auth) (GstRTSPAuth *auth, GstRTSPClient * client, GstRTSPClientState *state); - gboolean (*check_method) (GstRTSPAuth *auth, GstRTSPClient * client, GstRTSPClientState *state); + gboolean (*setup_auth) (GstRTSPAuth *auth, GstRTSPClient * client, + GQuark hint, GstRTSPClientState *state); + gboolean (*check_method) (GstRTSPAuth *auth, GstRTSPClient * client, + GQuark hint, GstRTSPClientState *state); }; GType gst_rtsp_auth_get_type (void); @@ -67,9 +69,9 @@ GstRTSPAuth * gst_rtsp_auth_new (void); void gst_rtsp_auth_set_basic (GstRTSPAuth *auth, const gchar * basic); gboolean gst_rtsp_auth_setup_auth (GstRTSPAuth *auth, GstRTSPClient * client, - GstRTSPClientState *state); + GQuark hint, GstRTSPClientState *state); gboolean gst_rtsp_auth_check_method (GstRTSPAuth *auth, GstRTSPClient * client, - GstRTSPClientState *state); + GQuark hint, GstRTSPClientState *state); /* helpers */ gchar * gst_rtsp_auth_make_basic (const gchar * user, const gchar * pass); diff --git a/gst/rtsp-server/rtsp-client.c b/gst/rtsp-server/rtsp-client.c index d73bb493c2..b829ffa315 100644 --- a/gst/rtsp-server/rtsp-client.c +++ b/gst/rtsp-server/rtsp-client.c @@ -255,7 +255,8 @@ send_generic_response (GstRTSPClient * client, GstRTSPStatusCode code, } static void -handle_unauthorized_request (GstRTSPClient * client, GstRTSPClientState * state) +handle_unauthorized_request (GstRTSPClient * client, GstRTSPAuth * auth, + GstRTSPClientState * state) { GstRTSPMessage response = { 0 }; @@ -264,9 +265,9 @@ handle_unauthorized_request (GstRTSPClient * client, GstRTSPClientState * state) state->response = &response; - if (client->auth) { + if (auth) { /* and let the authentication manager setup the auth tokens */ - gst_rtsp_auth_setup_auth (client->auth, client, state); + gst_rtsp_auth_setup_auth (auth, client, 0, state); } send_response (client, state->session, &response); @@ -293,6 +294,7 @@ find_media (GstRTSPClient * client, GstRTSPClientState * state) { GstRTSPMediaFactory *factory; GstRTSPMedia *media; + GstRTSPAuth *auth; if (!compare_uri (client->uri, state->uri)) { /* remove any previously cached values before we try to construct a new @@ -315,10 +317,20 @@ find_media (GstRTSPClient * client, GstRTSPClientState * state) state->factory = factory; + /* check if we have access to the factory */ + if ((auth = gst_rtsp_media_factory_get_auth (factory))) { + if (!gst_rtsp_auth_check (auth, client, 0, state)) + goto not_allowed; + + g_object_unref (auth); + } + /* prepare the media and add it to the pipeline */ if (!(media = gst_rtsp_media_factory_construct (factory, state->uri))) goto no_media; + g_object_unref (factory); + /* set ipv6 on the media before preparing */ media->is_ipv6 = client->is_ipv6; state->media = media; @@ -353,6 +365,13 @@ no_factory: send_generic_response (client, GST_RTSP_STS_NOT_FOUND, state); return NULL; } +not_allowed: + { + handle_unauthorized_request (client, auth, state); + g_object_unref (factory); + g_object_unref (auth); + return NULL; + } no_media: { send_generic_response (client, GST_RTSP_STS_SERVICE_UNAVAILABLE, state); @@ -1389,7 +1408,7 @@ session_not_found: } not_authorized: { - handle_unauthorized_request (client, &state); + handle_unauthorized_request (client, client->auth, &state); return; } } diff --git a/gst/rtsp-server/rtsp-media-factory.c b/gst/rtsp-server/rtsp-media-factory.c index dd0ef7987e..2fe309d320 100644 --- a/gst/rtsp-server/rtsp-media-factory.c +++ b/gst/rtsp-server/rtsp-media-factory.c @@ -354,7 +354,6 @@ gst_rtsp_media_factory_set_auth (GstRTSPMediaFactory * factory, } } - /** * gst_rtsp_media_factory_get_auth: * @factory: a #GstRTSPMediaFactory @@ -365,7 +364,7 @@ gst_rtsp_media_factory_set_auth (GstRTSPMediaFactory * factory, * usage. */ GstRTSPAuth * -gst_rtsp_factory_get_auth (GstRTSPMediaFactory * factory) +gst_rtsp_media_factory_get_auth (GstRTSPMediaFactory * factory) { GstRTSPAuth *result; @@ -377,7 +376,6 @@ gst_rtsp_factory_get_auth (GstRTSPMediaFactory * factory) return result; } - static gboolean compare_media (gpointer key, GstRTSPMedia * media1, GstRTSPMedia * media2) { @@ -660,6 +658,7 @@ static void default_configure (GstRTSPMediaFactory * factory, GstRTSPMedia * media) { gboolean shared, eos_shutdown; + GstRTSPAuth *auth; /* configure the sharedness */ GST_RTSP_MEDIA_FACTORY_LOCK (factory); @@ -669,4 +668,9 @@ default_configure (GstRTSPMediaFactory * factory, GstRTSPMedia * media) gst_rtsp_media_set_shared (media, shared); gst_rtsp_media_set_eos_shutdown (media, eos_shutdown); + + if ((auth = gst_rtsp_media_factory_get_auth (factory))) { + gst_rtsp_media_set_auth (media, auth); + g_object_unref (auth); + } } diff --git a/gst/rtsp-server/rtsp-media.c b/gst/rtsp-server/rtsp-media.c index 61d935207c..cd1e42ab71 100644 --- a/gst/rtsp-server/rtsp-media.c +++ b/gst/rtsp-server/rtsp-media.c @@ -522,6 +522,54 @@ gst_rtsp_media_is_eos_shutdown (GstRTSPMedia * media) return media->eos_shutdown; } +/** + * gst_rtsp_media_set_auth: + * @media: a #GstRTSPMedia + * @auth: a #GstRTSPAuth + * + * configure @auth to be used as the authentication manager of @media. + */ +void +gst_rtsp_media_set_auth (GstRTSPMedia * media, GstRTSPAuth * auth) +{ + GstRTSPAuth *old; + + g_return_if_fail (GST_IS_RTSP_MEDIA (media)); + + old = media->auth; + + if (old != auth) { + if (auth) + g_object_ref (auth); + media->auth = auth; + if (old) + g_object_unref (old); + } +} + +/** + * gst_rtsp_media_get_auth: + * @media: a #GstRTSPMedia + * + * Get the #GstRTSPAuth used as the authentication manager of @media. + * + * Returns: the #GstRTSPAuth of @media. g_object_unref() after + * usage. + */ +GstRTSPAuth * +gst_rtsp_media_get_auth (GstRTSPMedia * media) +{ + GstRTSPAuth *result; + + g_return_val_if_fail (GST_IS_RTSP_MEDIA (media), NULL); + + if ((result = media->auth)) + g_object_ref (result); + + return result; +} + + /** * gst_rtsp_media_n_streams: * @media: a #GstRTSPMedia diff --git a/gst/rtsp-server/rtsp-media.h b/gst/rtsp-server/rtsp-media.h index 33db2f9219..a62390ae37 100644 --- a/gst/rtsp-server/rtsp-media.h +++ b/gst/rtsp-server/rtsp-media.h @@ -85,6 +85,8 @@ struct _GstRTSPMediaTrans { GObject *rtpsource; }; +#include "rtsp-auth.h" + /** * GstRTSPMediaStream: * @srcpad: the srcpad of the stream @@ -204,6 +206,7 @@ struct _GstRTSPMedia { gboolean reused; gboolean is_ipv6; gboolean eos_shutdown; + GstRTSPAuth *auth; GstElement *element; GArray *streams; @@ -277,6 +280,9 @@ GstRTSPLowerTrans gst_rtsp_media_get_protocols (GstRTSPMedia *media); void gst_rtsp_media_set_eos_shutdown (GstRTSPMedia *media, gboolean eos_shutdown); gboolean gst_rtsp_media_is_eos_shutdown (GstRTSPMedia *media); +void gst_rtsp_media_set_auth (GstRTSPMedia *media, GstRTSPAuth *auth); +GstRTSPAuth * gst_rtsp_media_get_auth (GstRTSPMedia *media); + /* prepare the media for playback */ gboolean gst_rtsp_media_prepare (GstRTSPMedia *media); gboolean gst_rtsp_media_is_prepared (GstRTSPMedia *media); diff --git a/gst/rtsp-server/rtsp-session-pool.h b/gst/rtsp-server/rtsp-session-pool.h index 865b16baee..3cd56d4ef8 100644 --- a/gst/rtsp-server/rtsp-session-pool.h +++ b/gst/rtsp-server/rtsp-session-pool.h @@ -22,10 +22,14 @@ #ifndef __GST_RTSP_SESSION_POOL_H__ #define __GST_RTSP_SESSION_POOL_H__ -#include "rtsp-session.h" G_BEGIN_DECLS +typedef struct _GstRTSPSessionPool GstRTSPSessionPool; +typedef struct _GstRTSPSessionPoolClass GstRTSPSessionPoolClass; + +#include "rtsp-session.h" + #define GST_TYPE_RTSP_SESSION_POOL (gst_rtsp_session_pool_get_type ()) #define GST_IS_RTSP_SESSION_POOL(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_RTSP_SESSION_POOL)) #define GST_IS_RTSP_SESSION_POOL_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_RTSP_SESSION_POOL)) @@ -35,9 +39,6 @@ G_BEGIN_DECLS #define GST_RTSP_SESSION_POOL_CAST(obj) ((GstRTSPSessionPool*)(obj)) #define GST_RTSP_SESSION_POOL_CLASS_CAST(klass) ((GstRTSPSessionPoolClass*)(klass)) -typedef struct _GstRTSPSessionPool GstRTSPSessionPool; -typedef struct _GstRTSPSessionPoolClass GstRTSPSessionPoolClass; - /** * GstRTSPSessionPool: * @max_sessions: the maximum number of sessions. diff --git a/gst/rtsp-server/rtsp-session.h b/gst/rtsp-server/rtsp-session.h index 00bc3f3d64..07efb1958d 100644 --- a/gst/rtsp-server/rtsp-session.h +++ b/gst/rtsp-server/rtsp-session.h @@ -21,8 +21,6 @@ #include -#include "rtsp-media.h" - #ifndef __GST_RTSP_SESSION_H__ #define __GST_RTSP_SESSION_H__ @@ -43,6 +41,8 @@ typedef struct _GstRTSPSessionClass GstRTSPSessionClass; typedef struct _GstRTSPSessionStream GstRTSPSessionStream; typedef struct _GstRTSPSessionMedia GstRTSPSessionMedia; +#include "rtsp-media.h" + /** * GstRTSPSessionStream: * @trans: the media transport