factory-uri: add some debug
[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 enum
25 {
26   PROP_0,
27   PROP_LAST
28 };
29
30 GST_DEBUG_CATEGORY_STATIC (rtsp_auth_debug);
31 #define GST_CAT_DEFAULT rtsp_auth_debug
32
33 static void gst_rtsp_auth_get_property (GObject * object, guint propid,
34     GValue * value, GParamSpec * pspec);
35 static void gst_rtsp_auth_set_property (GObject * object, guint propid,
36     const GValue * value, GParamSpec * pspec);
37 static void gst_rtsp_auth_finalize (GObject * obj);
38
39 static gboolean default_setup_auth (GstRTSPAuth * auth, GstRTSPClient * client,
40     GQuark hint, GstRTSPClientState * state);
41 static gboolean default_check_method (GstRTSPAuth * auth,
42     GstRTSPClient * client, GQuark hint, GstRTSPClientState * state);
43
44 G_DEFINE_TYPE (GstRTSPAuth, gst_rtsp_auth, G_TYPE_OBJECT);
45
46 static void
47 gst_rtsp_auth_class_init (GstRTSPAuthClass * klass)
48 {
49   GObjectClass *gobject_class;
50
51   gobject_class = G_OBJECT_CLASS (klass);
52
53   gobject_class->get_property = gst_rtsp_auth_get_property;
54   gobject_class->set_property = gst_rtsp_auth_set_property;
55   gobject_class->finalize = gst_rtsp_auth_finalize;
56
57   klass->setup_auth = default_setup_auth;
58   klass->check_method = default_check_method;
59
60   GST_DEBUG_CATEGORY_INIT (rtsp_auth_debug, "rtspauth", 0, "GstRTSPAuth");
61 }
62
63 static void
64 gst_rtsp_auth_init (GstRTSPAuth * auth)
65 {
66   g_mutex_init (&auth->lock);
67   /* bitwise or of all methods that need authentication */
68   auth->methods = GST_RTSP_DESCRIBE |
69       GST_RTSP_ANNOUNCE |
70       GST_RTSP_GET_PARAMETER |
71       GST_RTSP_SET_PARAMETER |
72       GST_RTSP_PAUSE |
73       GST_RTSP_PLAY | GST_RTSP_RECORD | GST_RTSP_SETUP | GST_RTSP_TEARDOWN;
74 }
75
76 static void
77 gst_rtsp_auth_finalize (GObject * obj)
78 {
79   GstRTSPAuth *auth = GST_RTSP_AUTH (obj);
80
81   GST_INFO ("finalize auth %p", auth);
82   g_free (auth->basic);
83   g_mutex_clear (&auth->lock);
84
85   G_OBJECT_CLASS (gst_rtsp_auth_parent_class)->finalize (obj);
86 }
87
88 static void
89 gst_rtsp_auth_get_property (GObject * object, guint propid,
90     GValue * value, GParamSpec * pspec)
91 {
92   switch (propid) {
93     default:
94       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, propid, pspec);
95   }
96 }
97
98 static void
99 gst_rtsp_auth_set_property (GObject * object, guint propid,
100     const GValue * value, GParamSpec * pspec)
101 {
102   switch (propid) {
103     default:
104       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, propid, pspec);
105   }
106 }
107
108 /**
109  * gst_rtsp_auth_new:
110  *
111  * Create a new #GstRTSPAuth instance.
112  *
113  * Returns: a new #GstRTSPAuth
114  */
115 GstRTSPAuth *
116 gst_rtsp_auth_new (void)
117 {
118   GstRTSPAuth *result;
119
120   result = g_object_new (GST_TYPE_RTSP_AUTH, NULL);
121
122   return result;
123 }
124
125 /**
126  * gst_rtsp_auth_set_basic:
127  * @auth: a #GstRTSPAuth
128  * @basic: the basic token
129  *
130  * Set the basic token for the default authentication algorithm.
131  */
132 void
133 gst_rtsp_auth_set_basic (GstRTSPAuth * auth, const gchar * basic)
134 {
135   g_return_if_fail (GST_IS_RTSP_AUTH (auth));
136
137   g_mutex_lock (&auth->lock);
138   g_free (auth->basic);
139   auth->basic = g_strdup (basic);
140   g_mutex_unlock (&auth->lock);
141 }
142
143 static gboolean
144 default_setup_auth (GstRTSPAuth * auth, GstRTSPClient * client,
145     GQuark hint, GstRTSPClientState * state)
146 {
147   if (state->response == NULL)
148     return FALSE;
149
150   /* we only have Basic for now */
151   gst_rtsp_message_add_header (state->response, GST_RTSP_HDR_WWW_AUTHENTICATE,
152       "Basic realm=\"GStreamer RTSP Server\"");
153
154   return TRUE;
155 }
156
157 /**
158  * gst_rtsp_auth_setup_auth:
159  * @auth: a #GstRTSPAuth
160  * @client: the client
161  * @hint: TODO
162  * @state: TODO
163  *
164  * Add authentication tokens to @response.
165  *
166  * Returns: FALSE if something is wrong.
167  */
168 gboolean
169 gst_rtsp_auth_setup_auth (GstRTSPAuth * auth, GstRTSPClient * client,
170     GQuark hint, GstRTSPClientState * state)
171 {
172   gboolean result = FALSE;
173   GstRTSPAuthClass *klass;
174
175   g_return_val_if_fail (GST_IS_RTSP_AUTH (auth), FALSE);
176   g_return_val_if_fail (GST_IS_RTSP_CLIENT (client), FALSE);
177   g_return_val_if_fail (state != NULL, FALSE);
178
179   klass = GST_RTSP_AUTH_GET_CLASS (auth);
180
181   GST_DEBUG_OBJECT (auth, "setup auth");
182
183   if (klass->setup_auth)
184     result = klass->setup_auth (auth, client, hint, state);
185
186   return result;
187 }
188
189 static gboolean
190 default_check_method (GstRTSPAuth * auth, GstRTSPClient * client,
191     GQuark hint, GstRTSPClientState * state)
192 {
193   gboolean result = TRUE;
194   GstRTSPResult res;
195
196   if ((state->method & auth->methods) != 0) {
197     gchar *authorization;
198
199     result = FALSE;
200
201     res =
202         gst_rtsp_message_get_header (state->request, GST_RTSP_HDR_AUTHORIZATION,
203         &authorization, 0);
204     if (res < 0)
205       goto no_auth;
206
207     /* parse type */
208     if (g_ascii_strncasecmp (authorization, "basic ", 6) == 0) {
209       GST_DEBUG_OBJECT (auth, "check Basic auth");
210       g_mutex_lock (&auth->lock);
211       if (auth->basic && strcmp (&authorization[6], auth->basic) == 0)
212         result = TRUE;
213       g_mutex_unlock (&auth->lock);
214     } else if (g_ascii_strncasecmp (authorization, "digest ", 7) == 0) {
215       GST_DEBUG_OBJECT (auth, "check Digest auth");
216       /* not implemented yet */
217       result = FALSE;
218     }
219   }
220   return result;
221
222 no_auth:
223   {
224     GST_DEBUG_OBJECT (auth, "no authorization header found");
225     return FALSE;
226   }
227 }
228
229 /**
230  * gst_rtsp_auth_check:
231  * @auth: a #GstRTSPAuth
232  * @client: the client
233  * @hint: a hint
234  * @state: client state
235  *
236  * Check if @client is allowed to perform the actions of @state.
237  *
238  * Returns: FALSE if the action is not allowed.
239  */
240 gboolean
241 gst_rtsp_auth_check (GstRTSPAuth * auth, GstRTSPClient * client,
242     GQuark hint, GstRTSPClientState * state)
243 {
244   gboolean result = FALSE;
245   GstRTSPAuthClass *klass;
246
247   g_return_val_if_fail (GST_IS_RTSP_AUTH (auth), FALSE);
248   g_return_val_if_fail (GST_IS_RTSP_CLIENT (client), FALSE);
249   g_return_val_if_fail (state != NULL, FALSE);
250
251   klass = GST_RTSP_AUTH_GET_CLASS (auth);
252
253   GST_DEBUG_OBJECT (auth, "check state");
254
255   if (klass->check_method)
256     result = klass->check_method (auth, client, hint, state);
257
258   return result;
259 }
260
261 /**
262  * gst_rtsp_auth_make_basic:
263  * @user: a userid
264  * @pass: a password
265  *
266  * Construct a Basic authorisation token from @user and @pass.
267  *
268  * Returns: the base64 encoding of the string @user:@pass. g_free()
269  *    after usage.
270  */
271 gchar *
272 gst_rtsp_auth_make_basic (const gchar * user, const gchar * pass)
273 {
274   gchar *user_pass;
275   gchar *result;
276
277   g_return_val_if_fail (user != NULL, NULL);
278   g_return_val_if_fail (pass != NULL, NULL);
279
280   user_pass = g_strjoin (":", user, pass, NULL);
281   result = g_base64_encode ((guchar *) user_pass, strlen (user_pass));
282   g_free (user_pass);
283
284   return result;
285 }