/* GStreamer * Copyright (C) 2010 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., 51 Franklin St, Fifth Floor, * Boston, MA 02110-1301, USA. */ #include #include "rtsp-auth.h" #define GST_RTSP_AUTH_GET_PRIVATE(obj) \ (G_TYPE_INSTANCE_GET_PRIVATE ((obj), GST_TYPE_RTSP_AUTH, GstRTSPAuthPrivate)) struct _GstRTSPAuthPrivate { GMutex lock; gchar *basic; GstRTSPMethod methods; }; enum { PROP_0, PROP_LAST }; GST_DEBUG_CATEGORY_STATIC (rtsp_auth_debug); #define GST_CAT_DEFAULT rtsp_auth_debug static void gst_rtsp_auth_get_property (GObject * object, guint propid, GValue * value, GParamSpec * pspec); static void gst_rtsp_auth_set_property (GObject * object, guint propid, const GValue * value, GParamSpec * pspec); static void gst_rtsp_auth_finalize (GObject * obj); static gboolean default_setup_auth (GstRTSPAuth * auth, GstRTSPClient * client, GQuark hint, GstRTSPClientState * state); static gboolean default_check_method (GstRTSPAuth * auth, GstRTSPClient * client, GQuark hint, GstRTSPClientState * state); G_DEFINE_TYPE (GstRTSPAuth, gst_rtsp_auth, G_TYPE_OBJECT); static void gst_rtsp_auth_class_init (GstRTSPAuthClass * klass) { GObjectClass *gobject_class; g_type_class_add_private (klass, sizeof (GstRTSPAuthPrivate)); gobject_class = G_OBJECT_CLASS (klass); gobject_class->get_property = gst_rtsp_auth_get_property; gobject_class->set_property = gst_rtsp_auth_set_property; gobject_class->finalize = gst_rtsp_auth_finalize; klass->setup_auth = default_setup_auth; klass->check_method = default_check_method; GST_DEBUG_CATEGORY_INIT (rtsp_auth_debug, "rtspauth", 0, "GstRTSPAuth"); } static void gst_rtsp_auth_init (GstRTSPAuth * auth) { auth->priv = GST_RTSP_AUTH_GET_PRIVATE (auth); g_mutex_init (&auth->priv->lock); /* bitwise or of all methods that need authentication */ auth->priv->methods = GST_RTSP_DESCRIBE | GST_RTSP_ANNOUNCE | GST_RTSP_GET_PARAMETER | GST_RTSP_SET_PARAMETER | GST_RTSP_PAUSE | GST_RTSP_PLAY | GST_RTSP_RECORD | GST_RTSP_SETUP | GST_RTSP_TEARDOWN; } static void gst_rtsp_auth_finalize (GObject * obj) { GstRTSPAuth *auth = GST_RTSP_AUTH (obj); GstRTSPAuthPrivate *priv = auth->priv; GST_INFO ("finalize auth %p", auth); g_free (priv->basic); g_mutex_clear (&priv->lock); G_OBJECT_CLASS (gst_rtsp_auth_parent_class)->finalize (obj); } static void gst_rtsp_auth_get_property (GObject * object, guint propid, GValue * value, GParamSpec * pspec) { switch (propid) { default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, propid, pspec); } } static void gst_rtsp_auth_set_property (GObject * object, guint propid, const GValue * value, GParamSpec * pspec) { switch (propid) { default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, propid, pspec); } } /** * gst_rtsp_auth_new: * * Create a new #GstRTSPAuth instance. * * Returns: a new #GstRTSPAuth */ GstRTSPAuth * gst_rtsp_auth_new (void) { GstRTSPAuth *result; result = g_object_new (GST_TYPE_RTSP_AUTH, NULL); return result; } /** * gst_rtsp_auth_set_basic: * @auth: a #GstRTSPAuth * @basic: the basic token * * Set the basic token for the default authentication algorithm. */ void gst_rtsp_auth_set_basic (GstRTSPAuth * auth, const gchar * basic) { GstRTSPAuthPrivate *priv; g_return_if_fail (GST_IS_RTSP_AUTH (auth)); priv = auth->priv; g_mutex_lock (&priv->lock); g_free (priv->basic); priv->basic = g_strdup (basic); g_mutex_unlock (&priv->lock); } static gboolean default_setup_auth (GstRTSPAuth * auth, GstRTSPClient * client, GQuark hint, GstRTSPClientState * state) { if (state->response == NULL) return FALSE; /* we only have Basic for now */ gst_rtsp_message_add_header (state->response, GST_RTSP_HDR_WWW_AUTHENTICATE, "Basic realm=\"GStreamer RTSP Server\""); return TRUE; } /** * gst_rtsp_auth_setup_auth: * @auth: a #GstRTSPAuth * @client: the client * @hint: TODO * @state: TODO * * Add authentication tokens to @response. * * Returns: FALSE if something is wrong. */ gboolean gst_rtsp_auth_setup_auth (GstRTSPAuth * auth, GstRTSPClient * client, GQuark hint, GstRTSPClientState * state) { gboolean result = FALSE; GstRTSPAuthClass *klass; g_return_val_if_fail (GST_IS_RTSP_AUTH (auth), FALSE); g_return_val_if_fail (GST_IS_RTSP_CLIENT (client), FALSE); g_return_val_if_fail (state != NULL, FALSE); klass = GST_RTSP_AUTH_GET_CLASS (auth); GST_DEBUG_OBJECT (auth, "setup auth"); if (klass->setup_auth) result = klass->setup_auth (auth, client, hint, state); return result; } static gboolean default_check_method (GstRTSPAuth * auth, GstRTSPClient * client, GQuark hint, GstRTSPClientState * state) { GstRTSPAuthPrivate *priv = auth->priv; gboolean result = TRUE; GstRTSPResult res; if ((state->method & priv->methods) != 0) { gchar *authorization; result = FALSE; res = gst_rtsp_message_get_header (state->request, GST_RTSP_HDR_AUTHORIZATION, &authorization, 0); if (res < 0) goto no_auth; /* parse type */ if (g_ascii_strncasecmp (authorization, "basic ", 6) == 0) { GST_DEBUG_OBJECT (auth, "check Basic auth"); g_mutex_lock (&priv->lock); if (priv->basic && strcmp (&authorization[6], priv->basic) == 0) result = TRUE; g_mutex_unlock (&priv->lock); } else if (g_ascii_strncasecmp (authorization, "digest ", 7) == 0) { GST_DEBUG_OBJECT (auth, "check Digest auth"); /* not implemented yet */ result = FALSE; } } return result; no_auth: { GST_DEBUG_OBJECT (auth, "no authorization header found"); return FALSE; } } /** * gst_rtsp_auth_check: * @auth: a #GstRTSPAuth * @client: the client * @hint: a hint * @state: client state * * Check if @client is allowed to perform the actions of @state. * * Returns: FALSE if the action is not allowed. */ gboolean gst_rtsp_auth_check (GstRTSPAuth * auth, GstRTSPClient * client, GQuark hint, GstRTSPClientState * state) { gboolean result = FALSE; GstRTSPAuthClass *klass; g_return_val_if_fail (GST_IS_RTSP_AUTH (auth), FALSE); g_return_val_if_fail (GST_IS_RTSP_CLIENT (client), FALSE); g_return_val_if_fail (state != NULL, FALSE); klass = GST_RTSP_AUTH_GET_CLASS (auth); GST_DEBUG_OBJECT (auth, "check state"); if (klass->check_method) result = klass->check_method (auth, client, hint, state); return result; } /** * gst_rtsp_auth_make_basic: * @user: a userid * @pass: a password * * Construct a Basic authorisation token from @user and @pass. * * Returns: the base64 encoding of the string @user:@pass. g_free() * after usage. */ gchar * gst_rtsp_auth_make_basic (const gchar * user, const gchar * pass) { gchar *user_pass; gchar *result; g_return_val_if_fail (user != NULL, NULL); g_return_val_if_fail (pass != NULL, NULL); user_pass = g_strjoin (":", user, pass, NULL); result = g_base64_encode ((guchar *) user_pass, strlen (user_pass)); g_free (user_pass); return result; }