Tizen 2.0 Release
[external/libgnutls26.git] / lib / gnutls_db.c
1 /*
2  * Copyright (C) 2000, 2002, 2003, 2004, 2005, 2008, 2010 Free Software
3  * Foundation, Inc.
4  *
5  * Author: Nikos Mavrogiannopoulos
6  *
7  * This file is part of GnuTLS.
8  *
9  * The GnuTLS is free software; you can redistribute it and/or
10  * modify it under the terms of the GNU Lesser General Public License
11  * as published by the Free Software Foundation; either version 2.1 of
12  * the License, or (at your option) any later version.
13  *
14  * This library is distributed in the hope that it will be useful, but
15  * WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17  * Lesser General Public License for more details.
18  *
19  * You should have received a copy of the GNU Lesser General Public
20  * License along with this library; if not, write to the Free Software
21  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
22  * USA
23  *
24  */
25
26 /* This file contains functions that manipulate a database backend for
27  * resumed sessions.
28  */
29
30 #include "gnutls_int.h"
31 #include "gnutls_errors.h"
32 #include <gnutls_db.h>
33 #include "debug.h"
34 #include <gnutls_session_pack.h>
35 #include <gnutls_datum.h>
36
37 /**
38  * gnutls_db_set_retrieve_function:
39  * @session: is a #gnutls_session_t structure.
40  * @retr_func: is the function.
41  *
42  * Sets the function that will be used to retrieve data from the
43  * resumed sessions database.  This function must return a
44  * gnutls_datum_t containing the data on success, or a gnutls_datum_t
45  * containing null and 0 on failure.
46  *
47  * The datum's data must be allocated using the function
48  * gnutls_malloc().
49  *
50  * The first argument to @retr_func will be null unless
51  * gnutls_db_set_ptr() has been called.
52  **/
53 void
54 gnutls_db_set_retrieve_function (gnutls_session_t session,
55                                  gnutls_db_retr_func retr_func)
56 {
57   session->internals.db_retrieve_func = retr_func;
58 }
59
60 /**
61  * gnutls_db_set_remove_function:
62  * @session: is a #gnutls_session_t structure.
63  * @rem_func: is the function.
64  *
65  * Sets the function that will be used to remove data from the
66  * resumed sessions database. This function must return 0 on success.
67  *
68  * The first argument to @rem_func will be null unless
69  * gnutls_db_set_ptr() has been called.
70  **/
71 void
72 gnutls_db_set_remove_function (gnutls_session_t session,
73                                gnutls_db_remove_func rem_func)
74 {
75   session->internals.db_remove_func = rem_func;
76 }
77
78 /**
79  * gnutls_db_set_store_function:
80  * @session: is a #gnutls_session_t structure.
81  * @store_func: is the function
82  *
83  * Sets the function that will be used to store data from the resumed
84  * sessions database. This function must remove 0 on success.
85  *
86  * The first argument to store_func() will be null unless
87  * gnutls_db_set_ptr() has been called.
88  **/
89 void
90 gnutls_db_set_store_function (gnutls_session_t session,
91                               gnutls_db_store_func store_func)
92 {
93   session->internals.db_store_func = store_func;
94 }
95
96 /**
97  * gnutls_db_set_ptr:
98  * @session: is a #gnutls_session_t structure.
99  * @ptr: is the pointer
100  *
101  * Sets the pointer that will be provided to db store, retrieve and
102  * delete functions, as the first argument.
103  **/
104 void
105 gnutls_db_set_ptr (gnutls_session_t session, void *ptr)
106 {
107   session->internals.db_ptr = ptr;
108 }
109
110 /**
111  * gnutls_db_get_ptr:
112  * @session: is a #gnutls_session_t structure.
113  *
114  * Get db function pointer.
115  *
116  * Returns: the pointer that will be sent to db store, retrieve and
117  *   delete functions, as the first argument.
118  **/
119 void *
120 gnutls_db_get_ptr (gnutls_session_t session)
121 {
122   return session->internals.db_ptr;
123 }
124
125 /**
126  * gnutls_db_set_cache_expiration:
127  * @session: is a #gnutls_session_t structure.
128  * @seconds: is the number of seconds.
129  *
130  * Set the expiration time for resumed sessions. The default is 3600
131  * (one hour) at the time writing this.
132  **/
133 void
134 gnutls_db_set_cache_expiration (gnutls_session_t session, int seconds)
135 {
136   session->internals.expire_time = seconds;
137 }
138
139 /**
140  * gnutls_db_check_entry:
141  * @session: is a #gnutls_session_t structure.
142  * @session_entry: is the session data (not key)
143  *
144  * Check if database entry has expired.  This function is to be used
145  * when you want to clear unnesessary session which occupy space in
146  * your backend.
147  *
148  * Returns: Returns %GNUTLS_E_EXPIRED, if the database entry has
149  *   expired or 0 otherwise.
150  **/
151 int
152 gnutls_db_check_entry (gnutls_session_t session, gnutls_datum_t session_entry)
153 {
154   time_t timestamp;
155
156   timestamp = gnutls_time (0);
157
158   if (session_entry.data != NULL)
159     if (timestamp -
160         ((security_parameters_st *) (session_entry.data))->timestamp <=
161         session->internals.expire_time
162         || ((security_parameters_st *) (session_entry.data))->timestamp >
163         timestamp
164         || ((security_parameters_st *) (session_entry.data))->timestamp == 0)
165       return GNUTLS_E_EXPIRED;
166
167   return 0;
168 }
169
170 /* The format of storing data is:
171  * (forget it). Check gnutls_session_pack.c
172  */
173 int
174 _gnutls_server_register_current_session (gnutls_session_t session)
175 {
176   gnutls_datum_t key;
177   gnutls_datum_t content;
178   int ret = 0;
179
180   key.data = session->security_parameters.session_id;
181   key.size = session->security_parameters.session_id_size;
182
183   if (session->internals.resumable == RESUME_FALSE)
184     {
185       gnutls_assert ();
186       return GNUTLS_E_INVALID_SESSION;
187     }
188
189   if (session->security_parameters.session_id == NULL
190       || session->security_parameters.session_id_size == 0)
191     {
192       gnutls_assert ();
193       return GNUTLS_E_INVALID_SESSION;
194     }
195
196 /* copy data */
197   ret = _gnutls_session_pack (session, &content);
198   if (ret < 0)
199     {
200       gnutls_assert ();
201       return ret;
202     }
203
204   ret = _gnutls_store_session (session, key, content);
205   _gnutls_free_datum (&content);
206
207   return ret;
208 }
209
210 /* Checks if both db_store and db_retrieve functions have
211  * been set up.
212  */
213 static int
214 _gnutls_db_func_is_ok (gnutls_session_t session)
215 {
216   if (session->internals.db_store_func != NULL &&
217       session->internals.db_retrieve_func != NULL &&
218       session->internals.db_remove_func != NULL)
219     return 0;
220   else
221     return GNUTLS_E_DB_ERROR;
222 }
223
224
225 int
226 _gnutls_server_restore_session (gnutls_session_t session,
227                                 uint8_t * session_id, int session_id_size)
228 {
229   gnutls_datum_t data;
230   gnutls_datum_t key;
231   int ret;
232
233   key.data = session_id;
234   key.size = session_id_size;
235
236   if (_gnutls_db_func_is_ok (session) != 0)
237     {
238       gnutls_assert ();
239       return GNUTLS_E_INVALID_SESSION;
240     }
241
242   data = _gnutls_retrieve_session (session, key);
243
244   if (data.data == NULL)
245     {
246       gnutls_assert ();
247       return GNUTLS_E_INVALID_SESSION;
248     }
249
250   /* expiration check is performed inside */
251   ret = gnutls_session_set_data (session, data.data, data.size);
252   if (ret < 0)
253     {
254       gnutls_assert ();
255       return ret;
256     }
257
258   gnutls_free (data.data);
259
260   return 0;
261 }
262
263 int
264 _gnutls_db_remove_session (gnutls_session_t session, uint8_t * session_id,
265                            int session_id_size)
266 {
267   gnutls_datum_t key;
268
269   key.data = session_id;
270   key.size = session_id_size;
271
272   return _gnutls_remove_session (session, key);
273 }
274
275
276 /* Stores session data to the db backend.
277  */
278 int
279 _gnutls_store_session (gnutls_session_t session,
280                        gnutls_datum_t session_id, gnutls_datum_t session_data)
281 {
282   int ret = 0;
283
284   if (session->internals.resumable == RESUME_FALSE)
285     {
286       gnutls_assert ();
287       return GNUTLS_E_INVALID_SESSION;
288     }
289
290   if (_gnutls_db_func_is_ok (session) != 0)
291     {
292       return GNUTLS_E_DB_ERROR;
293     }
294
295   if (session_id.data == NULL || session_id.size == 0)
296     {
297       gnutls_assert ();
298       return GNUTLS_E_INVALID_SESSION;
299     }
300
301   if (session_data.data == NULL || session_data.size == 0)
302     {
303       gnutls_assert ();
304       return GNUTLS_E_INVALID_SESSION;
305     }
306   /* if we can't read why bother writing? */
307
308   if (session->internals.db_store_func != NULL)
309     ret =
310       session->internals.db_store_func (session->internals.db_ptr,
311                                         session_id, session_data);
312
313   return (ret == 0 ? ret : GNUTLS_E_DB_ERROR);
314
315 }
316
317 /* Retrieves session data from the db backend.
318  */
319 gnutls_datum_t
320 _gnutls_retrieve_session (gnutls_session_t session, gnutls_datum_t session_id)
321 {
322   gnutls_datum_t ret = { NULL, 0 };
323
324   if (session_id.data == NULL || session_id.size == 0)
325     {
326       gnutls_assert ();
327       return ret;
328     }
329
330   if (session->internals.db_retrieve_func != NULL)
331     ret =
332       session->internals.db_retrieve_func (session->internals.db_ptr,
333                                            session_id);
334
335   return ret;
336
337 }
338
339 /* Removes session data from the db backend.
340  */
341 int
342 _gnutls_remove_session (gnutls_session_t session, gnutls_datum_t session_id)
343 {
344   int ret = 0;
345
346   if (_gnutls_db_func_is_ok (session) != 0)
347     {
348       return GNUTLS_E_DB_ERROR;
349     }
350
351   if (session_id.data == NULL || session_id.size == 0)
352     return GNUTLS_E_INVALID_SESSION;
353
354   /* if we can't read why bother writing? */
355   if (session->internals.db_remove_func != NULL)
356     ret =
357       session->internals.db_remove_func (session->internals.db_ptr,
358                                          session_id);
359
360   return (ret == 0 ? ret : GNUTLS_E_DB_ERROR);
361
362 }
363
364 /**
365  * gnutls_db_remove_session:
366  * @session: is a #gnutls_session_t structure.
367  *
368  * This function will remove the current session data from the
369  * session database.  This will prevent future handshakes reusing
370  * these session data.  This function should be called if a session
371  * was terminated abnormally, and before gnutls_deinit() is called.
372  *
373  * Normally gnutls_deinit() will remove abnormally terminated
374  * sessions.
375  **/
376 void
377 gnutls_db_remove_session (gnutls_session_t session)
378 {
379   _gnutls_db_remove_session (session,
380                              session->security_parameters.session_id,
381                              session->security_parameters.session_id_size);
382 }