diff options
-rw-r--r-- | NEWS | 4 | ||||
-rw-r--r-- | THANKS | 1 | ||||
-rw-r--r-- | configure.in | 2 | ||||
-rw-r--r-- | lib/gnutls.h.in | 14 | ||||
-rw-r--r-- | lib/gnutls_db.c | 294 | ||||
-rw-r--r-- | lib/gnutls_db.h | 3 | ||||
-rw-r--r-- | lib/gnutls_int.h | 12 | ||||
-rw-r--r-- | lib/gnutls_record.c | 9 |
8 files changed, 270 insertions, 69 deletions
@@ -1,3 +1,7 @@ +Version 0.2.10 +- Corrected bugs in non blocking IO +- Added hooks to use external database to store sessions. + Version 0.2.9 (27/10/2001) - AUTH_INFO types and structures were moved to library internals - AUTH_FAILED is no longer returned in SRP authentication @@ -4,3 +4,4 @@ Neil Spring <nspring@saavie.org> Paul Sheer <psheer@icon.co.za> +Jon Nelson <jnelson@securepipe.com> diff --git a/configure.in b/configure.in index dfc65a693b..86e53dbf2a 100644 --- a/configure.in +++ b/configure.in @@ -11,7 +11,7 @@ AC_DEFINE_UNQUOTED(T_OS, "$target_os") GNUTLS_MAJOR_VERSION=0 GNUTLS_MINOR_VERSION=2 -GNUTLS_MICRO_VERSION=9 +GNUTLS_MICRO_VERSION=10 GNUTLS_VERSION=$GNUTLS_MAJOR_VERSION.$GNUTLS_MINOR_VERSION.$GNUTLS_MICRO_VERSION AC_DEFINE_UNQUOTED(GNUTLS_VERSION, "$GNUTLS_VERSION") diff --git a/lib/gnutls.h.in b/lib/gnutls.h.in index 1214994234..f17bb0f5e8 100644 --- a/lib/gnutls.h.in +++ b/lib/gnutls.h.in @@ -136,10 +136,18 @@ int gnutls_get_current_session( GNUTLS_STATE state, void* session, int *session_ /* returns the session ID */ int gnutls_get_current_session_id( GNUTLS_STATE state, void* session, int *session_size); +typedef int (*DB_STORE_FUNC)(void*, gnutls_datum key, gnutls_datum data); +typedef int (*DB_REMOVE_FUNC)(void*, gnutls_datum key); +typedef gnutls_datum (*DB_RETR_FUNC)(void*, gnutls_datum key); + int gnutls_set_lowat( GNUTLS_STATE state, int num); int gnutls_set_cache_expiration( GNUTLS_STATE state, int seconds); int gnutls_set_db_name( GNUTLS_STATE state, char* filename); int gnutls_clean_db( GNUTLS_STATE state); +void gnutls_set_db_retrieve_func( GNUTLS_STATE, DB_RETR_FUNC); +void gnutls_set_db_remove_func( GNUTLS_STATE, DB_REMOVE_FUNC); +void gnutls_set_db_store_func( GNUTLS_STATE, DB_STORE_FUNC); +void gnutls_set_db_ptr( GNUTLS_STATE, void* db_ptr); void gnutls_set_max_handshake_data_buffer_size( GNUTLS_STATE state, int max); @@ -222,9 +230,11 @@ int gnutls_dh_generate_params( gnutls_datum* prime, gnutls_datum* generator, int typedef ssize_t (*PULL_FUNC)(SOCKET, void*, size_t); typedef ssize_t (*PUSH_FUNC)(SOCKET, const void*, size_t); + typedef void (*LOG_FUNC)( const char*); -void gnutls_global_set_push_func( PUSH_FUNC push_func); -void gnutls_global_set_pull_func( PULL_FUNC pull_func); +void gnutls_set_push_func( GNUTLS_STATE, PUSH_FUNC push_func); +void gnutls_set_pull_func( GNUTLS_STATE, PULL_FUNC pull_func); + diff --git a/lib/gnutls_db.c b/lib/gnutls_db.c index 0ed1f73539..0a2da720d8 100644 --- a/lib/gnutls_db.c +++ b/lib/gnutls_db.c @@ -24,6 +24,7 @@ #include "gnutls_int.h" #include "gnutls_errors.h" #include "gnutls_session.h" +#include <gnutls_db.h> #include "debug.h" #ifdef HAVE_LIBGDBM @@ -35,6 +36,73 @@ #endif /** + * gnutls_set_db_retrieve_function - Sets the function that will be used to get data + * @state: is a &GNUTLS_STATE structure. + * @retr_func: is the function. + * + * Sets the function that will be used to retrieve data from the resumed + * sessions database. This function must return 0 on success. + * This function should only be used if you do + * not plan to use the included gdbm backend. + * + * The first argument to store_func() will be null unless gnutls_db_set_db_ptr() + * has been called. + * + **/ +void gnutls_set_db_retrieve_function( GNUTLS_STATE state, DB_RETR_FUNC retr_func) { + state->gnutls_internals.db_retrieve_func = retr_func; +} + +/** + * gnutls_set_db_remove_function - Sets the function that will be used to remove data + * @state: is a &GNUTLS_STATE structure. + * @rem_func: is the function. + * + * Sets the function that will be used to remove data from the resumed + * sessions database. This function must return 0 on success. + * This function should only be used if you do + * not plan to use the included gdbm backend. + * + * The first argument to rem_func() will be null unless gnutls_db_set_db_ptr() + * has been called. + * + **/ +void gnutls_set_db_remove_function( GNUTLS_STATE state, DB_REMOVE_FUNC rem_func) { + state->gnutls_internals.db_remove_func = rem_func; +} + +/** + * gnutls_set_db_store_function - Sets the function that will be used to put data + * @state: is a &GNUTLS_STATE structure. + * @store_func: is the function + * + * Sets the function that will be used to store data from the resumed + * sessions database. This function must remove 0 on success. + * This function should only be used if you do + * not plan to use the included gdbm backend. + * + * The first argument to store_func() will be null unless gnutls_db_set_ptr() + * has been called. + * + **/ +void gnutls_set_db_store_function( GNUTLS_STATE state, DB_STORE_FUNC store_func) { + state->gnutls_internals.db_store_func = store_func; +} + +/** + * gnutls_set_db_ptr - Sets a pointer to be sent to db functions + * @state: is a &GNUTLS_STATE structure. + * @ptr: is the pointer + * + * Sets the pointer that will be sent to store and retrieve functions, as + * the first argument. + * + **/ +void gnutls_set_db_ptr( GNUTLS_STATE state, void* ptr) { + state->gnutls_internals.db_ptr = ptr; +} + +/** * gnutls_set_cache_expiration - Sets the expiration time for resumed sessions. * @state: is a &GNUTLS_STATE structure. * @seconds: is the number of seconds. @@ -55,6 +123,9 @@ int gnutls_set_cache_expiration( GNUTLS_STATE state, int seconds) { * Sets the name of the (gdbm) database to be used to keep * the sessions to be resumed. This function also creates the database * - if it does not exist - and opens it for reading. + * You should not call this function if using an other backend + * than gdbm (ie. called function gnutls_set_db_store_func() etc.) + * **/ int gnutls_set_db_name( GNUTLS_STATE state, char* filename) { #ifdef HAVE_LIBGDBM @@ -100,7 +171,9 @@ GDBM_FILE dbf; * * This function Deletes all expired records in the resumed sessions' database. * This database may become huge if this function is not called. - * (this function is also quite expensive) + * This function is also quite expensive. This function should only + * be called if using the gdbm backend. + * **/ int gnutls_clean_db( GNUTLS_STATE state) { #ifdef HAVE_LIBGDBM @@ -111,7 +184,7 @@ time_t timestamp; if (GNUTLS_DBF==NULL) return GNUTLS_E_DB_ERROR; if (GNUTLS_DBNAME==NULL) return GNUTLS_E_DB_ERROR; - + dbf = gdbm_open(GNUTLS_DBNAME, 0, GDBM_WRITER, 0600, NULL); if (dbf==NULL) return GNUTLS_E_AGAIN; key = gdbm_firstkey(dbf); @@ -147,103 +220,206 @@ time_t timestamp; */ int _gnutls_server_register_current_session( GNUTLS_STATE state) { -#ifdef HAVE_LIBGDBM -GDBM_FILE dbf; -datum key = { state->security_parameters.session_id, state->security_parameters.session_id_size }; -datum content; +gnutls_datum key = { state->security_parameters.session_id, state->security_parameters.session_id_size }; +gnutls_datum content; int ret = 0, pos; if (state->gnutls_internals.resumable==RESUME_FALSE) return GNUTLS_E_INVALID_SESSION; - if (GNUTLS_DBNAME==NULL) - return GNUTLS_E_DB_ERROR; - if (state->security_parameters.session_id==NULL || state->security_parameters.session_id_size==0) return GNUTLS_E_INVALID_SESSION; - /* if we can't read why bother writing? */ - if (GNUTLS_DBF==NULL) - return GNUTLS_E_DB_ERROR; - /* allocate space for data */ - content.dsize = sizeof(SecurityParameters) + state->gnutls_key->auth_info_size + content.size = sizeof(SecurityParameters) + state->gnutls_key->auth_info_size + sizeof(state->gnutls_key->auth_info_size); - content.dptr = gnutls_malloc( content.dsize); - if (content.dptr==NULL) return GNUTLS_E_MEMORY_ERROR; + content.data = gnutls_malloc( content.size); + if (content.data==NULL) return GNUTLS_E_MEMORY_ERROR; /* copy data */ pos = 0; - memcpy( &content.dptr[0], (void*)&state->security_parameters, sizeof(SecurityParameters)); + memcpy( &content.data[0], (void*)&state->security_parameters, sizeof(SecurityParameters)); pos+=sizeof(SecurityParameters); - - memcpy( &content.dptr[pos], &state->gnutls_key->auth_info_size, sizeof(state->gnutls_key->auth_info_size)); + + memcpy( &content.data[pos], &state->gnutls_key->auth_info_size, sizeof(state->gnutls_key->auth_info_size)); pos+=sizeof(state->gnutls_key->auth_info_size); - - memcpy( &content.dptr[pos], state->gnutls_key->auth_info, state->gnutls_key->auth_info_size); - dbf = gdbm_open(GNUTLS_DBNAME, 0, GDBM_WRITER, 0600, NULL); - if (dbf==NULL) { - gnutls_free(content.dptr); - /* cannot open db for writing. This may happen if multiple - * instances try to write. - */ - return GNUTLS_E_AGAIN; - } - ret = gdbm_store( dbf, key, content, GDBM_INSERT); + memcpy( &content.data[pos], state->gnutls_key->auth_info, state->gnutls_key->auth_info_size); - gnutls_free( content.dptr); + ret = _gnutls_store_session( state, key, content); - gdbm_close(dbf); - return (ret == 0 ? ret : GNUTLS_E_UNKNOWN_ERROR); -#else - return GNUTLS_E_UNIMPLEMENTED_FEATURE; -#endif + gnutls_free( content.data); + + return ret; } int _gnutls_server_restore_session( GNUTLS_STATE state, uint8* session_id, int session_id_size) { -#ifdef HAVE_LIBGDBM -datum content; -datum key = { session_id, session_id_size}; +gnutls_datum data; +gnutls_datum key = { session_id, session_id_size }; int ret; - if (GNUTLS_DBNAME==NULL) return GNUTLS_E_DB_ERROR; + data = _gnutls_retrieve_session( state, key); - if (GNUTLS_DBF==NULL) return GNUTLS_E_DB_ERROR; - content = gdbm_fetch( GNUTLS_DBF, key); - - if (content.dptr==NULL) { + if (data.data==NULL) { return GNUTLS_E_INVALID_SESSION; } /* expiration check is performed inside */ - ret = gnutls_set_current_session( state, content.dptr, content.dsize); - free(content.dptr); + ret = gnutls_set_current_session( state, data.data, data.size); + free(data.data); - return ret; -#else - return GNUTLS_E_UNIMPLEMENTED_FEATURE; -#endif + return 0; } int _gnutls_db_remove_session( GNUTLS_STATE state, uint8* session_id, int session_id_size) { +gnutls_datum key = { session_id, session_id_size }; + + return _gnutls_remove_session( state, key); +} + + +/* Checks if both db_store and db_retrieve functions have + * been set up. + */ +static int _gnutls_db_func_is_ok( GNUTLS_STATE state) { + if (state->gnutls_internals.db_store_func!=NULL && + state->gnutls_internals.db_retrieve_func!=NULL && + state->gnutls_internals.db_remove_func!=NULL) return 0; + else return GNUTLS_E_DB_ERROR; +} + + + +/* Stores session data to the db backend. + */ +int _gnutls_store_session( GNUTLS_STATE state, gnutls_datum session_id, gnutls_datum session_data) +{ #ifdef HAVE_LIBGDBM GDBM_FILE dbf; -datum key = { session_id, session_id_size}; -int ret; +datum key = { session_id.data, session_id.size }; +datum content = {session_data.data, session_data.size}; +#endif +int ret = 0; - if (GNUTLS_DBNAME==NULL) return GNUTLS_E_DB_ERROR; + if (state->gnutls_internals.resumable==RESUME_FALSE) + return GNUTLS_E_INVALID_SESSION; - dbf = gdbm_open(GNUTLS_DBNAME, 0, GDBM_READER, 0600, NULL); - if (dbf==NULL) return GNUTLS_E_AGAIN; - ret = gdbm_delete( dbf, key); - gdbm_close(dbf); + if (GNUTLS_DBNAME==NULL && _gnutls_db_func_is_ok(state)!=0) { + return GNUTLS_E_DB_ERROR; + } + + if (session_id.data==NULL || session_id.size==0) + return GNUTLS_E_INVALID_SESSION; + + if (session_data.data==NULL || session_data.size==0) + return GNUTLS_E_INVALID_SESSION; - return (ret==0 ? ret : GNUTLS_E_DB_ERROR); + /* if we can't read why bother writing? */ + if (GNUTLS_DBF==NULL) { /* use external backend. */ + + ret = state->gnutls_internals.db_store_func( state->gnutls_internals.db_ptr, session_id, session_data); + + } else { /* use gdbm */ +#ifdef HAVE_LIBGDBM + dbf = gdbm_open(GNUTLS_DBNAME, 0, GDBM_WRITER, 0600, NULL); + if (dbf==NULL) { + /* cannot open db for writing. This may happen if multiple + * instances try to write. + */ + return GNUTLS_E_AGAIN; + } + ret = gdbm_store( dbf, key, content, GDBM_INSERT); + + gdbm_close(dbf); #else - return GNUTLS_E_UNIMPLEMENTED_FEATURE; + return GNUTLS_E_UNIMPLEMENTED_FEATURE; +#endif + } + + + return (ret == 0 ? ret : GNUTLS_E_DB_ERROR); + +} + +/* Retrieves session data from the db backend. + */ +gnutls_datum _gnutls_retrieve_session( GNUTLS_STATE state, gnutls_datum session_id) +{ +#ifdef HAVE_LIBGDBM +datum key = { session_id.data, session_id.size }; +datum content; +#endif +gnutls_datum ret = { NULL, 0 }; + + if (GNUTLS_DBNAME==NULL && _gnutls_db_func_is_ok(state)!=0) { + return ret; + } + + if (session_id.data==NULL || session_id.size==0) + return ret; + + /* if we can't read why bother writing? */ + if (GNUTLS_DBF==NULL) { /* use external backend. */ + + ret = state->gnutls_internals.db_retrieve_func( state->gnutls_internals.db_ptr, session_id); + + } else { /* use gdbm */ +#ifdef HAVE_LIBGDBM + content = gdbm_fetch( GNUTLS_DBF, key); + ret.data = content.dptr; + ret.size = content.dsize; +#else + return ret; #endif + } + + + return ret; + } +/* Removes session data from the db backend. + */ +int _gnutls_remove_session( GNUTLS_STATE state, gnutls_datum session_id) +{ +#ifdef HAVE_LIBGDBM +GDBM_FILE dbf; +datum key = { session_id.data, session_id.size }; +#endif +int ret = 0; + + if (GNUTLS_DBNAME==NULL && _gnutls_db_func_is_ok(state)!=0) { + return GNUTLS_E_DB_ERROR; + } + + if (session_id.data==NULL || session_id.size==0) + return GNUTLS_E_INVALID_SESSION; + + /* if we can't read why bother writing? */ + if (GNUTLS_DBF==NULL) { /* use external backend. */ + + ret = state->gnutls_internals.db_remove_func( state->gnutls_internals.db_ptr, session_id); + + } else { /* use gdbm */ +#ifdef HAVE_LIBGDBM + dbf = gdbm_open(GNUTLS_DBNAME, 0, GDBM_WRITER, 0600, NULL); + if (dbf==NULL) { + /* cannot open db for writing. This may happen if multiple + * instances try to write. + */ + return GNUTLS_E_AGAIN; + } + ret = gdbm_delete( dbf, key); + + gdbm_close(dbf); +#else + return GNUTLS_E_UNIMPLEMENTED_FEATURE; +#endif + } + + + return (ret == 0 ? ret : GNUTLS_E_DB_ERROR); + +} diff --git a/lib/gnutls_db.h b/lib/gnutls_db.h index 4c0c5f1228..bfc9c2ef3b 100644 --- a/lib/gnutls_db.h +++ b/lib/gnutls_db.h @@ -24,3 +24,6 @@ int _gnutls_server_register_current_session( GNUTLS_STATE state); int _gnutls_server_restore_session( GNUTLS_STATE state, uint8* session_id, int session_id_size); int gnutls_clean_db( GNUTLS_STATE state); int _gnutls_db_remove_session( GNUTLS_STATE state, uint8* session_id, int session_id_size); +int _gnutls_store_session( GNUTLS_STATE state, gnutls_datum session_id, gnutls_datum session_data); +gnutls_datum _gnutls_retrieve_session( GNUTLS_STATE state, gnutls_datum session_id); +int _gnutls_remove_session( GNUTLS_STATE state, gnutls_datum session_id); diff --git a/lib/gnutls_int.h b/lib/gnutls_int.h index 7577fcb546..baa219aa24 100644 --- a/lib/gnutls_int.h +++ b/lib/gnutls_int.h @@ -150,6 +150,11 @@ typedef enum ResumableSession { RESUME_TRUE, RESUME_FALSE } ResumableSession; */ typedef ssize_t (*PULL_FUNC)(SOCKET, void*, size_t); typedef ssize_t (*PUSH_FUNC)(SOCKET, const void*, size_t); +/* Store & Retrieve functions defines: + */ +typedef int (*DB_STORE_FUNC)(void*, gnutls_datum key, gnutls_datum data); +typedef int (*DB_REMOVE_FUNC)(void*, gnutls_datum key); +typedef gnutls_datum (*DB_RETR_FUNC)(void*, gnutls_datum key); typedef struct { KXAlgorithm algorithm; @@ -425,6 +430,13 @@ typedef struct { */ PULL_FUNC _gnutls_pull_func; PUSH_FUNC _gnutls_push_func; + /* STORE & RETRIEVE functions. Only used if other + * backend than gdbm is used. + */ + DB_STORE_FUNC db_store_func; + DB_RETR_FUNC db_retrieve_func; + DB_REMOVE_FUNC db_remove_func; + void* db_ptr; } GNUTLS_INTERNALS; struct GNUTLS_STATE_INT { diff --git a/lib/gnutls_record.c b/lib/gnutls_record.c index 500e1b1e9c..0c2830b98d 100644 --- a/lib/gnutls_record.c +++ b/lib/gnutls_record.c @@ -55,7 +55,7 @@ void _gnutls_set_current_version(GNUTLS_STATE state, GNUTLS_Version version) { * if you have changed the default low water value (default is 1). * Normally you will not need that function. * This function is only usefull if using berkeley style sockets. - * Otherwise it does nothing. + * Otherwise it must be called and set lowat to zero. * **/ int gnutls_set_lowat(GNUTLS_STATE state, int num) { @@ -63,8 +63,6 @@ int gnutls_set_lowat(GNUTLS_STATE state, int num) { return 0; } -extern ssize_t (*_gnutls_pull_func)( SOCKET, void*, size_t); - /** * gnutls_init - This function initializes the state to null (null encryption etc...). * @con_end: is used to indicate if this state is to be used for server or @@ -108,10 +106,7 @@ int gnutls_init(GNUTLS_STATE * state, ConnectionEnd con_end) (*state)->gnutls_internals.expire_time = DEFAULT_EXPIRE_TIME; /* one hour default */ - if (_gnutls_pull_func==NULL) - gnutls_set_lowat((*state), DEFAULT_LOWAT); /* the default for tcp */ - else - gnutls_set_lowat((*state), 0); + gnutls_set_lowat((*state), DEFAULT_LOWAT); /* the default for tcp */ gnutls_set_max_handshake_data_buffer_size( (*state), MAX_HANDSHAKE_DATA_BUFFER_SIZE); |