media: disconnect from signal handlers in unprepare()
[platform/upstream/gstreamer.git] / gst / rtsp-server / rtsp-auth.c
1 /* GStreamer
2  * Copyright (C) 2010 Wim Taymans <wim.taymans at gmail.com>
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Library General Public
6  * License as published by the Free Software Foundation; either
7  * version 2 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Library General Public License for more details.
13  *
14  * You should have received a copy of the GNU Library General Public
15  * License along with this library; if not, write to the
16  * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
17  * Boston, MA 02110-1301, USA.
18  */
19
20 #include <string.h>
21
22 #include "rtsp-auth.h"
23
24 #define GST_RTSP_AUTH_GET_PRIVATE(obj)  \
25    (G_TYPE_INSTANCE_GET_PRIVATE ((obj), GST_TYPE_RTSP_AUTH, GstRTSPAuthPrivate))
26
27 struct _GstRTSPAuthPrivate
28 {
29   GMutex lock;
30   gchar *basic;                 /* protected by lock */
31   GstRTSPMethod methods;
32 };
33
34 enum
35 {
36   PROP_0,
37   PROP_LAST
38 };
39
40 GST_DEBUG_CATEGORY_STATIC (rtsp_auth_debug);
41 #define GST_CAT_DEFAULT rtsp_auth_debug
42
43 static void gst_rtsp_auth_get_property (GObject * object, guint propid,
44     GValue * value, GParamSpec * pspec);
45 static void gst_rtsp_auth_set_property (GObject * object, guint propid,
46     const GValue * value, GParamSpec * pspec);
47 static void gst_rtsp_auth_finalize (GObject * obj);
48
49 static gboolean default_setup_auth (GstRTSPAuth * auth, GstRTSPClient * client,
50     GQuark hint, GstRTSPClientState * state);
51 static gboolean default_check_method (GstRTSPAuth * auth,
52     GstRTSPClient * client, GQuark hint, GstRTSPClientState * state);
53
54 G_DEFINE_TYPE (GstRTSPAuth, gst_rtsp_auth, G_TYPE_OBJECT);
55
56 static void
57 gst_rtsp_auth_class_init (GstRTSPAuthClass * klass)
58 {
59   GObjectClass *gobject_class;
60
61   g_type_class_add_private (klass, sizeof (GstRTSPAuthPrivate));
62
63   gobject_class = G_OBJECT_CLASS (klass);
64
65   gobject_class->get_property = gst_rtsp_auth_get_property;
66   gobject_class->set_property = gst_rtsp_auth_set_property;
67   gobject_class->finalize = gst_rtsp_auth_finalize;
68
69   klass->setup_auth = default_setup_auth;
70   klass->check_method = default_check_method;
71
72   GST_DEBUG_CATEGORY_INIT (rtsp_auth_debug, "rtspauth", 0, "GstRTSPAuth");
73 }
74
75 static void
76 gst_rtsp_auth_init (GstRTSPAuth * auth)
77 {
78   auth->priv = GST_RTSP_AUTH_GET_PRIVATE (auth);
79
80   g_mutex_init (&auth->priv->lock);
81   /* bitwise or of all methods that need authentication */
82   auth->priv->methods = GST_RTSP_DESCRIBE |
83       GST_RTSP_ANNOUNCE |
84       GST_RTSP_GET_PARAMETER |
85       GST_RTSP_SET_PARAMETER |
86       GST_RTSP_PAUSE |
87       GST_RTSP_PLAY | GST_RTSP_RECORD | GST_RTSP_SETUP | GST_RTSP_TEARDOWN;
88 }
89
90 static void
91 gst_rtsp_auth_finalize (GObject * obj)
92 {
93   GstRTSPAuth *auth = GST_RTSP_AUTH (obj);
94   GstRTSPAuthPrivate *priv = auth->priv;
95
96   GST_INFO ("finalize auth %p", auth);
97   g_free (priv->basic);
98   g_mutex_clear (&priv->lock);
99
100   G_OBJECT_CLASS (gst_rtsp_auth_parent_class)->finalize (obj);
101 }
102
103 static void
104 gst_rtsp_auth_get_property (GObject * object, guint propid,
105     GValue * value, GParamSpec * pspec)
106 {
107   switch (propid) {
108     default:
109       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, propid, pspec);
110   }
111 }
112
113 static void
114 gst_rtsp_auth_set_property (GObject * object, guint propid,
115     const GValue * value, GParamSpec * pspec)
116 {
117   switch (propid) {
118     default:
119       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, propid, pspec);
120   }
121 }
122
123 /**
124  * gst_rtsp_auth_new:
125  *
126  * Create a new #GstRTSPAuth instance.
127  *
128  * Returns: a new #GstRTSPAuth
129  */
130 GstRTSPAuth *
131 gst_rtsp_auth_new (void)
132 {
133   GstRTSPAuth *result;
134
135   result = g_object_new (GST_TYPE_RTSP_AUTH, NULL);
136
137   return result;
138 }
139
140 /**
141  * gst_rtsp_auth_set_basic:
142  * @auth: a #GstRTSPAuth
143  * @basic: the basic token
144  *
145  * Set the basic token for the default authentication algorithm.
146  */
147 void
148 gst_rtsp_auth_set_basic (GstRTSPAuth * auth, const gchar * basic)
149 {
150   GstRTSPAuthPrivate *priv;
151
152   g_return_if_fail (GST_IS_RTSP_AUTH (auth));
153
154   priv = auth->priv;
155
156   g_mutex_lock (&priv->lock);
157   g_free (priv->basic);
158   priv->basic = g_strdup (basic);
159   g_mutex_unlock (&priv->lock);
160 }
161
162 static gboolean
163 default_setup_auth (GstRTSPAuth * auth, GstRTSPClient * client,
164     GQuark hint, GstRTSPClientState * state)
165 {
166   if (state->response == NULL)
167     return FALSE;
168
169   /* we only have Basic for now */
170   gst_rtsp_message_add_header (state->response, GST_RTSP_HDR_WWW_AUTHENTICATE,
171       "Basic realm=\"GStreamer RTSP Server\"");
172
173   return TRUE;
174 }
175
176 /**
177  * gst_rtsp_auth_setup_auth:
178  * @auth: a #GstRTSPAuth
179  * @client: the client
180  * @hint: TODO
181  * @state: TODO
182  *
183  * Add authentication tokens to @response.
184  *
185  * Returns: FALSE if something is wrong.
186  */
187 gboolean
188 gst_rtsp_auth_setup_auth (GstRTSPAuth * auth, GstRTSPClient * client,
189     GQuark hint, GstRTSPClientState * state)
190 {
191   gboolean result = FALSE;
192   GstRTSPAuthClass *klass;
193
194   g_return_val_if_fail (GST_IS_RTSP_AUTH (auth), FALSE);
195   g_return_val_if_fail (GST_IS_RTSP_CLIENT (client), FALSE);
196   g_return_val_if_fail (state != NULL, FALSE);
197
198   klass = GST_RTSP_AUTH_GET_CLASS (auth);
199
200   GST_DEBUG_OBJECT (auth, "setup auth");
201
202   if (klass->setup_auth)
203     result = klass->setup_auth (auth, client, hint, state);
204
205   return result;
206 }
207
208 static gboolean
209 default_check_method (GstRTSPAuth * auth, GstRTSPClient * client,
210     GQuark hint, GstRTSPClientState * state)
211 {
212   GstRTSPAuthPrivate *priv = auth->priv;
213   gboolean result = TRUE;
214   GstRTSPResult res;
215
216   if ((state->method & priv->methods) != 0) {
217     gchar *authorization;
218
219     result = FALSE;
220
221     res =
222         gst_rtsp_message_get_header (state->request, GST_RTSP_HDR_AUTHORIZATION,
223         &authorization, 0);
224     if (res < 0)
225       goto no_auth;
226
227     /* parse type */
228     if (g_ascii_strncasecmp (authorization, "basic ", 6) == 0) {
229       GST_DEBUG_OBJECT (auth, "check Basic auth");
230       g_mutex_lock (&priv->lock);
231       if (priv->basic && strcmp (&authorization[6], priv->basic) == 0)
232         result = TRUE;
233       g_mutex_unlock (&priv->lock);
234     } else if (g_ascii_strncasecmp (authorization, "digest ", 7) == 0) {
235       GST_DEBUG_OBJECT (auth, "check Digest auth");
236       /* not implemented yet */
237       result = FALSE;
238     }
239   }
240   return result;
241
242 no_auth:
243   {
244     GST_DEBUG_OBJECT (auth, "no authorization header found");
245     return FALSE;
246   }
247 }
248
249 /**
250  * gst_rtsp_auth_check:
251  * @auth: a #GstRTSPAuth
252  * @client: the client
253  * @hint: a hint
254  * @state: client state
255  *
256  * Check if @client is allowed to perform the actions of @state.
257  *
258  * Returns: FALSE if the action is not allowed.
259  */
260 gboolean
261 gst_rtsp_auth_check (GstRTSPAuth * auth, GstRTSPClient * client,
262     GQuark hint, GstRTSPClientState * state)
263 {
264   gboolean result = FALSE;
265   GstRTSPAuthClass *klass;
266
267   g_return_val_if_fail (GST_IS_RTSP_AUTH (auth), FALSE);
268   g_return_val_if_fail (GST_IS_RTSP_CLIENT (client), FALSE);
269   g_return_val_if_fail (state != NULL, FALSE);
270
271   klass = GST_RTSP_AUTH_GET_CLASS (auth);
272
273   GST_DEBUG_OBJECT (auth, "check state");
274
275   if (klass->check_method)
276     result = klass->check_method (auth, client, hint, state);
277
278   return result;
279 }
280
281 /**
282  * gst_rtsp_auth_make_basic:
283  * @user: a userid
284  * @pass: a password
285  *
286  * Construct a Basic authorisation token from @user and @pass.
287  *
288  * Returns: the base64 encoding of the string @user:@pass. g_free()
289  *    after usage.
290  */
291 gchar *
292 gst_rtsp_auth_make_basic (const gchar * user, const gchar * pass)
293 {
294   gchar *user_pass;
295   gchar *result;
296
297   g_return_val_if_fail (user != NULL, NULL);
298   g_return_val_if_fail (pass != NULL, NULL);
299
300   user_pass = g_strjoin (":", user, pass, NULL);
301   result = g_base64_encode ((guchar *) user_pass, strlen (user_pass));
302   g_free (user_pass);
303
304   return result;
305 }