gdbm was re-added and made optional.

This commit is contained in:
Nikos Mavrogiannopoulos
2013-02-07 20:43:11 +01:00
parent 6606883665
commit 14460456e7
15 changed files with 404 additions and 109 deletions

View File

@@ -111,6 +111,9 @@
/* Define to 1 if you have the `fstat' function. */
#undef HAVE_FSTAT
/* Enable the GDBM library */
#undef HAVE_GDBM
/* Define to 1 if you have the `getdtablesize' function. */
#undef HAVE_GETDTABLESIZE

View File

@@ -20,6 +20,25 @@ AC_C_BIGENDIAN
PKG_CHECK_MODULES([LIBGNUTLS], [gnutls >= 3.0.28])
gdbm_enabled=no
LIBS="$oldlibs -lgdbm"
AC_MSG_CHECKING([for gdbm library])
AC_LINK_IFELSE([AC_LANG_PROGRAM([
#include <gdbm.h>],[
GDBM_FILE dbf;
dbf = gdbm_open("",0,0,0,0);])],
[AC_MSG_RESULT(yes)
AC_SUBST([GDBM_LIBS], [-lgdbm])
AC_SUBST([GDBM_CFLAGS], [])
gdbm_enabled=yes
AC_DEFINE([HAVE_GDBM], 1, [Enable the GDBM library])],
[AC_MSG_RESULT(no)
AC_MSG_WARN([[
***
*** gdbm was not found. The server will not be able to maintain state across restarts.
*** ]])])
LIBS="$oldlibs"
LIBS="$oldlibs -lpam"
AC_MSG_CHECKING([for pam library])
AC_LINK_IFELSE([AC_LANG_PROGRAM([
@@ -56,5 +75,6 @@ AC_MSG_NOTICE([summary of build options:
Install prefix: ${prefix}
Compiler: ${CC}
CFlags: ${CFLAGS}
GDBM backend: ${gdbm_enabled}
])

View File

@@ -14,10 +14,10 @@ CCAN_SOURCES = ccan/build_assert/build_assert.h ccan/check_type/check_type.h \
ocserv_SOURCES = main.c main-auth.c worker-vpn.c worker-auth.c tlslib.c \
cookies.c http-parser/http_parser.c ipc.h \
http-parser/http_parser.c ipc.h cookies.c \
vpn.h cookies.h tlslib.h http-parser/http_parser.h log.c tun.c tun.h \
config.c pam.c pam.h worker-resume.c worker.h main-resume.c main.h \
main-user.c $(CCAN_SOURCES)
main-user.c cookies-gdbm.c cookies-hash.c $(CCAN_SOURCES)
ocserv_SOURCES += ocserv-args.def ocserv-args.c ocserv-args.h

View File

@@ -143,6 +143,8 @@ unsigned j;
READ_STRING("tls-priorities", config->priorities, 0);
READ_STRING("chroot-dir", config->chroot_dir, 0);
READ_STRING("cookie-db", config->cookie_db_name, 0);
READ_NUMERIC("cookie-validity", config->cookie_validity, 1);
READ_NUMERIC("auth-timeout", config->auth_timeout, 0);
READ_NUMERIC("max-clients", config->max_clients, 0);

169
src/cookies-gdbm.c Normal file
View File

@@ -0,0 +1,169 @@
/*
* Copyright (C) 2013 Nikos Mavrogiannopoulos
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include <config.h>
#include <gnutls/gnutls.h>
#include <gnutls/crypto.h>
#include <errno.h>
#include <stdlib.h>
#include <stdarg.h>
#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <limits.h>
#include <gdbm.h>
#include <sys/stat.h>
#include <main.h>
#include <cookies.h>
#ifdef HAVE_GDBM
static
int store_cookie_gdbm(main_server_st *s, const struct stored_cookie_st* sc)
{
GDBM_FILE dbf;
datum key;
datum data;
int ret;
dbf = gdbm_open((char*)s->config->cookie_db_name, 0, GDBM_WRCREAT, S_IRUSR|S_IWUSR, NULL);
if (dbf == NULL) {
syslog(LOG_ERR, "Cannot open cookie database: %s", s->config->cookie_db_name);
return -1;
}
key.dptr = (void*)sc->cookie;
key.dsize = sizeof(sc->cookie);
data.dptr = (void*)sc;
data.dsize = sizeof(*sc);
ret = gdbm_store( dbf, key, data, GDBM_INSERT);
if (ret != 0) {
ret = -1;
goto finish;
}
ret = 0;
finish:
gdbm_close(dbf);
return ret;
}
static
int retrieve_cookie_gdbm(main_server_st *s, const void* cookie, unsigned cookie_size,
struct stored_cookie_st* sc)
{
GDBM_FILE dbf;
datum key;
datum data;
int ret;
dbf = gdbm_open((char*)s->config->cookie_db_name, 0, GDBM_READER, 0, NULL);
if (dbf == NULL) {
syslog(LOG_ERR, "Cannot open cookie database: %s", s->config->cookie_db_name);
return -1;
}
key.dptr = (void*)cookie;
key.dsize = cookie_size;
data = gdbm_fetch( dbf, key);
if (data.dsize != sizeof(*sc)) {
ret = -1;
goto finish;
}
memcpy(sc, data.dptr, data.dsize);
if (sc->expiration >= time(0))
ret = 0;
else
ret = -1;
finish:
gdbm_close(dbf);
return ret;
}
static
void expire_cookies_gdbm(main_server_st* s)
{
GDBM_FILE dbf;
datum key;
datum data;
int deleted = 0;
struct stored_cookie_st sc;
time_t now = time(0);
dbf = gdbm_open((char*)s->config->cookie_db_name, 0, GDBM_WRITER, 0, NULL);
if (dbf == NULL)
return;
key = gdbm_firstkey(dbf);
if (key.dptr == NULL)
goto finish;
while(key.dptr != NULL) {
data = gdbm_fetch( dbf, key);
if (data.dsize != sizeof(sc)) {
gdbm_delete(dbf, key);
deleted++;
} else {
memcpy(&sc, data.dptr, data.dsize);
if (sc.expiration <= now) {
gdbm_delete(dbf, key);
deleted++;
}
}
key = gdbm_nextkey(dbf, key);
}
if (deleted > 0)
gdbm_reorganize(dbf);
finish:
gdbm_close(dbf);
}
static
int cookie_db_init_gdbm(main_server_st* s)
{
return 0;
}
static
void cookie_db_deinit_gdbm(main_server_st* s)
{
return;
}
struct cookie_storage_st gdbm_cookie_funcs = {
.store = store_cookie_gdbm,
.retrieve = retrieve_cookie_gdbm,
.expire = expire_cookies_gdbm,
.init = cookie_db_init_gdbm,
.deinit = cookie_db_deinit_gdbm,
};
#endif

150
src/cookies-hash.c Normal file
View File

@@ -0,0 +1,150 @@
/*
* Copyright (C) 2013 Nikos Mavrogiannopoulos
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include <config.h>
#include <gnutls/gnutls.h>
#include <gnutls/crypto.h>
#include <errno.h>
#include <stdlib.h>
#include <stdarg.h>
#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <limits.h>
#include <sys/stat.h>
#include <main.h>
#include <cookies.h>
#include <ccan/htable/htable.h>
#include <ccan/hash/hash.h>
#define MAX_COOKIES(n) ((n>0)?(2*n):4096)
/* receives allocated data and stores them.
*/
int store_cookie_hash(main_server_st *s, const struct stored_cookie_st* sc)
{
size_t key;
if (s->cookie_db->entries >= MAX_COOKIES(s->config->max_clients)) {
syslog(LOG_INFO, "Maximum number of cookies was reached (%u)", MAX_COOKIES(s->config->max_clients));
return -1;
}
key = hash_stable_8(sc->cookie, COOKIE_SIZE, 0);
htable_add(&s->cookie_db->ht, key, sc);
s->cookie_db->entries++;
return 0;
}
int retrieve_cookie_hash(main_server_st *s, const void* cookie, unsigned cookie_size,
struct stored_cookie_st* rsc)
{
size_t key;
struct htable_iter iter;
struct stored_cookie_st * sc;
key = hash_stable_8(cookie, cookie_size, 0);
sc = htable_firstval(&s->cookie_db->ht, &iter, key);
while(sc != NULL) {
if (cookie_size == COOKIE_SIZE &&
memcmp (cookie, sc->cookie, COOKIE_SIZE) == 0) {
if (sc->expiration < time(0))
return -1;
memcpy(rsc, sc, sizeof(*sc));
return 0;
}
sc = htable_nextval(&s->cookie_db->ht, &iter, key);
}
return -1;
}
void expire_cookies_hash(main_server_st* s)
{
struct stored_cookie_st *sc;
struct htable_iter iter;
time_t now = time(0);
sc = htable_first(&s->cookie_db->ht, &iter);
while(sc != NULL) {
if (sc->expiration <= now) {
htable_delval(&s->cookie_db->ht, &iter);
free(sc);
s->cookie_db->entries--;
}
sc = htable_next(&s->cookie_db->ht, &iter);
}
}
static size_t rehash(const void *_e, void *unused)
{
const struct stored_cookie_st *e = _e;
return hash_stable_8(e->cookie, COOKIE_SIZE, 0);
}
int cookie_db_init_hash(main_server_st * s)
{
hash_db_st * db;
db = malloc(sizeof(*db));
if (db == NULL)
return -1;
htable_init(&db->ht, rehash, NULL);
db->entries = 0;
s->cookie_db = db;
return 0;
}
void cookie_db_deinit_hash(main_server_st* s)
{
struct stored_cookie_st* cache;
struct htable_iter iter;
cache = htable_first(&s->cookie_db->ht, &iter);
while(cache != NULL) {
free(cache);
cache = htable_next(&s->cookie_db->ht, &iter);
}
htable_clear(&s->cookie_db->ht);
s->cookie_db->entries = 0;
return;
}
struct cookie_storage_st hash_cookie_funcs = {
.store = store_cookie_hash,
.retrieve = retrieve_cookie_hash,
.expire = expire_cookies_hash,
.init = cookie_db_init_hash,
.deinit = cookie_db_deinit_hash,
};

View File

@@ -30,111 +30,32 @@
#include <fcntl.h>
#include <unistd.h>
#include <limits.h>
#include <gdbm.h>
#include <sys/stat.h>
#include <main.h>
#include <cookies.h>
#include <ccan/htable/htable.h>
#include <ccan/hash/hash.h>
#define MAX_COOKIES(n) ((n>0)?(2*n):4096)
cookie_store_fn store_cookie;
cookie_retrieve_fn retrieve_cookie;
cookie_db_deinit_fn cookie_db_deinit;
cookie_expire_fn expire_cookies;
/* receives allocated data and stores them.
*/
int store_cookie(main_server_st *s, struct stored_cookie_st* sc)
int cookie_db_init(main_server_st* s)
{
size_t key;
struct cookie_storage_st* funcs;
if (s->cookie_db->entries >= MAX_COOKIES(s->config->max_clients)) {
syslog(LOG_INFO, "Maximum number of cookies was reached (%u)", MAX_COOKIES(s->config->max_clients));
return -1;
}
#ifdef HAVE_GDBM
if (s->config->cookie_db_name != NULL)
funcs = &gdbm_cookie_funcs;
else
#endif
funcs = &hash_cookie_funcs;
key = hash_stable_8(sc->cookie, COOKIE_SIZE, 0);
cookie_db_deinit = funcs->deinit;
expire_cookies = funcs->expire;
store_cookie = funcs->store;
retrieve_cookie = funcs->retrieve;
htable_add(&s->cookie_db->ht, key, sc);
s->cookie_db->entries++;
return 0;
}
int retrieve_cookie(main_server_st *s, const void* cookie, unsigned cookie_size,
struct stored_cookie_st* rsc)
{
size_t key;
struct htable_iter iter;
struct stored_cookie_st * sc;
key = hash_stable_8(cookie, cookie_size, 0);
sc = htable_firstval(&s->cookie_db->ht, &iter, key);
while(sc != NULL) {
if (cookie_size == COOKIE_SIZE &&
memcmp (cookie, sc->cookie, COOKIE_SIZE) == 0) {
if (sc->expiration < time(0))
return -1;
memcpy(rsc, sc, sizeof(*sc));
return 0;
}
sc = htable_nextval(&s->cookie_db->ht, &iter, key);
}
return -1;
}
void expire_cookies(main_server_st* s)
{
struct stored_cookie_st *sc;
struct htable_iter iter;
time_t now = time(0);
sc = htable_first(&s->cookie_db->ht, &iter);
while(sc != NULL) {
if (sc->expiration <= now) {
htable_delval(&s->cookie_db->ht, &iter);
free(sc);
s->cookie_db->entries--;
}
sc = htable_next(&s->cookie_db->ht, &iter);
}
}
static size_t rehash(const void *_e, void *unused)
{
const struct stored_cookie_st *e = _e;
return hash_stable_8(e->cookie, COOKIE_SIZE, 0);
}
void cookie_db_init(hash_db_st** _db)
{
hash_db_st * db;
db = malloc(sizeof(*db));
if (db == NULL)
exit(1);
htable_init(&db->ht, rehash, NULL);
db->entries = 0;
*_db = db;
}
void cookie_db_deinit(hash_db_st* db)
{
struct stored_cookie_st* cache;
struct htable_iter iter;
cache = htable_first(&db->ht, &iter);
while(cache != NULL) {
free(cache);
cache = htable_next(&db->ht, &iter);
}
htable_clear(&db->ht);
db->entries = 0;
return;
return funcs->init(s);
}

View File

@@ -12,12 +12,31 @@ struct stored_cookie_st {
time_t expiration;
};
int store_cookie(main_server_st *, struct stored_cookie_st* sc);
typedef int (*cookie_store_fn)(main_server_st *, const struct stored_cookie_st* sc);
int retrieve_cookie(main_server_st *, const void* cookie, unsigned cookie_size,
typedef int (*cookie_retrieve_fn)(main_server_st *, const void* cookie, unsigned cookie_size,
struct stored_cookie_st* sc);
void cookie_db_deinit(hash_db_st* db);
void cookie_db_init(hash_db_st** _db);
typedef void (*cookie_db_deinit_fn)(main_server_st*);
typedef void (*cookie_expire_fn)(main_server_st* s);
extern cookie_store_fn store_cookie;
extern cookie_retrieve_fn retrieve_cookie;
extern cookie_db_deinit_fn cookie_db_deinit;
extern cookie_expire_fn expire_cookies;
int cookie_db_init(main_server_st*);
struct cookie_storage_st {
cookie_store_fn store;
cookie_retrieve_fn retrieve;
cookie_expire_fn expire;
int (*init)(main_server_st *);
cookie_db_deinit_fn deinit;
};
extern struct cookie_storage_st gdbm_cookie_funcs;
extern struct cookie_storage_st hash_cookie_funcs;
#endif

View File

@@ -540,7 +540,6 @@ int main(int argc, char** argv)
list_head_init(&clist.head);
tun_st_init(&tun);
tls_cache_init(&s.tls_db);
cookie_db_init(&s.cookie_db);
signal(SIGINT, handle_term);
signal(SIGTERM, handle_term);
@@ -560,11 +559,17 @@ int main(int argc, char** argv)
fprintf(stderr, "This server requires root access to operate.\n");
exit(1);
}
s.config = &config;
s.tun = &tun;
s.llist = &llist;
s.clist = &clist;
ret = cookie_db_init(&s);
if (ret < 0) {
fprintf(stderr, "Could not initialize cookie database.\n");
exit(1);
}
/* Listen to network ports */
ret = listen_ports(&config, &llist, config.name);

View File

@@ -84,8 +84,6 @@ int handle_resume_fetch_req(main_server_st* s, struct proc_st* proc,
int handle_resume_store_req(main_server_st* s, struct proc_st *proc,
const struct cmd_resume_store_req_st * req);
void expire_cookies(main_server_st* s);
void
__attribute__ ((format(printf, 4, 5)))
mslog(const main_server_st * s, const struct proc_st* proc,

View File

@@ -2,7 +2,7 @@
*
* DO NOT EDIT THIS FILE (ocserv-args.c)
*
* It has been AutoGen-ed February 7, 2013 at 02:45:14 PM by AutoGen 5.16
* It has been AutoGen-ed February 7, 2013 at 08:21:00 PM by AutoGen 5.16
* From the definitions ocserv-args.def
* and the template file options
*

View File

@@ -110,6 +110,10 @@ auth-timeout = 40
# of that cookie.
cookie-validity = 14400
# A cookie database. If not set cookies are stored in memory and
# server restarts won't preserve them.
#cookie-db = /var/tmp/cookies.db
# Script to call when a client connects and obtains an IP
# Parameters: username hostname device IP-REAL IP-LOCAL IP-REMOTE
# hostname is the hostname selected by the client

View File

@@ -2,7 +2,7 @@
*
* DO NOT EDIT THIS FILE (ocserv-args.h)
*
* It has been AutoGen-ed February 7, 2013 at 02:45:14 PM by AutoGen 5.16
* It has been AutoGen-ed February 7, 2013 at 08:20:59 PM by AutoGen 5.16
* From the definitions ocserv-args.def
* and the template file options
*

View File

@@ -52,6 +52,7 @@ tls-priorities = "PERFORMANCE:%SERVER_PRECEDENCE:%COMPAT"
# which he can reconnect. This option sets the maximum lifetime
# of that cookie.
cookie-validity = 14400
#cookie-db = /tmp/db
run-as-user = nobody
run-as-group = nogroup

View File

@@ -73,6 +73,9 @@ struct cfg_st {
unsigned max_clients;
unsigned use_utmp;
/* if gdbm is there */
const char* cookie_db_name;
const char *connect_script;
const char *disconnect_script;