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