Skip to content

Commit

Permalink
Fixed memory leak issue in libfko when fko_new_with_data() was called…
Browse files Browse the repository at this point in the history
… with a bad key. Added autoconf checks for gdbm with fallback to ndbm for server builds. Added digest cache capability using gdbm (in ndbm compatibility mode) or ndbm for replay detection.

git-svn-id: file:///home/mbr/svn/fwknop/trunk@153 510a4753-2344-4c79-9c09-4d669213fbeb
  • Loading branch information
Damien Stuart committed Oct 16, 2009
1 parent 8b4b55f commit 8c1261c
Show file tree
Hide file tree
Showing 8 changed files with 265 additions and 37 deletions.
19 changes: 13 additions & 6 deletions configure.ac
Expand Up @@ -189,15 +189,23 @@ AC_ARG_ENABLE([server],
[])
AM_CONDITIONAL([WANT_SERVER], [test "$want_server" = yes])

dnl Check for libpcap if we are building the server component
dnl Check for libpcap, gdbm (or ndbm) if we are building the server component
dnl
have_pcap=yes
AS_IF([test "$want_server" = yes],
AC_CHECK_LIB([pcap],[pcap_open_live],
AC_DEFINE([HAVE_LIBPCAP], [1], [Define if you have libpcap]), [have_pcap=no]
# Looking for libpcap
#
AC_CHECK_LIB([pcap],[pcap_open_live], [],
[ AC_MSG_ERROR([fwknopd needs libpcap])]
)

# Looking for gdbm or fallback to ndbm or bail
#
AC_CHECK_LIB([gdbm],[dbm_open], [],
[ AC_CHECK_LIB([ndbm],[dbm_open], [],
[ AC_MSG_ERROR([fwknopd needs either gdbm or ndbm])]
)]
)
)
AM_CONDITIONAL([HAVE_LIBPCAP],[test "$have_pcap" = yes])

AC_CONFIG_FILES([Makefile
lib/Makefile
Expand All @@ -213,6 +221,5 @@ echo "
============================================
Client build: $want_client
Server build: $want_server
- with libpcap: $have_pcap
GPG encryption support: $have_gpgme
"
1 change: 1 addition & 0 deletions lib/fko_encryption.c
Expand Up @@ -111,6 +111,7 @@ _rijndael_decrypt(fko_ctx_t ctx, char *dec_key, int b64_len)
return(FKO_ERROR_MEMORY_ALLOCATION);

memmove(tbuf+strlen(B64_RIJNDAEL_SALT), tbuf, b64_len);

ctx->encrypted_msg = memcpy(tbuf, B64_RIJNDAEL_SALT, strlen(B64_RIJNDAEL_SALT));

/* Adjust b64_len for added SALT value and Make sure we are still
Expand Down
35 changes: 28 additions & 7 deletions lib/fko_funcs.c
Expand Up @@ -158,12 +158,11 @@ int
fko_new_with_data(fko_ctx_t *r_ctx, char *enc_msg, char *dec_key)
{
fko_ctx_t ctx;
int res = FKO_SUCCESS; /* Are we optimistic or what? */

int res = fko_new(r_ctx);
if(res != FKO_SUCCESS)
return res;

ctx = *r_ctx;
ctx = calloc(1, sizeof *ctx);
if(ctx == NULL)
return(FKO_ERROR_MEMORY_ALLOCATION);

/* First, add the data to the context.
*/
Expand All @@ -174,13 +173,35 @@ fko_new_with_data(fko_ctx_t *r_ctx, char *enc_msg, char *dec_key)
return(FKO_ERROR_MEMORY_ALLOCATION);
}

/* Consider it initialized here.
*/
ctx->initval = FKO_CTX_INITIALIZED;
FKO_SET_CTX_INITIALIZED(ctx);

/* If a decryption password is provided, go ahead and decrypt and
* decode.
*/
if(dec_key != NULL)
return(fko_decrypt_spa_data(ctx, dec_key));
{
res = fko_decrypt_spa_data(ctx, dec_key);

return(FKO_SUCCESS);
if(res != FKO_SUCCESS)
{
fko_destroy(ctx);
return(res);
}
}

#if HAVE_LIBGPGME
/* Set gpg signature verify on.
*/
ctx->verify_gpg_sigs = 1;
#endif /* HAVE_LIBGPGME */


*r_ctx = ctx;

return(res);
}

/* Destroy a context and free its resources
Expand Down
6 changes: 1 addition & 5 deletions server/Makefile.am
Expand Up @@ -4,14 +4,10 @@ fwknopd_SOURCES = fwknopd.c fwknopd.h config_init.c config_init.h \
fwknopd_common.h incoming_spa.c incoming_spa.h \
pcap_capture.c pcap_capture.h process_packet.c \
process_packet.h log_msg.c log_msg.h utils.c utils.h \
sig_handler.c sig_handler.h
sig_handler.c sig_handler.h replay_dbm.c replay_dbm.h

fwknopd_LDADD = $(top_builddir)/lib/libfko.la

if HAVE_LIBPCAP
fwknopd_LDADD += -lpcap
endif

fwknopd_CPPFLAGS = -I $(top_srcdir)/lib -I $(top_srcdir)/common -DSYSCONFDIR=\"$(sysconfdir)\"

fwknopddir = @sysconfdir@/fwknop
Expand Down
15 changes: 8 additions & 7 deletions server/fwknopd.c
Expand Up @@ -33,6 +33,7 @@
#include "log_msg.h"
#include "utils.h"
#include "sig_handler.h"
#include "replay_dbm.h"

/* Prototypes
*/
Expand All @@ -44,7 +45,7 @@ int
main(int argc, char **argv)
{
fko_ctx_t ctx;
int res, last_sig;
int res, last_sig, rpdb_count;
char *spa_data, *version;
char access_buf[MAX_LINE_LEN];
pid_t old_pid;
Expand Down Expand Up @@ -176,12 +177,12 @@ main(int argc, char **argv)
exit(EXIT_FAILURE);
}

#ifndef HAVE_LIBPCAP
log_msg(LOG_ERR|LOG_STDERR,
"libpcap is not avaiable, I'm hosed (for now).");
exit(EXIT_FAILURE);
#endif
/* Initialize the digest cache (replay attack detection dbm).
*/
rpdb_count = replay_db_init(&opts);

fprintf(stderr, "RPDB Count: %i\n", rpdb_count);

/* Intiate pcap capture mode...
*/
pcap_capture(&opts);
Expand Down
33 changes: 21 additions & 12 deletions server/incoming_spa.c
Expand Up @@ -25,6 +25,7 @@
*/
#include "fwknopd_common.h"
#include "incoming_spa.h"
#include "log_msg.h"

/* The pcap capture routine.
*/
Expand All @@ -45,27 +46,35 @@ fprintf(stderr, "SPA Packet: '%s'\n", spa_pkt->packet_data);

/* Get the decryption key
*/
// TODO: finish me

/* Decode the packet data
* --DSS TEMP note using the hard-coded "sdf" as the password.
* this is just for dev testing until I get the
* access.conf handling in.
*/
res = fko_new_with_data(&ctx, spa_pkt->packet_data, "sdf");

if(res == FKO_SUCCESS)
{

fprintf(stderr, "Decode res = %i\n", res);
display_ctx(ctx);
/* Reset the packet data length to 0.
*/
spa_pkt->packet_data_len = 0;

fko_destroy(ctx);
}
else
if(res != FKO_SUCCESS)
{
fprintf(stderr, "Error creating fko context: %s\n", fko_errstr(res));
return(-1);
}

/* Reset the packet data length to 0.
*/
spa_pkt->packet_data_len = 0;
fprintf(stderr, "Decode res = %i\n", res);


display_ctx(ctx);

res = replay_check(opts, ctx);

fko_destroy(ctx);

return(0);
return(res);
}

/***EOF***/
156 changes: 156 additions & 0 deletions server/replay_dbm.c
@@ -0,0 +1,156 @@
/*
*****************************************************************************
*
* File: replay_dbm.c
*
* Author: Damien S. Stuart
*
* Purpose: Provides the functions to check for possible replay attacks
* by using a dbm (ndbm or gdbm in ndbm compatibility mode) file
* to store a digest of previously received SPA packets.
*
* Copyright (C) 2009 Damien Stuart (dstuart@dstuart.org)
*
* License (GNU Public License):
*
* 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307
* USA
*
*****************************************************************************
*/
#include "replay_dbm.h"
#include "log_msg.h"

#if HAVE_LIBGDBM
/* NOTE: We are using gdbm in ndbm compatibility mode so we grab its
* version of ndbm.h
*/
// #include <gdbm.h>
#include <gdbm/ndbm.h>
#elif HAVE_LIBNDBM
#include <ndbm.h>
#else
#error "No DBM header file found. WTF?"
#endif

#if HAVE_SYS_SOCKET_H
#include <sys/socket.h>
#endif
#include <arpa/inet.h>

#include <fcntl.h>

#define MAX_DIGEST_SIZE 64

/* Check for the existence of the replay dbm file, and create it if it does
* not exist. Returns the number of db entries or -1 on error.
*/
int
replay_db_init(fko_srv_options_t *opts)
{
DBM *rpdb;
datum db_ent;

int db_count = 0;

rpdb = dbm_open(opts->config[CONF_DIGEST_FILE], O_RDWR|O_CREAT, S_IRUSR|S_IWUSR);

if(!rpdb)
{
perror("Unable to create digest cache file: ");
return(-1);
}

for (db_ent = dbm_firstkey(rpdb); db_ent.dptr != NULL; db_ent = dbm_nextkey(rpdb))
db_count++;

dbm_close(rpdb);

return(db_count);
}

/* Take an fko context, pull the digest and use it as the key to check the
* replay db (digest cache). Returns 1 if there was a match (a replay),
* 0 for no match, and -1 on error.
*/
int
replay_check(fko_srv_options_t *opts, fko_ctx_t ctx)
{
DBM *rpdb;
datum db_key, db_ent;

char ipaddr[INET_ADDRSTRLEN+1] = {0};

char *digest;
int digest_len, res;

res = fko_get_spa_digest(ctx, &digest);
if(res != FKO_SUCCESS)
{
log_msg(LOG_WARNING|LOG_STDERR, "Error getting digest from SPA data: %s",
fko_errstr(res));

return(-1);
}

digest_len = strlen(digest);

db_key.dptr = digest;
db_key.dsize = digest_len;

/* Check the db for the key
*/
rpdb = dbm_open(opts->config[CONF_DIGEST_FILE], O_RDWR, 0);

if(!rpdb)
{
log_msg(LOG_WARNING|LOG_STDERR, "Error opening digest_cache: %s",
strerror(errno));

return(-1);
}

db_ent = dbm_fetch(rpdb, db_key);

/* If the datum is not null, we have a match. Otherwise, we add
* this entry to the cache.
*/
if(db_ent.dptr != NULL)
{
/* Convert the IP to a human readable form
*/
inet_ntop(AF_INET, &(opts->spa_pkt.packet_src_ip),
ipaddr, INET_ADDRSTRLEN);

log_msg(LOG_WARNING|LOG_STDERR,
"Replay detected from source IP: %s", ipaddr);

res = 1;
} else {
db_ent.dptr = (char*)&(opts->spa_pkt.packet_src_ip);
db_ent.dsize = sizeof(opts->spa_pkt.packet_src_ip);

if(dbm_store(rpdb, db_key, db_ent, DBM_INSERT) != 0)
{
log_msg(LOG_WARNING|LOG_STDERR, "Error adding entry digest_cache: %s",
strerror(errno));

res = -1;
}

res = 0;
}

dbm_close(rpdb);

return(res);
}

/***EOF***/

0 comments on commit 8c1261c

Please sign in to comment.