Merge remote-tracking branch 'origin/0.10'
[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., 59 Temple Place - Suite 330,
17  * Boston, MA 02111-1307, 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   /* bitwise or of all methods that need authentication */
67   auth->methods = GST_RTSP_DESCRIBE |
68       GST_RTSP_ANNOUNCE |
69       GST_RTSP_GET_PARAMETER |
70       GST_RTSP_SET_PARAMETER |
71       GST_RTSP_PAUSE |
72       GST_RTSP_PLAY | GST_RTSP_RECORD | GST_RTSP_SETUP | GST_RTSP_TEARDOWN;
73 }
74
75 static void
76 gst_rtsp_auth_finalize (GObject * obj)
77 {
78   GstRTSPAuth *auth = GST_RTSP_AUTH (obj);
79
80   GST_INFO ("finalize auth %p", auth);
81   g_free (auth->basic);
82
83   G_OBJECT_CLASS (gst_rtsp_auth_parent_class)->finalize (obj);
84 }
85
86 static void
87 gst_rtsp_auth_get_property (GObject * object, guint propid,
88     GValue * value, GParamSpec * pspec)
89 {
90   GstRTSPAuth *auth = GST_RTSP_AUTH (object);
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   GstRTSPAuth *auth = GST_RTSP_AUTH (object);
103
104   switch (propid) {
105     default:
106       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, propid, pspec);
107   }
108 }
109
110 /**
111  * gst_rtsp_auth_new:
112  *
113  * Create a new #GstRTSPAuth instance.
114  *
115  * Returns: a new #GstRTSPAuth
116  */
117 GstRTSPAuth *
118 gst_rtsp_auth_new (void)
119 {
120   GstRTSPAuth *result;
121
122   result = g_object_new (GST_TYPE_RTSP_AUTH, NULL);
123
124   return result;
125 }
126
127 /**
128  * gst_rtsp_auth_set_basic:
129  * @auth: a #GstRTSPAuth
130  * @basic: the basic token
131  *
132  * Set the basic token for the default authentication algorithm.
133  */
134 void
135 gst_rtsp_auth_set_basic (GstRTSPAuth * auth, const gchar * basic)
136 {
137   g_free (auth->basic);
138   auth->basic = g_strdup (basic);
139 }
140
141 static gboolean
142 default_setup_auth (GstRTSPAuth * auth, GstRTSPClient * client,
143     GQuark hint, GstRTSPClientState * state)
144 {
145   if (state->response == NULL)
146     return FALSE;
147
148   /* we only have Basic for now */
149   gst_rtsp_message_add_header (state->response, GST_RTSP_HDR_WWW_AUTHENTICATE,
150       "Basic realm=\"GStreamer RTSP Server\"");
151
152   return TRUE;
153 }
154
155 /**
156  * gst_rtsp_auth_setup_auth:
157  * @auth: a #GstRTSPAuth
158  * @client: the client
159  * @uri: the requested uri
160  * @session: the session
161  * @request: the request
162  * @response: the response
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   klass = GST_RTSP_AUTH_GET_CLASS (auth);
176
177   GST_DEBUG_OBJECT (auth, "setup auth");
178
179   if (klass->setup_auth)
180     result = klass->setup_auth (auth, client, hint, state);
181
182   return result;
183 }
184
185 static gboolean
186 default_check_method (GstRTSPAuth * auth, GstRTSPClient * client,
187     GQuark hint, GstRTSPClientState * state)
188 {
189   gboolean result = TRUE;
190   GstRTSPResult res;
191
192   if (state->method & auth->methods != 0) {
193     gchar *authorization;
194
195     result = FALSE;
196
197     res =
198         gst_rtsp_message_get_header (state->request, GST_RTSP_HDR_AUTHORIZATION,
199         &authorization, 0);
200     if (res < 0)
201       goto no_auth;
202
203     /* parse type */
204     if (g_ascii_strncasecmp (authorization, "basic ", 6) == 0) {
205       GST_DEBUG_OBJECT (auth, "check Basic auth");
206       if (auth->basic && strcmp (&authorization[6], auth->basic) == 0)
207         result = TRUE;
208     } else if (g_ascii_strncasecmp (authorization, "digest ", 7) == 0) {
209       GST_DEBUG_OBJECT (auth, "check Digest auth");
210       /* not implemented yet */
211       result = FALSE;
212     }
213   }
214   return result;
215
216 no_auth:
217   {
218     GST_DEBUG_OBJECT (auth, "no authorization header found");
219     return FALSE;
220   }
221 }
222
223 /**
224  * gst_rtsp_auth_check_method:
225  * @auth: a #GstRTSPAuth
226  * @client: the client
227  * @hint: a hint
228  * @state: client state
229  *
230  * Check if @client is allowed to perform the actions of @state.
231  *
232  * Returns: FALSE if the action is not allowed.
233  */
234 gboolean
235 gst_rtsp_auth_check (GstRTSPAuth * auth, GstRTSPClient * client,
236     GQuark hint, GstRTSPClientState * state)
237 {
238   gboolean result = FALSE;
239   GstRTSPAuthClass *klass;
240
241   klass = GST_RTSP_AUTH_GET_CLASS (auth);
242
243   GST_DEBUG_OBJECT (auth, "check state");
244
245   if (klass->check_method)
246     result = klass->check_method (auth, client, hint, state);
247
248   return result;
249 }
250
251 /**
252  * gst_rtsp_auth_make_basic:
253  * @user: a userid
254  * @pass: a password
255  *
256  * Construct a Basic authorisation token from @user and @pass.
257  *
258  * Returns: the base64 encoding of the string @user:@pass. g_free()
259  *    after usage.
260  */
261 gchar *
262 gst_rtsp_auth_make_basic (const gchar * user, const gchar * pass)
263 {
264   gchar *user_pass;
265   gchar *result;
266
267   user_pass = g_strjoin (":", user, pass, NULL);
268   result = g_base64_encode ((guchar *) user_pass, strlen (user_pass));
269   g_free (user_pass);
270
271   return result;
272 }