summaryrefslogtreecommitdiff
path: root/src/libstrongswan/utils
diff options
context:
space:
mode:
Diffstat (limited to 'src/libstrongswan/utils')
-rw-r--r--src/libstrongswan/utils/backtrace.c495
-rw-r--r--src/libstrongswan/utils/backtrace.h32
-rw-r--r--src/libstrongswan/utils/capabilities.c453
-rw-r--r--src/libstrongswan/utils/capabilities.h137
-rw-r--r--src/libstrongswan/utils/chunk.c821
-rw-r--r--src/libstrongswan/utils/chunk.h375
-rw-r--r--src/libstrongswan/utils/debug.c112
-rw-r--r--src/libstrongswan/utils/debug.h154
-rw-r--r--src/libstrongswan/utils/enum.c81
-rw-r--r--src/libstrongswan/utils/enum.h136
-rw-r--r--src/libstrongswan/utils/enumerator.c558
-rw-r--r--src/libstrongswan/utils/enumerator.h158
-rw-r--r--src/libstrongswan/utils/hashtable.c426
-rw-r--r--src/libstrongswan/utils/hashtable.h122
-rw-r--r--src/libstrongswan/utils/host.c618
-rw-r--r--src/libstrongswan/utils/host.h219
-rw-r--r--src/libstrongswan/utils/identification.c155
-rw-r--r--src/libstrongswan/utils/identification.h15
-rw-r--r--src/libstrongswan/utils/integrity_checker.c321
-rw-r--r--src/libstrongswan/utils/integrity_checker.h110
-rw-r--r--src/libstrongswan/utils/leak_detective.c668
-rw-r--r--src/libstrongswan/utils/leak_detective.h16
-rw-r--r--src/libstrongswan/utils/linked_list.c574
-rw-r--r--src/libstrongswan/utils/linked_list.h302
-rw-r--r--src/libstrongswan/utils/optionsfrom.c16
-rw-r--r--src/libstrongswan/utils/printf_hook.c510
-rw-r--r--src/libstrongswan/utils/printf_hook.h247
-rw-r--r--src/libstrongswan/utils/settings.c1248
-rw-r--r--src/libstrongswan/utils/settings.h323
-rw-r--r--src/libstrongswan/utils/utils.c637
-rw-r--r--src/libstrongswan/utils/utils.h783
31 files changed, 7535 insertions, 3287 deletions
diff --git a/src/libstrongswan/utils/backtrace.c b/src/libstrongswan/utils/backtrace.c
index cb83d9830..93031908a 100644
--- a/src/libstrongswan/utils/backtrace.c
+++ b/src/libstrongswan/utils/backtrace.c
@@ -27,6 +27,8 @@
#include "backtrace.h"
+#include <utils/debug.h>
+
typedef struct private_backtrace_t private_backtrace_t;
/**
@@ -50,16 +52,344 @@ struct private_backtrace_t {
void *frames[];
};
+/**
+ * Forward declaration of method getter
+ */
+static backtrace_t get_methods();
+
+/**
+ * Write a format string with arguments to a FILE line, if it is NULL to DBG
+ */
+static void println(FILE *file, char *format, ...)
+{
+ char buf[512];
+ va_list args;
+
+ va_start(args, format);
+ if (file)
+ {
+ vfprintf(file, format, args);
+ fputs("\n", file);
+ }
+ else
+ {
+ vsnprintf(buf, sizeof(buf), format, args);
+ DBG1(DBG_LIB, "%s", buf);
+ }
+ va_end(args);
+}
+
+#ifdef HAVE_DLADDR
+
+/**
+ * Same as tty_escape_get(), but for a potentially NULL FILE*
+ */
+static char* esc(FILE *file, tty_escape_t escape)
+{
+ if (file)
+ {
+ return tty_escape_get(fileno(file), escape);
+ }
+ return "";
+}
+
+#ifdef HAVE_BFD_H
+
+#include <bfd.h>
+#include <collections/hashtable.h>
+#include <threading/mutex.h>
+
+/**
+ * Hashtable-cached bfd handle
+ */
+typedef struct {
+ /** binary file name on disk */
+ char *filename;
+ /** bfd handle */
+ bfd *abfd;
+ /** loaded symbols */
+ asymbol **syms;
+} bfd_entry_t;
+
+/**
+ * Destroy a bfd_entry
+ */
+static void bfd_entry_destroy(bfd_entry_t *this)
+{
+ free(this->filename);
+ free(this->syms);
+ bfd_close(this->abfd);
+ free(this);
+}
+
+/**
+ * Data to pass to find_addr()
+ */
+typedef struct {
+ /** used bfd entry */
+ bfd_entry_t *entry;
+ /** backtrace address */
+ bfd_vma vma;
+ /** stream to log to */
+ FILE *file;
+ /** TRUE if complete */
+ bool found;
+} bfd_find_data_t;
+
+/**
+ * bfd entry cache
+ */
+static hashtable_t *bfds;
+
+static mutex_t *bfd_mutex;
+
+/**
+ * Hashtable hash function
+ */
+static u_int bfd_hash(char *key)
+{
+ return chunk_hash(chunk_create(key, strlen(key)));
+}
+
+/**
+ * Hashtable equals function
+ */
+static bool bfd_equals(char *a, char *b)
+{
+ return streq(a, b);
+}
+
+/**
+ * See header.
+ */
+void backtrace_init()
+{
+ bfd_init();
+ bfds = hashtable_create((hashtable_hash_t)bfd_hash,
+ (hashtable_equals_t)bfd_equals, 8);
+ bfd_mutex = mutex_create(MUTEX_TYPE_DEFAULT);
+}
+
+/**
+ * See header.
+ */
+void backtrace_deinit()
+{
+ enumerator_t *enumerator;
+ bfd_entry_t *entry;
+ char *key;
+
+ enumerator = bfds->create_enumerator(bfds);
+ while (enumerator->enumerate(enumerator, &key, &entry))
+ {
+ bfds->remove_at(bfds, enumerator);
+ bfd_entry_destroy(entry);
+ }
+ enumerator->destroy(enumerator);
+
+ bfds->destroy(bfds);
+ bfd_mutex->destroy(bfd_mutex);
+}
+
+/**
+ * Find and print information to an address
+ */
+static void find_addr(bfd *abfd, asection *section, bfd_find_data_t *data)
+{
+ bfd_size_type size;
+ bfd_vma vma;
+ const char *source;
+ const char *function;
+ char fbuf[512] = "", sbuf[512] = "";
+ u_int line;
+
+ if (!data->found || (bfd_get_section_flags(abfd, section) & SEC_ALLOC) != 0)
+ {
+ vma = bfd_get_section_vma(abfd, section);
+ if (data->vma >= vma)
+ {
+ size = bfd_get_section_size(section);
+ if (data->vma < vma + size)
+ {
+ data->found = bfd_find_nearest_line(abfd, section,
+ data->entry->syms, data->vma - vma,
+ &source, &function, &line);
+ if (data->found)
+ {
+ if (source || function)
+ {
+ if (function)
+ {
+ snprintf(fbuf, sizeof(fbuf), "%s%s() ",
+ esc(data->file, TTY_FG_BLUE), function);
+ }
+ if (source)
+ {
+ snprintf(sbuf, sizeof(sbuf), "%s@ %s:%d",
+ esc(data->file, TTY_FG_GREEN), source, line);
+ }
+ println(data->file, " -> %s%s%s", fbuf, sbuf,
+ esc(data->file, TTY_FG_DEF));
+ }
+ }
+ }
+ }
+ }
+}
+
+/**
+ * Find a cached bfd entry, create'n'cache if not found
+ */
+static bfd_entry_t *get_bfd_entry(char *filename)
+{
+ bool dynamic = FALSE, ok = FALSE;
+ bfd_entry_t *entry;
+ long size;
+
+ /* check cache */
+ entry = bfds->get(bfds, filename);
+ if (entry)
+ {
+ return entry;
+ }
+
+ INIT(entry,
+ .abfd = bfd_openr(filename, NULL),
+ );
+
+ if (!entry->abfd)
+ {
+ free(entry);
+ return NULL;
+ }
+#ifdef BFD_DECOMPRESS
+ entry->abfd->flags |= BFD_DECOMPRESS;
+#endif
+ if (bfd_check_format(entry->abfd, bfd_archive) == 0 &&
+ bfd_check_format_matches(entry->abfd, bfd_object, NULL))
+ {
+ if (bfd_get_file_flags(entry->abfd) & HAS_SYMS)
+ {
+ size = bfd_get_symtab_upper_bound(entry->abfd);
+ if (size == 0)
+ {
+ size = bfd_get_dynamic_symtab_upper_bound(entry->abfd);
+ }
+ if (size >= 0)
+ {
+ entry->syms = malloc(size);
+ if (dynamic)
+ {
+ ok = bfd_canonicalize_dynamic_symtab(entry->abfd,
+ entry->syms) >= 0;
+ }
+ else
+ {
+ ok = bfd_canonicalize_symtab(entry->abfd,
+ entry->syms) >= 0;
+ }
+ }
+ }
+ }
+ if (ok)
+ {
+ entry->filename = strdup(filename);
+ bfds->put(bfds, entry->filename, entry);
+ return entry;
+ }
+ bfd_entry_destroy(entry);
+ return NULL;
+}
+
+/**
+ * Print the source file with line number to file, libbfd variant
+ */
+static void print_sourceline(FILE *file, char *filename, void *ptr, void *base)
+{
+ bfd_entry_t *entry;
+ bfd_find_data_t data = {
+ .file = file,
+ .vma = (uintptr_t)ptr,
+ };
+ bool old = FALSE;
+
+ bfd_mutex->lock(bfd_mutex);
+ if (lib->leak_detective)
+ {
+ old = lib->leak_detective->set_state(lib->leak_detective, FALSE);
+ }
+ entry = get_bfd_entry(filename);
+ if (entry)
+ {
+ data.entry = entry;
+ bfd_map_over_sections(entry->abfd, (void*)find_addr, &data);
+ }
+ if (lib->leak_detective)
+ {
+ lib->leak_detective->set_state(lib->leak_detective, old);
+ }
+ bfd_mutex->unlock(bfd_mutex);
+}
+
+#else /* !HAVE_BFD_H */
+
+void backtrace_init() {}
+void backtrace_deinit() {}
+
+/**
+ * Print the source file with line number to file, slow addr2line variant
+ */
+static void print_sourceline(FILE *file, char *filename, void *ptr, void* base)
+{
+ char buf[1024];
+ FILE *output;
+ int c, i = 0;
+
+#ifdef __APPLE__
+ snprintf(buf, sizeof(buf), "atos -o %s -l %p %p 2>&1 | tail -n1",
+ filename, base, ptr);
+#else /* !__APPLE__ */
+ snprintf(buf, sizeof(buf), "addr2line -e %s %p", filename, ptr);
+#endif /* __APPLE__ */
+
+
+ output = popen(buf, "r");
+ if (output)
+ {
+ while (i < sizeof(buf))
+ {
+ c = getc(output);
+ if (c == '\n' || c == EOF)
+ {
+ buf[i++] = 0;
+ break;
+ }
+ buf[i++] = c;
+ }
+ pclose(output);
+
+ println(file, " -> %s%s%s", esc(file, TTY_FG_GREEN), buf,
+ esc(file, TTY_FG_DEF));
+ }
+}
+
+#endif /* HAVE_BFD_H */
+
+#else /* !HAVE_DLADDR */
+
+void backtrace_init() {}
+void backtrace_deinit() {}
+
+#endif /* HAVE_DLADDR */
+
METHOD(backtrace_t, log_, void,
private_backtrace_t *this, FILE *file, bool detailed)
{
-#ifdef HAVE_BACKTRACE
+#if defined(HAVE_BACKTRACE) || defined(HAVE_LIBUNWIND_H)
size_t i;
- char **strings;
-
- strings = backtrace_symbols(this->frames, this->frame_count);
+ char **strings = NULL;
- fprintf(file, " dumping %d stack frame addresses:\n", this->frame_count);
+ println(file, " dumping %d stack frame addresses:", this->frame_count);
for (i = 0; i < this->frame_count; i++)
{
#ifdef HAVE_DLADDR
@@ -67,9 +397,6 @@ METHOD(backtrace_t, log_, void,
if (dladdr(this->frames[i], &info))
{
- char cmd[1024];
- FILE *output;
- int c;
void *ptr = this->frames[i];
if (strstr(info.dli_fname, ".so"))
@@ -78,53 +405,48 @@ METHOD(backtrace_t, log_, void,
}
if (info.dli_sname)
{
- fprintf(file, " \e[33m%s\e[0m @ %p (\e[31m%s\e[0m+0x%tx) [%p]\n",
- info.dli_fname, info.dli_fbase, info.dli_sname,
- this->frames[i] - info.dli_saddr, this->frames[i]);
+ println(file, " %s%s%s @ %p (%s%s%s+0x%tx) [%p]",
+ esc(file, TTY_FG_YELLOW), info.dli_fname,
+ esc(file, TTY_FG_DEF), info.dli_fbase,
+ esc(file, TTY_FG_RED), info.dli_sname,
+ esc(file, TTY_FG_DEF), this->frames[i] - info.dli_saddr,
+ this->frames[i]);
}
else
{
- fprintf(file, " \e[33m%s\e[0m @ %p [%p]\n", info.dli_fname,
- info.dli_fbase, this->frames[i]);
+ println(file, " %s%s%s @ %p [%p]",
+ esc(file, TTY_FG_YELLOW), info.dli_fname,
+ esc(file, TTY_FG_DEF), info.dli_fbase, this->frames[i]);
}
- if (detailed)
+ if (detailed && info.dli_fname[0])
{
- fprintf(file, " -> \e[32m");
- snprintf(cmd, sizeof(cmd), "addr2line -e %s %p",
- info.dli_fname, ptr);
- output = popen(cmd, "r");
- if (output)
- {
- while (TRUE)
- {
- c = getc(output);
- if (c == '\n' || c == EOF)
- {
- break;
- }
- fputc(c, file);
- }
- pclose(output);
- }
- else
- {
- #endif /* HAVE_DLADDR */
- fprintf(file, " %s\n", strings[i]);
- #ifdef HAVE_DLADDR
- }
- fprintf(file, "\n\e[0m");
+ print_sourceline(file, (char*)info.dli_fname,
+ ptr, info.dli_fbase);
}
}
else
+#endif /* HAVE_DLADDR */
{
- fprintf(file, " %s\n", strings[i]);
+#ifdef HAVE_BACKTRACE
+ if (!strings)
+ {
+ strings = backtrace_symbols(this->frames, this->frame_count);
+ }
+ if (strings)
+ {
+ println(file, " %s", strings[i]);
+ }
+ else
+#endif /* HAVE_BACKTRACE */
+ {
+ println(file, " %p", this->frames[i]);
+ }
}
-#endif /* HAVE_DLADDR */
}
- free (strings);
-#else /* !HAVE_BACKTRACE */
- fprintf(file, "C library does not support backtrace().\n");
-#endif /* HAVE_BACKTRACE */
+ free(strings);
+#else /* !HAVE_BACKTRACE && !HAVE_LIBUNWIND_H */
+ println(file, "no support for backtrace()/libunwind");
+#endif /* HAVE_BACKTRACE/HAVE_LIBUNWIND_H */
}
METHOD(backtrace_t, contains_function, bool,
@@ -214,12 +536,69 @@ METHOD(backtrace_t, create_frame_enumerator, enumerator_t*,
return &enumerator->public;
}
+METHOD(backtrace_t, clone, backtrace_t*,
+ private_backtrace_t *this)
+{
+ private_backtrace_t *clone;
+
+ clone = malloc(sizeof(private_backtrace_t) +
+ this->frame_count * sizeof(void*));
+ memcpy(clone->frames, this->frames, this->frame_count * sizeof(void*));
+ clone->frame_count = this->frame_count;
+
+ clone->public = get_methods();
+
+ return &clone->public;
+}
+
METHOD(backtrace_t, destroy, void,
private_backtrace_t *this)
{
free(this);
}
+#ifdef HAVE_LIBUNWIND_H
+#define UNW_LOCAL_ONLY
+#include <libunwind.h>
+
+/**
+ * libunwind variant for glibc backtrace()
+ */
+static inline int backtrace_unwind(void **frames, int count)
+{
+ unw_context_t context;
+ unw_cursor_t cursor;
+ unw_word_t ip;
+ int depth = 0;
+
+ unw_getcontext(&context);
+ unw_init_local(&cursor, &context);
+ do
+ {
+ unw_get_reg(&cursor, UNW_REG_IP, &ip);
+ frames[depth++] = (void*)ip;
+ }
+ while (depth < count && unw_step(&cursor) > 0);
+
+ return depth;
+}
+#endif /* HAVE_UNWIND */
+
+/**
+ * Get implementation methods of backtrace_t
+ */
+static backtrace_t get_methods()
+{
+ return (backtrace_t) {
+ .log = _log_,
+ .contains_function = _contains_function,
+ .equals = _equals,
+ .clone = _clone,
+ .create_frame_enumerator = _create_frame_enumerator,
+ .destroy = _destroy,
+ };
+}
+
/**
* See header
*/
@@ -229,7 +608,9 @@ backtrace_t *backtrace_create(int skip)
void *frames[50];
int frame_count = 0;
-#ifdef HAVE_BACKTRACE
+#ifdef HAVE_LIBUNWIND_H
+ frame_count = backtrace_unwind(frames, countof(frames));
+#elif defined(HAVE_BACKTRACE)
frame_count = backtrace(frames, countof(frames));
#endif /* HAVE_BACKTRACE */
frame_count = max(frame_count - skip, 0);
@@ -237,14 +618,24 @@ backtrace_t *backtrace_create(int skip)
memcpy(this->frames, frames + skip, frame_count * sizeof(void*));
this->frame_count = frame_count;
- this->public = (backtrace_t) {
- .log = _log_,
- .contains_function = _contains_function,
- .equals = _equals,
- .create_frame_enumerator = _create_frame_enumerator,
- .destroy = _destroy,
- };
+ this->public = get_methods();
return &this->public;
}
+/**
+ * See header
+ */
+void backtrace_dump(char *label, FILE *file, bool detailed)
+{
+ backtrace_t *backtrace;
+
+ backtrace = backtrace_create(2);
+
+ if (label)
+ {
+ println(file, "Debug backtrace: %s", label);
+ }
+ backtrace->log(backtrace, file, detailed);
+ backtrace->destroy(backtrace);
+}
diff --git a/src/libstrongswan/utils/backtrace.h b/src/libstrongswan/utils/backtrace.h
index 9d59d2503..416f58898 100644
--- a/src/libstrongswan/utils/backtrace.h
+++ b/src/libstrongswan/utils/backtrace.h
@@ -35,7 +35,10 @@ struct backtrace_t {
/**
* Log the backtrace to a FILE stream.
*
- * @param file FILE to log backtrace to
+ * If no file pointer is given, the backtrace is reported over the debug
+ * framework to the registered dbg() callback function.
+ *
+ * @param file FILE to log backtrace to, NULL for dbg() function
* @param detailed TRUE to resolve line/file using addr2line (slow)
*/
void (*log)(backtrace_t *this, FILE *file, bool detailed);
@@ -56,6 +59,14 @@ struct backtrace_t {
* @return TRUE if backtraces are equal
*/
bool (*equals)(backtrace_t *this, backtrace_t *other);
+
+ /**
+ * Create a copy of this backtrace.
+ *
+ * @return cloned copy
+ */
+ backtrace_t* (*clone)(backtrace_t *this);
+
/**
* Create an enumerator over the stack frame addresses.
*
@@ -77,4 +88,23 @@ struct backtrace_t {
*/
backtrace_t *backtrace_create(int skip);
+/**
+ * Create a backtrace, dump it and clean it up.
+ *
+ * @param label description to print for this backtrace, or NULL
+ * @param file FILE to log backtrace to, NULL to dbg() function
+ * @param detailed TRUE to resolve line/file using addr2line (slow)
+ */
+void backtrace_dump(char *label, FILE *file, bool detailed);
+
+/**
+ * Initialize backtracing framework.
+ */
+void backtrace_init();
+
+/**
+ * Deinitialize backtracing framework.
+ */
+void backtrace_deinit();
+
#endif /** BACKTRACE_H_ @}*/
diff --git a/src/libstrongswan/utils/capabilities.c b/src/libstrongswan/utils/capabilities.c
new file mode 100644
index 000000000..c5e90b6c3
--- /dev/null
+++ b/src/libstrongswan/utils/capabilities.c
@@ -0,0 +1,453 @@
+/*
+ * Copyright (C) 2012-2013 Tobias Brunner
+ * Hochschule fuer Technik Rapperswil
+ * Copyright (C) 2012 Martin Willi
+ * Copyright (C) 2012 revosec AG
+ *
+ * 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. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * 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.
+ */
+
+#include "capabilities.h"
+
+#include <errno.h>
+#include <string.h>
+#include <sys/types.h>
+#include <pwd.h>
+#include <grp.h>
+#include <unistd.h>
+#ifdef HAVE_PRCTL
+# include <sys/prctl.h>
+#endif /* HAVE_PRCTL */
+
+#include <utils/debug.h>
+
+#if !defined(HAVE_GETPWNAM_R) || \
+ !defined(HAVE_GETGRNAM_R) || \
+ !defined(HAVE_GETPWUID_R)
+# include <threading/mutex.h>
+# define EMULATE_R_FUNCS
+#endif
+
+typedef struct private_capabilities_t private_capabilities_t;
+
+/**
+ * Private data of an capabilities_t object.
+ */
+struct private_capabilities_t {
+
+ /**
+ * Public capabilities_t interface.
+ */
+ capabilities_t public;
+
+ /**
+ * user ID to switch during rights dropping
+ */
+ uid_t uid;
+
+ /**
+ * group ID to switch during rights dropping
+ */
+ gid_t gid;
+
+ /**
+ * capabilities to keep
+ */
+#ifdef CAPABILITIES_LIBCAP
+ cap_t caps;
+#endif /* CAPABILITIES_LIBCAP */
+#ifdef CAPABILITIES_NATIVE
+ struct __user_cap_data_struct caps[2];
+#endif /* CAPABILITIES_NATIVE */
+
+#ifdef EMULATE_R_FUNCS
+ /**
+ * mutex to emulate get(pw|gr)nam_r functions
+ */
+ mutex_t *mutex;
+#endif
+};
+
+/**
+ * Returns TRUE if the current process/user is member of the given group
+ */
+static bool has_group(gid_t group)
+{
+ gid_t *groups;
+ long ngroups, i;
+ bool found = FALSE;
+
+ if (group == getegid())
+ { /* it's unspecified if this is part of the list below or not */
+ return TRUE;
+ }
+ ngroups = sysconf(_SC_NGROUPS_MAX);
+ if (ngroups == -1)
+ {
+ DBG1(DBG_LIB, "getting groups for current process failed: %s",
+ strerror(errno));
+ return FALSE;
+ }
+ groups = calloc(ngroups + 1, sizeof(gid_t));
+ ngroups = getgroups(ngroups, groups);
+ if (ngroups == -1)
+ {
+ DBG1(DBG_LIB, "getting groups for current process failed: %s",
+ strerror(errno));
+ free(groups);
+ return FALSE;
+ }
+ for (i = 0; i < ngroups; i++)
+ {
+ if (group == groups[i])
+ {
+ found = TRUE;
+ break;
+ }
+ }
+ free(groups);
+ return found;
+}
+
+/**
+ * Verify that the current process has the given capability
+ */
+static bool has_capability(private_capabilities_t *this, u_int cap,
+ bool *ignore)
+{
+ if (cap == CAP_CHOWN)
+ { /* if new files/UNIX sockets are created they should be owned by the
+ * configured user and group. This requires a call to chown(2). But
+ * CAP_CHOWN is not always required. */
+ if (!this->uid || geteuid() == this->uid)
+ { /* if the owner does not change CAP_CHOWN is not needed */
+ if (!this->gid || has_group(this->gid))
+ { /* the same applies if the owner is a member of the group */
+ if (ignore)
+ { /* we don't have to keep this, if requested */
+ *ignore = TRUE;
+ }
+ return TRUE;
+ }
+ }
+ }
+#ifndef CAPABILITIES
+ /* if we can't check the actual capabilities assume only root has it */
+ return geteuid() == 0;
+#endif /* !CAPABILITIES */
+#ifdef CAPABILITIES_LIBCAP
+ cap_flag_value_t val;
+ cap_t caps;
+ bool ok;
+
+ caps = cap_get_proc();
+ if (!caps)
+ {
+ return FALSE;
+ }
+ ok = cap_get_flag(caps, cap, CAP_PERMITTED, &val) == 0 && val == CAP_SET;
+ cap_free(caps);
+ return ok;
+#endif /* CAPABILITIES_LIBCAP */
+#ifdef CAPABILITIES_NATIVE
+ struct __user_cap_header_struct header = {
+#if defined(_LINUX_CAPABILITY_VERSION_3)
+ .version = _LINUX_CAPABILITY_VERSION_3,
+#elif defined(_LINUX_CAPABILITY_VERSION_2)
+ .version = _LINUX_CAPABILITY_VERSION_2,
+#elif defined(_LINUX_CAPABILITY_VERSION_1)
+ .version = _LINUX_CAPABILITY_VERSION_1,
+#else
+ .version = _LINUX_CAPABILITY_VERSION,
+#endif
+ };
+ struct __user_cap_data_struct caps[2];
+ int i = 0;
+
+ if (cap >= 32)
+ {
+ i++;
+ cap -= 32;
+ }
+ return capget(&header, caps) == 0 && caps[i].permitted & (1 << cap);
+#endif /* CAPABILITIES_NATIVE */
+}
+
+/**
+ * Keep the given capability if it is held by the current process. Returns
+ * FALSE, if this is not the case.
+ */
+static bool keep_capability(private_capabilities_t *this, u_int cap)
+{
+#ifdef CAPABILITIES_LIBCAP
+ cap_set_flag(this->caps, CAP_EFFECTIVE, 1, &cap, CAP_SET);
+ cap_set_flag(this->caps, CAP_INHERITABLE, 1, &cap, CAP_SET);
+ cap_set_flag(this->caps, CAP_PERMITTED, 1, &cap, CAP_SET);
+#endif /* CAPABILITIES_LIBCAP */
+#ifdef CAPABILITIES_NATIVE
+ int i = 0;
+
+ if (cap >= 32)
+ {
+ i++;
+ cap -= 32;
+ }
+ this->caps[i].effective |= 1 << cap;
+ this->caps[i].permitted |= 1 << cap;
+ this->caps[i].inheritable |= 1 << cap;
+#endif /* CAPABILITIES_NATIVE */
+ return TRUE;
+}
+
+METHOD(capabilities_t, keep, bool,
+ private_capabilities_t *this, u_int cap)
+{
+ bool ignore = FALSE;
+
+ if (!has_capability(this, cap, &ignore))
+ {
+ return FALSE;
+ }
+ else if (ignore)
+ { /* don't keep capabilities that are not required */
+ return TRUE;
+ }
+ return keep_capability(this, cap);
+}
+
+METHOD(capabilities_t, check, bool,
+ private_capabilities_t *this, u_int cap)
+{
+ return has_capability(this, cap, NULL);
+}
+
+METHOD(capabilities_t, get_uid, uid_t,
+ private_capabilities_t *this)
+{
+ return this->uid ?: geteuid();
+}
+
+METHOD(capabilities_t, get_gid, gid_t,
+ private_capabilities_t *this)
+{
+ return this->gid ?: getegid();
+}
+
+METHOD(capabilities_t, set_uid, void,
+ private_capabilities_t *this, uid_t uid)
+{
+ this->uid = uid;
+}
+
+METHOD(capabilities_t, set_gid, void,
+ private_capabilities_t *this, gid_t gid)
+{
+ this->gid = gid;
+}
+
+METHOD(capabilities_t, resolve_uid, bool,
+ private_capabilities_t *this, char *username)
+{
+ struct passwd *pwp;
+ int err;
+
+#ifdef HAVE_GETPWNAM_R
+ struct passwd passwd;
+ char buf[1024];
+
+ err = getpwnam_r(username, &passwd, buf, sizeof(buf), &pwp);
+ if (pwp)
+ {
+ this->uid = pwp->pw_uid;
+ }
+#else /* HAVE GETPWNAM_R */
+ this->mutex->lock(this->mutex);
+ pwp = getpwnam(username);
+ if (pwp)
+ {
+ this->uid = pwp->pw_uid;
+ }
+ err = errno;
+ this->mutex->unlock(this->mutex);
+#endif /* HAVE GETPWNAM_R */
+ if (pwp)
+ {
+ return TRUE;
+ }
+ DBG1(DBG_LIB, "resolving user '%s' failed: %s", username,
+ err ? strerror(err) : "user not found");
+ return FALSE;
+}
+
+METHOD(capabilities_t, resolve_gid, bool,
+ private_capabilities_t *this, char *groupname)
+{
+ struct group *grp;
+ int err;
+
+#ifdef HAVE_GETGRNAM_R
+ struct group group;
+ char buf[1024];
+
+ err = getgrnam_r(groupname, &group, buf, sizeof(buf), &grp);
+ if (grp)
+ {
+ this->gid = grp->gr_gid;
+ }
+#else /* HAVE_GETGRNAM_R */
+ this->mutex->lock(this->mutex);
+ grp = getgrnam(groupname);
+ if (grp)
+ {
+ this->gid = grp->gr_gid;
+ }
+ err = errno;
+ this->mutex->unlock(this->mutex);
+#endif /* HAVE_GETGRNAM_R */
+ if (grp)
+ {
+ return TRUE;
+ }
+ DBG1(DBG_LIB, "resolving user '%s' failed: %s", groupname,
+ err ? strerror(err) : "group not found");
+ return FALSE;
+}
+
+/**
+ * Initialize supplementary groups for unprivileged user
+ */
+static bool init_supplementary_groups(private_capabilities_t *this)
+{
+ struct passwd *pwp;
+ int res = -1;
+
+#ifdef HAVE_GETPWUID_R
+ struct passwd pwd;
+ char buf[1024];
+
+ if (getpwuid_r(this->uid, &pwd, buf, sizeof(buf), &pwp) == 0 && pwp)
+ {
+ res = initgroups(pwp->pw_name, this->gid);
+ }
+#else /* HAVE_GETPWUID_R */
+ this->mutex->lock(this->mutex);
+ pwp = getpwuid(this->uid);
+ if (pwp)
+ {
+ res = initgroups(pwp->pw_name, this->gid);
+ }
+ this->mutex->unlock(this->mutex);
+#endif /* HAVE_GETPWUID_R */
+ return res == 0;
+}
+
+METHOD(capabilities_t, drop, bool,
+ private_capabilities_t *this)
+{
+#ifdef HAVE_PRCTL
+ prctl(PR_SET_KEEPCAPS, 1, 0, 0, 0);
+#endif
+
+ if (this->uid && !init_supplementary_groups(this))
+ {
+ DBG1(DBG_LIB, "initializing supplementary groups for %u failed",
+ this->uid);
+ return FALSE;
+ }
+ if (this->gid && setgid(this->gid) != 0)
+ {
+ DBG1(DBG_LIB, "change to unprivileged group %u failed: %s",
+ this->gid, strerror(errno));
+ return FALSE;
+ }
+ if (this->uid && setuid(this->uid) != 0)
+ {
+ DBG1(DBG_LIB, "change to unprivileged user %u failed: %s",
+ this->uid, strerror(errno));
+ return FALSE;
+ }
+
+#ifdef CAPABILITIES_LIBCAP
+ if (cap_set_proc(this->caps) != 0)
+ {
+ DBG1(DBG_LIB, "dropping capabilities failed: %s", strerror(errno));
+ return FALSE;
+ }
+#endif /* CAPABILITIES_LIBCAP */
+#ifdef CAPABILITIES_NATIVE
+ struct __user_cap_header_struct header = {
+#if defined(_LINUX_CAPABILITY_VERSION_3)
+ .version = _LINUX_CAPABILITY_VERSION_3,
+#elif defined(_LINUX_CAPABILITY_VERSION_2)
+ .version = _LINUX_CAPABILITY_VERSION_2,
+#elif defined(_LINUX_CAPABILITY_VERSION_1)
+ .version = _LINUX_CAPABILITY_VERSION_1,
+#else
+ .version = _LINUX_CAPABILITY_VERSION,
+#endif
+ };
+ if (capset(&header, this->caps) != 0)
+ {
+ DBG1(DBG_LIB, "dropping capabilities failed: %s", strerror(errno));
+ return FALSE;
+ }
+#endif /* CAPABILITIES_NATIVE */
+#ifdef CAPABILITIES
+ DBG1(DBG_LIB, "dropped capabilities, running as uid %u, gid %u",
+ geteuid(), getegid());
+#endif /* CAPABILITIES */
+ return TRUE;
+}
+
+METHOD(capabilities_t, destroy, void,
+ private_capabilities_t *this)
+{
+#ifdef EMULATE_R_FUNCS
+ this->mutex->destroy(this->mutex);
+#endif /* EMULATE_R_FUNCS */
+#ifdef CAPABILITIES_LIBCAP
+ cap_free(this->caps);
+#endif /* CAPABILITIES_LIBCAP */
+ free(this);
+}
+
+/**
+ * See header
+ */
+capabilities_t *capabilities_create()
+{
+ private_capabilities_t *this;
+
+ INIT(this,
+ .public = {
+ .keep = _keep,
+ .check = _check,
+ .get_uid = _get_uid,
+ .get_gid = _get_gid,
+ .set_uid = _set_uid,
+ .set_gid = _set_gid,
+ .resolve_uid = _resolve_uid,
+ .resolve_gid = _resolve_gid,
+ .drop = _drop,
+ .destroy = _destroy,
+ },
+ );
+
+#ifdef CAPABILITIES_LIBCAP
+ this->caps = cap_init();
+#endif /* CAPABILITIES_LIBCAP */
+
+#ifdef EMULATE_R_FUNCS
+ this->mutex = mutex_create(MUTEX_TYPE_DEFAULT);
+#endif /* EMULATE_R_FUNCS */
+
+ return &this->public;
+}
diff --git a/src/libstrongswan/utils/capabilities.h b/src/libstrongswan/utils/capabilities.h
new file mode 100644
index 000000000..fe11a4dfc
--- /dev/null
+++ b/src/libstrongswan/utils/capabilities.h
@@ -0,0 +1,137 @@
+/*
+ * Copyright (C) 2013 Tobias Brunner
+ * Hochschule fuer Technik Rapperswil
+ * Copyright (C) 2012 Martin Willi
+ * Copyright (C) 2012 revosec AG
+ *
+ * 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. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * 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.
+ */
+
+/**
+ * @defgroup capabilities capabilities
+ * @{ @ingroup utils
+ */
+
+#ifndef CAPABILITIES_H_
+#define CAPABILITIES_H_
+
+typedef struct capabilities_t capabilities_t;
+
+#include <library.h>
+#ifdef HAVE_SYS_CAPABILITY_H
+# include <sys/capability.h>
+#elif defined(CAPABILITIES_NATIVE)
+# include <linux/capability.h>
+#endif
+
+#ifndef CAP_CHOWN
+# define CAP_CHOWN 0
+#endif
+#ifndef CAP_NET_BIND_SERVICE
+# define CAP_NET_BIND_SERVICE 10
+#endif
+#ifndef CAP_NET_ADMIN
+# define CAP_NET_ADMIN 12
+#endif
+#ifndef CAP_NET_RAW
+# define CAP_NET_RAW 13
+#endif
+
+/**
+ * POSIX capability dropping abstraction layer.
+ */
+struct capabilities_t {
+
+ /**
+ * Register a capability to keep while calling drop(). Verifies that the
+ * capability is currently held.
+ *
+ * @note CAP_CHOWN is handled specially as it might not be required.
+ *
+ * @param cap capability to keep
+ * @return FALSE if the capability is currently not held
+ */
+ bool (*keep)(capabilities_t *this,
+ u_int cap) __attribute__((warn_unused_result));
+
+ /**
+ * Check if the given capability is currently held.
+ *
+ * @note CAP_CHOWN is handled specially as it might not be required.
+ *
+ * @param cap capability to check
+ * @return TRUE if the capability is currently held
+ */
+ bool (*check)(capabilities_t *this, u_int cap);
+
+ /**
+ * Get the user ID set through set_uid/resolve_uid.
+ *
+ * @return currently set user ID
+ */
+ uid_t (*get_uid)(capabilities_t *this);
+
+ /**
+ * Get the group ID set through set_gid/resolve_gid.
+ *
+ * @return currently set group ID
+ */
+ gid_t (*get_gid)(capabilities_t *this);
+
+ /**
+ * Set the numerical user ID to use during rights dropping.
+ *
+ * @param uid user ID to use
+ */
+ void (*set_uid)(capabilities_t *this, uid_t uid);
+
+ /**
+ * Set the numerical group ID to use during rights dropping.
+ *
+ * @param gid group ID to use
+ */
+ void (*set_gid)(capabilities_t *this, gid_t gid);
+
+ /**
+ * Resolve a username and set the user ID accordingly.
+ *
+ * @param username username get the uid for
+ * @return TRUE if username resolved and uid set
+ */
+ bool (*resolve_uid)(capabilities_t *this, char *username);
+
+ /**
+ * Resolve a groupname and set the group ID accordingly.
+ *
+ * @param groupname groupname to get the gid for
+ * @return TRUE if groupname resolved and gid set
+ */
+ bool (*resolve_gid)(capabilities_t *this, char *groupname);
+
+ /**
+ * Drop all capabilities not previously passed to keep(), switch to UID/GID.
+ *
+ * @return TRUE if capability drop successful
+ */
+ bool (*drop)(capabilities_t *this);
+
+ /**
+ * Destroy a capabilities_t.
+ */
+ void (*destroy)(capabilities_t *this);
+};
+
+/**
+ * Create a capabilities instance.
+ */
+capabilities_t *capabilities_create();
+
+#endif /** CAPABILITIES_H_ @}*/
diff --git a/src/libstrongswan/utils/chunk.c b/src/libstrongswan/utils/chunk.c
new file mode 100644
index 000000000..04f3eea7d
--- /dev/null
+++ b/src/libstrongswan/utils/chunk.c
@@ -0,0 +1,821 @@
+/*
+ * Copyright (C) 2008-2013 Tobias Brunner
+ * Copyright (C) 2005-2006 Martin Willi
+ * Copyright (C) 2005 Jan Hutter
+ * Hochschule fuer Technik Rapperswil
+ *
+ * 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. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * 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.
+ */
+
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <errno.h>
+#include <pthread.h>
+#include <ctype.h>
+
+#include "chunk.h"
+#include "debug.h"
+
+/**
+ * Empty chunk.
+ */
+chunk_t chunk_empty = { NULL, 0 };
+
+/**
+ * Described in header.
+ */
+chunk_t chunk_create_clone(u_char *ptr, chunk_t chunk)
+{
+ chunk_t clone = chunk_empty;
+
+ if (chunk.ptr && chunk.len > 0)
+ {
+ clone.ptr = ptr;
+ clone.len = chunk.len;
+ memcpy(clone.ptr, chunk.ptr, chunk.len);
+ }
+
+ return clone;
+}
+
+/**
+ * Described in header.
+ */
+size_t chunk_length(const char* mode, ...)
+{
+ va_list chunks;
+ size_t length = 0;
+
+ va_start(chunks, mode);
+ while (TRUE)
+ {
+ switch (*mode++)
+ {
+ case 'm':
+ case 'c':
+ case 's':
+ {
+ chunk_t ch = va_arg(chunks, chunk_t);
+ length += ch.len;
+ continue;
+ }
+ default:
+ break;
+ }
+ break;
+ }
+ va_end(chunks);
+ return length;
+}
+
+/**
+ * Described in header.
+ */
+chunk_t chunk_create_cat(u_char *ptr, const char* mode, ...)
+{
+ va_list chunks;
+ chunk_t construct = chunk_create(ptr, 0);
+
+ va_start(chunks, mode);
+ while (TRUE)
+ {
+ bool free_chunk = FALSE, clear_chunk = FALSE;
+ chunk_t ch;
+
+ switch (*mode++)
+ {
+ case 's':
+ clear_chunk = TRUE;
+ /* FALL */
+ case 'm':
+ free_chunk = TRUE;
+ /* FALL */
+ case 'c':
+ ch = va_arg(chunks, chunk_t);
+ memcpy(ptr, ch.ptr, ch.len);
+ ptr += ch.len;
+ construct.len += ch.len;
+ if (clear_chunk)
+ {
+ chunk_clear(&ch);
+ }
+ else if (free_chunk)
+ {
+ free(ch.ptr);
+ }
+ continue;
+ default:
+ break;
+ }
+ break;
+ }
+ va_end(chunks);
+
+ return construct;
+}
+
+/**
+ * Described in header.
+ */
+void chunk_split(chunk_t chunk, const char *mode, ...)
+{
+ va_list chunks;
+ u_int len;
+ chunk_t *ch;
+
+ va_start(chunks, mode);
+ while (TRUE)
+ {
+ if (*mode == '\0')
+ {
+ break;
+ }
+ len = va_arg(chunks, u_int);
+ ch = va_arg(chunks, chunk_t*);
+ /* a null chunk means skip len bytes */
+ if (ch == NULL)
+ {
+ chunk = chunk_skip(chunk, len);
+ continue;
+ }
+ switch (*mode++)
+ {
+ case 'm':
+ {
+ ch->len = min(chunk.len, len);
+ if (ch->len)
+ {
+ ch->ptr = chunk.ptr;
+ }
+ else
+ {
+ ch->ptr = NULL;
+ }
+ chunk = chunk_skip(chunk, ch->len);
+ continue;
+ }
+ case 'a':
+ {
+ ch->len = min(chunk.len, len);
+ if (ch->len)
+ {
+ ch->ptr = malloc(ch->len);
+ memcpy(ch->ptr, chunk.ptr, ch->len);
+ }
+ else
+ {
+ ch->ptr = NULL;
+ }
+ chunk = chunk_skip(chunk, ch->len);
+ continue;
+ }
+ case 'c':
+ {
+ ch->len = min(ch->len, chunk.len);
+ ch->len = min(ch->len, len);
+ if (ch->len)
+ {
+ memcpy(ch->ptr, chunk.ptr, ch->len);
+ }
+ else
+ {
+ ch->ptr = NULL;
+ }
+ chunk = chunk_skip(chunk, ch->len);
+ continue;
+ }
+ default:
+ break;
+ }
+ break;
+ }
+ va_end(chunks);
+}
+
+/**
+ * Described in header.
+ */
+bool chunk_write(chunk_t chunk, char *path, char *label, mode_t mask, bool force)
+{
+ mode_t oldmask;
+ FILE *fd;
+ bool good = FALSE;
+
+ if (!force && access(path, F_OK) == 0)
+ {
+ DBG1(DBG_LIB, " %s file '%s' already exists", label, path);
+ return FALSE;
+ }
+ oldmask = umask(mask);
+ fd = fopen(path, "w");
+ if (fd)
+ {
+ if (fwrite(chunk.ptr, sizeof(u_char), chunk.len, fd) == chunk.len)
+ {
+ DBG1(DBG_LIB, " written %s file '%s' (%d bytes)",
+ label, path, chunk.len);
+ good = TRUE;
+ }
+ else
+ {
+ DBG1(DBG_LIB, " writing %s file '%s' failed: %s",
+ label, path, strerror(errno));
+ }
+ fclose(fd);
+ }
+ else
+ {
+ DBG1(DBG_LIB, " could not open %s file '%s': %s", label, path,
+ strerror(errno));
+ }
+ umask(oldmask);
+ return good;
+}
+
+
+/** hex conversion digits */
+static char hexdig_upper[] = "0123456789ABCDEF";
+static char hexdig_lower[] = "0123456789abcdef";
+
+/**
+ * Described in header.
+ */
+chunk_t chunk_to_hex(chunk_t chunk, char *buf, bool uppercase)
+{
+ int i, len;
+ char *hexdig = hexdig_lower;
+
+ if (uppercase)
+ {
+ hexdig = hexdig_upper;
+ }
+
+ len = chunk.len * 2;
+ if (!buf)
+ {
+ buf = malloc(len + 1);
+ }
+ buf[len] = '\0';
+
+ for (i = 0; i < chunk.len; i++)
+ {
+ buf[i*2] = hexdig[(chunk.ptr[i] >> 4) & 0xF];
+ buf[i*2+1] = hexdig[(chunk.ptr[i] ) & 0xF];
+ }
+ return chunk_create(buf, len);
+}
+
+/**
+ * convert a signle hex character to its binary value
+ */
+static char hex2bin(char hex)
+{
+ switch (hex)
+ {
+ case '0' ... '9':
+ return hex - '0';
+ case 'A' ... 'F':
+ return hex - 'A' + 10;
+ case 'a' ... 'f':
+ return hex - 'a' + 10;
+ default:
+ return 0;
+ }
+}
+
+/**
+ * Described in header.
+ */
+chunk_t chunk_from_hex(chunk_t hex, char *buf)
+{
+ int i, len;
+ u_char *ptr;
+ bool odd = FALSE;
+
+ /* subtract the number of optional ':' separation characters */
+ len = hex.len;
+ ptr = hex.ptr;
+ for (i = 0; i < hex.len; i++)
+ {
+ if (*ptr++ == ':')
+ {
+ len--;
+ }
+ }
+
+ /* compute the number of binary bytes */
+ if (len % 2)
+ {
+ odd = TRUE;
+ len++;
+ }
+ len /= 2;
+
+ /* allocate buffer memory unless provided by caller */
+ if (!buf)
+ {
+ buf = malloc(len);
+ }
+
+ /* buffer is filled from the right */
+ memset(buf, 0, len);
+ hex.ptr += hex.len;
+
+ for (i = len - 1; i >= 0; i--)
+ {
+ /* skip separation characters */
+ if (*(--hex.ptr) == ':')
+ {
+ --hex.ptr;
+ }
+ buf[i] = hex2bin(*hex.ptr);
+ if (i > 0 || !odd)
+ {
+ buf[i] |= hex2bin(*(--hex.ptr)) << 4;
+ }
+ }
+ return chunk_create(buf, len);
+}
+
+/** base 64 conversion digits */
+static char b64digits[] =
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
+
+/**
+ * Described in header.
+ */
+chunk_t chunk_to_base64(chunk_t chunk, char *buf)
+{
+ int i, len;
+ char *pos;
+
+ len = chunk.len + ((3 - chunk.len % 3) % 3);
+ if (!buf)
+ {
+ buf = malloc(len * 4 / 3 + 1);
+ }
+ pos = buf;
+ for (i = 0; i < len; i+=3)
+ {
+ *pos++ = b64digits[chunk.ptr[i] >> 2];
+ if (i+1 >= chunk.len)
+ {
+ *pos++ = b64digits[(chunk.ptr[i] & 0x03) << 4];
+ *pos++ = '=';
+ *pos++ = '=';
+ break;
+ }
+ *pos++ = b64digits[((chunk.ptr[i] & 0x03) << 4) | (chunk.ptr[i+1] >> 4)];
+ if (i+2 >= chunk.len)
+ {
+ *pos++ = b64digits[(chunk.ptr[i+1] & 0x0F) << 2];
+ *pos++ = '=';
+ break;
+ }
+ *pos++ = b64digits[((chunk.ptr[i+1] & 0x0F) << 2) | (chunk.ptr[i+2] >> 6)];
+ *pos++ = b64digits[chunk.ptr[i+2] & 0x3F];
+ }
+ *pos = '\0';
+ return chunk_create(buf, len * 4 / 3);
+}
+
+/**
+ * convert a base 64 digit to its binary form (inversion of b64digits array)
+ */
+static int b642bin(char b64)
+{
+ switch (b64)
+ {
+ case 'A' ... 'Z':
+ return b64 - 'A';
+ case 'a' ... 'z':
+ return ('Z' - 'A' + 1) + b64 - 'a';
+ case '0' ... '9':
+ return ('Z' - 'A' + 1) + ('z' - 'a' + 1) + b64 - '0';
+ case '+':
+ case '-':
+ return 62;
+ case '/':
+ case '_':
+ return 63;
+ case '=':
+ return 0;
+ default:
+ return -1;
+ }
+}
+
+/**
+ * Described in header.
+ */
+chunk_t chunk_from_base64(chunk_t base64, char *buf)
+{
+ u_char *pos, byte[4];
+ int i, j, len, outlen;
+
+ len = base64.len / 4 * 3;
+ if (!buf)
+ {
+ buf = malloc(len);
+ }
+ pos = base64.ptr;
+ outlen = 0;
+ for (i = 0; i < len; i+=3)
+ {
+ outlen += 3;
+ for (j = 0; j < 4; j++)
+ {
+ if (*pos == '=')
+ {
+ outlen--;
+ }
+ byte[j] = b642bin(*pos++);
+ }
+ buf[i] = (byte[0] << 2) | (byte[1] >> 4);
+ buf[i+1] = (byte[1] << 4) | (byte[2] >> 2);
+ buf[i+2] = (byte[2] << 6) | (byte[3]);
+ }
+ return chunk_create(buf, outlen);
+}
+
+/** base 32 conversion digits */
+static char b32digits[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567";
+
+/**
+ * Described in header.
+ */
+chunk_t chunk_to_base32(chunk_t chunk, char *buf)
+{
+ int i, len;
+ char *pos;
+
+ len = chunk.len + ((5 - chunk.len % 5) % 5);
+ if (!buf)
+ {
+ buf = malloc(len * 8 / 5 + 1);
+ }
+ pos = buf;
+ for (i = 0; i < len; i+=5)
+ {
+ *pos++ = b32digits[chunk.ptr[i] >> 3];
+ if (i+1 >= chunk.len)
+ {
+ *pos++ = b32digits[(chunk.ptr[i] & 0x07) << 2];
+ memset(pos, '=', 6);
+ pos += 6;
+ break;
+ }
+ *pos++ = b32digits[((chunk.ptr[i] & 0x07) << 2) |
+ (chunk.ptr[i+1] >> 6)];
+ *pos++ = b32digits[(chunk.ptr[i+1] & 0x3E) >> 1];
+ if (i+2 >= chunk.len)
+ {
+ *pos++ = b32digits[(chunk.ptr[i+1] & 0x01) << 4];
+ memset(pos, '=', 4);
+ pos += 4;
+ break;
+ }
+ *pos++ = b32digits[((chunk.ptr[i+1] & 0x01) << 4) |
+ (chunk.ptr[i+2] >> 4)];
+ if (i+3 >= chunk.len)
+ {
+ *pos++ = b32digits[(chunk.ptr[i+2] & 0x0F) << 1];
+ memset(pos, '=', 3);
+ pos += 3;
+ break;
+ }
+ *pos++ = b32digits[((chunk.ptr[i+2] & 0x0F) << 1) |
+ (chunk.ptr[i+3] >> 7)];
+ *pos++ = b32digits[(chunk.ptr[i+3] & 0x7F) >> 2];
+ if (i+4 >= chunk.len)
+ {
+ *pos++ = b32digits[(chunk.ptr[i+3] & 0x03) << 3];
+ *pos++ = '=';
+ break;
+ }
+ *pos++ = b32digits[((chunk.ptr[i+3] & 0x03) << 3) |
+ (chunk.ptr[i+4] >> 5)];
+ *pos++ = b32digits[chunk.ptr[i+4] & 0x1F];
+ }
+ *pos = '\0';
+ return chunk_create(buf, len * 8 / 5);
+}
+
+/**
+ * Described in header.
+ */
+int chunk_compare(chunk_t a, chunk_t b)
+{
+ int compare_len = a.len - b.len;
+ int len = (compare_len < 0)? a.len : b.len;
+
+ if (compare_len != 0 || len == 0)
+ {
+ return compare_len;
+ }
+ return memcmp(a.ptr, b.ptr, len);
+};
+
+
+/**
+ * Described in header.
+ */
+bool chunk_increment(chunk_t chunk)
+{
+ int i;
+
+ for (i = chunk.len - 1; i >= 0; i--)
+ {
+ if (++chunk.ptr[i] != 0)
+ {
+ return FALSE;
+ }
+ }
+ return TRUE;
+}
+
+/**
+ * Remove non-printable characters from a chunk.
+ */
+bool chunk_printable(chunk_t chunk, chunk_t *sane, char replace)
+{
+ bool printable = TRUE;
+ int i;
+
+ if (sane)
+ {
+ *sane = chunk_clone(chunk);
+ }
+ for (i = 0; i < chunk.len; i++)
+ {
+ if (!isprint(chunk.ptr[i]))
+ {
+ if (sane)
+ {
+ sane->ptr[i] = replace;
+ }
+ printable = FALSE;
+ }
+ }
+ return printable;
+}
+
+/**
+ * Helper functions for chunk_mac()
+ */
+static inline u_int64_t sipget(u_char *in)
+{
+ u_int64_t v = 0;
+ int i;
+
+ for (i = 0; i < 64; i += 8, ++in)
+ {
+ v |= ((u_int64_t)*in) << i;
+ }
+ return v;
+}
+
+static inline u_int64_t siprotate(u_int64_t v, int shift)
+{
+ return (v << shift) | (v >> (64 - shift));
+}
+
+static inline void sipround(u_int64_t *v0, u_int64_t *v1, u_int64_t *v2,
+ u_int64_t *v3)
+{
+ *v0 += *v1;
+ *v1 = siprotate(*v1, 13);
+ *v1 ^= *v0;
+ *v0 = siprotate(*v0, 32);
+
+ *v2 += *v3;
+ *v3 = siprotate(*v3, 16);
+ *v3 ^= *v2;
+
+ *v2 += *v1;
+ *v1 = siprotate(*v1, 17);
+ *v1 ^= *v2;
+ *v2 = siprotate(*v2, 32);
+
+ *v0 += *v3;
+ *v3 = siprotate(*v3, 21);
+ *v3 ^= *v0;
+}
+
+static inline void sipcompress(u_int64_t *v0, u_int64_t *v1, u_int64_t *v2,
+ u_int64_t *v3, u_int64_t m)
+{
+ *v3 ^= m;
+ sipround(v0, v1, v2, v3);
+ sipround(v0, v1, v2, v3);
+ *v0 ^= m;
+}
+
+static inline u_int64_t siplast(size_t len, u_char *pos)
+{
+ u_int64_t b;
+ int rem = len & 7;
+
+ b = ((u_int64_t)len) << 56;
+ switch (rem)
+ {
+ case 7:
+ b |= ((u_int64_t)pos[6]) << 48;
+ case 6:
+ b |= ((u_int64_t)pos[5]) << 40;
+ case 5:
+ b |= ((u_int64_t)pos[4]) << 32;
+ case 4:
+ b |= ((u_int64_t)pos[3]) << 24;
+ case 3:
+ b |= ((u_int64_t)pos[2]) << 16;
+ case 2:
+ b |= ((u_int64_t)pos[1]) << 8;
+ case 1:
+ b |= ((u_int64_t)pos[0]);
+ break;
+ case 0:
+ break;
+ }
+ return b;
+}
+
+/**
+ * Caculate SipHash-2-4 with an optional first block given as argument.
+ */
+static u_int64_t chunk_mac_inc(chunk_t chunk, u_char *key, u_int64_t m)
+{
+ u_int64_t v0, v1, v2, v3, k0, k1;
+ size_t len = chunk.len;
+ u_char *pos = chunk.ptr, *end;
+
+ end = chunk.ptr + len - (len % 8);
+
+ k0 = sipget(key);
+ k1 = sipget(key + 8);
+
+ v0 = k0 ^ 0x736f6d6570736575ULL;
+ v1 = k1 ^ 0x646f72616e646f6dULL;
+ v2 = k0 ^ 0x6c7967656e657261ULL;
+ v3 = k1 ^ 0x7465646279746573ULL;
+
+ if (m)
+ {
+ sipcompress(&v0, &v1, &v2, &v3, m);
+ }
+
+ /* compression with c = 2 */
+ for (; pos != end; pos += 8)
+ {
+ m = sipget(pos);
+ sipcompress(&v0, &v1, &v2, &v3, m);
+ }
+ sipcompress(&v0, &v1, &v2, &v3, siplast(len, pos));
+
+ /* finalization with d = 4 */
+ v2 ^= 0xff;
+ sipround(&v0, &v1, &v2, &v3);
+ sipround(&v0, &v1, &v2, &v3);
+ sipround(&v0, &v1, &v2, &v3);
+ sipround(&v0, &v1, &v2, &v3);
+ return v0 ^ v1 ^ v2 ^ v3;
+}
+
+/**
+ * Described in header.
+ */
+u_int64_t chunk_mac(chunk_t chunk, u_char *key)
+{
+ return chunk_mac_inc(chunk, key, 0);
+}
+
+/**
+ * Secret key allocated randomly during first use.
+ */
+static u_char key[16];
+
+/**
+ * Static key used in case predictable hash values are required.
+ */
+static u_char static_key[] = {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f};
+
+/**
+ * Only allocate the key once
+ */
+static pthread_once_t key_allocated = PTHREAD_ONCE_INIT;
+
+/**
+ * Allocate a key on first use, we do this manually to avoid dependencies on
+ * plugins.
+ */
+static void allocate_key()
+{
+ ssize_t len;
+ size_t done = 0;
+ int fd;
+
+ fd = open("/dev/urandom", O_RDONLY);
+ if (fd >= 0)
+ {
+ while (done < sizeof(key))
+ {
+ len = read(fd, key + done, sizeof(key) - done);
+ if (len < 0)
+ {
+ break;
+ }
+ done += len;
+ }
+ close(fd);
+ }
+ /* on error we use random() to generate the key (better than nothing) */
+ if (done < sizeof(key))
+ {
+ srandom(time(NULL) + getpid());
+ for (; done < sizeof(key); done++)
+ {
+ key[done] = (u_char)random();
+ }
+ }
+}
+
+/**
+ * Described in header.
+ */
+u_int32_t chunk_hash_inc(chunk_t chunk, u_int32_t hash)
+{
+ pthread_once(&key_allocated, allocate_key);
+ /* we could use a mac of the previous hash, but this is faster */
+ return chunk_mac_inc(chunk, key, ((u_int64_t)hash) << 32 | hash);
+}
+
+/**
+ * Described in header.
+ */
+u_int32_t chunk_hash(chunk_t chunk)
+{
+ pthread_once(&key_allocated, allocate_key);
+ return chunk_mac(chunk, key);
+}
+
+/**
+ * Described in header.
+ */
+u_int32_t chunk_hash_static_inc(chunk_t chunk, u_int32_t hash)
+{ /* we could use a mac of the previous hash, but this is faster */
+ return chunk_mac_inc(chunk, static_key, ((u_int64_t)hash) << 32 | hash);
+}
+
+/**
+ * Described in header.
+ */
+u_int32_t chunk_hash_static(chunk_t chunk)
+{
+ return chunk_mac(chunk, static_key);
+}
+
+/**
+ * Described in header.
+ */
+int chunk_printf_hook(printf_hook_data_t *data, printf_hook_spec_t *spec,
+ const void *const *args)
+{
+ chunk_t *chunk = *((chunk_t**)(args[0]));
+ bool first = TRUE;
+ chunk_t copy = *chunk;
+ int written = 0;
+
+ if (!spec->hash)
+ {
+ u_int chunk_len = chunk->len;
+ const void *new_args[] = {&chunk->ptr, &chunk_len};
+ return mem_printf_hook(data, spec, new_args);
+ }
+
+ while (copy.len > 0)
+ {
+ if (first)
+ {
+ first = FALSE;
+ }
+ else
+ {
+ written += print_in_hook(data, ":");
+ }
+ written += print_in_hook(data, "%02x", *copy.ptr++);
+ copy.len--;
+ }
+ return written;
+}
diff --git a/src/libstrongswan/utils/chunk.h b/src/libstrongswan/utils/chunk.h
new file mode 100644
index 000000000..34ba77357
--- /dev/null
+++ b/src/libstrongswan/utils/chunk.h
@@ -0,0 +1,375 @@
+/*
+ * Copyright (C) 2008-2013 Tobias Brunner
+ * Copyright (C) 2005-2008 Martin Willi
+ * Copyright (C) 2005 Jan Hutter
+ * Hochschule fuer Technik Rapperswil
+ *
+ * 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. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * 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.
+ */
+
+/**
+ * @defgroup chunk chunk
+ * @{ @ingroup utils
+ */
+
+#ifndef CHUNK_H_
+#define CHUNK_H_
+
+#include <string.h>
+#include <stdarg.h>
+#include <sys/types.h>
+#ifdef HAVE_ALLOCA_H
+#include <alloca.h>
+#endif
+
+typedef struct chunk_t chunk_t;
+
+/**
+ * General purpose pointer/length abstraction.
+ */
+struct chunk_t {
+ /** Pointer to start of data */
+ u_char *ptr;
+ /** Length of data in bytes */
+ size_t len;
+};
+
+#include "utils.h"
+
+/**
+ * A { NULL, 0 }-chunk handy for initialization.
+ */
+extern chunk_t chunk_empty;
+
+/**
+ * Create a new chunk pointing to "ptr" with length "len"
+ */
+static inline chunk_t chunk_create(u_char *ptr, size_t len)
+{
+ chunk_t chunk = {ptr, len};
+ return chunk;
+}
+
+/**
+ * Create a clone of a chunk pointing to "ptr"
+ */
+chunk_t chunk_create_clone(u_char *ptr, chunk_t chunk);
+
+/**
+ * Calculate length of multiple chunks
+ */
+size_t chunk_length(const char *mode, ...);
+
+/**
+ * Concatenate chunks into a chunk pointing to "ptr".
+ *
+ * The mode string specifies the number of chunks, and how to handle each of
+ * them with a single character: 'c' for copy (allocate new chunk), 'm' for move
+ * (free given chunk) or 's' for sensitive-move (clear given chunk, then free).
+ */
+chunk_t chunk_create_cat(u_char *ptr, const char* mode, ...);
+
+/**
+ * Split up a chunk into parts, "mode" is a string of "a" (alloc),
+ * "c" (copy) and "m" (move). Each letter say for the corresponding chunk if
+ * it should get allocated on heap, copied into existing chunk, or the chunk
+ * should point into "chunk". The length of each part is an argument before
+ * each target chunk. E.g.:
+ * chunk_split(chunk, "mcac", 3, &a, 7, &b, 5, &c, d.len, &d);
+ */
+void chunk_split(chunk_t chunk, const char *mode, ...);
+
+/**
+ * Write the binary contents of a chunk_t to a file
+ *
+ * @param chunk contents to write to file
+ * @param path path where file is written to
+ * @param label label specifying file type
+ * @param mask file mode creation mask
+ * @param force overwrite existing file by force
+ * @return TRUE if write operation was successful
+ */
+bool chunk_write(chunk_t chunk, char *path, char *label, mode_t mask, bool force);
+
+/**
+ * Convert a chunk of data to hex encoding.
+ *
+ * The resulting string is '\\0' terminated, but the chunk does not include
+ * the '\\0'. If buf is supplied, it must hold at least (chunk.len * 2 + 1).
+ *
+ * @param chunk data to convert to hex encoding
+ * @param buf buffer to write to, NULL to malloc
+ * @param uppercase TRUE to use uppercase letters
+ * @return chunk of encoded data
+ */
+chunk_t chunk_to_hex(chunk_t chunk, char *buf, bool uppercase);
+
+/**
+ * Convert a hex encoded in a binary chunk.
+ *
+ * If buf is supplied, it must hold at least (hex.len / 2) + (hex.len % 2)
+ * bytes. It is filled by the right to give correct values for short inputs.
+ *
+ * @param hex hex encoded input data
+ * @param buf buffer to write decoded data, NULL to malloc
+ * @return converted data
+ */
+chunk_t chunk_from_hex(chunk_t hex, char *buf);
+
+/**
+ * Convert a chunk of data to its base64 encoding.
+ *
+ * The resulting string is '\\0' terminated, but the chunk does not include
+ * the '\\0'. If buf is supplied, it must hold at least (chunk.len * 4 / 3 + 1).
+ *
+ * @param chunk data to convert
+ * @param buf buffer to write to, NULL to malloc
+ * @return chunk of encoded data
+ */
+chunk_t chunk_to_base64(chunk_t chunk, char *buf);
+
+/**
+ * Convert a base64 in a binary chunk.
+ *
+ * If buf is supplied, it must hold at least (base64.len / 4 * 3).
+ *
+ * @param base64 base64 encoded input data
+ * @param buf buffer to write decoded data, NULL to malloc
+ * @return converted data
+ */
+chunk_t chunk_from_base64(chunk_t base64, char *buf);
+
+/**
+ * Convert a chunk of data to its base32 encoding.
+ *
+ * The resulting string is '\\0' terminated, but the chunk does not include
+ * the '\\0'. If buf is supplied, it must hold (chunk.len * 8 / 5 + 1) bytes.
+ *
+ * @param chunk data to convert
+ * @param buf buffer to write to, NULL to malloc
+ * @return chunk of encoded data
+ */
+chunk_t chunk_to_base32(chunk_t chunk, char *buf);
+
+/**
+ * Free contents of a chunk
+ */
+static inline void chunk_free(chunk_t *chunk)
+{
+ free(chunk->ptr);
+ *chunk = chunk_empty;
+}
+
+/**
+ * Overwrite the contents of a chunk and free it
+ */
+static inline void chunk_clear(chunk_t *chunk)
+{
+ if (chunk->ptr)
+ {
+ memwipe(chunk->ptr, chunk->len);
+ chunk_free(chunk);
+ }
+}
+
+/**
+ * Initialize a chunk using a char array
+ */
+#define chunk_from_chars(...) ((chunk_t){(char[]){__VA_ARGS__}, sizeof((char[]){__VA_ARGS__})})
+
+/**
+ * Initialize a chunk to point to a thing
+ */
+#define chunk_from_thing(thing) chunk_create((char*)&(thing), sizeof(thing))
+
+/**
+ * Initialize a chunk from a string, not containing 0-terminator
+ */
+#define chunk_from_str(str) ({char *x = (str); chunk_create(x, strlen(x));})
+
+/**
+ * Allocate a chunk on the heap
+ */
+#define chunk_alloc(bytes) ({size_t x = (bytes); chunk_create(x ? malloc(x) : NULL, x);})
+
+/**
+ * Allocate a chunk on the stack
+ */
+#define chunk_alloca(bytes) ({size_t x = (bytes); chunk_create(x ? alloca(x) : NULL, x);})
+
+/**
+ * Clone a chunk on heap
+ */
+#define chunk_clone(chunk) ({chunk_t x = (chunk); chunk_create_clone(x.len ? malloc(x.len) : NULL, x);})
+
+/**
+ * Clone a chunk on stack
+ */
+#define chunk_clonea(chunk) ({chunk_t x = (chunk); chunk_create_clone(x.len ? alloca(x.len) : NULL, x);})
+
+/**
+ * Concatenate chunks into a chunk on heap
+ */
+#define chunk_cat(mode, ...) chunk_create_cat(malloc(chunk_length(mode, __VA_ARGS__)), mode, __VA_ARGS__)
+
+/**
+ * Concatenate chunks into a chunk on stack
+ */
+#define chunk_cata(mode, ...) chunk_create_cat(alloca(chunk_length(mode, __VA_ARGS__)), mode, __VA_ARGS__)
+
+/**
+ * Skip n bytes in chunk (forward pointer, shorten length)
+ */
+static inline chunk_t chunk_skip(chunk_t chunk, size_t bytes)
+{
+ if (chunk.len > bytes)
+ {
+ chunk.ptr += bytes;
+ chunk.len -= bytes;
+ return chunk;
+ }
+ return chunk_empty;
+}
+
+/**
+ * Skip a leading zero-valued byte
+ */
+static inline chunk_t chunk_skip_zero(chunk_t chunk)
+{
+ if (chunk.len > 1 && *chunk.ptr == 0x00)
+ {
+ chunk.ptr++;
+ chunk.len--;
+ }
+ return chunk;
+}
+
+
+/**
+ * Compare two chunks, returns zero if a equals b
+ * or negative/positive if a is small/greater than b
+ */
+int chunk_compare(chunk_t a, chunk_t b);
+
+/**
+ * Compare two chunks for equality,
+ * NULL chunks are never equal.
+ */
+static inline bool chunk_equals(chunk_t a, chunk_t b)
+{
+ return a.ptr != NULL && b.ptr != NULL &&
+ a.len == b.len && memeq(a.ptr, b.ptr, a.len);
+}
+
+/**
+ * Compare two chunks (given as pointers) for equality (useful as callback),
+ * NULL chunks are never equal.
+ */
+static inline bool chunk_equals_ptr(chunk_t *a, chunk_t *b)
+{
+ return a != NULL && b != NULL && chunk_equals(*a, *b);
+}
+
+/**
+ * Increment a chunk, as it would reprensent a network order integer.
+ *
+ * @param chunk chunk to increment
+ * @return TRUE if an overflow occurred
+ */
+bool chunk_increment(chunk_t chunk);
+
+/**
+ * Check if a chunk has printable characters only.
+ *
+ * If sane is given, chunk is cloned into sane and all non printable characters
+ * get replaced by "replace".
+ *
+ * @param chunk chunk to check for printability
+ * @param sane pointer where sane version is allocated, or NULL
+ * @param replace character to use for replaceing unprintable characters
+ * @return TRUE if all characters in chunk are printable
+ */
+bool chunk_printable(chunk_t chunk, chunk_t *sane, char replace);
+
+/**
+ * Computes a 32 bit hash of the given chunk.
+ *
+ * @note The output of this function is randomized, that is, it will only
+ * produce the same output for the same input when calling it from the same
+ * process. For a more predictable hash function use chunk_hash_static()
+ * instead.
+ *
+ * @note This hash is only intended for hash tables not for cryptographic
+ * purposes.
+ *
+ * @param chunk data to hash
+ * @return hash value
+ */
+u_int32_t chunk_hash(chunk_t chunk);
+
+/**
+ * Incremental version of chunk_hash. Use this to hash two or more chunks.
+ *
+ * @param chunk data to hash
+ * @param hash previous hash value
+ * @return hash value
+ */
+u_int32_t chunk_hash_inc(chunk_t chunk, u_int32_t hash);
+
+/**
+ * Computes a 32 bit hash of the given chunk.
+ *
+ * Compared to chunk_hash() this will always calculate the same output for the
+ * same input. Therefore, it should not be used for hash tables (to prevent
+ * hash flooding).
+ *
+ * @note This hash is not intended for cryptographic purposes.
+ *
+ * @param chunk data to hash
+ * @return hash value
+ */
+u_int32_t chunk_hash_static(chunk_t chunk);
+
+/**
+ * Incremental version of chunk_hash_static(). Use this to hash two or more
+ * chunks in a predictable way.
+ *
+ * @param chunk data to hash
+ * @param hash previous hash value
+ * @return hash value
+ */
+u_int32_t chunk_hash_static_inc(chunk_t chunk, u_int32_t hash);
+
+/**
+ * Computes a quick MAC from the given chunk and key using SipHash.
+ *
+ * The key must have a length of 128-bit (16 bytes).
+ *
+ * @note While SipHash has strong features using it for cryptographic purposes
+ * is not recommended (in particular because of the rather short output size).
+ *
+ * @param chunk data to process
+ * @param key key to use
+ * @return MAC for given input and key
+ */
+u_int64_t chunk_mac(chunk_t chunk, u_char *key);
+
+/**
+ * printf hook function for chunk_t.
+ *
+ * Arguments are:
+ * chunk_t *chunk
+ * Use #-modifier to print a compact version
+ */
+int chunk_printf_hook(printf_hook_data_t *data, printf_hook_spec_t *spec,
+ const void *const *args);
+
+#endif /** CHUNK_H_ @}*/
diff --git a/src/libstrongswan/utils/debug.c b/src/libstrongswan/utils/debug.c
new file mode 100644
index 000000000..e8c9e6b98
--- /dev/null
+++ b/src/libstrongswan/utils/debug.c
@@ -0,0 +1,112 @@
+/*
+ * Copyright (C) 2006 Martin Willi
+ * Hochschule fuer Technik Rapperswil
+ *
+ * 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. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * 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.
+ */
+
+#include <stdarg.h>
+
+#include "debug.h"
+
+ENUM(debug_names, DBG_DMN, DBG_LIB,
+ "DMN",
+ "MGR",
+ "IKE",
+ "CHD",
+ "JOB",
+ "CFG",
+ "KNL",
+ "NET",
+ "ASN",
+ "ENC",
+ "TNC",
+ "IMC",
+ "IMV",
+ "PTS",
+ "TLS",
+ "APP",
+ "ESP",
+ "LIB",
+);
+
+ENUM(debug_lower_names, DBG_DMN, DBG_LIB,
+ "dmn",
+ "mgr",
+ "ike",
+ "chd",
+ "job",
+ "cfg",
+ "knl",
+ "net",
+ "asn",
+ "enc",
+ "tnc",
+ "imc",
+ "imv",
+ "pts",
+ "tls",
+ "app",
+ "esp",
+ "lib",
+);
+
+/**
+ * level logged by the default logger
+ */
+static level_t default_level = 1;
+
+/**
+ * stream logged to by the default logger
+ */
+static FILE *default_stream = NULL;
+
+/**
+ * default dbg function which printf all to stderr
+ */
+void dbg_default(debug_t group, level_t level, char *fmt, ...)
+{
+ if (!default_stream)
+ {
+ default_stream = stderr;
+ }
+ if (level <= default_level)
+ {
+ va_list args;
+
+ va_start(args, fmt);
+ vfprintf(default_stream, fmt, args);
+ fprintf(default_stream, "\n");
+ va_end(args);
+ }
+}
+
+/**
+ * set the level logged by the default stderr logger
+ */
+void dbg_default_set_level(level_t level)
+{
+ default_level = level;
+}
+
+/**
+ * set the stream logged by dbg_default() to
+ */
+void dbg_default_set_stream(FILE *stream)
+{
+ default_stream = stream;
+}
+
+/**
+ * The registered debug hook.
+ */
+void (*dbg) (debug_t group, level_t level, char *fmt, ...) = dbg_default;
+
diff --git a/src/libstrongswan/utils/debug.h b/src/libstrongswan/utils/debug.h
new file mode 100644
index 000000000..c46d3fe55
--- /dev/null
+++ b/src/libstrongswan/utils/debug.h
@@ -0,0 +1,154 @@
+/*
+ * Copyright (C) 2006 Martin Willi
+ * Hochschule fuer Technik Rapperswil
+ *
+ * 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. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * 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.
+ */
+
+/**
+ * @defgroup debug debug
+ * @{ @ingroup utils
+ */
+
+#ifndef DEBUG_H_
+#define DEBUG_H_
+
+typedef enum debug_t debug_t;
+typedef enum level_t level_t;
+
+#include <stdio.h>
+
+#include "utils/enum.h"
+
+/**
+ * Debug message group.
+ */
+enum debug_t {
+ /** daemon specific */
+ DBG_DMN,
+ /** IKE_SA_MANAGER */
+ DBG_MGR,
+ /** IKE_SA */
+ DBG_IKE,
+ /** CHILD_SA */
+ DBG_CHD,
+ /** job processing */
+ DBG_JOB,
+ /** configuration backends */
+ DBG_CFG,
+ /** kernel interface */
+ DBG_KNL,
+ /** networking/sockets */
+ DBG_NET,
+ /** low-level encoding/decoding (ASN.1, X.509 etc.) */
+ DBG_ASN,
+ /** message encoding/decoding */
+ DBG_ENC,
+ /** trusted network connect */
+ DBG_TNC,
+ /** integrity measurement client */
+ DBG_IMC,
+ /** integrity measurement verifier */
+ DBG_IMV,
+ /** platform trust service */
+ DBG_PTS,
+ /** libtls */
+ DBG_TLS,
+ /** applications other than daemons */
+ DBG_APP,
+ /** libipsec */
+ DBG_ESP,
+ /** libstrongswan */
+ DBG_LIB,
+ /** number of groups */
+ DBG_MAX,
+ /** pseudo group with all groups */
+ DBG_ANY = DBG_MAX,
+};
+
+/**
+ * short names of debug message group.
+ */
+extern enum_name_t *debug_names;
+
+/**
+ * short names of debug message group, lower case.
+ */
+extern enum_name_t *debug_lower_names;
+
+/**
+ * Debug levels used to control output verbosity.
+ */
+enum level_t {
+ /** absolutely silent */
+ LEVEL_SILENT = -1,
+ /** most important auditing logs */
+ LEVEL_AUDIT = 0,
+ /** control flow */
+ LEVEL_CTRL = 1,
+ /** diagnose problems */
+ LEVEL_DIAG = 2,
+ /** raw binary blobs */
+ LEVEL_RAW = 3,
+ /** including sensitive data (private keys) */
+ LEVEL_PRIVATE = 4,
+};
+
+#ifndef DEBUG_LEVEL
+# define DEBUG_LEVEL 4
+#endif /* DEBUG_LEVEL */
+
+/** debug macros, they call the dbg function hook */
+#if DEBUG_LEVEL >= 0
+# define DBG0(group, fmt, ...) dbg(group, 0, fmt, ##__VA_ARGS__)
+#endif /* DEBUG_LEVEL */
+#if DEBUG_LEVEL >= 1
+# define DBG1(group, fmt, ...) dbg(group, 1, fmt, ##__VA_ARGS__)
+#endif /* DEBUG_LEVEL */
+#if DEBUG_LEVEL >= 2
+# define DBG2(group, fmt, ...) dbg(group, 2, fmt, ##__VA_ARGS__)
+#endif /* DEBUG_LEVEL */
+#if DEBUG_LEVEL >= 3
+# define DBG3(group, fmt, ...) dbg(group, 3, fmt, ##__VA_ARGS__)
+#endif /* DEBUG_LEVEL */
+#if DEBUG_LEVEL >= 4
+# define DBG4(group, fmt, ...) dbg(group, 4, fmt, ##__VA_ARGS__)
+#endif /* DEBUG_LEVEL */
+
+#ifndef DBG0
+# define DBG0(...) {}
+#endif
+#ifndef DBG1
+# define DBG1(...) {}
+#endif
+#ifndef DBG2
+# define DBG2(...) {}
+#endif
+#ifndef DBG3
+# define DBG3(...) {}
+#endif
+#ifndef DBG4
+# define DBG4(...) {}
+#endif
+
+/** dbg function hook, uses dbg_default() by default */
+extern void (*dbg) (debug_t group, level_t level, char *fmt, ...);
+
+/** default logging function */
+void dbg_default(debug_t group, level_t level, char *fmt, ...);
+
+/** set the level logged by dbg_default() */
+void dbg_default_set_level(level_t level);
+
+/** set the stream logged by dbg_default() to */
+void dbg_default_set_stream(FILE *stream);
+
+#endif /** DEBUG_H_ @}*/
diff --git a/src/libstrongswan/utils/enum.c b/src/libstrongswan/utils/enum.c
new file mode 100644
index 000000000..3db9a34e0
--- /dev/null
+++ b/src/libstrongswan/utils/enum.c
@@ -0,0 +1,81 @@
+/*
+ * Copyright (C) 2006 Martin Willi
+ * Hochschule fuer Technik Rapperswil
+ *
+ * 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. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * 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.
+ */
+
+#include <stddef.h>
+#include <stdio.h>
+
+#include <library.h>
+
+#include "enum.h"
+
+/**
+ * See header.
+ */
+char *enum_to_name(enum_name_t *e, int val)
+{
+ do
+ {
+ if (val >= e->first && val <= e->last)
+ {
+ return e->names[val - e->first];
+ }
+ }
+ while ((e = e->next));
+ return NULL;
+}
+
+/**
+ * See header.
+ */
+int enum_from_name(enum_name_t *e, char *name)
+{
+ do
+ {
+ int i, count = e->last - e->first + 1;
+
+ for (i = 0; i < count; i++)
+ {
+ if (name && strcaseeq(name, e->names[i]))
+ {
+ return e->first + i;
+ }
+ }
+ }
+ while ((e = e->next));
+ return -1;
+}
+
+/**
+ * Described in header.
+ */
+int enum_printf_hook(printf_hook_data_t *data, printf_hook_spec_t *spec,
+ const void *const *args)
+{
+ enum_name_t *ed = *((enum_name_t**)(args[0]));
+ int val = *((int*)(args[1]));
+ char *name, buf[32];
+
+ name = enum_to_name(ed, val);
+ if (name == NULL)
+ {
+ snprintf(buf, sizeof(buf), "(%d)", val);
+ name = buf;
+ }
+ if (spec->minus)
+ {
+ return print_in_hook(data, "%-*s", spec->width, name);
+ }
+ return print_in_hook(data, "%*s", spec->width, name);
+}
diff --git a/src/libstrongswan/utils/enum.h b/src/libstrongswan/utils/enum.h
new file mode 100644
index 000000000..df8dbf8c1
--- /dev/null
+++ b/src/libstrongswan/utils/enum.h
@@ -0,0 +1,136 @@
+/*
+ * Copyright (C) 2009 Tobias Brunner
+ * Copyright (C) 2006-2008 Martin Willi
+ * Hochschule fuer Technik Rapperswil
+ *
+ * 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. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * 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.
+ */
+
+/**
+ * @defgroup enum enum
+ * @{ @ingroup utils
+ */
+
+#ifndef ENUM_H_
+#define ENUM_H_
+
+#include "printf_hook.h"
+
+typedef struct enum_name_t enum_name_t;
+
+/**
+ * Struct to store names for enums.
+ *
+ * To print the string representation of enumeration values, the strings
+ * are stored in these structures. Every enum_name contains a range
+ * of strings, multiple ranges are linked together.
+ * Use the convenience macros to define these linked ranges.
+ *
+ * For a single range, use:
+ * @code
+ ENUM(name, first, last, string1, string2, ...)
+ @endcode
+ * For multiple linked ranges, use:
+ * @code
+ ENUM_BEGIN(name, first, last, string1, string2, ...)
+ ENUM_NEXT(name, first, last, last_from_previous, string3, ...)
+ ENUM_NEXT(name, first, last, last_from_previous, string4, ...)
+ ENUM_END(name, last_from_previous)
+ @endcode
+ * The ENUM and the ENUM_END define a enum_name_t pointer with the name supplied
+ * in "name".
+ *
+ * Resolving of enum names is done using a printf hook. A printf fromat
+ * character %N is replaced by the enum string. Printf needs two arguments to
+ * resolve a %N, the enum_name_t* (the defined name in ENUM_BEGIN) followed
+ * by the numerical enum value.
+ */
+struct enum_name_t {
+ /** value of the first enum string */
+ int first;
+ /** value of the last enum string */
+ int last;
+ /** next enum_name_t in list */
+ enum_name_t *next;
+ /** array of strings containing names from first to last */
+ char *names[];
+};
+
+/**
+ * Begin a new enum_name list.
+ *
+ * @param name name of the enum_name list
+ * @param first enum value of the first enum string
+ * @param last enum value of the last enum string
+ * @param ... a list of strings
+ */
+#define ENUM_BEGIN(name, first, last, ...) static enum_name_t name##last = {first, last, NULL, { __VA_ARGS__ }}
+
+/**
+ * Continue a enum name list startetd with ENUM_BEGIN.
+ *
+ * @param name name of the enum_name list
+ * @param first enum value of the first enum string
+ * @param last enum value of the last enum string
+ * @param prev enum value of the "last" defined in ENUM_BEGIN/previous ENUM_NEXT
+ * @param ... a list of strings
+ */
+#define ENUM_NEXT(name, first, last, prev, ...) static enum_name_t name##last = {first, last, &name##prev, { __VA_ARGS__ }}
+
+/**
+ * Complete enum name list started with ENUM_BEGIN.
+ *
+ * @param name name of the enum_name list
+ * @param prev enum value of the "last" defined in ENUM_BEGIN/previous ENUM_NEXT
+ */
+#define ENUM_END(name, prev) enum_name_t *name = &name##prev;
+
+/**
+ * Define a enum name with only one range.
+ *
+ * This is a convenience macro to use when a enum_name list contains only
+ * one range, and is equal as defining ENUM_BEGIN followed by ENUM_END.
+ *
+ * @param name name of the enum_name list
+ * @param first enum value of the first enum string
+ * @param last enum value of the last enum string
+ * @param ... a list of strings
+ */
+#define ENUM(name, first, last, ...) ENUM_BEGIN(name, first, last, __VA_ARGS__); ENUM_END(name, last)
+
+/**
+ * Convert a enum value to its string representation.
+ *
+ * @param e enum names for this enum value
+ * @param val enum value to get string for
+ * @return string for enum, NULL if not found
+ */
+char *enum_to_name(enum_name_t *e, int val);
+
+/**
+ * Convert a enum string back to its enum value.
+ *
+ * @param e enum names for this enum value
+ * @param name name to get enum value for
+ * @return enum value, -1 if not found
+ */
+int enum_from_name(enum_name_t *e, char *name);
+
+/**
+ * printf hook function for enum_names_t.
+ *
+ * Arguments are:
+ * enum_names_t *names, int value
+ */
+int enum_printf_hook(printf_hook_data_t *data, printf_hook_spec_t *spec,
+ const void *const *args);
+
+#endif /** ENUM_H_ @}*/
diff --git a/src/libstrongswan/utils/enumerator.c b/src/libstrongswan/utils/enumerator.c
deleted file mode 100644
index fb461b448..000000000
--- a/src/libstrongswan/utils/enumerator.c
+++ /dev/null
@@ -1,558 +0,0 @@
-/*
- * Copyright (C) 2008 Tobias Brunner
- * Copyright (C) 2007 Martin Willi
- * Hochschule fuer Technik Rapperswil
- *
- * 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. See <http://www.fsf.org/copyleft/gpl.txt>.
- *
- * 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.
- */
-
-#include "enumerator.h"
-
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <unistd.h>
-#include <limits.h>
-#include <stdio.h>
-#include <dirent.h>
-#include <errno.h>
-#include <string.h>
-
-#include <debug.h>
-
-/**
- * Implementation of enumerator_create_empty().enumerate
- */
-static bool enumerate_empty(enumerator_t *enumerator, ...)
-{
- return FALSE;
-}
-
-/**
- * See header
- */
-enumerator_t* enumerator_create_empty()
-{
- enumerator_t *this = malloc_thing(enumerator_t);
- this->enumerate = enumerate_empty;
- this->destroy = (void*)free;
- return this;
-}
-
-/**
- * Enumerator implementation for directory enumerator
- */
-typedef struct {
- /** implements enumerator_t */
- enumerator_t public;
- /** directory handle */
- DIR *dir;
- /** absolute path of current file */
- char full[PATH_MAX];
- /** where directory part of full ends and relative file gets written */
- char *full_end;
-} dir_enum_t;
-
-/**
- * Implementation of enumerator_create_directory().destroy
- */
-static void destroy_dir_enum(dir_enum_t *this)
-{
- closedir(this->dir);
- free(this);
-}
-
-/**
- * Implementation of enumerator_create_directory().enumerate
- */
-static bool enumerate_dir_enum(dir_enum_t *this, char **relative,
- char **absolute, struct stat *st)
-{
- struct dirent *entry = readdir(this->dir);
- size_t remaining;
- int len;
-
- if (!entry)
- {
- return FALSE;
- }
- if (streq(entry->d_name, ".") || streq(entry->d_name, ".."))
- {
- return enumerate_dir_enum(this, relative, absolute, st);
- }
- if (relative)
- {
- *relative = entry->d_name;
- }
- if (absolute || st)
- {
- remaining = sizeof(this->full) - (this->full_end - this->full);
- len = snprintf(this->full_end, remaining, "%s", entry->d_name);
- if (len < 0 || len >= remaining)
- {
- DBG1(DBG_LIB, "buffer too small to enumerate file '%s'",
- entry->d_name);
- return FALSE;
- }
- if (absolute)
- {
- *absolute = this->full;
- }
- if (st)
- {
- if (stat(this->full, st))
- {
- DBG1(DBG_LIB, "stat() on '%s' failed: %s", this->full,
- strerror(errno));
- return FALSE;
- }
- }
- }
- return TRUE;
-}
-
-/**
- * See header
- */
-enumerator_t* enumerator_create_directory(char *path)
-{
- int len;
- dir_enum_t *this = malloc_thing(dir_enum_t);
- this->public.enumerate = (void*)enumerate_dir_enum;
- this->public.destroy = (void*)destroy_dir_enum;
-
- if (*path == '\0')
- {
- path = "./";
- }
- len = snprintf(this->full, sizeof(this->full)-1, "%s", path);
- if (len < 0 || len >= sizeof(this->full)-1)
- {
- DBG1(DBG_LIB, "path string '%s' too long", path);
- free(this);
- return NULL;
- }
- /* append a '/' if not already done */
- if (this->full[len-1] != '/')
- {
- this->full[len++] = '/';
- this->full[len] = '\0';
- }
- this->full_end = &this->full[len];
-
- this->dir = opendir(path);
- if (this->dir == NULL)
- {
- DBG1(DBG_LIB, "opening directory '%s' failed: %s", path, strerror(errno));
- free(this);
- return NULL;
- }
- return &this->public;
-}
-
-/**
- * Enumerator implementation for directory enumerator
- */
-typedef struct {
- /** implements enumerator_t */
- enumerator_t public;
- /** string to parse */
- char *string;
- /** current position */
- char *pos;
- /** separater chars */
- char *sep;
- /** trim chars */
- char *trim;
-} token_enum_t;
-
-/**
- * Implementation of enumerator_create_token().destroy
- */
-static void destroy_token_enum(token_enum_t *this)
-{
- free(this->string);
- free(this);
-}
-
-/**
- * Implementation of enumerator_create_token().enumerate
- */
-static bool enumerate_token_enum(token_enum_t *this, char **token)
-{
- char *pos = NULL, *tmp, *sep, *trim;
- bool last = FALSE;
-
- /* trim leading characters/separators */
- while (*this->pos)
- {
- trim = this->trim;
- while (*trim)
- {
- if (*trim == *this->pos)
- {
- this->pos++;
- break;
- }
- trim++;
- }
- sep = this->sep;
- while (*sep)
- {
- if (*sep == *this->pos)
- {
- this->pos++;
- break;
- }
- sep++;
- }
- if (!*trim && !*sep)
- {
- break;
- }
- }
-
- switch (*this->pos)
- {
- case '"':
- case '\'':
- {
- /* read quoted token */
- tmp = strchr(this->pos + 1, *this->pos);
- if (tmp)
- {
- *token = this->pos + 1;
- *tmp = '\0';
- this->pos = tmp + 1;
- return TRUE;
- }
- /* unterminated string, FALL-THROUGH */
- }
- default:
- {
- /* find nearest separator */
- sep = this->sep;
- while (*sep)
- {
- tmp = strchr(this->pos, *sep);
- if (tmp && (pos == NULL || tmp < pos))
- {
- pos = tmp;
- }
- sep++;
- }
- *token = this->pos;
- if (pos)
- {
- *pos = '\0';
- this->pos = pos + 1;
- }
- else
- {
- last = TRUE;
- pos = this->pos = strchr(this->pos, '\0');
- }
- break;
- }
- }
-
- /* trim trailing characters/separators */
- pos--;
- while (pos >= *token)
- {
- trim = this->trim;
- while (*trim)
- {
- if (*trim == *pos)
- {
- *(pos--) = '\0';
- break;
- }
- trim++;
- }
- sep = this->sep;
- while (*sep)
- {
- if (*sep == *pos)
- {
- *(pos--) = '\0';
- break;
- }
- sep++;
- }
- if (!*trim && !*sep)
- {
- break;
- }
- }
-
- if (!last || pos >= *token)
- {
- return TRUE;
- }
- return FALSE;
-}
-
-/**
- * See header
- */
-enumerator_t* enumerator_create_token(char *string, char *sep, char *trim)
-{
- token_enum_t *enumerator = malloc_thing(token_enum_t);
-
- enumerator->public.enumerate = (void*)enumerate_token_enum;
- enumerator->public.destroy = (void*)destroy_token_enum;
- enumerator->string = strdup(string);
- enumerator->pos = enumerator->string;
- enumerator->sep = sep;
- enumerator->trim = trim;
-
- return &enumerator->public;
-}
-
-/**
- * enumerator for nested enumerations
- */
-typedef struct {
- /* implements enumerator_t */
- enumerator_t public;
- /* outer enumerator */
- enumerator_t *outer;
- /* inner enumerator */
- enumerator_t *inner;
- /* constructor for inner enumerator */
- enumerator_t *(*create_inner)(void *outer, void *data);
- /* data to pass to constructor above */
- void *data;
- /* destructor for data */
- void (*destroy_data)(void *data);
-} nested_enumerator_t;
-
-
-/**
- * Implementation of enumerator_create_nested().enumerate()
- */
-static bool enumerate_nested(nested_enumerator_t *this, void *v1, void *v2,
- void *v3, void *v4, void *v5)
-{
- while (TRUE)
- {
- while (this->inner == NULL)
- {
- void *outer;
-
- if (!this->outer->enumerate(this->outer, &outer))
- {
- return FALSE;
- }
- this->inner = this->create_inner(outer, this->data);
- }
- if (this->inner->enumerate(this->inner, v1, v2, v3, v4, v5))
- {
- return TRUE;
- }
- this->inner->destroy(this->inner);
- this->inner = NULL;
- }
-}
-
-/**
- * Implementation of enumerator_create_nested().destroy()
- **/
-static void destroy_nested(nested_enumerator_t *this)
-{
- if (this->destroy_data)
- {
- this->destroy_data(this->data);
- }
- DESTROY_IF(this->inner);
- this->outer->destroy(this->outer);
- free(this);
-}
-
-/**
- * See header
- */
-enumerator_t *enumerator_create_nested(enumerator_t *outer,
- enumerator_t *(inner_constructor)(void *outer, void *data),
- void *data, void (*destroy_data)(void *data))
-{
- nested_enumerator_t *enumerator = malloc_thing(nested_enumerator_t);
-
- enumerator->public.enumerate = (void*)enumerate_nested;
- enumerator->public.destroy = (void*)destroy_nested;
- enumerator->outer = outer;
- enumerator->inner = NULL;
- enumerator->create_inner = (void*)inner_constructor;
- enumerator->data = data;
- enumerator->destroy_data = destroy_data;
-
- return &enumerator->public;
-}
-
-/**
- * enumerator for filtered enumerator
- */
-typedef struct {
- enumerator_t public;
- enumerator_t *unfiltered;
- void *data;
- bool (*filter)(void *data, ...);
- void (*destructor)(void *data);
-} filter_enumerator_t;
-
-/**
- * Implementation of enumerator_create_filter().destroy
- */
-static void destroy_filter(filter_enumerator_t *this)
-{
- if (this->destructor)
- {
- this->destructor(this->data);
- }
- this->unfiltered->destroy(this->unfiltered);
- free(this);
-}
-
-/**
- * Implementation of enumerator_create_filter().enumerate
- */
-static bool enumerate_filter(filter_enumerator_t *this, void *o1, void *o2,
- void *o3, void *o4, void *o5)
-{
- void *i1, *i2, *i3, *i4, *i5;
-
- while (this->unfiltered->enumerate(this->unfiltered, &i1, &i2, &i3, &i4, &i5))
- {
- if (this->filter(this->data, &i1, o1, &i2, o2, &i3, o3, &i4, o4, &i5, o5))
- {
- return TRUE;
- }
- }
- return FALSE;
-}
-
-/**
- * see header
- */
-enumerator_t *enumerator_create_filter(enumerator_t *unfiltered,
- bool (*filter)(void *data, ...),
- void *data, void (*destructor)(void *data))
-{
- filter_enumerator_t *this = malloc_thing(filter_enumerator_t);
-
- this->public.enumerate = (void*)enumerate_filter;
- this->public.destroy = (void*)destroy_filter;
- this->unfiltered = unfiltered;
- this->filter = filter;
- this->data = data;
- this->destructor = destructor;
-
- return &this->public;
-}
-
-/**
- * enumerator for cleaner enumerator
- */
-typedef struct {
- enumerator_t public;
- enumerator_t *wrapped;
- void (*cleanup)(void *data);
- void *data;
-} cleaner_enumerator_t;
-
-/**
- * Implementation of enumerator_create_cleanup().destroy
- */
-static void destroy_cleaner(cleaner_enumerator_t *this)
-{
- this->cleanup(this->data);
- this->wrapped->destroy(this->wrapped);
- free(this);
-}
-
-/**
- * Implementation of enumerator_create_cleaner().enumerate
- */
-static bool enumerate_cleaner(cleaner_enumerator_t *this, void *v1, void *v2,
- void *v3, void *v4, void *v5)
-{
- return this->wrapped->enumerate(this->wrapped, v1, v2, v3, v4, v5);
-}
-
-/**
- * see header
- */
-enumerator_t *enumerator_create_cleaner(enumerator_t *wrapped,
- void (*cleanup)(void *data), void *data)
-{
- cleaner_enumerator_t *this = malloc_thing(cleaner_enumerator_t);
-
- this->public.enumerate = (void*)enumerate_cleaner;
- this->public.destroy = (void*)destroy_cleaner;
- this->wrapped = wrapped;
- this->cleanup = cleanup;
- this->data = data;
-
- return &this->public;
-}
-
-/**
- * enumerator for single enumerator
- */
-typedef struct {
- enumerator_t public;
- void *item;
- void (*cleanup)(void *item);
- bool done;
-} single_enumerator_t;
-
-/**
- * Implementation of enumerator_create_single().destroy
- */
-static void destroy_single(single_enumerator_t *this)
-{
- if (this->cleanup)
- {
- this->cleanup(this->item);
- }
- free(this);
-}
-
-/**
- * Implementation of enumerator_create_single().enumerate
- */
-static bool enumerate_single(single_enumerator_t *this, void **item)
-{
- if (this->done)
- {
- return FALSE;
- }
- *item = this->item;
- this->done = TRUE;
- return TRUE;
-}
-
-/**
- * see header
- */
-enumerator_t *enumerator_create_single(void *item, void (*cleanup)(void *item))
-{
- single_enumerator_t *this = malloc_thing(single_enumerator_t);
-
- this->public.enumerate = (void*)enumerate_single;
- this->public.destroy = (void*)destroy_single;
- this->item = item;
- this->cleanup = cleanup;
- this->done = FALSE;
-
- return &this->public;
-}
-
diff --git a/src/libstrongswan/utils/enumerator.h b/src/libstrongswan/utils/enumerator.h
deleted file mode 100644
index 12b5712ae..000000000
--- a/src/libstrongswan/utils/enumerator.h
+++ /dev/null
@@ -1,158 +0,0 @@
-/*
- * Copyright (C) 2007 Martin Willi
- * Hochschule fuer Technik Rapperswil
- *
- * 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. See <http://www.fsf.org/copyleft/gpl.txt>.
- *
- * 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.
- */
-
-/**
- * @defgroup enumerator enumerator
- * @{ @ingroup utils
- */
-
-#ifndef ENUMERATOR_H_
-#define ENUMERATOR_H_
-
-typedef struct enumerator_t enumerator_t;
-
-#include "../utils.h"
-
-/**
- * Enumerator interface, allows enumeration over collections.
- */
-struct enumerator_t {
-
- /**
- * Enumerate collection.
- *
- * The enumerate function takes a variable argument list containing
- * pointers where the enumerated values get written.
- *
- * @param ... variable list of enumerated items, implementation dependent
- * @return TRUE if pointers returned
- */
- bool (*enumerate)(enumerator_t *this, ...);
-
- /**
- * Destroy a enumerator instance.
- */
- void (*destroy)(enumerator_t *this);
-};
-
-/**
- * Create an enumerator which enumerates over nothing
- *
- * @return an enumerator over no values
- */
-enumerator_t* enumerator_create_empty();
-
-/**
- * Create an enumerator which enumerates over a single item
- *
- * @param item item to enumerate
- * @param cleanup cleanup function called on destroy with the item
- * @return an enumerator over a single value
- */
-enumerator_t *enumerator_create_single(void *item, void (*cleanup)(void *item));
-
-/**
- * Create an enumerator over files/subdirectories in a directory.
- *
- * This enumerator_t.enumerate() function returns a (to the directory) relative
- * filename (as a char*), an absolute filename (as a char*) and a file status
- * (to a struct stat), which all may be NULL. "." and ".." entries are
- * skipped. Example:
- *
- * @code
- char *rel, *abs;
- struct stat st;
- enumerator_t *e;
-
- e = enumerator_create_directory("/tmp");
- if (e)
- {
- while (e->enumerate(e, &rel, &abs, &st))
- {
- if (S_ISDIR(st.st_mode) && *rel != '.')
- {
- printf("%s\n", abs);
- }
- }
- e->destroy(e);
- }
- @endcode
- *
- * @param path path of the directory
- * @return the directory enumerator, NULL on failure
- */
-enumerator_t* enumerator_create_directory(char *path);
-
-/**
- * Create an enumerator over tokens of a string.
- *
- * Tokens are separated by one of the characters in sep and trimmed by the
- * characters in trim.
- *
- * @param string string to parse
- * @param sep separator characters
- * @param trim characters to trim from tokens
- * @return enumerator over char* tokens
- */
-enumerator_t* enumerator_create_token(char *string, char *sep, char *trim);
-
-/**
- * Creates an enumerator which enumerates over enumerated enumerators :-).
- *
- * The variable argument list of enumeration values is limit to 5.
- *
- * @param outer outer enumerator
- * @param inner_constructor constructor to inner enumerator
- * @param data data to pass to each inner_constructor call
- * @param destroy_data destructor to pass to data
- * @return the nested enumerator
- */
-enumerator_t *enumerator_create_nested(enumerator_t *outer,
- enumerator_t *(*inner_constructor)(void *outer, void *data),
- void *data, void (*destroy_data)(void *data));
-
-/**
- * Creates an enumerator which filters output of another enumerator.
- *
- * The filter function receives the user supplied "data" followed by a
- * unfiltered enumeration item, followed by an output pointer where to write
- * the filtered data. Then the next input/output pair follows.
- * It returns TRUE to deliver the
- * values to the caller of enumerate(), FALSE to filter this enumeration.
- *
- * The variable argument list of enumeration values is limit to 5.
- *
- * @param unfiltered unfiltered enumerator to wrap, gets destroyed
- * @param filter filter function
- * @param data user data to supply to filter
- * @param destructor destructor function to clean up data after use
- * @return the filtered enumerator
- */
-enumerator_t *enumerator_create_filter(enumerator_t *unfiltered,
- bool (*filter)(void *data, ...),
- void *data, void (*destructor)(void *data));
-
-/**
- * Create an enumerator wrapper which does a cleanup on destroy.
- *
- * @param wrapped wrapped enumerator
- * @param cleanup cleanup function called on destroy
- * @param data user data to supply to cleanup
- * @return the enumerator with cleanup
- */
-enumerator_t *enumerator_create_cleaner(enumerator_t *wrapped,
- void (*cleanup)(void *data), void *data);
-
-#endif /** ENUMERATOR_H_ @}*/
diff --git a/src/libstrongswan/utils/hashtable.c b/src/libstrongswan/utils/hashtable.c
deleted file mode 100644
index 33f645170..000000000
--- a/src/libstrongswan/utils/hashtable.c
+++ /dev/null
@@ -1,426 +0,0 @@
-/*
- * Copyright (C) 2008-2011 Tobias Brunner
- * Hochschule fuer Technik Rapperswil
- *
- * 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. See <http://www.fsf.org/copyleft/gpl.txt>.
- *
- * 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.
- */
-
-
-#include "hashtable.h"
-
-/** The maximum capacity of the hash table (MUST be a power of 2) */
-#define MAX_CAPACITY (1 << 30)
-
-typedef struct pair_t pair_t;
-
-/**
- * This pair holds a pointer to the key and value it represents.
- */
-struct pair_t {
- /**
- * Key of a hash table item.
- */
- void *key;
-
- /**
- * Value of a hash table item.
- */
- void *value;
-
- /**
- * Cached hash (used in case of a resize).
- */
- u_int hash;
-
- /**
- * Next pair in an overflow list.
- */
- pair_t *next;
-};
-
-/**
- * Creates an empty pair object.
- */
-static inline pair_t *pair_create(void *key, void *value, u_int hash)
-{
- pair_t *this;
-
- INIT(this,
- .key = key,
- .value = value,
- .hash = hash,
- );
-
- return this;
-}
-
-typedef struct private_hashtable_t private_hashtable_t;
-
-/**
- * Private data of a hashtable_t object.
- *
- */
-struct private_hashtable_t {
- /**
- * Public part of hash table.
- */
- hashtable_t public;
-
- /**
- * The number of items in the hash table.
- */
- u_int count;
-
- /**
- * The current capacity of the hash table (always a power of 2).
- */
- u_int capacity;
-
- /**
- * The current mask to calculate the row index (capacity - 1).
- */
- u_int mask;
-
- /**
- * The load factor.
- */
- float load_factor;
-
- /**
- * The actual table.
- */
- pair_t **table;
-
- /**
- * The hashing function.
- */
- hashtable_hash_t hash;
-
- /**
- * The equality function.
- */
- hashtable_equals_t equals;
-};
-
-typedef struct private_enumerator_t private_enumerator_t;
-
-/**
- * hash table enumerator implementation
- */
-struct private_enumerator_t {
-
- /**
- * implements enumerator interface
- */
- enumerator_t enumerator;
-
- /**
- * associated hash table
- */
- private_hashtable_t *table;
-
- /**
- * current row index
- */
- u_int row;
-
- /**
- * number of remaining items in hashtable
- */
- u_int count;
-
- /**
- * current pair
- */
- pair_t *current;
-
- /**
- * previous pair (used by remove_at)
- */
- pair_t *prev;
-
-};
-
-/**
- * This function returns the next-highest power of two for the given number.
- * The algorithm works by setting all bits on the right-hand side of the most
- * significant 1 to 1 and then increments the whole number so it rolls over
- * to the nearest power of two. Note: returns 0 for n == 0
- */
-static u_int get_nearest_powerof2(u_int n)
-{
- u_int i;
-
- --n;
- for (i = 1; i < sizeof(u_int) * 8; i <<= 1)
- {
- n |= n >> i;
- }
- return ++n;
-}
-
-/**
- * Init hash table parameters
- */
-static void init_hashtable(private_hashtable_t *this, u_int capacity)
-{
- capacity = max(1, min(capacity, MAX_CAPACITY));
- this->capacity = get_nearest_powerof2(capacity);
- this->mask = this->capacity - 1;
- this->load_factor = 0.75;
-
- this->table = calloc(this->capacity, sizeof(pair_t*));
-}
-
-/**
- * Double the size of the hash table and rehash all the elements.
- */
-static void rehash(private_hashtable_t *this)
-{
- pair_t **old_table;
- u_int row, old_capacity;
-
- if (this->capacity >= MAX_CAPACITY)
- {
- return;
- }
-
- old_capacity = this->capacity;
- old_table = this->table;
-
- init_hashtable(this, old_capacity << 1);
-
- for (row = 0; row < old_capacity; row++)
- {
- pair_t *pair, *next;
- u_int new_row;
-
- pair = old_table[row];
- while (pair)
- { /* insert pair at the front of new bucket*/
- next = pair->next;
- new_row = pair->hash & this->mask;
- pair->next = this->table[new_row];
- this->table[new_row] = pair;
- pair = next;
- }
- }
- free(old_table);
-}
-
-METHOD(hashtable_t, put, void*,
- private_hashtable_t *this, void *key, void *value)
-{
- void *old_value = NULL;
- pair_t *pair;
- u_int hash, row;
-
- hash = this->hash(key);
- row = hash & this->mask;
- pair = this->table[row];
- while (pair)
- { /* search existing bucket for key */
- if (this->equals(key, pair->key))
- {
- old_value = pair->value;
- pair->value = value;
- pair->key = key;
- break;
- }
- pair = pair->next;
- }
- if (!pair)
- { /* insert at the front of bucket */
- pair = pair_create(key, value, hash);
- pair->next = this->table[row];
- this->table[row] = pair;
- this->count++;
- }
- if (this->count >= this->capacity * this->load_factor)
- {
- rehash(this);
- }
- return old_value;
-}
-
-METHOD(hashtable_t, get, void*,
- private_hashtable_t *this, void *key)
-{
- void *value = NULL;
- pair_t *pair;
-
- pair = this->table[this->hash(key) & this->mask];
- while (pair)
- {
- if (this->equals(key, pair->key))
- {
- value = pair->value;
- break;
- }
- pair = pair->next;
- }
- return value;
-}
-
-METHOD(hashtable_t, remove_, void*,
- private_hashtable_t *this, void *key)
-{
- void *value = NULL;
- pair_t *pair, *prev = NULL;
- u_int row;
-
- row = this->hash(key) & this->mask;
- pair = this->table[row];
- while (pair)
- {
- if (this->equals(key, pair->key))
- {
- if (prev)
- {
- prev->next = pair->next;
- }
- else
- {
- this->table[row] = pair->next;
- }
- value = pair->value;
- this->count--;
- free(pair);
- break;
- }
- prev = pair;
- pair = pair->next;
- }
- return value;
-}
-
-METHOD(hashtable_t, remove_at, void,
- private_hashtable_t *this, private_enumerator_t *enumerator)
-{
- if (enumerator->table == this && enumerator->current)
- {
- pair_t *current = enumerator->current;
- if (enumerator->prev)
- {
- enumerator->prev->next = current->next;
- }
- else
- {
- this->table[enumerator->row] = current->next;
- }
- enumerator->current = enumerator->prev;
- free(current);
- this->count--;
- }
-}
-
-METHOD(hashtable_t, get_count, u_int,
- private_hashtable_t *this)
-{
- return this->count;
-}
-
-METHOD(enumerator_t, enumerate, bool,
- private_enumerator_t *this, void **key, void **value)
-{
- while (this->count && this->row < this->table->capacity)
- {
- this->prev = this->current;
- if (this->current)
- {
- this->current = this->current->next;
- }
- else
- {
- this->current = this->table->table[this->row];
- }
- if (this->current)
- {
- if (key)
- {
- *key = this->current->key;
- }
- if (value)
- {
- *value = this->current->value;
- }
- this->count--;
- return TRUE;
- }
- this->row++;
- }
- return FALSE;
-}
-
-METHOD(hashtable_t, create_enumerator, enumerator_t*,
- private_hashtable_t *this)
-{
- private_enumerator_t *enumerator;
-
- INIT(enumerator,
- .enumerator = {
- .enumerate = (void*)_enumerate,
- .destroy = (void*)free,
- },
- .table = this,
- .count = this->count,
- );
-
- return &enumerator->enumerator;
-}
-
-METHOD(hashtable_t, destroy, void,
- private_hashtable_t *this)
-{
- pair_t *pair, *next;
- u_int row;
-
- for (row = 0; row < this->capacity; row++)
- {
- pair = this->table[row];
- while (pair)
- {
- next = pair->next;
- free(pair);
- pair = next;
- }
- }
- free(this->table);
- free(this);
-}
-
-/*
- * Described in header.
- */
-hashtable_t *hashtable_create(hashtable_hash_t hash, hashtable_equals_t equals,
- u_int capacity)
-{
- private_hashtable_t *this;
-
- INIT(this,
- .public = {
- .put = _put,
- .get = _get,
- .remove = _remove_,
- .remove_at = (void*)_remove_at,
- .get_count = _get_count,
- .create_enumerator = _create_enumerator,
- .destroy = _destroy,
- },
- .hash = hash,
- .equals = equals,
- );
-
- init_hashtable(this, capacity);
-
- return &this->public;
-}
-
diff --git a/src/libstrongswan/utils/hashtable.h b/src/libstrongswan/utils/hashtable.h
deleted file mode 100644
index 27aca9b68..000000000
--- a/src/libstrongswan/utils/hashtable.h
+++ /dev/null
@@ -1,122 +0,0 @@
-/*
- * Copyright (C) 2008-2010 Tobias Brunner
- * Hochschule fuer Technik Rapperswil
- *
- * 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. See <http://www.fsf.org/copyleft/gpl.txt>.
- *
- * 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.
- */
-
-/**
- * @defgroup hashtable hashtable
- * @{ @ingroup utils
- */
-
-#ifndef HASHTABLE_H_
-#define HASHTABLE_H_
-
-#include <utils/enumerator.h>
-
-typedef struct hashtable_t hashtable_t;
-
-/**
- * Prototype for a function that computes the hash code from the given key.
- *
- * @param key key to hash
- * @return hash code
- */
-typedef u_int (*hashtable_hash_t)(void *key);
-
-/**
- * Prototype for a function that compares the two keys for equality.
- *
- * @param key first key (the one we are looking for)
- * @param other_key second key
- * @return TRUE if the keys are equal
- */
-typedef bool (*hashtable_equals_t)(void *key, void *other_key);
-
-/**
- * Class implementing a hash table.
- *
- * General purpose hash table. This hash table is not synchronized.
- */
-struct hashtable_t {
-
- /**
- * Create an enumerator over the hash table key/value pairs.
- *
- * @return enumerator over (void *key, void *value)
- */
- enumerator_t *(*create_enumerator) (hashtable_t *this);
-
- /**
- * Adds the given value with the given key to the hash table, if there
- * exists no entry with that key. NULL is returned in this case.
- * Otherwise the existing value is replaced and the function returns the
- * old value.
- *
- * @param key the key to store
- * @param value the value to store
- * @return NULL if no item was replaced, the old value otherwise
- */
- void *(*put) (hashtable_t *this, void *key, void *value);
-
- /**
- * Returns the value with the given key, if the hash table contains such an
- * entry, otherwise NULL is returned.
- *
- * @param key the key of the requested value
- * @return the value, NULL if not found
- */
- void *(*get) (hashtable_t *this, void *key);
-
- /**
- * Removes the value with the given key from the hash table and returns the
- * removed value (or NULL if no such value existed).
- *
- * @param key the key of the value to remove
- * @return the removed value, NULL if not found
- */
- void *(*remove) (hashtable_t *this, void *key);
-
- /**
- * Removes the key and value pair from the hash table at which the given
- * enumerator currently points.
- *
- * @param enumerator enumerator, from create_enumerator
- */
- void (*remove_at) (hashtable_t *this, enumerator_t *enumerator);
-
- /**
- * Gets the number of items in the hash table.
- *
- * @return number of items
- */
- u_int (*get_count) (hashtable_t *this);
-
- /**
- * Destroys a hash table object.
- */
- void (*destroy) (hashtable_t *this);
-
-};
-
-/**
- * Creates an empty hash table object.
- *
- * @param hash hash function
- * @param equals equals function
- * @param capacity initial capacity
- * @return hashtable_t object.
- */
-hashtable_t *hashtable_create(hashtable_hash_t hash, hashtable_equals_t equals,
- u_int capacity);
-
-#endif /** HASHTABLE_H_ @}*/
diff --git a/src/libstrongswan/utils/host.c b/src/libstrongswan/utils/host.c
deleted file mode 100644
index d3020a5d0..000000000
--- a/src/libstrongswan/utils/host.c
+++ /dev/null
@@ -1,618 +0,0 @@
-/*
- * Copyright (C) 2006-2009 Tobias Brunner
- * Copyright (C) 2006 Daniel Roethlisberger
- * Copyright (C) 2005-2006 Martin Willi
- * Copyright (C) 2005 Jan Hutter
- * Hochschule fuer Technik Rapperswil
- *
- * 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. See <http://www.fsf.org/copyleft/gpl.txt>.
- *
- * 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.
- */
-
-#define _GNU_SOURCE
-#include <sys/socket.h>
-#include <netdb.h>
-#include <string.h>
-
-#include "host.h"
-
-#include <debug.h>
-
-#define IPV4_LEN 4
-#define IPV6_LEN 16
-
-typedef struct private_host_t private_host_t;
-
-/**
- * Private Data of a host object.
- */
-struct private_host_t {
- /**
- * Public data
- */
- host_t public;
-
- /**
- * low-lewel structure, which stores the address
- */
- union {
- /** generic type */
- struct sockaddr address;
- /** maximum sockaddr size */
- struct sockaddr_storage address_max;
- /** IPv4 address */
- struct sockaddr_in address4;
- /** IPv6 address */
- struct sockaddr_in6 address6;
- };
- /**
- * length of address structure
- */
- socklen_t socklen;
-};
-
-
-METHOD(host_t, get_sockaddr, sockaddr_t*,
- private_host_t *this)
-{
- return &(this->address);
-}
-
-METHOD(host_t, get_sockaddr_len, socklen_t*,
- private_host_t *this)
-{
- return &(this->socklen);
-}
-
-METHOD(host_t, is_anyaddr, bool,
- private_host_t *this)
-{
- switch (this->address.sa_family)
- {
- case AF_INET:
- {
- u_int8_t zeroes[IPV4_LEN];
-
- memset(zeroes, 0, IPV4_LEN);
- return memeq(zeroes, &(this->address4.sin_addr.s_addr), IPV4_LEN);
- }
- case AF_INET6:
- {
- u_int8_t zeroes[IPV6_LEN];
-
- memset(zeroes, 0, IPV6_LEN);
- return memeq(zeroes, &(this->address6.sin6_addr.s6_addr), IPV6_LEN);
- }
- default:
- {
- return FALSE;
- }
- }
-}
-
-/**
- * Described in header.
- */
-int host_printf_hook(char *dst, size_t dstlen, printf_hook_spec_t *spec,
- const void *const *args)
-{
- private_host_t *this = *((private_host_t**)(args[0]));
- char buffer[INET6_ADDRSTRLEN + 16];
-
- if (this == NULL)
- {
- snprintf(buffer, sizeof(buffer), "(null)");
- }
- else if (is_anyaddr(this))
- {
- snprintf(buffer, sizeof(buffer), "%%any%s",
- this->address.sa_family == AF_INET6 ? "6" : "");
- }
- else
- {
- void *address;
- u_int16_t port;
- int len;
-
- address = &this->address6.sin6_addr;
- port = this->address6.sin6_port;
-
- switch (this->address.sa_family)
- {
- case AF_INET:
- address = &this->address4.sin_addr;
- port = this->address4.sin_port;
- /* fall */
- case AF_INET6:
-
- if (inet_ntop(this->address.sa_family, address,
- buffer, sizeof(buffer)) == NULL)
- {
- snprintf(buffer, sizeof(buffer),
- "(address conversion failed)");
- }
- else if (spec->hash)
- {
- len = strlen(buffer);
- snprintf(buffer + len, sizeof(buffer) - len,
- "[%d]", ntohs(port));
- }
- break;
- default:
- snprintf(buffer, sizeof(buffer), "(family not supported)");
- break;
- }
- }
- if (spec->minus)
- {
- return print_in_hook(dst, dstlen, "%-*s", spec->width, buffer);
- }
- return print_in_hook(dst, dstlen, "%*s", spec->width, buffer);
-}
-
-METHOD(host_t, get_address, chunk_t,
- private_host_t *this)
-{
- chunk_t address = chunk_empty;
-
- switch (this->address.sa_family)
- {
- case AF_INET:
- {
- address.ptr = (char*)&(this->address4.sin_addr.s_addr);
- address.len = IPV4_LEN;
- return address;
- }
- case AF_INET6:
- {
- address.ptr = (char*)&(this->address6.sin6_addr.s6_addr);
- address.len = IPV6_LEN;
- return address;
- }
- default:
- {
- /* return empty chunk */
- return address;
- }
- }
-}
-
-METHOD(host_t, get_family, int,
- private_host_t *this)
-{
- return this->address.sa_family;
-}
-
-METHOD(host_t, get_port, u_int16_t,
- private_host_t *this)
-{
- switch (this->address.sa_family)
- {
- case AF_INET:
- {
- return ntohs(this->address4.sin_port);
- }
- case AF_INET6:
- {
- return ntohs(this->address6.sin6_port);
- }
- default:
- {
- return 0;
- }
- }
-}
-
-METHOD(host_t, set_port, void,
- private_host_t *this, u_int16_t port)
-{
- switch (this->address.sa_family)
- {
- case AF_INET:
- {
- this->address4.sin_port = htons(port);
- break;
- }
- case AF_INET6:
- {
- this->address6.sin6_port = htons(port);
- break;
- }
- default:
- {
- break;
- }
- }
-}
-
-METHOD(host_t, clone_, host_t*,
- private_host_t *this)
-{
- private_host_t *new;
-
- new = malloc_thing(private_host_t);
- memcpy(new, this, sizeof(private_host_t));
-
- return &new->public;
-}
-
-/**
- * Implements host_t.ip_equals
- */
-static bool ip_equals(private_host_t *this, private_host_t *other)
-{
- if (this->address.sa_family != other->address.sa_family)
- {
- /* 0.0.0.0 and 0::0 are equal */
- return (is_anyaddr(this) && is_anyaddr(other));
- }
-
- switch (this->address.sa_family)
- {
- case AF_INET:
- {
- return memeq(&this->address4.sin_addr, &other->address4.sin_addr,
- sizeof(this->address4.sin_addr));
- }
- case AF_INET6:
- {
- return memeq(&this->address6.sin6_addr, &other->address6.sin6_addr,
- sizeof(this->address6.sin6_addr));
- }
- default:
- break;
- }
- return FALSE;
-}
-
-/**
- * Implements host_t.get_differences
- */
-static host_diff_t get_differences(host_t *this, host_t *other)
-{
- host_diff_t ret = HOST_DIFF_NONE;
-
- if (!this->ip_equals(this, other))
- {
- ret |= HOST_DIFF_ADDR;
- }
-
- if (this->get_port(this) != other->get_port(other))
- {
- ret |= HOST_DIFF_PORT;
- }
-
- return ret;
-}
-
-/**
- * Implements host_t.equals
- */
-static bool equals(private_host_t *this, private_host_t *other)
-{
- if (!ip_equals(this, other))
- {
- return FALSE;
- }
-
- switch (this->address.sa_family)
- {
- case AF_INET:
- {
- return (this->address4.sin_port == other->address4.sin_port);
- }
- case AF_INET6:
- {
- return (this->address6.sin6_port == other->address6.sin6_port);
- }
- default:
- break;
- }
- return FALSE;
-}
-
-METHOD(host_t, destroy, void,
- private_host_t *this)
-{
- free(this);
-}
-
-/**
- * Creates an empty host_t object
- */
-static private_host_t *host_create_empty(void)
-{
- private_host_t *this;
-
- INIT(this,
- .public = {
- .get_sockaddr = _get_sockaddr,
- .get_sockaddr_len = _get_sockaddr_len,
- .clone = _clone_,
- .get_family = _get_family,
- .get_address = _get_address,
- .get_port = _get_port,
- .set_port = _set_port,
- .get_differences = get_differences,
- .ip_equals = (bool (*)(host_t *,host_t *))ip_equals,
- .equals = (bool (*)(host_t *,host_t *)) equals,
- .is_anyaddr = _is_anyaddr,
- .destroy = _destroy,
- },
- );
-
- return this;
-}
-
-/*
- * Create a %any host with port
- */
-static host_t *host_create_any_port(int family, u_int16_t port)
-{
- host_t *this;
-
- this = host_create_any(family);
- this->set_port(this, port);
- return this;
-}
-
-/*
- * Described in header.
- */
-host_t *host_create_from_string(char *string, u_int16_t port)
-{
- private_host_t *this;
-
- if (streq(string, "%any"))
- {
- return host_create_any_port(AF_INET, port);
- }
- if (streq(string, "%any6"))
- {
- return host_create_any_port(AF_INET6, port);
- }
-
- this = host_create_empty();
- if (strchr(string, '.'))
- {
- this->address.sa_family = AF_INET;
- }
- else
- {
- this->address.sa_family = AF_INET6;
- }
- switch (this->address.sa_family)
- {
- case AF_INET:
- {
- if (inet_pton(AF_INET, string, &this->address4.sin_addr) <=0)
- {
- break;
- }
- this->address4.sin_port = htons(port);
- this->socklen = sizeof(struct sockaddr_in);
- return &this->public;
- }
- case AF_INET6:
- {
- if (inet_pton(AF_INET6, string, &this->address6.sin6_addr) <=0)
- {
- break;
- }
- this->address6.sin6_port = htons(port);
- this->socklen = sizeof(struct sockaddr_in6);
- return &this->public;
- }
- default:
- {
- break;
- }
- }
- free(this);
- return NULL;
-}
-
-/*
- * Described in header.
- */
-host_t *host_create_from_sockaddr(sockaddr_t *sockaddr)
-{
- private_host_t *this = host_create_empty();
-
- switch (sockaddr->sa_family)
- {
- case AF_INET:
- {
- memcpy(&this->address4, sockaddr, sizeof(struct sockaddr_in));
- this->socklen = sizeof(struct sockaddr_in);
- return &this->public;
- }
- case AF_INET6:
- {
- memcpy(&this->address6, sockaddr, sizeof(struct sockaddr_in6));
- this->socklen = sizeof(struct sockaddr_in6);
- return &this->public;
- }
- default:
- break;
- }
- free(this);
- return NULL;
-}
-
-/*
- * Described in header.
- */
-host_t *host_create_from_dns(char *string, int af, u_int16_t port)
-{
- private_host_t *this;
- struct addrinfo hints, *result;
- int error;
-
- if (streq(string, "%any"))
- {
- return host_create_any_port(af ? af : AF_INET, port);
- }
- if (streq(string, "%any6"))
- {
- return host_create_any_port(af ? af : AF_INET6, port);
- }
- if (af == AF_INET && strchr(string, ':'))
- { /* do not try to convert v6 addresses for v4 family */
- return NULL;
- }
-
- memset(&hints, 0, sizeof(hints));
- hints.ai_family = af;
- error = getaddrinfo(string, NULL, &hints, &result);
- if (error != 0)
- {
- DBG1(DBG_LIB, "resolving '%s' failed: %s", string, gai_strerror(error));
- return NULL;
- }
- /* result is a linked list, but we use only the first address */
- this = (private_host_t*)host_create_from_sockaddr(result->ai_addr);
- freeaddrinfo(result);
- if (this)
- {
- switch (this->address.sa_family)
- {
- case AF_INET:
- this->address4.sin_port = htons(port);
- break;
- case AF_INET6:
- this->address6.sin6_port = htons(port);
- break;
- }
- return &this->public;
- }
- return NULL;
-}
-
-/*
- * Described in header.
- */
-host_t *host_create_from_chunk(int family, chunk_t address, u_int16_t port)
-{
- private_host_t *this;
-
- switch (family)
- {
- case AF_INET:
- if (address.len < IPV4_LEN)
- {
- return NULL;
- }
- address.len = IPV4_LEN;
- break;
- case AF_INET6:
- if (address.len < IPV6_LEN)
- {
- return NULL;
- }
- address.len = IPV6_LEN;
- break;
- case AF_UNSPEC:
- switch (address.len)
- {
- case IPV4_LEN:
- family = AF_INET;
- break;
- case IPV6_LEN:
- family = AF_INET6;
- break;
- default:
- return NULL;
- }
- break;
- default:
- return NULL;
- }
- this = host_create_empty();
- this->address.sa_family = family;
- switch (family)
- {
- case AF_INET:
- memcpy(&this->address4.sin_addr.s_addr, address.ptr, address.len);
- this->address4.sin_port = htons(port);
- this->socklen = sizeof(struct sockaddr_in);
- break;
- case AF_INET6:
- memcpy(&this->address6.sin6_addr.s6_addr, address.ptr, address.len);
- this->address6.sin6_port = htons(port);
- this->socklen = sizeof(struct sockaddr_in6);
- break;
- }
- return &this->public;
-}
-
-/*
- * Described in header.
- */
-host_t *host_create_from_subnet(char *string, int *bits)
-{
- char *pos, buf[64];
- host_t *net;
-
- pos = strchr(string, '/');
- if (pos)
- {
- if (pos - string >= sizeof(buf))
- {
- return NULL;
- }
- strncpy(buf, string, pos - string);
- buf[pos - string] = '\0';
- *bits = atoi(pos + 1);
- return host_create_from_string(buf, 0);
- }
- net = host_create_from_string(string, 0);
- if (net)
- {
- if (net->get_family(net) == AF_INET)
- {
- *bits = 32;
- }
- else
- {
- *bits = 128;
- }
- }
- return net;
-}
-
-/*
- * Described in header.
- */
-host_t *host_create_any(int family)
-{
- private_host_t *this = host_create_empty();
-
- memset(&this->address_max, 0, sizeof(struct sockaddr_storage));
- this->address.sa_family = family;
-
- switch (family)
- {
- case AF_INET:
- {
- this->socklen = sizeof(struct sockaddr_in);
- return &(this->public);
- }
- case AF_INET6:
- {
- this->socklen = sizeof(struct sockaddr_in6);
- return &this->public;
- }
- default:
- break;
- }
- free(this);
- return NULL;
-}
diff --git a/src/libstrongswan/utils/host.h b/src/libstrongswan/utils/host.h
deleted file mode 100644
index 0a1be6e47..000000000
--- a/src/libstrongswan/utils/host.h
+++ /dev/null
@@ -1,219 +0,0 @@
-/*
- * Copyright (C) 2006-2009 Tobias Brunner
- * Copyright (C) 2006 Daniel Roethlisberger
- * Copyright (C) 2005-2008 Martin Willi
- * Copyright (C) 2005 Jan Hutter
- * Hochschule fuer Technik Rapperswil
- *
- * 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. See <http://www.fsf.org/copyleft/gpl.txt>.
- *
- * 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.
- */
-
-/**
- * @defgroup host host
- * @{ @ingroup utils
- */
-
-#ifndef HOST_H_
-#define HOST_H_
-
-typedef enum host_diff_t host_diff_t;
-typedef struct host_t host_t;
-
-#include <stdlib.h>
-#include <stdio.h>
-#include <sys/types.h>
-#include <sys/socket.h>
-#include <netinet/in.h>
-#include <arpa/inet.h>
-
-#include <chunk.h>
-
-/**
- * Differences between two hosts. They differ in
- * address, port, or both.
- */
-enum host_diff_t {
- HOST_DIFF_NONE = 0,
- HOST_DIFF_ADDR = 1,
- HOST_DIFF_PORT = 2,
-};
-
-/**
- * Representates a Host
- *
- * Host object, identifies a address:port pair and defines some
- * useful functions on it.
- */
-struct host_t {
-
- /**
- * Build a clone of this host object.
- *
- * @return cloned host
- */
- host_t *(*clone) (host_t *this);
-
- /**
- * Get a pointer to the internal sockaddr struct.
- *
- * This is used for sending and receiving via sockets.
- *
- * @return pointer to the internal sockaddr structure
- */
- sockaddr_t *(*get_sockaddr) (host_t *this);
-
- /**
- * Get the length of the sockaddr struct.
- *
- * Depending on the family, the length of the sockaddr struct
- * is different. Use this function to get the length of the sockaddr
- * struct returned by get_sock_addr.
- *
- * This is used for sending and receiving via sockets.
- *
- * @return length of the sockaddr struct
- */
- socklen_t *(*get_sockaddr_len) (host_t *this);
-
- /**
- * Gets the family of the address
- *
- * @return family
- */
- int (*get_family) (host_t *this);
-
- /**
- * Checks if the ip address of host is set to default route.
- *
- * @return TRUE if host is 0.0.0.0 or 0::0, FALSE otherwise
- */
- bool (*is_anyaddr) (host_t *this);
-
- /**
- * Get the address of this host as chunk_t
- *
- * Returned chunk points to internal data.
- *
- * @return address string,
- */
- chunk_t (*get_address) (host_t *this);
-
- /**
- * Get the port of this host
- *
- * @return port number
- */
- u_int16_t (*get_port) (host_t *this);
-
- /**
- * Set the port of this host
- *
- * @param port port numer
- */
- void (*set_port) (host_t *this, u_int16_t port);
-
- /**
- * Compare the ips of two hosts hosts.
- *
- * @param other the other to compare
- * @return TRUE if addresses are equal.
- */
- bool (*ip_equals) (host_t *this, host_t *other);
-
- /**
- * Compare two hosts, with port.
- *
- * @param other the other to compare
- * @return TRUE if addresses and ports are equal.
- */
- bool (*equals) (host_t *this, host_t *other);
-
- /**
- * Compare two hosts and return the differences.
- *
- * @param other the other to compare
- * @return differences in a combination of host_diff_t's
- */
- host_diff_t (*get_differences) (host_t *this, host_t *other);
-
- /**
- * Destroy this host object.
- */
- void (*destroy) (host_t *this);
-};
-
-/**
- * Constructor to create a host_t object from an address string.
- *
- * @param string string of an address, such as "152.96.193.130"
- * @param port port number
- * @return host_t, NULL if string not an address.
- */
-host_t *host_create_from_string(char *string, u_int16_t port);
-
-/**
- * Constructor to create a host_t from a DNS name.
- *
- * @param string hostname to resolve
- * @param family family to prefer, 0 for first match
- * @param port port number
- * @return host_t, NULL lookup failed
- */
-host_t *host_create_from_dns(char *string, int family, u_int16_t port);
-
-/**
- * Constructor to create a host_t object from an address chunk.
- *
- * If family is AF_UNSPEC, it is guessed using address.len.
- *
- * @param family Address family, such as AF_INET or AF_INET6
- * @param address address as chunk_t in network order
- * @param port port number
- * @return host_t, NULL if family not supported/chunk invalid
- */
-host_t *host_create_from_chunk(int family, chunk_t address, u_int16_t port);
-
-/**
- * Constructor to create a host_t object from a sockaddr struct
- *
- * @param sockaddr sockaddr struct which contains family, address and port
- * @return host_t, NULL if family not supported
- */
-host_t *host_create_from_sockaddr(sockaddr_t *sockaddr);
-
-/**
- * Create a host from a CIDR subnet definition (1.2.3.0/24), return bits.
- *
- * @param string string to parse
- * @param bits gets the number of network bits in CIDR notation
- * @return network start address, NULL on error
- */
-host_t *host_create_from_subnet(char *string, int *bits);
-
-/**
- * Create a host without an address, a "any" host.
- *
- * @param family family of the any host
- * @return host_t, NULL if family not supported
- */
-host_t *host_create_any(int family);
-
-/**
- * printf hook function for host_t.
- *
- * Arguments are:
- * host_t *host
- * Use #-modifier to include port number
- */
-int host_printf_hook(char *dst, size_t len, printf_hook_spec_t *spec,
- const void *const *args);
-
-#endif /** HOST_H_ @}*/
diff --git a/src/libstrongswan/utils/identification.c b/src/libstrongswan/utils/identification.c
index 9f0007f78..5df3e5fe2 100644
--- a/src/libstrongswan/utils/identification.c
+++ b/src/libstrongswan/utils/identification.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2009 Tobias Brunner
+ * Copyright (C) 2009-2012 Tobias Brunner
* Copyright (C) 2005-2009 Martin Willi
* Copyright (C) 2005 Jan Hutter
* Hochschule fuer Technik Rapperswil
@@ -49,10 +49,10 @@ ENUM_BEGIN(id_type_names, ID_ANY, ID_KEY_ID,
"ID_DER_ASN1_DN",
"ID_DER_ASN1_GN",
"ID_KEY_ID");
-ENUM_NEXT(id_type_names, ID_DER_ASN1_GN_URI, ID_MYID, ID_KEY_ID,
+ENUM_NEXT(id_type_names, ID_DER_ASN1_GN_URI, ID_USER_ID, ID_KEY_ID,
"ID_DER_ASN1_GN_URI",
- "ID_MYID");
-ENUM_END(id_type_names, ID_MYID);
+ "ID_USER_ID");
+ENUM_END(id_type_names, ID_USER_ID);
/**
* coding of X.501 distinguished name
@@ -277,6 +277,23 @@ METHOD(identification_t, create_part_enumerator, enumerator_t*,
}
/**
+ * Print a separator between two RDNs
+ */
+static inline bool print_separator(char **buf, size_t *len)
+{
+ int written;
+
+ written = snprintf(*buf, *len, ", ");
+ if (written < 0 || written >= *len)
+ {
+ return FALSE;
+ }
+ *buf += written;
+ *len -= written;
+ return TRUE;
+}
+
+/**
* Print a DN with all its RDN in a buffer to present it to the user
*/
static void dntoa(chunk_t dn, char *buf, size_t len)
@@ -292,8 +309,14 @@ static void dntoa(chunk_t dn, char *buf, size_t len)
{
empty = FALSE;
- oid = asn1_known_oid(oid_data);
+ /* previous RDN was empty but it wasn't the last one */
+ if (finished && !print_separator(&buf, &len))
+ {
+ break;
+ }
+ finished = FALSE;
+ oid = asn1_known_oid(oid_data);
if (oid == OID_UNKNOWN)
{
written = snprintf(buf, len, "%#B=", &oid_data);
@@ -310,7 +333,7 @@ static void dntoa(chunk_t dn, char *buf, size_t len)
len -= written;
chunk_printable(data, &printable, '?');
- written = snprintf(buf, len, "%.*s", printable.len, printable.ptr);
+ written = snprintf(buf, len, "%.*s", (int)printable.len, printable.ptr);
chunk_free(&printable);
if (written < 0 || written >= len)
{
@@ -319,21 +342,19 @@ static void dntoa(chunk_t dn, char *buf, size_t len)
buf += written;
len -= written;
- if (data.ptr + data.len != dn.ptr + dn.len)
- {
- written = snprintf(buf, len, ", ");
- if (written < 0 || written >= len)
- {
- break;
- }
- buf += written;
- len -= written;
+ if (!data.ptr)
+ { /* we can't calculate if we're finished, assume we are */
+ finished = TRUE;
}
- else
+ else if (data.ptr + data.len == dn.ptr + dn.len)
{
finished = TRUE;
break;
}
+ else if (!print_separator(&buf, &len))
+ {
+ break;
+ }
}
if (empty)
{
@@ -377,7 +398,7 @@ static status_t atodn(char *src, chunk_t *dn)
switch (state)
{
case SEARCH_OID:
- if (*src != ' ' && *src != '/' && *src != ',')
+ if (*src != ' ' && *src != '/' && *src != ',' && *src != '\0')
{
oid.ptr = src;
oid.len = 1;
@@ -414,14 +435,22 @@ static status_t atodn(char *src, chunk_t *dn)
}
break;
case SEARCH_NAME:
- if (*src != ' ' && *src != '=')
+ if (*src == ' ' || *src == '=')
+ {
+ break;
+ }
+ else if (*src != ',' && *src != '/' && *src != '\0')
{
name.ptr = src;
name.len = 1;
whitespace = 0;
state = READ_NAME;
+ break;
}
- break;
+ name = chunk_empty;
+ whitespace = 0;
+ state = READ_NAME;
+ /* fall-through */
case READ_NAME:
if (*src != ',' && *src != '/' && *src != '\0')
{
@@ -473,6 +502,11 @@ static status_t atodn(char *src, chunk_t *dn)
}
} while (*src++ != '\0');
+ if (state == READ_OID)
+ { /* unterminated OID */
+ status = INVALID_ARG;
+ }
+
/* build the distinguished name sequence */
{
int i;
@@ -485,7 +519,6 @@ static status_t atodn(char *src, chunk_t *dn)
free(rdns[i].ptr);
}
}
-
if (status != SUCCESS)
{
free(dn->ptr);
@@ -748,8 +781,8 @@ METHOD(identification_t, matches_dn, id_match_t,
/**
* Described in header.
*/
-int identification_printf_hook(char *dst, size_t len, printf_hook_spec_t *spec,
- const void *const *args)
+int identification_printf_hook(printf_hook_data_t *data,
+ printf_hook_spec_t *spec, const void *const *args)
{
private_identification_t *this = *((private_identification_t**)(args[0]));
chunk_t proper;
@@ -757,7 +790,7 @@ int identification_printf_hook(char *dst, size_t len, printf_hook_spec_t *spec,
if (this == NULL)
{
- return print_in_hook(dst, len, "%*s", spec->width, "(null)");
+ return print_in_hook(data, "%*s", spec->width, "(null)");
}
switch (this->type)
@@ -782,40 +815,38 @@ int identification_printf_hook(char *dst, size_t len, printf_hook_spec_t *spec,
case ID_FQDN:
case ID_RFC822_ADDR:
case ID_DER_ASN1_GN_URI:
+ case ID_USER_ID:
chunk_printable(this->encoded, &proper, '?');
- snprintf(buf, sizeof(buf), "%.*s", proper.len, proper.ptr);
+ snprintf(buf, sizeof(buf), "%.*s", (int)proper.len, proper.ptr);
chunk_free(&proper);
break;
case ID_DER_ASN1_DN:
dntoa(this->encoded, buf, sizeof(buf));
break;
case ID_DER_ASN1_GN:
- snprintf(buf, sizeof(buf), "(ASN.1 general Name");
+ snprintf(buf, sizeof(buf), "(ASN.1 general name)");
break;
case ID_KEY_ID:
if (chunk_printable(this->encoded, NULL, '?') &&
this->encoded.len != HASH_SIZE_SHA1)
{ /* fully printable, use ascii version */
- snprintf(buf, sizeof(buf), "%.*s",
- this->encoded.len, this->encoded.ptr);
+ snprintf(buf, sizeof(buf), "%.*s", (int)this->encoded.len,
+ this->encoded.ptr);
}
else
{ /* not printable, hex dump */
snprintf(buf, sizeof(buf), "%#B", &this->encoded);
}
break;
- case ID_MYID:
- snprintf(buf, sizeof(buf), "%%myid");
- break;
default:
snprintf(buf, sizeof(buf), "(unknown ID type: %d)", this->type);
break;
}
if (spec->minus)
{
- return print_in_hook(dst, len, "%-*s", spec->width, buf);
+ return print_in_hook(data, "%-*s", spec->width, buf);
}
- return print_in_hook(dst, len, "%*s", spec->width, buf);
+ return print_in_hook(data, "%*s", spec->width, buf);
}
METHOD(identification_t, clone_, identification_t*,
@@ -865,6 +896,7 @@ static private_identification_t *identification_create(id_type_t type)
break;
case ID_FQDN:
case ID_RFC822_ADDR:
+ case ID_USER_ID:
this->public.matches = _matches_string;
this->public.equals = _equals_strcasecmp;
this->public.contains_wildcards = _contains_wildcards_memchr;
@@ -908,14 +940,15 @@ identification_t *identification_create_from_string(char *string)
else
{
this = identification_create(ID_KEY_ID);
- this->encoded = chunk_clone(chunk_create(string, strlen(string)));
+ this->encoded = chunk_from_str(strdup(string));
}
return &this->public;
}
else if (strchr(string, '@') == NULL)
{
- if (streq(string, "%any")
- || streq(string, "%any6")
+ if (streq(string, "")
+ || streq(string, "%any")
+ || streq(string, "%any6")
|| streq(string, "0.0.0.0")
|| streq(string, "*")
|| streq(string, "::")
@@ -940,11 +973,7 @@ identification_t *identification_create_from_string(char *string)
else
{ /* not IPv4, mostly FQDN */
this = identification_create(ID_FQDN);
- this->encoded.len = strlen(string);
- if (this->encoded.len)
- {
- this->encoded.ptr = strdup(string);
- }
+ this->encoded = chunk_from_str(strdup(string));
}
return &this->public;
}
@@ -961,11 +990,7 @@ identification_t *identification_create_from_string(char *string)
else
{ /* not IPv4/6 fallback to KEY_ID */
this = identification_create(ID_KEY_ID);
- this->encoded.len = strlen(string);
- if (this->encoded.len)
- {
- this->encoded.ptr = strdup(string);
- }
+ this->encoded = chunk_from_str(strdup(string));
}
return &this->public;
}
@@ -975,34 +1000,30 @@ identification_t *identification_create_from_string(char *string)
{
if (*string == '@')
{
- if (*(string + 1) == '#')
+ string++;
+ if (*string == '#')
{
this = identification_create(ID_KEY_ID);
- string += 2;
- this->encoded = chunk_from_hex(
- chunk_create(string, strlen(string)), NULL);
+ this->encoded = chunk_from_hex(chunk_from_str(string + 1), NULL);
+ return &this->public;
+ }
+ else if (*string == '@')
+ {
+ this = identification_create(ID_USER_FQDN);
+ this->encoded = chunk_clone(chunk_from_str(string + 1));
return &this->public;
}
else
{
this = identification_create(ID_FQDN);
- string += 1;
- this->encoded.len = strlen(string);
- if (this->encoded.len)
- {
- this->encoded.ptr = strdup(string);
- }
+ this->encoded = chunk_clone(chunk_from_str(string));
return &this->public;
}
}
else
{
this = identification_create(ID_RFC822_ADDR);
- this->encoded.len = strlen(string);
- if (this->encoded.len)
- {
- this->encoded.ptr = strdup(string);
- }
+ this->encoded = chunk_from_str(strdup(string));
return &this->public;
}
}
@@ -1015,9 +1036,16 @@ identification_t * identification_create_from_data(chunk_t data)
{
char buf[data.len + 1];
- /* use string constructor */
- snprintf(buf, sizeof(buf), "%.*s", data.len, data.ptr);
- return identification_create_from_string(buf);
+ if (is_asn1(data))
+ {
+ return identification_create_from_encoding(ID_DER_ASN1_DN, data);
+ }
+ else
+ {
+ /* use string constructor */
+ snprintf(buf, sizeof(buf), "%.*s", (int)data.len, data.ptr);
+ return identification_create_from_string(buf);
+ }
}
/*
@@ -1065,4 +1093,3 @@ identification_t *identification_create_from_sockaddr(sockaddr_t *sockaddr)
}
}
}
-
diff --git a/src/libstrongswan/utils/identification.h b/src/libstrongswan/utils/identification.h
index 3978b23f3..e62446879 100644
--- a/src/libstrongswan/utils/identification.h
+++ b/src/libstrongswan/utils/identification.h
@@ -29,8 +29,8 @@ typedef struct identification_t identification_t;
typedef enum id_match_t id_match_t;
typedef enum id_part_t id_part_t;
-#include <chunk.h>
-#include <utils/enumerator.h>
+#include <utils/chunk.h>
+#include <collections/enumerator.h>
/**
* Matches returned from identification_t.match
@@ -126,14 +126,14 @@ enum id_type_t {
ID_KEY_ID = 11,
/**
- * private type which represents a GeneralName of type URI
+ * Private ID type which represents a GeneralName of type URI
*/
ID_DER_ASN1_GN_URI = 201,
/**
- * Private ID used by the pluto daemon for opportunistic encryption
+ * Private ID type which represents a user ID
*/
- ID_MYID = 203,
+ ID_USER_ID = 202
};
/**
@@ -241,7 +241,6 @@ struct identification_t {
* no match at all, 1 means a bad match, and 2 a slightly better match.
*
* @param other the ID containing one or more wildcards
- * @param wildcards returns the number of wildcards, may be NULL
* @return match value as described above
*/
id_match_t (*matches) (identification_t *this, identification_t *other);
@@ -342,7 +341,7 @@ identification_t * identification_create_from_sockaddr(sockaddr_t *sockaddr);
* Arguments are:
* identification_t *identification
*/
-int identification_printf_hook(char *dst, size_t len, printf_hook_spec_t *spec,
- const void *const *args);
+int identification_printf_hook(printf_hook_data_t *data,
+ printf_hook_spec_t *spec, const void *const *args);
#endif /** IDENTIFICATION_H_ @}*/
diff --git a/src/libstrongswan/utils/integrity_checker.c b/src/libstrongswan/utils/integrity_checker.c
new file mode 100644
index 000000000..d59a76232
--- /dev/null
+++ b/src/libstrongswan/utils/integrity_checker.c
@@ -0,0 +1,321 @@
+/*
+ * Copyright (C) 2009 Martin Willi
+ * Hochschule fuer Technik Rapperswil
+ *
+ * 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. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * 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.
+ */
+
+#define _GNU_SOURCE
+
+#include "integrity_checker.h"
+
+#include <dlfcn.h>
+#include <link.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <unistd.h>
+#include <sys/mman.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+
+#include "debug.h"
+#include "library.h"
+
+typedef struct private_integrity_checker_t private_integrity_checker_t;
+
+/**
+ * Private data of an integrity_checker_t object.
+ */
+struct private_integrity_checker_t {
+
+ /**
+ * Public integrity_checker_t interface.
+ */
+ integrity_checker_t public;
+
+ /**
+ * dlopen handle to checksum library
+ */
+ void *handle;
+
+ /**
+ * checksum array
+ */
+ integrity_checksum_t *checksums;
+
+ /**
+ * number of checksums in array
+ */
+ int checksum_count;
+};
+
+METHOD(integrity_checker_t, build_file, u_int32_t,
+ private_integrity_checker_t *this, char *file, size_t *len)
+{
+ u_int32_t checksum;
+ chunk_t contents;
+ struct stat sb;
+ void *addr;
+ int fd;
+
+ fd = open(file, O_RDONLY);
+ if (fd == -1)
+ {
+ DBG1(DBG_LIB, " opening '%s' failed: %s", file, strerror(errno));
+ return 0;
+ }
+
+ if (fstat(fd, &sb) == -1)
+ {
+ DBG1(DBG_LIB, " getting file size of '%s' failed: %s", file,
+ strerror(errno));
+ close(fd);
+ return 0;
+ }
+
+ addr = mmap(NULL, sb.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
+ if (addr == MAP_FAILED)
+ {
+ DBG1(DBG_LIB, " mapping '%s' failed: %s", file, strerror(errno));
+ close(fd);
+ return 0;
+ }
+
+ *len = sb.st_size;
+ contents = chunk_create(addr, sb.st_size);
+ checksum = chunk_hash_static(contents);
+
+ munmap(addr, sb.st_size);
+ close(fd);
+
+ return checksum;
+}
+
+/**
+ * dl_iterate_phdr callback function
+ */
+static int callback(struct dl_phdr_info *dlpi, size_t size, Dl_info *dli)
+{
+ /* We are looking for the dlpi_addr matching the address of our dladdr().
+ * dl_iterate_phdr() returns such an address for other (unknown) objects
+ * in very rare cases (e.g. in a chrooted gentoo, but only if
+ * the checksum_builder is invoked by 'make'). As a workaround, we filter
+ * objects by dlpi_name; valid objects have a library name.
+ */
+ if (dli->dli_fbase == (void*)dlpi->dlpi_addr &&
+ dlpi->dlpi_name && *dlpi->dlpi_name)
+ {
+ int i;
+
+ for (i = 0; i < dlpi->dlpi_phnum; i++)
+ {
+ const ElfW(Phdr) *sgmt = &dlpi->dlpi_phdr[i];
+
+ /* we are interested in the executable LOAD segment */
+ if (sgmt->p_type == PT_LOAD && (sgmt->p_flags & PF_X))
+ {
+ /* safe begin of segment in dli_fbase */
+ dli->dli_fbase = (void*)sgmt->p_vaddr + dlpi->dlpi_addr;
+ /* safe end of segment in dli_saddr */
+ dli->dli_saddr = dli->dli_fbase + sgmt->p_memsz;
+ return 1;
+ }
+ }
+ }
+ return 0;
+}
+
+METHOD(integrity_checker_t, build_segment, u_int32_t,
+ private_integrity_checker_t *this, void *sym, size_t *len)
+{
+ chunk_t segment;
+ Dl_info dli;
+
+ if (dladdr(sym, &dli) == 0)
+ {
+ DBG1(DBG_LIB, " unable to locate symbol: %s", dlerror());
+ return 0;
+ }
+ /* we reuse the Dl_info struct as in/out parameter */
+ if (!dl_iterate_phdr((void*)callback, &dli))
+ {
+ DBG1(DBG_LIB, " executable section not found");
+ return 0;
+ }
+
+ segment = chunk_create(dli.dli_fbase, dli.dli_saddr - dli.dli_fbase);
+ *len = segment.len;
+ return chunk_hash_static(segment);
+}
+
+/**
+ * Find a checksum by its name
+ */
+static integrity_checksum_t *find_checksum(private_integrity_checker_t *this,
+ char *name)
+{
+ int i;
+
+ for (i = 0; i < this->checksum_count; i++)
+ {
+ if (streq(this->checksums[i].name, name))
+ {
+ return &this->checksums[i];
+ }
+ }
+ return NULL;
+}
+
+METHOD(integrity_checker_t, check_file, bool,
+ private_integrity_checker_t *this, char *name, char *file)
+{
+ integrity_checksum_t *cs;
+ u_int32_t sum;
+ size_t len = 0;
+
+ cs = find_checksum(this, name);
+ if (!cs)
+ {
+ DBG1(DBG_LIB, " '%s' file checksum not found", name);
+ return FALSE;
+ }
+ sum = build_file(this, file, &len);
+ if (!sum)
+ {
+ return FALSE;
+ }
+ if (cs->file_len != len)
+ {
+ DBG1(DBG_LIB, " invalid '%s' file size: %u bytes, expected %u bytes",
+ name, len, cs->file_len);
+ return FALSE;
+ }
+ if (cs->file != sum)
+ {
+ DBG1(DBG_LIB, " invalid '%s' file checksum: %08x, expected %08x",
+ name, sum, cs->file);
+ return FALSE;
+ }
+ DBG2(DBG_LIB, " valid '%s' file checksum: %08x", name, sum);
+ return TRUE;
+}
+
+METHOD(integrity_checker_t, check_segment, bool,
+ private_integrity_checker_t *this, char *name, void *sym)
+{
+ integrity_checksum_t *cs;
+ u_int32_t sum;
+ size_t len = 0;
+
+ cs = find_checksum(this, name);
+ if (!cs)
+ {
+ DBG1(DBG_LIB, " '%s' segment checksum not found", name);
+ return FALSE;
+ }
+ sum = build_segment(this, sym, &len);
+ if (!sum)
+ {
+ return FALSE;
+ }
+ if (cs->segment_len != len)
+ {
+ DBG1(DBG_LIB, " invalid '%s' segment size: %u bytes,"
+ " expected %u bytes", name, len, cs->segment_len);
+ return FALSE;
+ }
+ if (cs->segment != sum)
+ {
+ DBG1(DBG_LIB, " invalid '%s' segment checksum: %08x, expected %08x",
+ name, sum, cs->segment);
+ return FALSE;
+ }
+ DBG2(DBG_LIB, " valid '%s' segment checksum: %08x", name, sum);
+ return TRUE;
+}
+
+METHOD(integrity_checker_t, check, bool,
+ private_integrity_checker_t *this, char *name, void *sym)
+{
+ Dl_info dli;
+
+ if (dladdr(sym, &dli) == 0)
+ {
+ DBG1(DBG_LIB, "unable to locate symbol: %s", dlerror());
+ return FALSE;
+ }
+ if (!check_file(this, name, (char*)dli.dli_fname))
+ {
+ return FALSE;
+ }
+ if (!check_segment(this, name, sym))
+ {
+ return FALSE;
+ }
+ return TRUE;
+}
+
+METHOD(integrity_checker_t, destroy, void,
+ private_integrity_checker_t *this)
+{
+ if (this->handle)
+ {
+ dlclose(this->handle);
+ }
+ free(this);
+}
+
+/**
+ * See header
+ */
+integrity_checker_t *integrity_checker_create(char *checksum_library)
+{
+ private_integrity_checker_t *this;
+
+ INIT(this,
+ .public = {
+ .check_file = _check_file,
+ .build_file = _build_file,
+ .check_segment = _check_segment,
+ .build_segment = _build_segment,
+ .check = _check,
+ .destroy = _destroy,
+ },
+ );
+
+ if (checksum_library)
+ {
+ this->handle = dlopen(checksum_library, RTLD_LAZY);
+ if (this->handle)
+ {
+ int *checksum_count;
+
+ this->checksums = dlsym(this->handle, "checksums");
+ checksum_count = dlsym(this->handle, "checksum_count");
+ if (this->checksums && checksum_count)
+ {
+ this->checksum_count = *checksum_count;
+ }
+ else
+ {
+ DBG1(DBG_LIB, "checksum library '%s' invalid",
+ checksum_library);
+ }
+ }
+ else
+ {
+ DBG1(DBG_LIB, "loading checksum library '%s' failed",
+ checksum_library);
+ }
+ }
+ return &this->public;
+}
+
diff --git a/src/libstrongswan/utils/integrity_checker.h b/src/libstrongswan/utils/integrity_checker.h
new file mode 100644
index 000000000..afaa114b3
--- /dev/null
+++ b/src/libstrongswan/utils/integrity_checker.h
@@ -0,0 +1,110 @@
+/*
+ * Copyright (C) 2009 Martin Willi
+ * Hochschule fuer Technik Rapperswil
+ *
+ * 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. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * 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.
+ */
+
+/**
+ * @defgroup integrity_checker integrity_checker
+ * @{ @ingroup utils
+ */
+
+#ifndef INTEGRITY_CHECKER_H_
+#define INTEGRITY_CHECKER_H_
+
+#include "utils.h"
+
+typedef struct integrity_checker_t integrity_checker_t;
+typedef struct integrity_checksum_t integrity_checksum_t;
+
+/**
+ * Struct to hold a precalculated checksum, implemented in the checksum library.
+ */
+struct integrity_checksum_t {
+ /* name of the checksum */
+ char *name;
+ /* size in bytes of the file on disk */
+ size_t file_len;
+ /* checksum of the file on disk */
+ u_int32_t file;
+ /* size in bytes of executable segment in memory */
+ size_t segment_len;
+ /* checksum of the executable segment in memory */
+ u_int32_t segment;
+};
+
+/**
+ * Code integrity checker to detect non-malicious file manipulation.
+ *
+ * The integrity checker reads the checksums from a separate library
+ * libchecksum.so to compare the checksums.
+ */
+struct integrity_checker_t {
+
+ /**
+ * Check the integrity of a file on disk.
+ *
+ * @param name name to lookup checksum
+ * @param file path to file
+ * @return TRUE if integrity tested successfully
+ */
+ bool (*check_file)(integrity_checker_t *this, char *name, char *file);
+
+ /**
+ * Build the integrity checksum of a file on disk.
+ *
+ * @param file path to file
+ * @param len return length in bytes of file
+ * @return checksum, 0 on error
+ */
+ u_int32_t (*build_file)(integrity_checker_t *this, char *file, size_t *len);
+
+ /**
+ * Check the integrity of the code segment in memory.
+ *
+ * @param name name to lookup checksum
+ * @param sym a symbol in the segment to check
+ * @return TRUE if integrity tested successfully
+ */
+ bool (*check_segment)(integrity_checker_t *this, char *name, void *sym);
+ /**
+ * Build the integrity checksum of a code segment in memory.
+ *
+ * @param sym a symbol in the segment to check
+ * @param len return length in bytes of code segment in memory
+ * @return checksum, 0 on error
+ */
+ u_int32_t (*build_segment)(integrity_checker_t *this, void *sym, size_t *len);
+
+ /**
+ * Check both, on disk file integrity and loaded segment.
+ *
+ * @param name name to lookup checksum
+ * @param sym a symbol to look up library and segment
+ * @return TRUE if integrity tested successfully
+ */
+ bool (*check)(integrity_checker_t *this, char *name, void *sym);
+
+ /**
+ * Destroy a integrity_checker_t.
+ */
+ void (*destroy)(integrity_checker_t *this);
+};
+
+/**
+ * Create a integrity_checker instance.
+ *
+ * @param checksum_library library containing checksums
+ */
+integrity_checker_t *integrity_checker_create(char *checksum_library);
+
+#endif /** INTEGRITY_CHECKER_H_ @}*/
diff --git a/src/libstrongswan/utils/leak_detective.c b/src/libstrongswan/utils/leak_detective.c
index 0a8789335..ffbc62085 100644
--- a/src/libstrongswan/utils/leak_detective.c
+++ b/src/libstrongswan/utils/leak_detective.c
@@ -1,5 +1,6 @@
/*
- * Copyright (C) 2006-2008 Martin Willi
+ * Copyright (C) 2013 Tobias Brunner
+ * Copyright (C) 2006-2013 Martin Willi
* Hochschule fuer Technik Rapperswil
*
* This program is free software; you can redistribute it and/or modify it
@@ -14,27 +15,38 @@
*/
#define _GNU_SOURCE
-#include <sched.h>
#include <stddef.h>
#include <string.h>
#include <stdio.h>
-#include <malloc.h>
#include <signal.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <syslog.h>
-#include <pthread.h>
#include <netdb.h>
#include <locale.h>
+#include <dlfcn.h>
+#include <time.h>
+#include <errno.h>
+
+#ifdef __APPLE__
+#include <sys/mman.h>
+#include <malloc/malloc.h>
+/* overload some of our types clashing with mach */
+#define host_t strongswan_host_t
+#define processor_t strongswan_processor_t
+#define thread_t strongswan_thread_t
+#endif /* __APPLE__ */
#include "leak_detective.h"
#include <library.h>
-#include <debug.h>
+#include <utils/debug.h>
#include <utils/backtrace.h>
-#include <utils/hashtable.h>
+#include <collections/hashtable.h>
+#include <threading/thread_value.h>
+#include <threading/spinlock.h>
typedef struct private_leak_detective_t private_leak_detective_t;
@@ -69,21 +81,6 @@ struct private_leak_detective_t {
*/
#define MEMORY_ALLOC_PATTERN 0xEE
-
-static void install_hooks(void);
-static void uninstall_hooks(void);
-static void *malloc_hook(size_t, const void *);
-static void *realloc_hook(void *, size_t, const void *);
-static void free_hook(void*, const void *);
-
-void *(*old_malloc_hook)(size_t, const void *);
-void *(*old_realloc_hook)(void *, size_t, const void *);
-void (*old_free_hook)(void*, const void *);
-
-static u_int count_malloc = 0;
-static u_int count_free = 0;
-static u_int count_realloc = 0;
-
typedef struct memory_header_t memory_header_t;
typedef struct memory_tail_t memory_tail_t;
@@ -108,6 +105,11 @@ struct memory_header_t {
backtrace_t *backtrace;
/**
+ * Padding to make sizeof(memory_header_t) == 32
+ */
+ u_int32_t padding[sizeof(void*) == sizeof(u_int32_t) ? 3 : 0];
+
+ /**
* Number of bytes following after the header
*/
u_int32_t bytes;
@@ -136,50 +138,337 @@ struct memory_tail_t {
* the others on it...
*/
static memory_header_t first_header = {
- magic: MEMORY_HEADER_MAGIC,
- bytes: 0,
- backtrace: NULL,
- previous: NULL,
- next: NULL
+ .magic = MEMORY_HEADER_MAGIC,
};
/**
- * are the hooks currently installed?
+ * Spinlock to access header linked list
*/
-static bool installed = FALSE;
+static spinlock_t *lock;
+
+/**
+ * Is leak detection currently enabled?
+ */
+static bool enabled = FALSE;
+
+/**
+ * Is leak detection disabled for the current thread?
+ */
+static thread_value_t *thread_disabled;
/**
* Installs the malloc hooks, enables leak detection
*/
-static void install_hooks()
+static void enable_leak_detective()
+{
+ enabled = TRUE;
+}
+
+/**
+ * Uninstalls the malloc hooks, disables leak detection
+ */
+static void disable_leak_detective()
+{
+ enabled = FALSE;
+}
+
+/**
+ * Enable/Disable leak detective for the current thread
+ *
+ * @return Previous value
+ */
+static bool enable_thread(bool enable)
+{
+ bool before;
+
+ before = thread_disabled->get(thread_disabled) == NULL;
+ thread_disabled->set(thread_disabled, enable ? NULL : (void*)TRUE);
+ return before;
+}
+
+/**
+ * Add a header to the beginning of the list
+ */
+static void add_hdr(memory_header_t *hdr)
{
- if (!installed)
+ lock->lock(lock);
+ hdr->next = first_header.next;
+ if (hdr->next)
{
- old_malloc_hook = __malloc_hook;
- old_realloc_hook = __realloc_hook;
- old_free_hook = __free_hook;
- __malloc_hook = malloc_hook;
- __realloc_hook = realloc_hook;
- __free_hook = free_hook;
- installed = TRUE;
+ hdr->next->previous = hdr;
}
+ hdr->previous = &first_header;
+ first_header.next = hdr;
+ lock->unlock(lock);
}
/**
- * Uninstalls the malloc hooks, disables leak detection
+ * Remove a header from the list
+ */
+static void remove_hdr(memory_header_t *hdr)
+{
+ lock->lock(lock);
+ if (hdr->next)
+ {
+ hdr->next->previous = hdr->previous;
+ }
+ hdr->previous->next = hdr->next;
+ lock->unlock(lock);
+}
+
+/**
+ * Check if a header is in the list
+ */
+static bool has_hdr(memory_header_t *hdr)
+{
+ memory_header_t *current;
+ bool found = FALSE;
+
+ lock->lock(lock);
+ for (current = &first_header; current != NULL; current = current->next)
+ {
+ if (current == hdr)
+ {
+ found = TRUE;
+ break;
+ }
+ }
+ lock->unlock(lock);
+
+ return found;
+}
+
+#ifdef __APPLE__
+
+/**
+ * Copy of original default zone, with functions we call in hooks
+ */
+static malloc_zone_t original;
+
+/**
+ * Call original malloc()
+ */
+static void* real_malloc(size_t size)
+{
+ return original.malloc(malloc_default_zone(), size);
+}
+
+/**
+ * Call original free()
+ */
+static void real_free(void *ptr)
+{
+ original.free(malloc_default_zone(), ptr);
+}
+
+/**
+ * Call original realloc()
+ */
+static void* real_realloc(void *ptr, size_t size)
+{
+ return original.realloc(malloc_default_zone(), ptr, size);
+}
+
+/**
+ * Hook definition: static function with _hook suffix, takes additional zone
+ */
+#define HOOK(ret, name, ...) \
+ static ret name ## _hook(malloc_zone_t *_z, __VA_ARGS__)
+
+/**
+ * forward declaration of hooks
+ */
+HOOK(void*, malloc, size_t bytes);
+HOOK(void*, calloc, size_t nmemb, size_t size);
+HOOK(void*, valloc, size_t size);
+HOOK(void, free, void *ptr);
+HOOK(void*, realloc, void *old, size_t bytes);
+
+/**
+ * malloc zone size(), must consider the memory header prepended
+ */
+HOOK(size_t, size, const void *ptr)
+{
+ bool before;
+ size_t size;
+
+ if (enabled)
+ {
+ before = enable_thread(FALSE);
+ if (before)
+ {
+ ptr -= sizeof(memory_header_t);
+ }
+ }
+ size = original.size(malloc_default_zone(), ptr);
+ if (enabled)
+ {
+ enable_thread(before);
+ }
+ return size;
+}
+
+/**
+ * Version of malloc zones we currently support
+ */
+#define MALLOC_ZONE_VERSION 8 /* Snow Leopard */
+
+/**
+ * Hook-in our malloc functions into the default zone
+ */
+static bool register_hooks()
+{
+ malloc_zone_t *zone;
+ void *page;
+
+ zone = malloc_default_zone();
+ if (zone->version != MALLOC_ZONE_VERSION)
+ {
+ DBG1(DBG_CFG, "malloc zone version %d unsupported (requiring %d)",
+ zone->version, MALLOC_ZONE_VERSION);
+ return FALSE;
+ }
+
+ original = *zone;
+
+ page = (void*)((uintptr_t)zone / getpagesize() * getpagesize());
+ if (mprotect(page, getpagesize(), PROT_WRITE | PROT_READ) != 0)
+ {
+ DBG1(DBG_CFG, "malloc zone unprotection failed: %s", strerror(errno));
+ return FALSE;
+ }
+
+ zone->size = size_hook;
+ zone->malloc = malloc_hook;
+ zone->calloc = calloc_hook;
+ zone->valloc = valloc_hook;
+ zone->free = free_hook;
+ zone->realloc = realloc_hook;
+
+ /* those other functions can be NULLed out to not use them */
+ zone->batch_malloc = NULL;
+ zone->batch_free = NULL;
+ zone->memalign = NULL;
+ zone->free_definite_size = NULL;
+
+ return TRUE;
+}
+
+#else /* !__APPLE__ */
+
+/**
+ * dlsym() might do a malloc(), but we can't do one before we get the malloc()
+ * function pointer. Use this minimalistic malloc implementation instead.
+ */
+static void* malloc_for_dlsym(size_t size)
+{
+ static char buf[1024] = {};
+ static size_t used = 0;
+ char *ptr;
+
+ /* roundup to a multiple of 32 */
+ size = (size - 1) / 32 * 32 + 32;
+
+ if (used + size > sizeof(buf))
+ {
+ return NULL;
+ }
+ ptr = buf + used;
+ used += size;
+ return ptr;
+}
+
+/**
+ * Lookup a malloc function, while disabling wrappers
+ */
+static void* get_malloc_fn(char *name)
+{
+ bool before = FALSE;
+ void *fn;
+
+ if (enabled)
+ {
+ before = enable_thread(FALSE);
+ }
+ fn = dlsym(RTLD_NEXT, name);
+ if (enabled)
+ {
+ enable_thread(before);
+ }
+ return fn;
+}
+
+/**
+ * Call original malloc()
+ */
+static void* real_malloc(size_t size)
+{
+ static void* (*fn)(size_t size);
+ static int recursive = 0;
+
+ if (!fn)
+ {
+ /* checking recursiveness should actually be thread-specific. But as
+ * it is very likely that the first allocation is done before we go
+ * multi-threaded, we keep it simple. */
+ if (recursive)
+ {
+ return malloc_for_dlsym(size);
+ }
+ recursive++;
+ fn = get_malloc_fn("malloc");
+ recursive--;
+ }
+ return fn(size);
+}
+
+/**
+ * Call original free()
+ */
+static void real_free(void *ptr)
+{
+ static void (*fn)(void *ptr);
+
+ if (!fn)
+ {
+ fn = get_malloc_fn("free");
+ }
+ return fn(ptr);
+}
+
+/**
+ * Call original realloc()
*/
-static void uninstall_hooks()
+static void* real_realloc(void *ptr, size_t size)
{
- if (installed)
+ static void* (*fn)(void *ptr, size_t size);
+
+ if (!fn)
{
- __malloc_hook = old_malloc_hook;
- __free_hook = old_free_hook;
- __realloc_hook = old_realloc_hook;
- installed = FALSE;
+ fn = get_malloc_fn("realloc");
}
+ return fn(ptr, size);
}
/**
+ * Hook definition: plain function overloading existing malloc calls
+ */
+#define HOOK(ret, name, ...) ret name(__VA_ARGS__)
+
+/**
+ * Hook initialization when not using hooks, resolve functions.
+ */
+static bool register_hooks()
+{
+ void *buf = real_malloc(8);
+ real_realloc(buf, 16);
+ real_free(buf);
+ return TRUE;
+}
+
+#endif /* !__APPLE__ */
+
+/**
* Leak report white list
*
* List of functions using static allocation buffers or should be suppressed
@@ -188,17 +477,12 @@ static void uninstall_hooks()
char *whitelist[] = {
/* backtraces, including own */
"backtrace_create",
+ "safe_strerror",
/* pthread stuff */
"pthread_create",
"pthread_setspecific",
"__pthread_setspecific",
/* glibc functions */
- "mktime",
- "ctime",
- "__gmtime_r",
- "localtime_r",
- "tzset",
- "time_printf_hook",
"inet_ntoa",
"strerror",
"getprotobyname",
@@ -224,6 +508,9 @@ char *whitelist[] = {
"getpwent_r",
"setpwent",
"endpwent",
+ "getspnam_r",
+ "getpwuid_r",
+ "initgroups",
/* ignore dlopen, as we do not dlclose to get proper leak reports */
"dlopen",
"dlerror",
@@ -243,18 +530,16 @@ char *whitelist[] = {
"Curl_client_write",
/* ClearSilver */
"nerr_init",
- /* OpenSSL */
- "RSA_new_method",
- "DH_new_method",
- "ENGINE_load_builtin_engines",
- "OPENSSL_config",
- "ecdsa_check",
- "ERR_put_error",
/* libgcrypt */
"gcry_control",
"gcry_check_version",
"gcry_randomize",
"gcry_create_nonce",
+ /* OpenSSL: These are needed for unit-tests only, the openssl plugin
+ * does properly clean up any memory during destroy(). */
+ "ECDSA_do_sign_ex",
+ "ECDSA_verify",
+ "RSA_new_method",
/* NSPR */
"PR_CallOnce",
/* libapr */
@@ -273,6 +558,14 @@ char *whitelist[] = {
"gnutls_global_init",
};
+/**
+ * Some functions are hard to whitelist, as they don't use a symbol directly.
+ * Use some static initialization to suppress them on leak reports
+ */
+static void init_static_allocations()
+{
+ tzset();
+}
/**
* Hashtable hash function
@@ -305,7 +598,8 @@ static bool equals(backtrace_t *a, backtrace_t *b)
* Summarize and print backtraces
*/
static int print_traces(private_leak_detective_t *this,
- FILE *out, int thresh, bool detailed, int *whitelisted)
+ FILE *out, int thresh, int thresh_count,
+ bool detailed, int *whitelisted, size_t *sum)
{
int leaks = 0;
memory_header_t *hdr;
@@ -319,11 +613,13 @@ static int print_traces(private_leak_detective_t *this,
/** number of allocations */
u_int count;
} *entry;
+ bool before;
- uninstall_hooks();
+ before = enable_thread(FALSE);
entries = hashtable_create((hashtable_hash_t)hash,
(hashtable_equals_t)equals, 1024);
+ lock->lock(lock);
for (hdr = first_header.next; hdr != NULL; hdr = hdr->next)
{
if (whitelisted &&
@@ -342,29 +638,37 @@ static int print_traces(private_leak_detective_t *this,
else
{
INIT(entry,
- .backtrace = hdr->backtrace,
+ .backtrace = hdr->backtrace->clone(hdr->backtrace),
.bytes = hdr->bytes,
.count = 1,
);
- entries->put(entries, hdr->backtrace, entry);
+ entries->put(entries, entry->backtrace, entry);
+ }
+ if (sum)
+ {
+ *sum += hdr->bytes;
}
leaks++;
}
+ lock->unlock(lock);
enumerator = entries->create_enumerator(entries);
while (enumerator->enumerate(enumerator, NULL, &entry))
{
- if (!thresh || entry->bytes >= thresh)
+ if (out &&
+ (!thresh || entry->bytes >= thresh) &&
+ (!thresh_count || entry->count >= thresh_count))
{
fprintf(out, "%d bytes total, %d allocations, %d bytes average:\n",
entry->bytes, entry->count, entry->bytes / entry->count);
entry->backtrace->log(entry->backtrace, out, detailed);
}
+ entry->backtrace->destroy(entry->backtrace);
free(entry);
}
enumerator->destroy(enumerator);
entries->destroy(entries);
- install_hooks();
+ enable_thread(before);
return leaks;
}
@@ -373,9 +677,10 @@ METHOD(leak_detective_t, report, void,
{
if (lib->leak_detective)
{
- int leaks = 0, whitelisted = 0;
+ int leaks, whitelisted = 0;
+ size_t sum = 0;
- leaks = print_traces(this, stderr, 0, detailed, &whitelisted);
+ leaks = print_traces(this, stderr, 0, 0, detailed, &whitelisted, &sum);
switch (leaks)
{
case 0:
@@ -385,7 +690,7 @@ METHOD(leak_detective_t, report, void,
fprintf(stderr, "One leak detected");
break;
default:
- fprintf(stderr, "%d leaks detected", leaks);
+ fprintf(stderr, "%d leaks detected, %zu bytes", leaks, sum);
break;
}
fprintf(stderr, ", %d suppressed by whitelist\n", whitelisted);
@@ -396,85 +701,115 @@ METHOD(leak_detective_t, report, void,
}
}
+METHOD(leak_detective_t, leaks, int,
+ private_leak_detective_t *this)
+{
+ if (lib->leak_detective)
+ {
+ int leaks, whitelisted = 0;
+
+ leaks = print_traces(this, NULL, 0, 0, FALSE, &whitelisted, NULL);
+ return leaks;
+ }
+ return 0;
+}
+
+METHOD(leak_detective_t, set_state, bool,
+ private_leak_detective_t *this, bool enable)
+{
+ return enable_thread(enable);
+}
+
METHOD(leak_detective_t, usage, void,
private_leak_detective_t *this, FILE *out)
{
- int oldpolicy, thresh;
bool detailed;
- pthread_t thread_id = pthread_self();
- struct sched_param oldparams, params;
+ int thresh, thresh_count;
+ size_t sum = 0;
thresh = lib->settings->get_int(lib->settings,
"libstrongswan.leak_detective.usage_threshold", 10240);
+ thresh_count = lib->settings->get_int(lib->settings,
+ "libstrongswan.leak_detective.usage_threshold_count", 0);
detailed = lib->settings->get_bool(lib->settings,
"libstrongswan.leak_detective.detailed", TRUE);
- pthread_getschedparam(thread_id, &oldpolicy, &oldparams);
- params.__sched_priority = sched_get_priority_max(SCHED_FIFO);
- pthread_setschedparam(thread_id, SCHED_FIFO, &params);
-
- print_traces(this, out, thresh, detailed, NULL);
+ print_traces(this, out, thresh, thresh_count, detailed, NULL, &sum);
- pthread_setschedparam(thread_id, oldpolicy, &oldparams);
+ fprintf(out, "Total memory usage: %zu\n", sum);
}
/**
- * Hook function for malloc()
+ * Wrapped malloc() function
*/
-void *malloc_hook(size_t bytes, const void *caller)
+HOOK(void*, malloc, size_t bytes)
{
memory_header_t *hdr;
memory_tail_t *tail;
- pthread_t thread_id = pthread_self();
- int oldpolicy;
- struct sched_param oldparams, params;
+ bool before;
- pthread_getschedparam(thread_id, &oldpolicy, &oldparams);
-
- params.__sched_priority = sched_get_priority_max(SCHED_FIFO);
- pthread_setschedparam(thread_id, SCHED_FIFO, &params);
+ if (!enabled || thread_disabled->get(thread_disabled))
+ {
+ return real_malloc(bytes);
+ }
- count_malloc++;
- uninstall_hooks();
- hdr = malloc(sizeof(memory_header_t) + bytes + sizeof(memory_tail_t));
+ hdr = real_malloc(sizeof(memory_header_t) + bytes + sizeof(memory_tail_t));
tail = ((void*)hdr) + bytes + sizeof(memory_header_t);
/* set to something which causes crashes */
memset(hdr, MEMORY_ALLOC_PATTERN,
sizeof(memory_header_t) + bytes + sizeof(memory_tail_t));
+ before = enable_thread(FALSE);
+ hdr->backtrace = backtrace_create(2);
+ enable_thread(before);
+
hdr->magic = MEMORY_HEADER_MAGIC;
hdr->bytes = bytes;
- hdr->backtrace = backtrace_create(3);
tail->magic = MEMORY_TAIL_MAGIC;
- install_hooks();
- /* insert at the beginning of the list */
- hdr->next = first_header.next;
- if (hdr->next)
- {
- hdr->next->previous = hdr;
- }
- hdr->previous = &first_header;
- first_header.next = hdr;
-
- pthread_setschedparam(thread_id, oldpolicy, &oldparams);
+ add_hdr(hdr);
return hdr + 1;
}
/**
- * Hook function for free()
+ * Wrapped calloc() function
+ */
+HOOK(void*, calloc, size_t nmemb, size_t size)
+{
+ void *ptr;
+
+ size *= nmemb;
+ ptr = malloc(size);
+ memset(ptr, 0, size);
+
+ return ptr;
+}
+
+/**
+ * Wrapped valloc(), TODO: currently not supported
*/
-void free_hook(void *ptr, const void *caller)
+HOOK(void*, valloc, size_t size)
{
- memory_header_t *hdr, *current;
+ DBG1(DBG_LIB, "valloc() used, but leak-detective hook missing");
+ return NULL;
+}
+
+/**
+ * Wrapped free() function
+ */
+HOOK(void, free, void *ptr)
+{
+ memory_header_t *hdr;
memory_tail_t *tail;
backtrace_t *backtrace;
- pthread_t thread_id = pthread_self();
- int oldpolicy;
- struct sched_param oldparams, params;
- bool found = FALSE;
+ bool before;
+ if (!enabled || thread_disabled->get(thread_disabled))
+ {
+ real_free(ptr);
+ return;
+ }
/* allow freeing of NULL */
if (ptr == NULL)
{
@@ -483,25 +818,11 @@ void free_hook(void *ptr, const void *caller)
hdr = ptr - sizeof(memory_header_t);
tail = ptr + hdr->bytes;
- pthread_getschedparam(thread_id, &oldpolicy, &oldparams);
-
- params.__sched_priority = sched_get_priority_max(SCHED_FIFO);
- pthread_setschedparam(thread_id, SCHED_FIFO, &params);
-
- count_free++;
- uninstall_hooks();
+ before = enable_thread(FALSE);
if (hdr->magic != MEMORY_HEADER_MAGIC ||
tail->magic != MEMORY_TAIL_MAGIC)
{
- for (current = &first_header; current != NULL; current = current->next)
- {
- if (current == hdr)
- {
- found = TRUE;
- break;
- }
- }
- if (found)
+ if (has_hdr(hdr))
{
/* memory was allocated by our hooks but is corrupted */
fprintf(stderr, "freeing corrupted memory (%p): "
@@ -511,100 +832,96 @@ void free_hook(void *ptr, const void *caller)
else
{
/* memory was not allocated by our hooks */
- fprintf(stderr, "freeing invalid memory (%p)", ptr);
+ fprintf(stderr, "freeing invalid memory (%p)\n", ptr);
}
- backtrace = backtrace_create(3);
+ backtrace = backtrace_create(2);
backtrace->log(backtrace, stderr, TRUE);
backtrace->destroy(backtrace);
}
else
{
- /* remove item from list */
- if (hdr->next)
- {
- hdr->next->previous = hdr->previous;
- }
- hdr->previous->next = hdr->next;
+ remove_hdr(hdr);
+
hdr->backtrace->destroy(hdr->backtrace);
/* clear MAGIC, set mem to something remarkable */
memset(hdr, MEMORY_FREE_PATTERN,
sizeof(memory_header_t) + hdr->bytes + sizeof(memory_tail_t));
- free(hdr);
+ real_free(hdr);
}
-
- install_hooks();
- pthread_setschedparam(thread_id, oldpolicy, &oldparams);
+ enable_thread(before);
}
/**
- * Hook function for realloc()
+ * Wrapped realloc() function
*/
-void *realloc_hook(void *old, size_t bytes, const void *caller)
+HOOK(void*, realloc, void *old, size_t bytes)
{
memory_header_t *hdr;
memory_tail_t *tail;
backtrace_t *backtrace;
- pthread_t thread_id = pthread_self();
- int oldpolicy;
- struct sched_param oldparams, params;
+ bool before;
+ if (!enabled || thread_disabled->get(thread_disabled))
+ {
+ return real_realloc(old, bytes);
+ }
/* allow reallocation of NULL */
if (old == NULL)
{
- return malloc_hook(bytes, caller);
+ return malloc(bytes);
+ }
+ /* handle zero size as a free() */
+ if (bytes == 0)
+ {
+ free(old);
+ return NULL;
}
hdr = old - sizeof(memory_header_t);
tail = old + hdr->bytes;
- pthread_getschedparam(thread_id, &oldpolicy, &oldparams);
+ remove_hdr(hdr);
- params.__sched_priority = sched_get_priority_max(SCHED_FIFO);
- pthread_setschedparam(thread_id, SCHED_FIFO, &params);
-
- count_realloc++;
- uninstall_hooks();
if (hdr->magic != MEMORY_HEADER_MAGIC ||
tail->magic != MEMORY_TAIL_MAGIC)
{
- fprintf(stderr, "reallocating invalid memory (%p): "
- "header magic 0x%x, tail magic 0x%x:\n",
- old, hdr->magic, tail->magic);
- backtrace = backtrace_create(3);
+ fprintf(stderr, "reallocating invalid memory (%p):\n"
+ "header magic 0x%x:\n", old, hdr->magic);
+ backtrace = backtrace_create(2);
backtrace->log(backtrace, stderr, TRUE);
backtrace->destroy(backtrace);
}
- /* clear tail magic, allocate, set tail magic */
- memset(&tail->magic, MEMORY_ALLOC_PATTERN, sizeof(tail->magic));
- hdr = realloc(hdr, sizeof(memory_header_t) + bytes + sizeof(memory_tail_t));
+ else
+ {
+ /* clear tail magic, allocate, set tail magic */
+ memset(&tail->magic, MEMORY_ALLOC_PATTERN, sizeof(tail->magic));
+ }
+ hdr = real_realloc(hdr,
+ sizeof(memory_header_t) + bytes + sizeof(memory_tail_t));
tail = ((void*)hdr) + bytes + sizeof(memory_header_t);
tail->magic = MEMORY_TAIL_MAGIC;
/* update statistics */
hdr->bytes = bytes;
+
+ before = enable_thread(FALSE);
hdr->backtrace->destroy(hdr->backtrace);
- hdr->backtrace = backtrace_create(3);
+ hdr->backtrace = backtrace_create(2);
+ enable_thread(before);
+
+ add_hdr(hdr);
- /* update header of linked list neighbours */
- if (hdr->next)
- {
- hdr->next->previous = hdr;
- }
- hdr->previous->next = hdr;
- install_hooks();
- pthread_setschedparam(thread_id, oldpolicy, &oldparams);
return hdr + 1;
}
METHOD(leak_detective_t, destroy, void,
private_leak_detective_t *this)
{
- if (installed)
- {
- uninstall_hooks();
- }
+ disable_leak_detective();
+ lock->destroy(lock);
+ thread_disabled->destroy(thread_disabled);
free(this);
}
@@ -618,25 +935,24 @@ leak_detective_t *leak_detective_create()
INIT(this,
.public = {
.report = _report,
+ .leaks = _leaks,
.usage = _usage,
+ .set_state = _set_state,
.destroy = _destroy,
},
);
- if (getenv("LEAK_DETECTIVE_DISABLE") == NULL)
- {
- cpu_set_t mask;
+ lock = spinlock_create();
+ thread_disabled = thread_value_create(NULL);
- CPU_ZERO(&mask);
- CPU_SET(0, &mask);
+ init_static_allocations();
- if (sched_setaffinity(0, sizeof(cpu_set_t), &mask) != 0)
+ if (getenv("LEAK_DETECTIVE_DISABLE") == NULL)
+ {
+ if (register_hooks())
{
- fprintf(stderr, "setting CPU affinity failed: %m");
+ enable_leak_detective();
}
-
- install_hooks();
}
return &this->public;
}
-
diff --git a/src/libstrongswan/utils/leak_detective.h b/src/libstrongswan/utils/leak_detective.h
index 8c80d2532..7a29e81d7 100644
--- a/src/libstrongswan/utils/leak_detective.h
+++ b/src/libstrongswan/utils/leak_detective.h
@@ -43,6 +43,13 @@ struct leak_detective_t {
void (*report)(leak_detective_t *this, bool detailed);
/**
+ * Number of detected leaks.
+ *
+ * @return number of leaks
+ */
+ int (*leaks)(leak_detective_t *this);
+
+ /**
* Report current memory usage to out.
*
* @param out target to write usage report to
@@ -50,6 +57,14 @@ struct leak_detective_t {
void (*usage)(leak_detective_t *this, FILE *out);
/**
+ * Enable/disable leak detective hooks for the current thread.
+ *
+ * @param TRUE to enable, FALSE to disable
+ * @return state active before calling set_state
+ */
+ bool (*set_state)(leak_detective_t *this, bool enabled);
+
+ /**
* Destroy a leak_detective instance.
*/
void (*destroy)(leak_detective_t *this);
@@ -61,4 +76,3 @@ struct leak_detective_t {
leak_detective_t *leak_detective_create();
#endif /** LEAK_DETECTIVE_H_ @}*/
-
diff --git a/src/libstrongswan/utils/linked_list.c b/src/libstrongswan/utils/linked_list.c
deleted file mode 100644
index 59d416f2f..000000000
--- a/src/libstrongswan/utils/linked_list.c
+++ /dev/null
@@ -1,574 +0,0 @@
-/*
- * Copyright (C) 2007-2011 Tobias Brunner
- * Copyright (C) 2005-2006 Martin Willi
- * Copyright (C) 2005 Jan Hutter
- * Hochschule fuer Technik Rapperswil
- *
- * 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. See <http://www.fsf.org/copyleft/gpl.txt>.
- *
- * 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.
- */
-
-#include <stdlib.h>
-
-#include "linked_list.h"
-
-typedef struct element_t element_t;
-
-/**
- * This element holds a pointer to the value it represents.
- */
-struct element_t {
-
- /**
- * Value of a list item.
- */
- void *value;
-
- /**
- * Previous list element.
- *
- * NULL if first element in list.
- */
- element_t *previous;
-
- /**
- * Next list element.
- *
- * NULL if last element in list.
- */
- element_t *next;
-};
-
-/**
- * Creates an empty linked list object.
- */
-element_t *element_create(void *value)
-{
- element_t *this;
- INIT(this,
- .value = value,
- );
- return this;
-}
-
-
-typedef struct private_linked_list_t private_linked_list_t;
-
-/**
- * Private data of a linked_list_t object.
- *
- */
-struct private_linked_list_t {
- /**
- * Public part of linked list.
- */
- linked_list_t public;
-
- /**
- * Number of items in the list.
- */
- int count;
-
- /**
- * First element in list.
- * NULL if no elements in list.
- */
- element_t *first;
-
- /**
- * Last element in list.
- * NULL if no elements in list.
- */
- element_t *last;
-};
-
-typedef struct private_enumerator_t private_enumerator_t;
-
-/**
- * linked lists enumerator implementation
- */
-struct private_enumerator_t {
-
- /**
- * implements enumerator interface
- */
- enumerator_t enumerator;
-
- /**
- * associated linked list
- */
- private_linked_list_t *list;
-
- /**
- * current item
- */
- element_t *current;
-
- /**
- * enumerator has enumerated all items
- */
- bool finished;
-};
-
-METHOD(enumerator_t, enumerate, bool,
- private_enumerator_t *this, void **item)
-{
- if (this->finished)
- {
- return FALSE;
- }
- if (!this->current)
- {
- this->current = this->list->first;
- }
- else
- {
- this->current = this->current->next;
- }
- if (!this->current)
- {
- this->finished = TRUE;
- return FALSE;
- }
- *item = this->current->value;
- return TRUE;
-}
-
-METHOD(linked_list_t, create_enumerator, enumerator_t*,
- private_linked_list_t *this)
-{
- private_enumerator_t *enumerator;
-
- INIT(enumerator,
- .enumerator = {
- .enumerate = (void*)_enumerate,
- .destroy = (void*)free,
- },
- .list = this,
- );
-
- return &enumerator->enumerator;
-}
-
-METHOD(linked_list_t, reset_enumerator, void,
- private_linked_list_t *this, private_enumerator_t *enumerator)
-{
- enumerator->current = NULL;
- enumerator->finished = FALSE;
-}
-
-METHOD(linked_list_t, has_more, bool,
- private_linked_list_t *this, private_enumerator_t *enumerator)
-{
- if (enumerator->current)
- {
- return enumerator->current->next != NULL;
- }
- return !enumerator->finished && this->first != NULL;
-}
-
-METHOD(linked_list_t, get_count, int,
- private_linked_list_t *this)
-{
- return this->count;
-}
-
-METHOD(linked_list_t, insert_first, void,
- private_linked_list_t *this, void *item)
-{
- element_t *element;
-
- element = element_create(item);
- if (this->count == 0)
- {
- /* first entry in list */
- this->first = element;
- this->last = element;
- }
- else
- {
- element->next = this->first;
- this->first->previous = element;
- this->first = element;
- }
- this->count++;
-}
-
-/**
- * unlink an element form the list, returns following element
- */
-static element_t* remove_element(private_linked_list_t *this,
- element_t *element)
-{
- element_t *next, *previous;
-
- next = element->next;
- previous = element->previous;
- free(element);
- if (next)
- {
- next->previous = previous;
- }
- else
- {
- this->last = previous;
- }
- if (previous)
- {
- previous->next = next;
- }
- else
- {
- this->first = next;
- }
- if (--this->count == 0)
- {
- this->first = NULL;
- this->last = NULL;
- }
- return next;
-}
-
-METHOD(linked_list_t, get_first, status_t,
- private_linked_list_t *this, void **item)
-{
- if (this->count == 0)
- {
- return NOT_FOUND;
- }
- *item = this->first->value;
- return SUCCESS;
-}
-
-METHOD(linked_list_t, remove_first, status_t,
- private_linked_list_t *this, void **item)
-{
- if (get_first(this, item) == SUCCESS)
- {
- remove_element(this, this->first);
- return SUCCESS;
- }
- return NOT_FOUND;
-}
-
-METHOD(linked_list_t, insert_last, void,
- private_linked_list_t *this, void *item)
-{
- element_t *element;
-
- element = element_create(item);
- if (this->count == 0)
- {
- /* first entry in list */
- this->first = element;
- this->last = element;
- }
- else
- {
- element->previous = this->last;
- this->last->next = element;
- this->last = element;
- }
- this->count++;
-}
-
-METHOD(linked_list_t, insert_before, void,
- private_linked_list_t *this, private_enumerator_t *enumerator,
- void *item)
-{
- element_t *current, *element;
-
- current = enumerator->current;
- if (!current)
- {
- if (enumerator->finished)
- {
- this->public.insert_last(&this->public, item);
- }
- else
- {
- this->public.insert_first(&this->public, item);
- }
- return;
- }
- element = element_create(item);
- if (current->previous)
- {
- current->previous->next = element;
- element->previous = current->previous;
- current->previous = element;
- element->next = current;
- }
- else
- {
- current->previous = element;
- element->next = current;
- this->first = element;
- }
- this->count++;
-}
-
-METHOD(linked_list_t, replace, void*,
- private_linked_list_t *this, private_enumerator_t *enumerator,
- void *item)
-{
- void *old = NULL;
-
- if (enumerator->current)
- {
- old = enumerator->current->value;
- enumerator->current->value = item;
- }
- return old;
-}
-
-METHOD(linked_list_t, get_last, status_t,
- private_linked_list_t *this, void **item)
-{
- if (this->count == 0)
- {
- return NOT_FOUND;
- }
- *item = this->last->value;
- return SUCCESS;
-}
-
-METHOD(linked_list_t, remove_last, status_t,
- private_linked_list_t *this, void **item)
-{
- if (get_last(this, item) == SUCCESS)
- {
- remove_element(this, this->last);
- return SUCCESS;
- }
- return NOT_FOUND;
-}
-
-METHOD(linked_list_t, remove_, int,
- private_linked_list_t *this, void *item, bool (*compare)(void*,void*))
-{
- element_t *current = this->first;
- int removed = 0;
-
- while (current)
- {
- if ((compare && compare(current->value, item)) ||
- (!compare && current->value == item))
- {
- removed++;
- current = remove_element(this, current);
- }
- else
- {
- current = current->next;
- }
- }
- return removed;
-}
-
-METHOD(linked_list_t, remove_at, void,
- private_linked_list_t *this, private_enumerator_t *enumerator)
-{
- element_t *current;
-
- if (enumerator->current)
- {
- current = enumerator->current;
- enumerator->current = current->previous;
- remove_element(this, current);
- }
-}
-
-METHOD(linked_list_t, find_first, status_t,
- private_linked_list_t *this, linked_list_match_t match,
- void **item, void *d1, void *d2, void *d3, void *d4, void *d5)
-{
- element_t *current = this->first;
-
- while (current)
- {
- if ((match && match(current->value, d1, d2, d3, d4, d5)) ||
- (!match && item && current->value == *item))
- {
- if (item != NULL)
- {
- *item = current->value;
- }
- return SUCCESS;
- }
- current = current->next;
- }
- return NOT_FOUND;
-}
-
-METHOD(linked_list_t, find_last, status_t,
- private_linked_list_t *this, linked_list_match_t match,
- void **item, void *d1, void *d2, void *d3, void *d4, void *d5)
-{
- element_t *current = this->last;
-
- while (current)
- {
- if ((match && match(current->value, d1, d2, d3, d4, d5)) ||
- (!match && item && current->value == *item))
- {
- if (item != NULL)
- {
- *item = current->value;
- }
- return SUCCESS;
- }
- current = current->previous;
- }
- return NOT_FOUND;
-}
-
-METHOD(linked_list_t, invoke_offset, void,
- private_linked_list_t *this, size_t offset,
- void *d1, void *d2, void *d3, void *d4, void *d5)
-{
- element_t *current = this->first;
- linked_list_invoke_t *method;
-
- while (current)
- {
- method = current->value + offset;
- (*method)(current->value, d1, d2, d3, d4, d5);
- current = current->next;
- }
-}
-
-METHOD(linked_list_t, invoke_function, void,
- private_linked_list_t *this, linked_list_invoke_t fn,
- void *d1, void *d2, void *d3, void *d4, void *d5)
-{
- element_t *current = this->first;
-
- while (current)
- {
- fn(current->value, d1, d2, d3, d4, d5);
- current = current->next;
- }
-}
-
-METHOD(linked_list_t, clone_offset, linked_list_t*,
- private_linked_list_t *this, size_t offset)
-{
- element_t *current = this->first;
- linked_list_t *clone;
-
- clone = linked_list_create();
- while (current)
- {
- void* (**method)(void*) = current->value + offset;
- clone->insert_last(clone, (*method)(current->value));
- current = current->next;
- }
-
- return clone;
-}
-
-METHOD(linked_list_t, clone_function, linked_list_t*,
- private_linked_list_t *this, void* (*fn)(void*))
-{
- element_t *current = this->first;
- linked_list_t *clone;
-
- clone = linked_list_create();
- while (current)
- {
- clone->insert_last(clone, fn(current->value));
- current = current->next;
- }
- return clone;
-}
-
-METHOD(linked_list_t, destroy, void,
- private_linked_list_t *this)
-{
- void *value;
-
- /* Remove all list items before destroying list */
- while (remove_first(this, &value) == SUCCESS)
- {
- /* values are not destroyed so memory leaks are possible
- * if list is not empty when deleting */
- }
- free(this);
-}
-
-METHOD(linked_list_t, destroy_offset, void,
- private_linked_list_t *this, size_t offset)
-{
- element_t *current = this->first, *next;
-
- while (current)
- {
- void (**method)(void*) = current->value + offset;
- (*method)(current->value);
- next = current->next;
- free(current);
- current = next;
- }
- free(this);
-}
-
-METHOD(linked_list_t, destroy_function, void,
- private_linked_list_t *this, void (*fn)(void*))
-{
- element_t *current = this->first, *next;
-
- while (current)
- {
- fn(current->value);
- next = current->next;
- free(current);
- current = next;
- }
- free(this);
-}
-
-/*
- * Described in header.
- */
-linked_list_t *linked_list_create()
-{
- private_linked_list_t *this;
-
- INIT(this,
- .public = {
- .get_count = _get_count,
- .create_enumerator = _create_enumerator,
- .reset_enumerator = (void*)_reset_enumerator,
- .has_more = (void*)_has_more,
- .get_first = _get_first,
- .get_last = _get_last,
- .find_first = (void*)_find_first,
- .find_last = (void*)_find_last,
- .insert_first = _insert_first,
- .insert_last = _insert_last,
- .insert_before = (void*)_insert_before,
- .replace = (void*)_replace,
- .remove_first = _remove_first,
- .remove_last = _remove_last,
- .remove = _remove_,
- .remove_at = (void*)_remove_at,
- .invoke_offset = (void*)_invoke_offset,
- .invoke_function = (void*)_invoke_function,
- .clone_offset = _clone_offset,
- .clone_function = _clone_function,
- .destroy = _destroy,
- .destroy_offset = _destroy_offset,
- .destroy_function = _destroy_function,
- },
- );
-
- return &this->public;
-}
diff --git a/src/libstrongswan/utils/linked_list.h b/src/libstrongswan/utils/linked_list.h
deleted file mode 100644
index 293ca8661..000000000
--- a/src/libstrongswan/utils/linked_list.h
+++ /dev/null
@@ -1,302 +0,0 @@
-/*
- * Copyright (C) 2007-2011 Tobias Brunner
- * Copyright (C) 2005-2008 Martin Willi
- * Copyright (C) 2005 Jan Hutter
- * Hochschule fuer Technik Rapperswil
- *
- * 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. See <http://www.fsf.org/copyleft/gpl.txt>.
- *
- * 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.
- */
-
-/**
- * @defgroup linked_list linked_list
- * @{ @ingroup utils
- */
-
-#ifndef LINKED_LIST_H_
-#define LINKED_LIST_H_
-
-typedef struct linked_list_t linked_list_t;
-
-#include <utils/enumerator.h>
-
-/**
- * Method to match elements in a linked list (used in find_* functions)
- *
- * @param item current list item
- * @param ... user supplied data (only pointers, at most 5)
- * @return
- * - TRUE, if the item matched
- * - FALSE, otherwise
- */
-typedef bool (*linked_list_match_t)(void *item, ...);
-
-/**
- * Method to be invoked on elements in a linked list (used in invoke_* functions)
- *
- * @param item current list item
- * @param ... user supplied data (only pointers, at most 5)
- */
-typedef void (*linked_list_invoke_t)(void *item, ...);
-
-/**
- * Class implementing a double linked list.
- *
- * General purpose linked list. This list is not synchronized.
- */
-struct linked_list_t {
-
- /**
- * Gets the count of items in the list.
- *
- * @return number of items in list
- */
- int (*get_count) (linked_list_t *this);
-
- /**
- * Create an enumerator over the list.
- *
- * @note The enumerator's position is invalid before the first call
- * to enumerate().
- *
- * @return enumerator over list items
- */
- enumerator_t* (*create_enumerator)(linked_list_t *this);
-
- /**
- * Resets the enumerator's current position to the beginning of the list.
- *
- * @param enumerator enumerator to reset
- */
- void (*reset_enumerator)(linked_list_t *this, enumerator_t *enumerator);
-
- /**
- * Checks if there are more elements following after the enumerator's
- * current position.
- *
- * @param enumerator enumerator to check
- */
- bool (*has_more)(linked_list_t *this, enumerator_t *enumerator);
-
- /**
- * Inserts a new item at the beginning of the list.
- *
- * @param item item value to insert in list
- */
- void (*insert_first) (linked_list_t *this, void *item);
-
- /**
- * Removes the first item in the list and returns its value.
- *
- * @param item returned value of first item, or NULL
- * @return SUCCESS, or NOT_FOUND if list is empty
- */
- status_t (*remove_first) (linked_list_t *this, void **item);
-
- /**
- * Inserts a new item before the item the enumerator currently points to.
- *
- * If this method is called before starting the enumeration the item is
- * inserted first. If it is called after all items have been enumerated
- * the item is inserted last. This is helpful when inserting items into
- * a sorted list.
- *
- * @note The position of the enumerator is not changed.
- *
- * @param enumerator enumerator with position
- * @param item item value to insert in list
- */
- void (*insert_before)(linked_list_t *this, enumerator_t *enumerator,
- void *item);
-
- /**
- * Replaces the item the enumerator currently points to with the given item.
- *
- * @param enumerator enumerator with position
- * @param item item value to replace current item with
- * @return current item or NULL if the enumerator is at an
- * invalid position
- */
- void *(*replace)(linked_list_t *this, enumerator_t *enumerator, void *item);
-
- /**
- * Remove an item from the list where the enumerator points to.
- *
- * @param enumerator enumerator with position
- */
- void (*remove_at)(linked_list_t *this, enumerator_t *enumerator);
-
- /**
- * Remove items from the list matching the given item.
- *
- * If a compare function is given, it is called for each item, with the
- * first parameter being the current list item and the second parameter
- * being the supplied item. Return TRUE from the compare function to remove
- * the item, return FALSE to keep it in the list.
- *
- * If compare is NULL, comparison is done by pointers.
- *
- * @param item item to remove/pass to comparator
- * @param compare compare function, or NULL
- * @return number of removed items
- */
- int (*remove)(linked_list_t *this, void *item, bool (*compare)(void*,void*));
-
- /**
- * Returns the value of the first list item without removing it.
- *
- * @param item returned value of first item
- * @return SUCCESS, NOT_FOUND if list is empty
- */
- status_t (*get_first) (linked_list_t *this, void **item);
-
- /**
- * Inserts a new item at the end of the list.
- *
- * @param item value to insert into list
- */
- void (*insert_last) (linked_list_t *this, void *item);
-
- /**
- * Removes the last item in the list and returns its value.
- *
- * @param item returned value of last item, or NULL
- * @return SUCCESS, NOT_FOUND if list is empty
- */
- status_t (*remove_last) (linked_list_t *this, void **item);
-
- /**
- * Returns the value of the last list item without removing it.
- *
- * @param item returned value of last item
- * @return SUCCESS, NOT_FOUND if list is empty
- */
- status_t (*get_last) (linked_list_t *this, void **item);
-
- /** Find the first matching element in the list.
- *
- * The first object passed to the match function is the current list item,
- * followed by the user supplied data.
- * If the supplied function returns TRUE this function returns SUCCESS, and
- * the current object is returned in the third parameter, otherwise,
- * the next item is checked.
- *
- * If match is NULL, *item and the current object are compared.
- *
- * @warning Only use pointers as user supplied data.
- *
- * @param match comparison function to call on each object, or NULL
- * @param item the list item, if found
- * @param ... user data to supply to match function (limited to 5 arguments)
- * @return SUCCESS if found, NOT_FOUND otherwise
- */
- status_t (*find_first) (linked_list_t *this, linked_list_match_t match,
- void **item, ...);
-
- /** Find the last matching element in the list.
- *
- * The first object passed to the match function is the current list item,
- * followed by the user supplied data.
- * If the supplied function returns TRUE this function returns SUCCESS, and
- * the current object is returned in the third parameter, otherwise,
- * the next item is checked.
- *
- * If match is NULL, *item and the current object are compared.
- *
- * @warning Only use pointers as user supplied data.
- *
- * @param match comparison function to call on each object, or NULL
- * @param item the list item, if found
- * @param ... user data to supply to match function (limited to 5 arguments)
- * @return SUCCESS if found, NOT_FOUND otherwise
- */
- status_t (*find_last) (linked_list_t *this, linked_list_match_t match,
- void **item, ...);
-
- /**
- * Invoke a method on all of the contained objects.
- *
- * If a linked list contains objects with function pointers,
- * invoke() can call a method on each of the objects. The
- * method is specified by an offset of the function pointer,
- * which can be evalutated at compile time using the offsetof
- * macro, e.g.: list->invoke(list, offsetof(object_t, method));
- *
- * @warning Only use pointers as user supplied data.
- *
- * @param offset offset of the method to invoke on objects
- * @param ... user data to supply to called function (limited to 5 arguments)
- */
- void (*invoke_offset) (linked_list_t *this, size_t offset, ...);
-
- /**
- * Invoke a function on all of the contained objects.
- *
- * @warning Only use pointers as user supplied data.
- *
- * @param function offset of the method to invoke on objects
- * @param ... user data to supply to called function (limited to 5 arguments)
- */
- void (*invoke_function) (linked_list_t *this, linked_list_invoke_t function, ...);
-
- /**
- * Clones a list and its objects using the objects' clone method.
- *
- * @param offset offset ot the objects clone function
- * @return cloned list
- */
- linked_list_t *(*clone_offset) (linked_list_t *this, size_t offset);
-
- /**
- * Clones a list and its objects using a given function.
- *
- * @param function function that clones an object
- * @return cloned list
- */
- linked_list_t *(*clone_function) (linked_list_t *this, void*(*)(void*));
-
- /**
- * Destroys a linked_list object.
- */
- void (*destroy) (linked_list_t *this);
-
- /**
- * Destroys a list and its objects using the destructor.
- *
- * If a linked list and the contained objects should be destroyed, use
- * destroy_offset. The supplied offset specifies the destructor to
- * call on each object. The offset may be calculated using the offsetof
- * macro, e.g.: list->destroy_offset(list, offsetof(object_t, destroy));
- *
- * @param offset offset of the objects destructor
- */
- void (*destroy_offset) (linked_list_t *this, size_t offset);
-
- /**
- * Destroys a list and its contents using a a cleanup function.
- *
- * If a linked list and its contents should get destroyed using a specific
- * cleanup function, use destroy_function. This is useful when the
- * list contains malloc()-ed blocks which should get freed,
- * e.g.: list->destroy_function(list, free);
- *
- * @param function function to call on each object
- */
- void (*destroy_function) (linked_list_t *this, void (*)(void*));
-};
-
-/**
- * Creates an empty linked list object.
- *
- * @return linked_list_t object.
- */
-linked_list_t *linked_list_create(void);
-
-#endif /** LINKED_LIST_H_ @}*/
diff --git a/src/libstrongswan/utils/optionsfrom.c b/src/libstrongswan/utils/optionsfrom.c
index 5fd4cfd4d..117071351 100644
--- a/src/libstrongswan/utils/optionsfrom.c
+++ b/src/libstrongswan/utils/optionsfrom.c
@@ -2,22 +2,22 @@
* Copyright (C) 2007-2008 Andreas Steffen
* Hochschule fuer Technik Rapperswil
*
- * This library is free software; you can redistribute it and/or modify it
- * under the terms of the GNU Library General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or (at your
- * option) any later version. See <http://www.fsf.org/copyleft/lgpl.txt>.
+ * 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. See <http://www.fsf.org/copyleft/gpl.txt>.
*
- * This library is distributed in the hope that it will be useful, but
+ * 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 Library General Public
- * License for more details.
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
*/
#include <stdio.h>
#include <errno.h>
#include <library.h>
-#include <debug.h>
+#include <utils/debug.h>
#include <utils/lexparser.h>
#include "optionsfrom.h"
diff --git a/src/libstrongswan/utils/printf_hook.c b/src/libstrongswan/utils/printf_hook.c
new file mode 100644
index 000000000..f030f45c8
--- /dev/null
+++ b/src/libstrongswan/utils/printf_hook.c
@@ -0,0 +1,510 @@
+/*
+ * Copyright (C) 2009 Tobias Brunner
+ * Copyright (C) 2006-2008 Martin Willi
+ * Hochschule fuer Technik Rapperswil
+ *
+ * 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. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * 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.
+ */
+
+#include "printf_hook.h"
+
+#include "utils.h"
+#include "debug.h"
+
+#include <stdio.h>
+#include <stdarg.h>
+#include <string.h>
+
+typedef struct private_printf_hook_t private_printf_hook_t;
+typedef struct printf_hook_handler_t printf_hook_handler_t;
+
+#define PRINTF_BUF_LEN 8192
+#define ARGS_MAX 3
+
+/**
+ * private data of printf_hook
+ */
+struct private_printf_hook_t {
+
+ /**
+ * public functions
+ */
+ printf_hook_t public;
+};
+
+/**
+ * struct with information about a registered handler
+ */
+struct printf_hook_handler_t {
+
+ /**
+ * callback function
+ */
+ printf_hook_function_t hook;
+
+ /**
+ * number of arguments
+ */
+ int numargs;
+
+ /**
+ * types of the arguments
+ */
+ int argtypes[ARGS_MAX];
+
+#ifdef USE_VSTR
+ /**
+ * name required for Vstr
+ */
+ char *name;
+#endif
+};
+
+/* A-Z | 6 other chars | a-z */
+#define NUM_HANDLERS 58
+static printf_hook_handler_t *printf_hooks[NUM_HANDLERS];
+
+#define SPEC_TO_INDEX(spec) ((int)(spec) - (int)'A')
+#define IS_VALID_SPEC(spec) (SPEC_TO_INDEX(spec) > -1 && SPEC_TO_INDEX(spec) < NUM_HANDLERS)
+
+#if !defined(USE_VSTR) && \
+ (defined(HAVE_PRINTF_FUNCTION) || defined(HAVE_PRINTF_SPECIFIER))
+
+/**
+ * Printf hook print function. This is actually of type "printf_function",
+ * however glibc does it typedef to function, but uclibc to a pointer.
+ * So we redefine it here.
+ */
+static int custom_print(FILE *stream, const struct printf_info *info,
+ const void *const *args)
+{
+ printf_hook_spec_t spec;
+ printf_hook_handler_t *handler = printf_hooks[SPEC_TO_INDEX(info->spec)];
+ printf_hook_data_t data = {
+ .stream = stream,
+ };
+
+ spec.hash = info->alt;
+ spec.plus = info->showsign;
+ spec.minus = info->left;
+ spec.width = info->width;
+
+ return handler->hook(&data, &spec, args);
+}
+
+/**
+ * Printf hook arginfo function, which is actually of type
+ * "printf_arginfo_[size_]function".
+ */
+static int custom_arginfo(const struct printf_info *info, size_t n, int *argtypes
+#ifdef HAVE_PRINTF_SPECIFIER
+ , int *size
+#endif
+ )
+{
+ int i;
+ printf_hook_handler_t *handler = printf_hooks[SPEC_TO_INDEX(info->spec)];
+
+ if (handler->numargs <= n)
+ {
+ for (i = 0; i < handler->numargs; ++i)
+ {
+ argtypes[i] = handler->argtypes[i];
+ }
+ }
+ /* we never set "size", as we have no user defined types */
+ return handler->numargs;
+}
+
+#else
+
+#include <errno.h>
+#include <unistd.h> /* for STDOUT_FILENO */
+
+/**
+ * These are used below, whenever the public wrapper functions are called before
+ * initialization or after destruction.
+ */
+#undef vprintf
+#undef vfprintf
+#undef vsnprintf
+
+/**
+ * Vstr custom format specifier callback function.
+ */
+static int custom_fmt_cb(Vstr_base *base, size_t pos, Vstr_fmt_spec *fmt_spec)
+{
+ int i;
+ const void *args[ARGS_MAX];
+ printf_hook_spec_t spec;
+ printf_hook_handler_t *handler = printf_hooks[SPEC_TO_INDEX(fmt_spec->name[0])];
+ printf_hook_data_t data = {
+ .base = base,
+ .pos = pos,
+ };
+
+ for (i = 0; i < handler->numargs; i++)
+ {
+ switch(handler->argtypes[i])
+ {
+ case PRINTF_HOOK_ARGTYPE_INT:
+ args[i] = VSTR_FMT_CB_ARG_PTR(fmt_spec, i);
+ break;
+ case PRINTF_HOOK_ARGTYPE_POINTER:
+ args[i] = &VSTR_FMT_CB_ARG_PTR(fmt_spec, i);
+ break;
+ }
+ }
+
+ spec.hash = fmt_spec->fmt_hash;
+ spec.plus = fmt_spec->fmt_plus;
+ spec.minus = fmt_spec->fmt_minus;
+ spec.width = fmt_spec->fmt_field_width;
+
+ handler->hook(&data, &spec, args);
+ return 1;
+}
+
+/**
+ * Add a custom format handler to the given Vstr_conf object
+ */
+static void vstr_fmt_add_handler(Vstr_conf *conf, printf_hook_handler_t *handler)
+{
+ int *at = handler->argtypes;
+ switch(handler->numargs)
+ {
+ case 1:
+ vstr_fmt_add(conf, handler->name, custom_fmt_cb, at[0],
+ VSTR_TYPE_FMT_END);
+ break;
+ case 2:
+ vstr_fmt_add(conf, handler->name, custom_fmt_cb, at[0],
+ at[1], VSTR_TYPE_FMT_END);
+ break;
+ case 3:
+ vstr_fmt_add(conf, handler->name, custom_fmt_cb, at[0],
+ at[1], at[2], VSTR_TYPE_FMT_END);
+ break;
+ }
+}
+
+/**
+ * Management of thread-specific Vstr_conf objects
+ */
+#include <threading/thread_value.h>
+
+static thread_value_t *vstr_conf = NULL;
+
+static Vstr_conf *create_vstr_conf()
+{
+ int i;
+ Vstr_conf *conf = vstr_make_conf();
+ vstr_cntl_conf(conf, VSTR_CNTL_CONF_SET_FMT_CHAR_ESC, '%');
+ vstr_cntl_conf(conf, VSTR_CNTL_CONF_SET_TYPE_GRPALLOC_CACHE,
+ VSTR_TYPE_CNTL_CONF_GRPALLOC_CSTR);
+ vstr_cntl_conf(conf, VSTR_CNTL_CONF_SET_NUM_BUF_SZ, PRINTF_BUF_LEN);
+ for (i = 0; i < NUM_HANDLERS; ++i)
+ {
+ printf_hook_handler_t *handler = printf_hooks[i];
+ if (handler)
+ {
+ vstr_fmt_add_handler(conf, handler);
+ }
+ }
+ return conf;
+}
+
+static inline Vstr_conf *get_vstr_conf()
+{
+ Vstr_conf *conf = NULL;
+ if (vstr_conf)
+ {
+ conf = (Vstr_conf*)vstr_conf->get(vstr_conf);
+ if (!conf)
+ {
+ conf = create_vstr_conf();
+ vstr_conf->set(vstr_conf, conf);
+ }
+ }
+ return conf;
+}
+
+/**
+ * Described in header
+ */
+size_t vstr_print_in_hook(struct Vstr_base *base, size_t pos, const char *fmt,
+ ...)
+{
+ va_list args;
+ int written;
+
+ va_start(args, fmt);
+ written = vstr_add_vfmt(base, pos, fmt, args);
+ va_end(args);
+ return written;
+}
+
+/**
+ * Wrapper functions for printf and alike
+ */
+int vstr_wrapper_printf(const char *format, ...)
+{
+ int written;
+ va_list args;
+ va_start(args, format);
+ written = vstr_wrapper_vprintf(format, args);
+ va_end(args);
+ return written;
+}
+int vstr_wrapper_fprintf(FILE *stream, const char *format, ...)
+{
+ int written;
+ va_list args;
+ va_start(args, format);
+ written = vstr_wrapper_vfprintf(stream, format, args);
+ va_end(args);
+ return written;
+}
+int vstr_wrapper_sprintf(char *str, const char *format, ...)
+{
+ int written;
+ va_list args;
+ va_start(args, format);
+ written = vstr_wrapper_vsprintf(str, format, args);
+ va_end(args);
+ return written;
+}
+int vstr_wrapper_snprintf(char *str, size_t size, const char *format, ...)
+{
+ int written;
+ va_list args;
+ va_start(args, format);
+ written = vstr_wrapper_vsnprintf(str, size, format, args);
+ va_end(args);
+ return written;
+}
+int vstr_wrapper_asprintf(char **str, const char *format, ...)
+{
+ int written;
+ va_list args;
+ va_start(args, format);
+ written = vstr_wrapper_vasprintf(str, format, args);
+ va_end(args);
+ return written;
+}
+static inline int vstr_wrapper_vprintf_internal(Vstr_conf *conf, int fd,
+ const char *format,
+ va_list args)
+{
+ int written;
+ Vstr_base *s = vstr_make_base(conf);
+ vstr_add_vfmt(s, 0, format, args);
+ written = s->len;
+ while (s->len)
+ {
+ if (!vstr_sc_write_fd(s, 1, s->len, fd, NULL))
+ {
+ if (errno != EAGAIN && errno != EINTR)
+ {
+ written -= s->len;
+ break;
+ }
+ }
+ }
+ vstr_free_base(s);
+ return written;
+}
+int vstr_wrapper_vprintf(const char *format, va_list args)
+{
+ Vstr_conf *conf = get_vstr_conf();
+ if (conf)
+ {
+ return vstr_wrapper_vprintf_internal(conf, STDOUT_FILENO, format, args);
+ }
+ return vprintf(format, args);
+}
+int vstr_wrapper_vfprintf(FILE *stream, const char *format, va_list args)
+{
+ Vstr_conf *conf = get_vstr_conf();
+ if (conf)
+ {
+ return vstr_wrapper_vprintf_internal(conf, fileno(stream), format,
+ args);
+ }
+ return vfprintf(stream, format, args);
+}
+static inline int vstr_wrapper_vsnprintf_internal(char *str, size_t size,
+ const char *format,
+ va_list args)
+{
+ Vstr_conf *conf = get_vstr_conf();
+ if (conf)
+ {
+ int written;
+ Vstr_base *s = vstr_make_base(conf);
+ vstr_add_vfmt(s, 0, format, args);
+ written = s->len;
+ vstr_export_cstr_buf(s, 1, s->len, str, (size > 0) ? size : s->len + 1);
+ vstr_free_base(s);
+ return written;
+ }
+ return vsnprintf(str, size, format, args);
+}
+int vstr_wrapper_vsprintf(char *str, const char *format, va_list args)
+{
+ return vstr_wrapper_vsnprintf_internal(str, 0, format, args);
+}
+int vstr_wrapper_vsnprintf(char *str, size_t size, const char *format,
+ va_list args)
+{
+ return (size > 0) ? vstr_wrapper_vsnprintf_internal(str, size, format, args) : 0;
+}
+int vstr_wrapper_vasprintf(char **str, const char *format, va_list args)
+{
+ size_t len = 100;
+ int written;
+ *str = malloc(len);
+ while (TRUE)
+ {
+ va_list ac;
+ va_copy(ac, args);
+ written = vstr_wrapper_vsnprintf_internal(*str, len, format, ac);
+ va_end(ac);
+ if (written < len)
+ {
+ break;
+ }
+ len = written + 1;
+ *str = realloc(*str, len);
+ }
+ return written;
+}
+#endif
+
+METHOD(printf_hook_t, add_handler, void,
+ private_printf_hook_t *this, char spec,
+ printf_hook_function_t hook, ...)
+{
+ int i = -1;
+ printf_hook_handler_t *handler;
+ printf_hook_argtype_t argtype;
+ va_list args;
+
+ if (!IS_VALID_SPEC(spec))
+ {
+ DBG1(DBG_LIB, "'%c' is not a valid printf hook specifier, "
+ "not registered!", spec);
+ return;
+ }
+
+ handler = malloc_thing(printf_hook_handler_t);
+ handler->hook = hook;
+
+ va_start(args, hook);
+ while ((argtype = va_arg(args, printf_hook_argtype_t)) != PRINTF_HOOK_ARGTYPE_END)
+ {
+ if (++i >= ARGS_MAX)
+ {
+ DBG1(DBG_LIB, "Too many arguments for printf hook with "
+ "specifier '%c', not registered!", spec);
+ va_end(args);
+ free(handler);
+ return;
+ }
+ handler->argtypes[i] = argtype;
+ }
+ va_end(args);
+
+ handler->numargs = i + 1;
+
+ if (handler->numargs > 0)
+ {
+#if !defined(USE_VSTR) && \
+ (defined(HAVE_PRINTF_FUNCTION) || defined(HAVE_PRINTF_SPECIFIER))
+# ifdef HAVE_PRINTF_SPECIFIER
+ register_printf_specifier(spec, custom_print, custom_arginfo);
+# else
+ register_printf_function(spec, custom_print, custom_arginfo);
+# endif
+#else
+ Vstr_conf *conf = get_vstr_conf();
+ handler->name = malloc(2);
+ handler->name[0] = spec;
+ handler->name[1] = '\0';
+ vstr_fmt_add_handler(conf, handler);
+#endif
+ printf_hooks[SPEC_TO_INDEX(spec)] = handler;
+ }
+ else
+ {
+ free(handler);
+ }
+}
+
+METHOD(printf_hook_t, destroy, void,
+ private_printf_hook_t *this)
+{
+ int i;
+#ifdef USE_VSTR
+ Vstr_conf *conf = get_vstr_conf();
+#endif
+
+ for (i = 0; i < NUM_HANDLERS; ++i)
+ {
+ printf_hook_handler_t *handler = printf_hooks[i];
+ if (handler)
+ {
+#ifdef USE_VSTR
+ vstr_fmt_del(conf, handler->name);
+ free(handler->name);
+#endif
+ free(handler);
+ }
+ }
+
+#ifdef USE_VSTR
+ /* freeing the Vstr_conf of the main thread */
+ vstr_conf->destroy(vstr_conf);
+ vstr_conf = NULL;
+ vstr_exit();
+#endif
+ free(this);
+}
+
+/*
+ * see header file
+ */
+printf_hook_t *printf_hook_create()
+{
+ private_printf_hook_t *this;
+
+ INIT(this,
+ .public = {
+ .add_handler = _add_handler,
+ .destroy = _destroy,
+ },
+ );
+
+ memset(printf_hooks, 0, sizeof(printf_hooks));
+
+#ifdef USE_VSTR
+ if (!vstr_init())
+ {
+ DBG1(DBG_LIB, "failed to initialize Vstr library!");
+ free(this);
+ return NULL;
+ }
+ vstr_conf = thread_value_create((thread_cleanup_t)vstr_free_conf);
+#endif
+
+ return &this->public;
+}
+
diff --git a/src/libstrongswan/utils/printf_hook.h b/src/libstrongswan/utils/printf_hook.h
new file mode 100644
index 000000000..1425910be
--- /dev/null
+++ b/src/libstrongswan/utils/printf_hook.h
@@ -0,0 +1,247 @@
+/*
+ * Copyright (C) 2009 Tobias Brunner
+ * Copyright (C) 2006-2008 Martin Willi
+ * Hochschule fuer Technik Rapperswil
+ *
+ * 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. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * 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.
+ */
+
+/**
+ * @defgroup printf_hook printf_hook
+ * @{ @ingroup utils
+ */
+
+#ifndef PRINTF_HOOK_H_
+#define PRINTF_HOOK_H_
+
+typedef struct printf_hook_t printf_hook_t;
+typedef struct printf_hook_spec_t printf_hook_spec_t;
+typedef struct printf_hook_data_t printf_hook_data_t;
+typedef enum printf_hook_argtype_t printf_hook_argtype_t;
+
+#if !defined(USE_VSTR) && \
+ !defined(HAVE_PRINTF_FUNCTION) && \
+ !defined(HAVE_PRINTF_SPECIFIER)
+/* assume newer glibc register_printf_specifier if none given */
+#define HAVE_PRINTF_SPECIFIER
+#endif
+
+#if !defined(USE_VSTR) && \
+ (defined(HAVE_PRINTF_FUNCTION) || defined(HAVE_PRINTF_SPECIFIER))
+
+#include <stdio.h>
+#include <printf.h>
+
+enum printf_hook_argtype_t {
+ PRINTF_HOOK_ARGTYPE_END = -1,
+ PRINTF_HOOK_ARGTYPE_INT = PA_INT,
+ PRINTF_HOOK_ARGTYPE_POINTER = PA_POINTER,
+};
+
+/**
+ * Data to pass to a printf hook.
+ */
+struct printf_hook_data_t {
+
+ /**
+ * Output FILE stream
+ */
+ FILE *stream;;
+};
+
+/**
+ * Helper macro to be used in printf hook callbacks.
+ */
+#define print_in_hook(data, fmt, ...) ({\
+ ssize_t _written = fprintf(data->stream, fmt, ##__VA_ARGS__);\
+ if (_written < 0)\
+ {\
+ _written = 0;\
+ }\
+ _written;\
+})
+
+#else
+
+#include <vstr.h>
+
+enum printf_hook_argtype_t {
+ PRINTF_HOOK_ARGTYPE_END = VSTR_TYPE_FMT_END,
+ PRINTF_HOOK_ARGTYPE_INT = VSTR_TYPE_FMT_INT,
+ PRINTF_HOOK_ARGTYPE_POINTER = VSTR_TYPE_FMT_PTR_VOID,
+};
+
+/**
+ * Redefining printf and alike
+ */
+#include <stdio.h>
+#include <stdarg.h>
+
+int vstr_wrapper_printf(const char *format, ...);
+int vstr_wrapper_fprintf(FILE *stream, const char *format, ...);
+int vstr_wrapper_sprintf(char *str, const char *format, ...);
+int vstr_wrapper_snprintf(char *str, size_t size, const char *format, ...);
+int vstr_wrapper_asprintf(char **str, const char *format, ...);
+
+int vstr_wrapper_vprintf(const char *format, va_list ap);
+int vstr_wrapper_vfprintf(FILE *stream, const char *format, va_list ap);
+int vstr_wrapper_vsprintf(char *str, const char *format, va_list ap);
+int vstr_wrapper_vsnprintf(char *str, size_t size, const char *format, va_list ap);
+int vstr_wrapper_vasprintf(char **str, const char *format, va_list ap);
+
+#ifdef printf
+#undef printf
+#endif
+#ifdef fprintf
+#undef fprintf
+#endif
+#ifdef sprintf
+#undef sprintf
+#endif
+#ifdef snprintf
+#undef snprintf
+#endif
+#ifdef asprintf
+#undef asprintf
+#endif
+#ifdef vprintf
+#undef vprintf
+#endif
+#ifdef vfprintf
+#undef vfprintf
+#endif
+#ifdef vsprintf
+#undef vsprintf
+#endif
+#ifdef vsnprintf
+#undef vsnprintf
+#endif
+#ifdef vasprintf
+#undef vasprintf
+#endif
+
+#define printf vstr_wrapper_printf
+#define fprintf vstr_wrapper_fprintf
+#define sprintf vstr_wrapper_sprintf
+#define snprintf vstr_wrapper_snprintf
+#define asprintf vstr_wrapper_asprintf
+
+#define vprintf vstr_wrapper_vprintf
+#define vfprintf vstr_wrapper_vfprintf
+#define vsprintf vstr_wrapper_vsprintf
+#define vsnprintf vstr_wrapper_vsnprintf
+#define vasprintf vstr_wrapper_vasprintf
+
+/**
+ * Data to pass to a printf hook.
+ */
+struct printf_hook_data_t {
+
+ /**
+ * Base to append printf to
+ */
+ Vstr_base *base;
+
+ /**
+ * Position in base to write to
+ */
+ size_t pos;
+};
+
+/**
+ * Wrapper around vstr_add_vfmt(), avoids having to link all users of
+ * print_in_hook() against libvstr.
+ *
+ * @param base Vstr_string to add string to
+ * @param pos position to write to
+ * @param fmt format string
+ * @param ... arguments
+ * @return number of characters written
+ */
+size_t vstr_print_in_hook(struct Vstr_base *base, size_t pos, const char *fmt,
+ ...);
+
+/**
+ * Helper macro to be used in printf hook callbacks.
+ */
+#define print_in_hook(data, fmt, ...) ({\
+ size_t _written; \
+ _written = vstr_print_in_hook(data->base, data->pos, fmt, ##__VA_ARGS__);\
+ data->pos += _written;\
+ _written;\
+})
+
+#endif
+
+/**
+ * Callback function type for printf hooks.
+ *
+ * @param data hook data, to pass to print_in_hook()
+ * @param spec format specifier
+ * @param args arguments array
+ * @return number of characters written
+ */
+typedef int (*printf_hook_function_t)(printf_hook_data_t *data,
+ printf_hook_spec_t *spec,
+ const void *const *args);
+
+/**
+ * Properties of the format specifier
+ */
+struct printf_hook_spec_t {
+ /**
+ * TRUE if a '#' was used in the format specifier
+ */
+ int hash;
+
+ /**
+ * TRUE if a '-' was used in the format specifier
+ */
+ int minus;
+
+ /**
+ * TRUE if a '+' was used in the format specifier
+ */
+ int plus;
+
+ /**
+ * The width as given in the format specifier.
+ */
+ int width;
+};
+
+/**
+ * Printf handler management.
+ */
+struct printf_hook_t {
+
+ /**
+ * Register a printf handler.
+ *
+ * @param spec printf hook format character
+ * @param hook hook function
+ * @param ... list of PRINTF_HOOK_ARGTYPE_*, MUST end with PRINTF_HOOK_ARGTYPE_END
+ */
+ void (*add_handler)(printf_hook_t *this, char spec,
+ printf_hook_function_t hook, ...);
+
+ /**
+ * Destroy a printf_hook instance.
+ */
+ void (*destroy)(printf_hook_t *this);
+};
+
+/**
+ * Create a printf_hook instance.
+ */
+printf_hook_t *printf_hook_create();
+
+#endif /** PRINTF_HOOK_H_ @}*/
diff --git a/src/libstrongswan/utils/settings.c b/src/libstrongswan/utils/settings.c
new file mode 100644
index 000000000..809ca10ab
--- /dev/null
+++ b/src/libstrongswan/utils/settings.c
@@ -0,0 +1,1248 @@
+/*
+ * Copyright (C) 2010 Tobias Brunner
+ * Copyright (C) 2008 Martin Willi
+ * Hochschule fuer Technik Rapperswil
+ *
+ * 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. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * 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.
+ */
+
+#define _GNU_SOURCE
+#include <string.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <errno.h>
+#include <limits.h>
+#include <libgen.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+
+#ifdef HAVE_GLOB_H
+#include <glob.h>
+#endif /* HAVE_GLOB_H */
+
+#include "settings.h"
+
+#include "collections/linked_list.h"
+#include "threading/rwlock.h"
+#include "utils/debug.h"
+
+#define MAX_INCLUSION_LEVEL 10
+
+typedef struct private_settings_t private_settings_t;
+typedef struct section_t section_t;
+typedef struct kv_t kv_t;
+
+/**
+ * private data of settings
+ */
+struct private_settings_t {
+
+ /**
+ * public functions
+ */
+ settings_t public;
+
+ /**
+ * top level section
+ */
+ section_t *top;
+
+ /**
+ * contents of loaded files and in-memory settings (char*)
+ */
+ linked_list_t *contents;
+
+ /**
+ * lock to safely access the settings
+ */
+ rwlock_t *lock;
+};
+
+/**
+ * section containing subsections and key value pairs
+ */
+struct section_t {
+
+ /**
+ * name of the section
+ */
+ char *name;
+
+ /**
+ * subsections, as section_t
+ */
+ linked_list_t *sections;
+
+ /**
+ * key value pairs, as kv_t
+ */
+ linked_list_t *kv;
+};
+
+/**
+ * Key value pair
+ */
+struct kv_t {
+
+ /**
+ * key string, relative
+ */
+ char *key;
+
+ /**
+ * value as string
+ */
+ char *value;
+};
+
+/**
+ * create a key/value pair
+ */
+static kv_t *kv_create(char *key, char *value)
+{
+ kv_t *this;
+ INIT(this,
+ .key = strdup(key),
+ .value = value,
+ );
+ return this;
+}
+
+/**
+ * destroy a key/value pair
+ */
+static void kv_destroy(kv_t *this)
+{
+ free(this->key);
+ free(this);
+}
+
+/**
+ * create a section with the given name
+ */
+static section_t *section_create(char *name)
+{
+ section_t *this;
+ INIT(this,
+ .name = strdupnull(name),
+ .sections = linked_list_create(),
+ .kv = linked_list_create(),
+ );
+ return this;
+}
+
+/**
+ * destroy a section
+ */
+static void section_destroy(section_t *this)
+{
+ this->kv->destroy_function(this->kv, (void*)kv_destroy);
+ this->sections->destroy_function(this->sections, (void*)section_destroy);
+ free(this->name);
+ free(this);
+}
+
+/**
+ * Purge contents of a section
+ */
+static void section_purge(section_t *this)
+{
+ this->kv->destroy_function(this->kv, (void*)kv_destroy);
+ this->kv = linked_list_create();
+ this->sections->destroy_function(this->sections, (void*)section_destroy);
+ this->sections = linked_list_create();
+}
+
+/**
+ * callback to find a section by name
+ */
+static bool section_find(section_t *this, char *name)
+{
+ return streq(this->name, name);
+}
+
+/**
+ * callback to find a kv pair by key
+ */
+static bool kv_find(kv_t *this, char *key)
+{
+ return streq(this->key, key);
+}
+
+/**
+ * Print a format key, but consume already processed arguments
+ */
+static bool print_key(char *buf, int len, char *start, char *key, va_list args)
+{
+ va_list copy;
+ bool res;
+ char *pos;
+
+ va_copy(copy, args);
+ while (start < key)
+ {
+ pos = strchr(start, '%');
+ if (!pos)
+ {
+ start += strlen(start) + 1;
+ continue;
+ }
+ pos++;
+ switch (*pos)
+ {
+ case 'd':
+ va_arg(copy, int);
+ break;
+ case 's':
+ va_arg(copy, char*);
+ break;
+ case 'N':
+ va_arg(copy, enum_name_t*);
+ va_arg(copy, int);
+ break;
+ case '%':
+ break;
+ default:
+ DBG1(DBG_CFG, "settings with %%%c not supported!", *pos);
+ break;
+ }
+ start = pos;
+ if (*start)
+ {
+ start++;
+ }
+ }
+ res = vsnprintf(buf, len, key, copy) < len;
+ va_end(copy);
+ return res;
+}
+
+/**
+ * Find a section by a given key, using buffered key, reusable buffer.
+ * If "ensure" is TRUE, the sections are created if they don't exist.
+ */
+static section_t *find_section_buffered(section_t *section,
+ char *start, char *key, va_list args, char *buf, int len,
+ bool ensure)
+{
+ char *pos;
+ section_t *found = NULL;
+
+ if (section == NULL)
+ {
+ return NULL;
+ }
+ pos = strchr(key, '.');
+ if (pos)
+ {
+ *pos = '\0';
+ pos++;
+ }
+ if (!print_key(buf, len, start, key, args))
+ {
+ return NULL;
+ }
+ if (section->sections->find_first(section->sections,
+ (linked_list_match_t)section_find,
+ (void**)&found, buf) != SUCCESS)
+ {
+ if (ensure)
+ {
+ found = section_create(buf);
+ section->sections->insert_last(section->sections, found);
+ }
+ }
+ if (found && pos)
+ {
+ return find_section_buffered(found, start, pos, args, buf, len, ensure);
+ }
+ return found;
+}
+
+/**
+ * Find a section by a given key (thread-safe).
+ */
+static section_t *find_section(private_settings_t *this, section_t *section,
+ char *key, va_list args)
+{
+ char buf[128], keybuf[512];
+ section_t *found;
+
+ if (snprintf(keybuf, sizeof(keybuf), "%s", key) >= sizeof(keybuf))
+ {
+ return NULL;
+ }
+ this->lock->read_lock(this->lock);
+ found = find_section_buffered(section, keybuf, keybuf, args, buf,
+ sizeof(buf), FALSE);
+ this->lock->unlock(this->lock);
+ return found;
+}
+
+/**
+ * Ensure that the section with the given key exists (thread-safe).
+ */
+static section_t *ensure_section(private_settings_t *this, section_t *section,
+ char *key, va_list args)
+{
+ char buf[128], keybuf[512];
+ section_t *found;
+
+ if (snprintf(keybuf, sizeof(keybuf), "%s", key) >= sizeof(keybuf))
+ {
+ return NULL;
+ }
+ /* we might have to change the tree */
+ this->lock->write_lock(this->lock);
+ found = find_section_buffered(section, keybuf, keybuf, args, buf,
+ sizeof(buf), TRUE);
+ this->lock->unlock(this->lock);
+ return found;
+}
+
+/**
+ * Find the key/value pair for a key, using buffered key, reusable buffer
+ * If "ensure" is TRUE, the sections (and key/value pair) are created if they
+ * don't exist.
+ */
+static kv_t *find_value_buffered(section_t *section, char *start, char *key,
+ va_list args, char *buf, int len, bool ensure)
+{
+ char *pos;
+ kv_t *kv = NULL;
+ section_t *found = NULL;
+
+ if (section == NULL)
+ {
+ return NULL;
+ }
+
+ pos = strchr(key, '.');
+ if (pos)
+ {
+ *pos = '\0';
+ pos++;
+
+ if (!print_key(buf, len, start, key, args))
+ {
+ return NULL;
+ }
+ if (section->sections->find_first(section->sections,
+ (linked_list_match_t)section_find,
+ (void**)&found, buf) != SUCCESS)
+ {
+ if (!ensure)
+ {
+ return NULL;
+ }
+ found = section_create(buf);
+ section->sections->insert_last(section->sections, found);
+ }
+ return find_value_buffered(found, start, pos, args, buf, len,
+ ensure);
+ }
+ else
+ {
+ if (!print_key(buf, len, start, key, args))
+ {
+ return NULL;
+ }
+ if (section->kv->find_first(section->kv, (linked_list_match_t)kv_find,
+ (void**)&kv, buf) != SUCCESS)
+ {
+ if (ensure)
+ {
+ kv = kv_create(buf, NULL);
+ section->kv->insert_last(section->kv, kv);
+ }
+ }
+ }
+ return kv;
+}
+
+/**
+ * Find the string value for a key (thread-safe).
+ */
+static char *find_value(private_settings_t *this, section_t *section,
+ char *key, va_list args)
+{
+ char buf[128], keybuf[512], *value = NULL;
+ kv_t *kv;
+
+ if (snprintf(keybuf, sizeof(keybuf), "%s", key) >= sizeof(keybuf))
+ {
+ return NULL;
+ }
+ this->lock->read_lock(this->lock);
+ kv = find_value_buffered(section, keybuf, keybuf, args, buf, sizeof(buf),
+ FALSE);
+ if (kv)
+ {
+ value = kv->value;
+ }
+ this->lock->unlock(this->lock);
+ return value;
+}
+
+/**
+ * Set a value to a copy of the given string (thread-safe).
+ */
+static void set_value(private_settings_t *this, section_t *section,
+ char *key, va_list args, char *value)
+{
+ char buf[128], keybuf[512];
+ kv_t *kv;
+
+ if (snprintf(keybuf, sizeof(keybuf), "%s", key) >= sizeof(keybuf))
+ {
+ return;
+ }
+ this->lock->write_lock(this->lock);
+ kv = find_value_buffered(section, keybuf, keybuf, args, buf, sizeof(buf),
+ TRUE);
+ if (kv)
+ {
+ if (!value)
+ {
+ kv->value = NULL;
+ }
+ else if (kv->value && (strlen(value) <= strlen(kv->value)))
+ { /* overwrite in-place, if possible */
+ strcpy(kv->value, value);
+ }
+ else
+ { /* otherwise clone the string and store it in the cache */
+ kv->value = strdup(value);
+ this->contents->insert_last(this->contents, kv->value);
+ }
+ }
+ this->lock->unlock(this->lock);
+}
+
+METHOD(settings_t, get_str, char*,
+ private_settings_t *this, char *key, char *def, ...)
+{
+ char *value;
+ va_list args;
+
+ va_start(args, def);
+ value = find_value(this, this->top, key, args);
+ va_end(args);
+ if (value)
+ {
+ return value;
+ }
+ return def;
+}
+
+/**
+ * Described in header
+ */
+inline bool settings_value_as_bool(char *value, bool def)
+{
+ if (value)
+ {
+ if (strcaseeq(value, "1") ||
+ strcaseeq(value, "yes") ||
+ strcaseeq(value, "true") ||
+ strcaseeq(value, "enabled"))
+ {
+ return TRUE;
+ }
+ else if (strcaseeq(value, "0") ||
+ strcaseeq(value, "no") ||
+ strcaseeq(value, "false") ||
+ strcaseeq(value, "disabled"))
+ {
+ return FALSE;
+ }
+ }
+ return def;
+}
+
+METHOD(settings_t, get_bool, bool,
+ private_settings_t *this, char *key, bool def, ...)
+{
+ char *value;
+ va_list args;
+
+ va_start(args, def);
+ value = find_value(this, this->top, key, args);
+ va_end(args);
+ return settings_value_as_bool(value, def);
+}
+
+/**
+ * Described in header
+ */
+inline int settings_value_as_int(char *value, int def)
+{
+ int intval;
+ if (value)
+ {
+ errno = 0;
+ intval = strtol(value, NULL, 10);
+ if (errno == 0)
+ {
+ return intval;
+ }
+ }
+ return def;
+}
+
+METHOD(settings_t, get_int, int,
+ private_settings_t *this, char *key, int def, ...)
+{
+ char *value;
+ va_list args;
+
+ va_start(args, def);
+ value = find_value(this, this->top, key, args);
+ va_end(args);
+ return settings_value_as_int(value, def);
+}
+
+/**
+ * Described in header
+ */
+inline double settings_value_as_double(char *value, double def)
+{
+ double dval;
+ if (value)
+ {
+ errno = 0;
+ dval = strtod(value, NULL);
+ if (errno == 0)
+ {
+ return dval;
+ }
+ }
+ return def;
+}
+
+METHOD(settings_t, get_double, double,
+ private_settings_t *this, char *key, double def, ...)
+{
+ char *value;
+ va_list args;
+
+ va_start(args, def);
+ value = find_value(this, this->top, key, args);
+ va_end(args);
+ return settings_value_as_double(value, def);
+}
+
+/**
+ * Described in header
+ */
+inline u_int32_t settings_value_as_time(char *value, u_int32_t def)
+{
+ char *endptr;
+ u_int32_t timeval;
+ if (value)
+ {
+ errno = 0;
+ timeval = strtoul(value, &endptr, 10);
+ if (errno == 0)
+ {
+ switch (*endptr)
+ {
+ case 'd': /* time in days */
+ timeval *= 24 * 3600;
+ break;
+ case 'h': /* time in hours */
+ timeval *= 3600;
+ break;
+ case 'm': /* time in minutes */
+ timeval *= 60;
+ break;
+ case 's': /* time in seconds */
+ default:
+ break;
+ }
+ return timeval;
+ }
+ }
+ return def;
+}
+
+METHOD(settings_t, get_time, u_int32_t,
+ private_settings_t *this, char *key, u_int32_t def, ...)
+{
+ char *value;
+ va_list args;
+
+ va_start(args, def);
+ value = find_value(this, this->top, key, args);
+ va_end(args);
+ return settings_value_as_time(value, def);
+}
+
+METHOD(settings_t, set_str, void,
+ private_settings_t *this, char *key, char *value, ...)
+{
+ va_list args;
+ va_start(args, value);
+ set_value(this, this->top, key, args, value);
+ va_end(args);
+}
+
+METHOD(settings_t, set_bool, void,
+ private_settings_t *this, char *key, bool value, ...)
+{
+ va_list args;
+ va_start(args, value);
+ set_value(this, this->top, key, args, value ? "1" : "0");
+ va_end(args);
+}
+
+METHOD(settings_t, set_int, void,
+ private_settings_t *this, char *key, int value, ...)
+{
+ char val[16];
+ va_list args;
+ va_start(args, value);
+ if (snprintf(val, sizeof(val), "%d", value) < sizeof(val))
+ {
+ set_value(this, this->top, key, args, val);
+ }
+ va_end(args);
+}
+
+METHOD(settings_t, set_double, void,
+ private_settings_t *this, char *key, double value, ...)
+{
+ char val[64];
+ va_list args;
+ va_start(args, value);
+ if (snprintf(val, sizeof(val), "%f", value) < sizeof(val))
+ {
+ set_value(this, this->top, key, args, val);
+ }
+ va_end(args);
+}
+
+METHOD(settings_t, set_time, void,
+ private_settings_t *this, char *key, u_int32_t value, ...)
+{
+ char val[16];
+ va_list args;
+ va_start(args, value);
+ if (snprintf(val, sizeof(val), "%u", value) < sizeof(val))
+ {
+ set_value(this, this->top, key, args, val);
+ }
+ va_end(args);
+}
+
+METHOD(settings_t, set_default_str, bool,
+ private_settings_t *this, char *key, char *value, ...)
+{
+ char *old;
+ va_list args;
+
+ va_start(args, value);
+ old = find_value(this, this->top, key, args);
+ va_end(args);
+
+ if (!old)
+ {
+ va_start(args, value);
+ set_value(this, this->top, key, args, value);
+ va_end(args);
+ return TRUE;
+ }
+ return FALSE;
+}
+
+/**
+ * Enumerate section names, not sections
+ */
+static bool section_filter(void *null, section_t **in, char **out)
+{
+ *out = (*in)->name;
+ return TRUE;
+}
+
+METHOD(settings_t, create_section_enumerator, enumerator_t*,
+ private_settings_t *this, char *key, ...)
+{
+ section_t *section;
+ va_list args;
+
+ va_start(args, key);
+ section = find_section(this, this->top, key, args);
+ va_end(args);
+
+ if (!section)
+ {
+ return enumerator_create_empty();
+ }
+ this->lock->read_lock(this->lock);
+ return enumerator_create_filter(
+ section->sections->create_enumerator(section->sections),
+ (void*)section_filter, this->lock, (void*)this->lock->unlock);
+}
+
+/**
+ * Enumerate key and values, not kv_t entries
+ */
+static bool kv_filter(void *null, kv_t **in, char **key,
+ void *none, char **value)
+{
+ *key = (*in)->key;
+ *value = (*in)->value;
+ return TRUE;
+}
+
+METHOD(settings_t, create_key_value_enumerator, enumerator_t*,
+ private_settings_t *this, char *key, ...)
+{
+ section_t *section;
+ va_list args;
+
+ va_start(args, key);
+ section = find_section(this, this->top, key, args);
+ va_end(args);
+
+ if (!section)
+ {
+ return enumerator_create_empty();
+ }
+ this->lock->read_lock(this->lock);
+ return enumerator_create_filter(
+ section->kv->create_enumerator(section->kv),
+ (void*)kv_filter, this->lock, (void*)this->lock->unlock);
+}
+
+/**
+ * parse text, truncate "skip" chars, delimited by term respecting brackets.
+ *
+ * Chars in "skip" are truncated at the beginning and the end of the resulting
+ * token. "term" contains a list of characters to read up to (first match),
+ * while "br" contains bracket counterparts found in "term" to skip.
+ */
+static char parse(char **text, char *skip, char *term, char *br, char **token)
+{
+ char *best = NULL;
+ char best_term = '\0';
+
+ /* skip leading chars */
+ while (strchr(skip, **text))
+ {
+ (*text)++;
+ if (!**text)
+ {
+ return 0;
+ }
+ }
+ /* mark begin of subtext */
+ *token = *text;
+ while (*term)
+ {
+ char *pos = *text;
+ int level = 1;
+
+ /* find terminator */
+ while (*pos)
+ {
+ if (*pos == *term)
+ {
+ level--;
+ }
+ else if (br && *pos == *br)
+ {
+ level++;
+ }
+ if (level == 0)
+ {
+ if (best == NULL || best > pos)
+ {
+ best = pos;
+ best_term = *term;
+ }
+ break;
+ }
+ pos++;
+ }
+ /* try next terminator */
+ term++;
+ if (br)
+ {
+ br++;
+ }
+ }
+ if (best)
+ {
+ /* update input */
+ *text = best;
+ /* null trailing bytes */
+ do
+ {
+ *best = '\0';
+ best--;
+ }
+ while (best >= *token && strchr(skip, *best));
+ /* return found terminator */
+ return best_term;
+ }
+ return 0;
+}
+
+/**
+ * Check if "text" starts with "pattern".
+ * Characters in "skip" are skipped first. If found, TRUE is returned and "text"
+ * is modified to point to the character right after "pattern".
+ */
+static bool starts_with(char **text, char *skip, char *pattern)
+{
+ char *pos = *text;
+ int len = strlen(pattern);
+ while (strchr(skip, *pos))
+ {
+ pos++;
+ if (!*pos)
+ {
+ return FALSE;
+ }
+ }
+ if (strlen(pos) < len || !strneq(pos, pattern, len))
+ {
+ return FALSE;
+ }
+ *text = pos + len;
+ return TRUE;
+}
+
+/**
+ * Check if what follows in "text" is an include statement.
+ * If this function returns TRUE, "text" will point to the character right after
+ * the include pattern, which is returned in "pattern".
+ */
+static bool parse_include(char **text, char **pattern)
+{
+ char *pos = *text;
+ if (!starts_with(&pos, "\n\t ", "include"))
+ {
+ return FALSE;
+ }
+ if (starts_with(&pos, "\t ", "="))
+ { /* ignore "include = value" */
+ return FALSE;
+ }
+ *text = pos;
+ return parse(text, "\t ", "\n", NULL, pattern) != 0;
+}
+
+/**
+ * Forward declaration.
+ */
+static bool parse_files(linked_list_t *contents, char *file, int level,
+ char *pattern, section_t *section);
+
+/**
+ * Parse a section
+ */
+static bool parse_section(linked_list_t *contents, char *file, int level,
+ char **text, section_t *section)
+{
+ bool finished = FALSE;
+ char *key, *value, *inner;
+
+ while (!finished)
+ {
+ if (parse_include(text, &value))
+ {
+ if (!parse_files(contents, file, level, value, section))
+ {
+ DBG1(DBG_LIB, "failed to include '%s'", value);
+ return FALSE;
+ }
+ continue;
+ }
+ switch (parse(text, "\t\n ", "{=#", NULL, &key))
+ {
+ case '{':
+ if (parse(text, "\t ", "}", "{", &inner))
+ {
+ section_t *sub;
+ if (!strlen(key))
+ {
+ DBG1(DBG_LIB, "skipping section without name in '%s'",
+ section->name);
+ continue;
+ }
+ if (section->sections->find_first(section->sections,
+ (linked_list_match_t)section_find,
+ (void**)&sub, key) != SUCCESS)
+ {
+ sub = section_create(key);
+ if (parse_section(contents, file, level, &inner, sub))
+ {
+ section->sections->insert_last(section->sections,
+ sub);
+ continue;
+ }
+ section_destroy(sub);
+ }
+ else
+ { /* extend the existing section */
+ if (parse_section(contents, file, level, &inner, sub))
+ {
+ continue;
+ }
+ }
+ DBG1(DBG_LIB, "parsing subsection '%s' failed", key);
+ break;
+ }
+ DBG1(DBG_LIB, "matching '}' not found near %s", *text);
+ break;
+ case '=':
+ if (parse(text, "\t ", "\n", NULL, &value))
+ {
+ kv_t *kv;
+ if (!strlen(key))
+ {
+ DBG1(DBG_LIB, "skipping value without key in '%s'",
+ section->name);
+ continue;
+ }
+ if (section->kv->find_first(section->kv,
+ (linked_list_match_t)kv_find,
+ (void**)&kv, key) != SUCCESS)
+ {
+ kv = kv_create(key, value);
+ section->kv->insert_last(section->kv, kv);
+ }
+ else
+ { /* replace with the most recently read value */
+ kv->value = value;
+ }
+ continue;
+ }
+ DBG1(DBG_LIB, "parsing value failed near %s", *text);
+ break;
+ case '#':
+ parse(text, "", "\n", NULL, &value);
+ continue;
+ default:
+ finished = TRUE;
+ continue;
+ }
+ return FALSE;
+ }
+ return TRUE;
+}
+
+/**
+ * Parse a file and add the settings to the given section.
+ */
+static bool parse_file(linked_list_t *contents, char *file, int level,
+ section_t *section)
+{
+ bool success;
+ char *text, *pos;
+ struct stat st;
+ FILE *fd;
+ int len;
+
+ DBG2(DBG_LIB, "loading config file '%s'", file);
+ if (stat(file, &st) == -1)
+ {
+ if (errno == ENOENT)
+ {
+ DBG2(DBG_LIB, "'%s' does not exist, ignored", file);
+ return TRUE;
+ }
+ DBG1(DBG_LIB, "failed to stat '%s': %s", file, strerror(errno));
+ return FALSE;
+ }
+ else if (!S_ISREG(st.st_mode))
+ {
+ DBG1(DBG_LIB, "'%s' is not a regular file", file);
+ return FALSE;
+ }
+ fd = fopen(file, "r");
+ if (fd == NULL)
+ {
+ DBG1(DBG_LIB, "'%s' is not readable", file);
+ return FALSE;
+ }
+ fseek(fd, 0, SEEK_END);
+ len = ftell(fd);
+ rewind(fd);
+ text = malloc(len + 1);
+ text[len] = '\0';
+ if (fread(text, 1, len, fd) != len)
+ {
+ free(text);
+ fclose(fd);
+ return FALSE;
+ }
+ fclose(fd);
+
+ pos = text;
+ success = parse_section(contents, file, level, &pos, section);
+ if (!success)
+ {
+ free(text);
+ }
+ else
+ {
+ contents->insert_last(contents, text);
+ }
+ return success;
+}
+
+/**
+ * Load the files matching "pattern", which is resolved with glob(3), if
+ * available.
+ * If the pattern is relative, the directory of "file" is used as base.
+ */
+static bool parse_files(linked_list_t *contents, char *file, int level,
+ char *pattern, section_t *section)
+{
+ bool success = TRUE;
+ char pat[PATH_MAX];
+
+ if (level > MAX_INCLUSION_LEVEL)
+ {
+ DBG1(DBG_LIB, "maximum level of %d includes reached, ignored",
+ MAX_INCLUSION_LEVEL);
+ return TRUE;
+ }
+
+ if (!strlen(pattern))
+ {
+ DBG2(DBG_LIB, "empty include pattern, ignored");
+ return TRUE;
+ }
+
+ if (!file || pattern[0] == '/')
+ { /* absolute path */
+ if (snprintf(pat, sizeof(pat), "%s", pattern) >= sizeof(pat))
+ {
+ DBG1(DBG_LIB, "include pattern too long, ignored");
+ return TRUE;
+ }
+ }
+ else
+ { /* base relative paths to the directory of the current file */
+ char *dir = strdup(file);
+ dir = dirname(dir);
+ if (snprintf(pat, sizeof(pat), "%s/%s", dir, pattern) >= sizeof(pat))
+ {
+ DBG1(DBG_LIB, "include pattern too long, ignored");
+ free(dir);
+ return TRUE;
+ }
+ free(dir);
+ }
+#ifdef HAVE_GLOB_H
+ {
+ int status;
+ glob_t buf;
+
+ status = glob(pat, GLOB_ERR, NULL, &buf);
+ if (status == GLOB_NOMATCH)
+ {
+ DBG2(DBG_LIB, "no files found matching '%s', ignored", pat);
+ }
+ else if (status != 0)
+ {
+ DBG1(DBG_LIB, "expanding file pattern '%s' failed", pat);
+ success = FALSE;
+ }
+ else
+ {
+ char **expanded;
+ for (expanded = buf.gl_pathv; *expanded != NULL; expanded++)
+ {
+ success &= parse_file(contents, *expanded, level + 1, section);
+ if (!success)
+ {
+ break;
+ }
+ }
+ }
+ globfree(&buf);
+ }
+#else /* HAVE_GLOB_H */
+ /* if glob(3) is not available, try to load pattern directly */
+ success = parse_file(contents, pat, level + 1, section);
+#endif /* HAVE_GLOB_H */
+ return success;
+}
+
+/**
+ * Recursivly extends "base" with "extension".
+ */
+static void section_extend(section_t *base, section_t *extension)
+{
+ enumerator_t *enumerator;
+ section_t *sec;
+ kv_t *kv;
+
+ enumerator = extension->sections->create_enumerator(extension->sections);
+ while (enumerator->enumerate(enumerator, (void**)&sec))
+ {
+ section_t *found;
+ if (base->sections->find_first(base->sections,
+ (linked_list_match_t)section_find, (void**)&found,
+ sec->name) == SUCCESS)
+ {
+ section_extend(found, sec);
+ }
+ else
+ {
+ extension->sections->remove_at(extension->sections, enumerator);
+ base->sections->insert_last(base->sections, sec);
+ }
+ }
+ enumerator->destroy(enumerator);
+
+ enumerator = extension->kv->create_enumerator(extension->kv);
+ while (enumerator->enumerate(enumerator, (void**)&kv))
+ {
+ kv_t *found;
+ if (base->kv->find_first(base->kv, (linked_list_match_t)kv_find,
+ (void**)&found, kv->key) == SUCCESS)
+ {
+ found->value = kv->value;
+ }
+ else
+ {
+ extension->kv->remove_at(extension->kv, enumerator);
+ base->kv->insert_last(base->kv, kv);
+ }
+ }
+ enumerator->destroy(enumerator);
+}
+
+/**
+ * Load settings from files matching the given file pattern.
+ * All sections and values are added relative to "parent".
+ * All files (even included ones) have to be loaded successfully.
+ */
+static bool load_files_internal(private_settings_t *this, section_t *parent,
+ char *pattern, bool merge)
+{
+ char *text;
+ linked_list_t *contents;
+ section_t *section;
+
+ if (pattern == NULL)
+ {
+#ifdef STRONGSWAN_CONF
+ pattern = STRONGSWAN_CONF;
+#else
+ return FALSE;
+#endif
+ }
+
+ contents = linked_list_create();
+ section = section_create(NULL);
+
+ if (!parse_files(contents, NULL, 0, pattern, section))
+ {
+ contents->destroy_function(contents, (void*)free);
+ section_destroy(section);
+ return FALSE;
+ }
+
+ this->lock->write_lock(this->lock);
+ if (!merge)
+ {
+ section_purge(parent);
+ }
+ /* extend parent section */
+ section_extend(parent, section);
+ /* move contents of loaded files to main store */
+ while (contents->remove_first(contents, (void**)&text) == SUCCESS)
+ {
+ this->contents->insert_last(this->contents, text);
+ }
+ this->lock->unlock(this->lock);
+
+ section_destroy(section);
+ contents->destroy(contents);
+ return TRUE;
+}
+
+METHOD(settings_t, load_files, bool,
+ private_settings_t *this, char *pattern, bool merge)
+{
+ return load_files_internal(this, this->top, pattern, merge);
+}
+
+METHOD(settings_t, load_files_section, bool,
+ private_settings_t *this, char *pattern, bool merge, char *key, ...)
+{
+ section_t *section;
+ va_list args;
+
+ va_start(args, key);
+ section = ensure_section(this, this->top, key, args);
+ va_end(args);
+
+ if (!section)
+ {
+ return FALSE;
+ }
+ return load_files_internal(this, section, pattern, merge);
+}
+
+METHOD(settings_t, destroy, void,
+ private_settings_t *this)
+{
+ section_destroy(this->top);
+ this->contents->destroy_function(this->contents, (void*)free);
+ this->lock->destroy(this->lock);
+ free(this);
+}
+
+/*
+ * see header file
+ */
+settings_t *settings_create(char *file)
+{
+ private_settings_t *this;
+
+ INIT(this,
+ .public = {
+ .get_str = _get_str,
+ .get_int = _get_int,
+ .get_double = _get_double,
+ .get_time = _get_time,
+ .get_bool = _get_bool,
+ .set_str = _set_str,
+ .set_int = _set_int,
+ .set_double = _set_double,
+ .set_time = _set_time,
+ .set_bool = _set_bool,
+ .set_default_str = _set_default_str,
+ .create_section_enumerator = _create_section_enumerator,
+ .create_key_value_enumerator = _create_key_value_enumerator,
+ .load_files = _load_files,
+ .load_files_section = _load_files_section,
+ .destroy = _destroy,
+ },
+ .top = section_create(NULL),
+ .contents = linked_list_create(),
+ .lock = rwlock_create(RWLOCK_TYPE_DEFAULT),
+ );
+
+ load_files(this, file, FALSE);
+
+ return &this->public;
+}
+
diff --git a/src/libstrongswan/utils/settings.h b/src/libstrongswan/utils/settings.h
new file mode 100644
index 000000000..df0c534e9
--- /dev/null
+++ b/src/libstrongswan/utils/settings.h
@@ -0,0 +1,323 @@
+/*
+ * Copyright (C) 2010 Tobias Brunner
+ * Copyright (C) 2008 Martin Willi
+ * Hochschule fuer Technik Rapperswil
+ *
+ * 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. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * 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.
+ */
+
+/**
+ * @defgroup settings settings
+ * @{ @ingroup utils
+ */
+
+#ifndef SETTINGS_H_
+#define SETTINGS_H_
+
+typedef struct settings_t settings_t;
+
+#include "utils.h"
+#include "collections/enumerator.h"
+
+/**
+ * Convert a string value returned by a key/value enumerator to a boolean.
+ *
+ * @see settings_t.create_key_value_enumerator()
+ * @see settings_t.get_bool()
+ * @param value the string value
+ * @param def the default value, if value is NULL or invalid
+ */
+bool settings_value_as_bool(char *value, bool def);
+
+/**
+ * Convert a string value returned by a key/value enumerator to an integer.
+ *
+ * @see settings_t.create_key_value_enumerator()
+ * @see settings_t.get_int()
+ * @param value the string value
+ * @param def the default value, if value is NULL or invalid
+ */
+int settings_value_as_int(char *value, int def);
+
+/**
+ * Convert a string value returned by a key/value enumerator to a double.
+ *
+ * @see settings_t.create_key_value_enumerator()
+ * @see settings_t.get_double()
+ * @param value the string value
+ * @param def the default value, if value is NULL or invalid
+ */
+double settings_value_as_double(char *value, double def);
+
+/**
+ * Convert a string value returned by a key/value enumerator to a time value.
+ *
+ * @see settings_t.create_key_value_enumerator()
+ * @see settings_t.get_time()
+ * @param value the string value
+ * @param def the default value, if value is NULL or invalid
+ */
+u_int32_t settings_value_as_time(char *value, u_int32_t def);
+
+/**
+ * Generic configuration options read from a config file.
+ *
+ * The syntax is quite simple:
+ * @code
+ * settings := (section|keyvalue)*
+ * section := name { settings }
+ * keyvalue := key = value\n
+ * @endcode
+ * E.g.:
+ * @code
+ a = b
+ section-one {
+ somevalue = asdf
+ subsection {
+ othervalue = xxx
+ }
+ yetanother = zz
+ }
+ section-two {
+ }
+ @endcode
+ *
+ * The values are accessed using the get() functions using dotted keys, e.g.
+ * section-one.subsection.othervalue
+ *
+ * Currently only a limited set of printf format specifiers are supported
+ * (namely %s, %d and %N, see implementation for details).
+ *
+ * \section includes Including other files
+ * Other files can be included, using the include statement e.g.
+ * @code
+ * include /somepath/subconfig.conf
+ * @endcode
+ * Shell patterns like *.conf are possible.
+ *
+ * If the path is relative, the directory of the file containing the include
+ * statement is used as base.
+ *
+ * Sections loaded from included files extend previously loaded sections,
+ * already existing values are replaced.
+ *
+ * All settings included from files are added relative to the section the
+ * include statement is in.
+ *
+ * The following files result in the same final config as above:
+ *
+ * @code
+ a = b
+ section-one {
+ somevalue = before include
+ include include.conf
+ }
+ include two.conf
+ @endcode
+ * include.conf
+ * @code
+ somevalue = asdf
+ subsection {
+ othervalue = yyy
+ }
+ yetanother = zz
+ @endcode
+ * two.conf
+ * @code
+ section-one {
+ subsection {
+ othervalue = xxx
+ }
+ }
+ section-two {
+ }
+ @endcode
+ */
+struct settings_t {
+
+ /**
+ * Get a settings value as a string.
+ *
+ * @param key key including sections, printf style format
+ * @param def value returned if key not found
+ * @param ... argument list for key
+ * @return value pointing to internal string
+ */
+ char* (*get_str)(settings_t *this, char *key, char *def, ...);
+
+ /**
+ * Get a boolean yes|no, true|false value.
+ *
+ * @param key key including sections, printf style format
+ * @param def value returned if key not found
+ * @param ... argument list for key
+ * @return value of the key
+ */
+ bool (*get_bool)(settings_t *this, char *key, bool def, ...);
+
+ /**
+ * Get an integer value.
+ *
+ * @param key key including sections, printf style format
+ * @param def value returned if key not found
+ * @param ... argument list for key
+ * @return value of the key
+ */
+ int (*get_int)(settings_t *this, char *key, int def, ...);
+
+ /**
+ * Get an double value.
+ *
+ * @param key key including sections, printf style format
+ * @param def value returned if key not found
+ * @param ... argument list for key
+ * @return value of the key
+ */
+ double (*get_double)(settings_t *this, char *key, double def, ...);
+
+ /**
+ * Get a time value.
+ *
+ * @param key key including sections, printf style format
+ * @param def value returned if key not found
+ * @param ... argument list for key
+ * @return value of the key (in seconds)
+ */
+ u_int32_t (*get_time)(settings_t *this, char *key, u_int32_t def, ...);
+
+ /**
+ * Set a string value.
+ *
+ * @param key key including sections, printf style format
+ * @param value value to set (gets cloned)
+ * @param ... argument list for key
+ */
+ void (*set_str)(settings_t *this, char *key, char *value, ...);
+
+ /**
+ * Set a boolean value.
+ *
+ * @param key key including sections, printf style format
+ * @param value value to set
+ * @param ... argument list for key
+ */
+ void (*set_bool)(settings_t *this, char *key, bool value, ...);
+
+ /**
+ * Set an integer value.
+ *
+ * @param key key including sections, printf style format
+ * @param value value to set
+ * @param ... argument list for key
+ */
+ void (*set_int)(settings_t *this, char *key, int value, ...);
+
+ /**
+ * Set an double value.
+ *
+ * @param key key including sections, printf style format
+ * @param value value to set
+ * @param ... argument list for key
+ */
+ void (*set_double)(settings_t *this, char *key, double value, ...);
+
+ /**
+ * Set a time value.
+ *
+ * @param key key including sections, printf style format
+ * @param def value to set
+ * @param ... argument list for key
+ */
+ void (*set_time)(settings_t *this, char *key, u_int32_t value, ...);
+
+ /**
+ * Set a default for string value.
+ *
+ * @param key key including sections, printf style format
+ * @param def value to set if unconfigured
+ * @param ... argument list for key
+ * @return TRUE if a new default value for key has been set
+ */
+ bool (*set_default_str)(settings_t *this, char *key, char *value, ...);
+
+ /**
+ * Create an enumerator over subsection names of a section.
+ *
+ * @param section section including parents, printf style format
+ * @param ... argument list for key
+ * @return enumerator over subsection names
+ */
+ enumerator_t* (*create_section_enumerator)(settings_t *this,
+ char *section, ...);
+
+ /**
+ * Create an enumerator over key/value pairs in a section.
+ *
+ * @param section section name to list key/value pairs of, printf style
+ * @param ... argument list for section
+ * @return enumerator over (char *key, char *value)
+ */
+ enumerator_t* (*create_key_value_enumerator)(settings_t *this,
+ char *section, ...);
+
+ /**
+ * Load settings from the files matching the given pattern.
+ *
+ * If merge is TRUE, existing sections are extended, existing values
+ * replaced, by those found in the loaded files. If it is FALSE, existing
+ * sections are purged before reading the new config.
+ *
+ * @note If any of the files matching the pattern fails to load, no settings
+ * are added at all. So, it's all or nothing.
+ *
+ * @param pattern file pattern
+ * @param merge TRUE to merge config with existing values
+ * @return TRUE, if settings were loaded successfully
+ */
+ bool (*load_files)(settings_t *this, char *pattern, bool merge);
+
+ /**
+ * Load settings from the files matching the given pattern.
+ *
+ * If merge is TRUE, existing sections are extended, existing values
+ * replaced, by those found in the loaded files. If it is FALSE, existing
+ * sections are purged before reading the new config.
+ *
+ * All settings are loaded relative to the given section. The section is
+ * created, if it does not yet exist.
+ *
+ * @note If any of the files matching the pattern fails to load, no settings
+ * are added at all. So, it's all or nothing.
+ *
+ * @param pattern file pattern
+ * @param merge TRUE to merge config with existing values
+ * @param section section name of parent section, printf style
+ * @param ... argument list for section
+ * @return TRUE, if settings were loaded successfully
+ */
+ bool (*load_files_section)(settings_t *this, char *pattern, bool merge,
+ char *section, ...);
+
+ /**
+ * Destroy a settings instance.
+ */
+ void (*destroy)(settings_t *this);
+};
+
+/**
+ * Load settings from a file.
+ *
+ * @param file file to read settings from, NULL for default
+ * @return settings object
+ */
+settings_t *settings_create(char *file);
+
+#endif /** SETTINGS_H_ @}*/
diff --git a/src/libstrongswan/utils/utils.c b/src/libstrongswan/utils/utils.c
new file mode 100644
index 000000000..30084cd81
--- /dev/null
+++ b/src/libstrongswan/utils/utils.c
@@ -0,0 +1,637 @@
+/*
+ * Copyright (C) 2008-2012 Tobias Brunner
+ * Copyright (C) 2005-2008 Martin Willi
+ * Hochschule fuer Technik Rapperswil
+ *
+ * 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. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * 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.
+ */
+
+#include "utils.h"
+
+#include <sys/stat.h>
+#include <string.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <inttypes.h>
+#include <stdint.h>
+#include <limits.h>
+#include <dirent.h>
+#include <time.h>
+#include <pthread.h>
+
+#include "collections/enumerator.h"
+#include "utils/debug.h"
+
+ENUM(status_names, SUCCESS, NEED_MORE,
+ "SUCCESS",
+ "FAILED",
+ "OUT_OF_RES",
+ "ALREADY_DONE",
+ "NOT_SUPPORTED",
+ "INVALID_ARG",
+ "NOT_FOUND",
+ "PARSE_ERROR",
+ "VERIFY_ERROR",
+ "INVALID_STATE",
+ "DESTROY_ME",
+ "NEED_MORE",
+);
+
+/**
+ * Described in header.
+ */
+void memxor(u_int8_t dst[], u_int8_t src[], size_t n)
+{
+ int m, i;
+
+ /* byte wise XOR until dst aligned */
+ for (i = 0; (uintptr_t)&dst[i] % sizeof(long) && i < n; i++)
+ {
+ dst[i] ^= src[i];
+ }
+ /* try to use words if src shares an aligment with dst */
+ switch (((uintptr_t)&src[i] % sizeof(long)))
+ {
+ case 0:
+ for (m = n - sizeof(long); i <= m; i += sizeof(long))
+ {
+ *(long*)&dst[i] ^= *(long*)&src[i];
+ }
+ break;
+ case sizeof(int):
+ for (m = n - sizeof(int); i <= m; i += sizeof(int))
+ {
+ *(int*)&dst[i] ^= *(int*)&src[i];
+ }
+ break;
+ case sizeof(short):
+ for (m = n - sizeof(short); i <= m; i += sizeof(short))
+ {
+ *(short*)&dst[i] ^= *(short*)&src[i];
+ }
+ break;
+ default:
+ break;
+ }
+ /* byte wise XOR of the rest */
+ for (; i < n; i++)
+ {
+ dst[i] ^= src[i];
+ }
+}
+
+/**
+ * Described in header.
+ */
+void memwipe_noinline(void *ptr, size_t n)
+{
+ memwipe_inline(ptr, n);
+}
+
+/**
+ * Described in header.
+ */
+void *memstr(const void *haystack, const char *needle, size_t n)
+{
+ unsigned const char *pos = haystack;
+ size_t l;
+
+ if (!haystack || !needle || (l = strlen(needle)) == 0)
+ {
+ return NULL;
+ }
+ for (; n >= l; ++pos, --n)
+ {
+ if (memeq(pos, needle, l))
+ {
+ return (void*)pos;
+ }
+ }
+ return NULL;
+}
+
+/**
+ * Described in header.
+ */
+char* translate(char *str, const char *from, const char *to)
+{
+ char *pos = str;
+ if (strlen(from) != strlen(to))
+ {
+ return str;
+ }
+ while (pos && *pos)
+ {
+ char *match;
+ if ((match = strchr(from, *pos)) != NULL)
+ {
+ *pos = to[match - from];
+ }
+ pos++;
+ }
+ return str;
+}
+
+/**
+ * Described in header.
+ */
+bool mkdir_p(const char *path, mode_t mode)
+{
+ int len;
+ char *pos, full[PATH_MAX];
+ pos = full;
+ if (!path || *path == '\0')
+ {
+ return TRUE;
+ }
+ len = snprintf(full, sizeof(full)-1, "%s", path);
+ if (len < 0 || len >= sizeof(full)-1)
+ {
+ DBG1(DBG_LIB, "path string %s too long", path);
+ return FALSE;
+ }
+ /* ensure that the path ends with a '/' */
+ if (full[len-1] != '/')
+ {
+ full[len++] = '/';
+ full[len] = '\0';
+ }
+ /* skip '/' at the beginning */
+ while (*pos == '/')
+ {
+ pos++;
+ }
+ while ((pos = strchr(pos, '/')))
+ {
+ *pos = '\0';
+ if (access(full, F_OK) < 0)
+ {
+ if (mkdir(full, mode) < 0)
+ {
+ DBG1(DBG_LIB, "failed to create directory %s", full);
+ return FALSE;
+ }
+ }
+ *pos = '/';
+ pos++;
+ }
+ return TRUE;
+}
+
+ENUM(tty_color_names, TTY_RESET, TTY_BG_DEF,
+ "\e[0m",
+ "\e[1m",
+ "\e[4m",
+ "\e[5m",
+ "\e[30m",
+ "\e[31m",
+ "\e[32m",
+ "\e[33m",
+ "\e[34m",
+ "\e[35m",
+ "\e[36m",
+ "\e[37m",
+ "\e[39m",
+ "\e[40m",
+ "\e[41m",
+ "\e[42m",
+ "\e[43m",
+ "\e[44m",
+ "\e[45m",
+ "\e[46m",
+ "\e[47m",
+ "\e[49m",
+);
+
+/**
+ * Get the escape string for a given TTY color, empty string on non-tty FILE
+ */
+char* tty_escape_get(int fd, tty_escape_t escape)
+{
+ if (!isatty(fd))
+ {
+ return "";
+ }
+ switch (escape)
+ {
+ case TTY_RESET:
+ case TTY_BOLD:
+ case TTY_UNDERLINE:
+ case TTY_BLINKING:
+ case TTY_FG_BLACK:
+ case TTY_FG_RED:
+ case TTY_FG_GREEN:
+ case TTY_FG_YELLOW:
+ case TTY_FG_BLUE:
+ case TTY_FG_MAGENTA:
+ case TTY_FG_CYAN:
+ case TTY_FG_WHITE:
+ case TTY_FG_DEF:
+ case TTY_BG_BLACK:
+ case TTY_BG_RED:
+ case TTY_BG_GREEN:
+ case TTY_BG_YELLOW:
+ case TTY_BG_BLUE:
+ case TTY_BG_MAGENTA:
+ case TTY_BG_CYAN:
+ case TTY_BG_WHITE:
+ case TTY_BG_DEF:
+ return enum_to_name(tty_color_names, escape);
+ /* warn if a excape code is missing */
+ }
+ return "";
+}
+
+/**
+ * The size of the thread-specific error buffer
+ */
+#define STRERROR_BUF_LEN 256
+
+/**
+ * Key to store thread-specific error buffer
+ */
+static pthread_key_t strerror_buf_key;
+
+/**
+ * Only initialize the key above once
+ */
+static pthread_once_t strerror_buf_key_once = PTHREAD_ONCE_INIT;
+
+/**
+ * Create the key used for the thread-specific error buffer
+ */
+static void create_strerror_buf_key()
+{
+ pthread_key_create(&strerror_buf_key, free);
+}
+
+/**
+ * Retrieve the error buffer assigned to the current thread (or create it)
+ */
+static inline char *get_strerror_buf()
+{
+ char *buf;
+
+ pthread_once(&strerror_buf_key_once, create_strerror_buf_key);
+ buf = pthread_getspecific(strerror_buf_key);
+ if (!buf)
+ {
+ buf = malloc(STRERROR_BUF_LEN);
+ pthread_setspecific(strerror_buf_key, buf);
+ }
+ return buf;
+}
+
+#ifdef HAVE_STRERROR_R
+/*
+ * Described in header.
+ */
+const char *safe_strerror(int errnum)
+{
+ char *buf = get_strerror_buf(), *msg;
+
+#ifdef STRERROR_R_CHAR_P
+ /* char* version which may or may not return the original buffer */
+ msg = strerror_r(errnum, buf, STRERROR_BUF_LEN);
+#else
+ /* int version returns 0 on success */
+ msg = strerror_r(errnum, buf, STRERROR_BUF_LEN) ? "Unknown error" : buf;
+#endif
+ return msg;
+}
+#else /* HAVE_STRERROR_R */
+/* we actually wan't to call strerror(3) below */
+#undef strerror
+/*
+ * Described in header.
+ */
+const char *safe_strerror(int errnum)
+{
+ static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
+ char *buf = get_strerror_buf();
+
+ /* use a mutex to ensure calling strerror(3) is thread-safe */
+ pthread_mutex_lock(&mutex);
+ strncpy(buf, strerror(errnum), STRERROR_BUF_LEN);
+ pthread_mutex_unlock(&mutex);
+ buf[STRERROR_BUF_LEN - 1] = '\0';
+ return buf;
+}
+#endif /* HAVE_STRERROR_R */
+
+
+#ifndef HAVE_CLOSEFROM
+/**
+ * Described in header.
+ */
+void closefrom(int lowfd)
+{
+ char fd_dir[PATH_MAX];
+ int maxfd, fd, len;
+
+ /* try to close only open file descriptors on Linux... */
+ len = snprintf(fd_dir, sizeof(fd_dir), "/proc/%u/fd", getpid());
+ if (len > 0 && len < sizeof(fd_dir) && access(fd_dir, F_OK) == 0)
+ {
+ enumerator_t *enumerator = enumerator_create_directory(fd_dir);
+ if (enumerator)
+ {
+ char *rel;
+ while (enumerator->enumerate(enumerator, &rel, NULL, NULL))
+ {
+ fd = atoi(rel);
+ if (fd >= lowfd)
+ {
+ close(fd);
+ }
+ }
+ enumerator->destroy(enumerator);
+ return;
+ }
+ }
+
+ /* ...fall back to closing all fds otherwise */
+ maxfd = (int)sysconf(_SC_OPEN_MAX);
+ if (maxfd < 0)
+ {
+ maxfd = 256;
+ }
+ for (fd = lowfd; fd < maxfd; fd++)
+ {
+ close(fd);
+ }
+}
+#endif /* HAVE_CLOSEFROM */
+
+/**
+ * Return monotonic time
+ */
+time_t time_monotonic(timeval_t *tv)
+{
+#if defined(HAVE_CLOCK_GETTIME) && \
+ (defined(HAVE_CONDATTR_CLOCK_MONOTONIC) || \
+ defined(HAVE_PTHREAD_COND_TIMEDWAIT_MONOTONIC))
+ /* as we use time_monotonic() for condvar operations, we use the
+ * monotonic time source only if it is also supported by pthread. */
+ timespec_t ts;
+
+ if (clock_gettime(CLOCK_MONOTONIC, &ts) == 0)
+ {
+ if (tv)
+ {
+ tv->tv_sec = ts.tv_sec;
+ tv->tv_usec = ts.tv_nsec / 1000;
+ }
+ return ts.tv_sec;
+ }
+#endif /* HAVE_CLOCK_GETTIME && (...) */
+ /* Fallback to non-monotonic timestamps:
+ * On MAC OS X, creating monotonic timestamps is rather difficult. We
+ * could use mach_absolute_time() and catch sleep/wakeup notifications.
+ * We stick to the simpler (non-monotonic) gettimeofday() for now.
+ * But keep in mind: we need the same time source here as in condvar! */
+ if (!tv)
+ {
+ return time(NULL);
+ }
+ if (gettimeofday(tv, NULL) != 0)
+ { /* should actually never fail if passed pointers are valid */
+ return -1;
+ }
+ return tv->tv_sec;
+}
+
+/**
+ * return null
+ */
+void *return_null()
+{
+ return NULL;
+}
+
+/**
+ * returns TRUE
+ */
+bool return_true()
+{
+ return TRUE;
+}
+
+/**
+ * returns FALSE
+ */
+bool return_false()
+{
+ return FALSE;
+}
+
+/**
+ * returns FAILED
+ */
+status_t return_failed()
+{
+ return FAILED;
+}
+
+/**
+ * returns SUCCESS
+ */
+status_t return_success()
+{
+ return SUCCESS;
+}
+
+/**
+ * nop operation
+ */
+void nop()
+{
+}
+
+#ifndef HAVE_GCC_ATOMIC_OPERATIONS
+
+/**
+ * We use a single mutex for all refcount variables.
+ */
+static pthread_mutex_t ref_mutex = PTHREAD_MUTEX_INITIALIZER;
+
+/**
+ * Increase refcount
+ */
+refcount_t ref_get(refcount_t *ref)
+{
+ refcount_t current;
+
+ pthread_mutex_lock(&ref_mutex);
+ current = ++(*ref);
+ pthread_mutex_unlock(&ref_mutex);
+
+ return current;
+}
+
+/**
+ * Decrease refcount
+ */
+bool ref_put(refcount_t *ref)
+{
+ bool more_refs;
+
+ pthread_mutex_lock(&ref_mutex);
+ more_refs = --(*ref) > 0;
+ pthread_mutex_unlock(&ref_mutex);
+ return !more_refs;
+}
+
+/**
+ * Single mutex for all compare and swap operations.
+ */
+static pthread_mutex_t cas_mutex = PTHREAD_MUTEX_INITIALIZER;
+
+/**
+ * Compare and swap if equal to old value
+ */
+#define _cas_impl(name, type) \
+bool cas_##name(type *ptr, type oldval, type newval) \
+{ \
+ bool swapped; \
+ pthread_mutex_lock(&cas_mutex); \
+ if ((swapped = (*ptr == oldval))) { *ptr = newval; } \
+ pthread_mutex_unlock(&cas_mutex); \
+ return swapped; \
+}
+
+_cas_impl(bool, bool)
+_cas_impl(ptr, void*)
+
+#endif /* HAVE_GCC_ATOMIC_OPERATIONS */
+
+/**
+ * Described in header.
+ */
+int time_printf_hook(printf_hook_data_t *data, printf_hook_spec_t *spec,
+ const void *const *args)
+{
+ static const char* months[] = {
+ "Jan", "Feb", "Mar", "Apr", "May", "Jun",
+ "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
+ };
+ time_t *time = *((time_t**)(args[0]));
+ bool utc = *((bool*)(args[1]));;
+ struct tm t;
+
+ if (*time == UNDEFINED_TIME)
+ {
+ return print_in_hook(data, "--- -- --:--:--%s----",
+ utc ? " UTC " : " ");
+ }
+ if (utc)
+ {
+ gmtime_r(time, &t);
+ }
+ else
+ {
+ localtime_r(time, &t);
+ }
+ return print_in_hook(data, "%s %02d %02d:%02d:%02d%s%04d",
+ months[t.tm_mon], t.tm_mday, t.tm_hour, t.tm_min,
+ t.tm_sec, utc ? " UTC " : " ", t.tm_year + 1900);
+}
+
+/**
+ * Described in header.
+ */
+int time_delta_printf_hook(printf_hook_data_t *data, printf_hook_spec_t *spec,
+ const void *const *args)
+{
+ char* unit = "second";
+ time_t *arg1 = *((time_t**)(args[0]));
+ time_t *arg2 = *((time_t**)(args[1]));
+ u_int64_t delta = llabs(*arg1 - *arg2);
+
+ if (delta > 2 * 60 * 60 * 24)
+ {
+ delta /= 60 * 60 * 24;
+ unit = "day";
+ }
+ else if (delta > 2 * 60 * 60)
+ {
+ delta /= 60 * 60;
+ unit = "hour";
+ }
+ else if (delta > 2 * 60)
+ {
+ delta /= 60;
+ unit = "minute";
+ }
+ return print_in_hook(data, "%" PRIu64 " %s%s", delta, unit,
+ (delta == 1) ? "" : "s");
+}
+
+/**
+ * Number of bytes per line to dump raw data
+ */
+#define BYTES_PER_LINE 16
+
+static char hexdig_upper[] = "0123456789ABCDEF";
+
+/**
+ * Described in header.
+ */
+int mem_printf_hook(printf_hook_data_t *data,
+ printf_hook_spec_t *spec, const void *const *args)
+{
+ char *bytes = *((void**)(args[0]));
+ u_int len = *((int*)(args[1]));
+
+ char buffer[BYTES_PER_LINE * 3];
+ char ascii_buffer[BYTES_PER_LINE + 1];
+ char *buffer_pos = buffer;
+ char *bytes_pos = bytes;
+ char *bytes_roof = bytes + len;
+ int line_start = 0;
+ int i = 0;
+ int written = 0;
+
+ written += print_in_hook(data, "=> %u bytes @ %p", len, bytes);
+
+ while (bytes_pos < bytes_roof)
+ {
+ *buffer_pos++ = hexdig_upper[(*bytes_pos >> 4) & 0xF];
+ *buffer_pos++ = hexdig_upper[ *bytes_pos & 0xF];
+
+ ascii_buffer[i++] =
+ (*bytes_pos > 31 && *bytes_pos < 127) ? *bytes_pos : '.';
+
+ if (++bytes_pos == bytes_roof || i == BYTES_PER_LINE)
+ {
+ int padding = 3 * (BYTES_PER_LINE - i);
+
+ while (padding--)
+ {
+ *buffer_pos++ = ' ';
+ }
+ *buffer_pos++ = '\0';
+ ascii_buffer[i] = '\0';
+
+ written += print_in_hook(data, "\n%4d: %s %s",
+ line_start, buffer, ascii_buffer);
+
+ buffer_pos = buffer;
+ line_start += BYTES_PER_LINE;
+ i = 0;
+ }
+ else
+ {
+ *buffer_pos++ = ' ';
+ }
+ }
+ return written;
+}
diff --git a/src/libstrongswan/utils/utils.h b/src/libstrongswan/utils/utils.h
new file mode 100644
index 000000000..d055f712d
--- /dev/null
+++ b/src/libstrongswan/utils/utils.h
@@ -0,0 +1,783 @@
+/*
+ * Copyright (C) 2008-2012 Tobias Brunner
+ * Copyright (C) 2008 Martin Willi
+ * Hochschule fuer Technik Rapperswil
+ *
+ * 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. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * 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.
+ */
+
+/**
+ * @defgroup utils_i utils
+ * @{ @ingroup utils
+ */
+
+#ifndef UTILS_H_
+#define UTILS_H_
+
+#include <sys/types.h>
+#include <stdlib.h>
+#include <stddef.h>
+#include <sys/time.h>
+#include <arpa/inet.h>
+#include <string.h>
+
+#include "enum.h"
+
+/**
+ * strongSwan program return codes
+ */
+#define SS_RC_LIBSTRONGSWAN_INTEGRITY 64
+#define SS_RC_DAEMON_INTEGRITY 65
+#define SS_RC_INITIALIZATION_FAILED 66
+
+#define SS_RC_FIRST SS_RC_LIBSTRONGSWAN_INTEGRITY
+#define SS_RC_LAST SS_RC_INITIALIZATION_FAILED
+
+/**
+ * Number of bits in a byte
+ */
+#define BITS_PER_BYTE 8
+
+/**
+ * Default length for various auxiliary text buffers
+ */
+#define BUF_LEN 512
+
+/**
+ * General purpose boolean type.
+ */
+#ifdef HAVE_STDBOOL_H
+# include <stdbool.h>
+#else
+# ifndef HAVE__BOOL
+# define _Bool signed char
+# endif /* HAVE__BOOL */
+# define bool _Bool
+# define false 0
+# define true 1
+# define __bool_true_false_are_defined 1
+#endif /* HAVE_STDBOOL_H */
+#ifndef FALSE
+# define FALSE false
+#endif /* FALSE */
+#ifndef TRUE
+# define TRUE true
+#endif /* TRUE */
+
+/**
+ * Helper function that compares two strings for equality
+ */
+static inline bool streq(const char *x, const char *y)
+{
+ return strcmp(x, y) == 0;
+}
+
+/**
+ * Helper function that compares two strings for equality, length limited
+ */
+static inline bool strneq(const char *x, const char *y, size_t len)
+{
+ return strncmp(x, y, len) == 0;
+}
+
+/**
+ * Helper function that checks if a string starts with a given prefix
+ */
+static inline bool strpfx(const char *x, const char *prefix)
+{
+ return strneq(x, prefix, strlen(prefix));
+}
+
+/**
+ * Helper function that compares two strings for equality ignoring case
+ */
+static inline bool strcaseeq(const char *x, const char *y)
+{
+ return strcasecmp(x, y) == 0;
+}
+
+/**
+ * Helper function that compares two strings for equality ignoring case, length limited
+ */
+static inline bool strncaseeq(const char *x, const char *y, size_t len)
+{
+ return strncasecmp(x, y, len) == 0;
+}
+
+/**
+ * NULL-safe strdup variant
+ */
+static inline char *strdupnull(const char *s)
+{
+ return s ? strdup(s) : NULL;
+}
+
+/**
+ * Helper function that compares two binary blobs for equality
+ */
+static inline bool memeq(const void *x, const void *y, size_t len)
+{
+ return memcmp(x, y, len) == 0;
+}
+
+/**
+ * Macro gives back larger of two values.
+ */
+#define max(x,y) ({ \
+ typeof(x) _x = (x); \
+ typeof(y) _y = (y); \
+ _x > _y ? _x : _y; })
+
+
+/**
+ * Macro gives back smaller of two values.
+ */
+#define min(x,y) ({ \
+ typeof(x) _x = (x); \
+ typeof(y) _y = (y); \
+ _x < _y ? _x : _y; })
+
+/**
+ * Call destructor of an object, if object != NULL
+ */
+#define DESTROY_IF(obj) if (obj) (obj)->destroy(obj)
+
+/**
+ * Call offset destructor of an object, if object != NULL
+ */
+#define DESTROY_OFFSET_IF(obj, offset) if (obj) obj->destroy_offset(obj, offset);
+
+/**
+ * Call function destructor of an object, if object != NULL
+ */
+#define DESTROY_FUNCTION_IF(obj, fn) if (obj) obj->destroy_function(obj, fn);
+
+/**
+ * Debug macro to follow control flow
+ */
+#define POS printf("%s, line %d\n", __FILE__, __LINE__)
+
+/**
+ * Object allocation/initialization macro, using designated initializer.
+ */
+#define INIT(this, ...) { (this) = malloc(sizeof(*(this))); \
+ *(this) = (typeof(*(this))){ __VA_ARGS__ }; }
+
+/**
+ * Method declaration/definition macro, providing private and public interface.
+ *
+ * Defines a method name with this as first parameter and a return value ret,
+ * and an alias for this method with a _ prefix, having the this argument
+ * safely casted to the public interface iface.
+ * _name is provided a function pointer, but will get optimized out by GCC.
+ */
+#define METHOD(iface, name, ret, this, ...) \
+ static ret name(union {iface *_public; this;} \
+ __attribute__((transparent_union)), ##__VA_ARGS__); \
+ static typeof(name) *_##name = (typeof(name)*)name; \
+ static ret name(this, ##__VA_ARGS__)
+
+/**
+ * Same as METHOD(), but is defined for two public interfaces.
+ */
+#define METHOD2(iface1, iface2, name, ret, this, ...) \
+ static ret name(union {iface1 *_public1; iface2 *_public2; this;} \
+ __attribute__((transparent_union)), ##__VA_ARGS__); \
+ static typeof(name) *_##name = (typeof(name)*)name; \
+ static ret name(this, ##__VA_ARGS__)
+
+/**
+ * Architecture independent bitfield definition helpers (at least with GCC).
+ *
+ * Defines a bitfield with a type t and a fixed size of bitfield members, e.g.:
+ * BITFIELD2(u_int8_t,
+ * low: 4,
+ * high: 4,
+ * ) flags;
+ * The member defined first placed at bit 0.
+ */
+#if BYTE_ORDER == LITTLE_ENDIAN
+#define BITFIELD2(t, a, b,...) struct { t a; t b; __VA_ARGS__}
+#define BITFIELD3(t, a, b, c,...) struct { t a; t b; t c; __VA_ARGS__}
+#define BITFIELD4(t, a, b, c, d,...) struct { t a; t b; t c; t d; __VA_ARGS__}
+#define BITFIELD5(t, a, b, c, d, e,...) struct { t a; t b; t c; t d; t e; __VA_ARGS__}
+#elif BYTE_ORDER == BIG_ENDIAN
+#define BITFIELD2(t, a, b,...) struct { t b; t a; __VA_ARGS__}
+#define BITFIELD3(t, a, b, c,...) struct { t c; t b; t a; __VA_ARGS__}
+#define BITFIELD4(t, a, b, c, d,...) struct { t d; t c; t b; t a; __VA_ARGS__}
+#define BITFIELD5(t, a, b, c, d, e,...) struct { t e; t d; t c; t b; t a; __VA_ARGS__}
+#endif
+
+/**
+ * Macro to allocate a sized type.
+ */
+#define malloc_thing(thing) ((thing*)malloc(sizeof(thing)))
+
+/**
+ * Get the number of elements in an array
+ */
+#define countof(array) (sizeof(array)/sizeof(array[0]))
+
+/**
+ * Ignore result of functions tagged with warn_unused_result attributes
+ */
+#define ignore_result(call) { if(call){}; }
+
+/**
+ * Assign a function as a class method
+ */
+#define ASSIGN(method, function) (method = (typeof(method))function)
+
+/**
+ * time_t not defined
+ */
+#define UNDEFINED_TIME 0
+
+/**
+ * Maximum time since epoch causing wrap-around on Jan 19 03:14:07 UTC 2038
+ */
+#define TIME_32_BIT_SIGNED_MAX 0x7fffffff
+
+/**
+ * define some missing fixed width int types on OpenSolaris.
+ * TODO: since the uintXX_t types are defined by the C99 standard we should
+ * probably use those anyway
+ */
+#ifdef __sun
+ #include <stdint.h>
+ typedef uint8_t u_int8_t;
+ typedef uint16_t u_int16_t;
+ typedef uint32_t u_int32_t;
+ typedef uint64_t u_int64_t;
+#endif
+
+typedef enum status_t status_t;
+
+/**
+ * Return values of function calls.
+ */
+enum status_t {
+ /**
+ * Call succeeded.
+ */
+ SUCCESS,
+
+ /**
+ * Call failed.
+ */
+ FAILED,
+
+ /**
+ * Out of resources.
+ */
+ OUT_OF_RES,
+
+ /**
+ * The suggested operation is already done
+ */
+ ALREADY_DONE,
+
+ /**
+ * Not supported.
+ */
+ NOT_SUPPORTED,
+
+ /**
+ * One of the arguments is invalid.
+ */
+ INVALID_ARG,
+
+ /**
+ * Something could not be found.
+ */
+ NOT_FOUND,
+
+ /**
+ * Error while parsing.
+ */
+ PARSE_ERROR,
+
+ /**
+ * Error while verifying.
+ */
+ VERIFY_ERROR,
+
+ /**
+ * Object in invalid state.
+ */
+ INVALID_STATE,
+
+ /**
+ * Destroy object which called method belongs to.
+ */
+ DESTROY_ME,
+
+ /**
+ * Another call to the method is required.
+ */
+ NEED_MORE,
+};
+
+/**
+ * enum_names for type status_t.
+ */
+extern enum_name_t *status_names;
+
+typedef enum tty_escape_t tty_escape_t;
+
+/**
+ * Excape codes for tty colors
+ */
+enum tty_escape_t {
+ /** text properties */
+ TTY_RESET,
+ TTY_BOLD,
+ TTY_UNDERLINE,
+ TTY_BLINKING,
+
+ /** foreground colors */
+ TTY_FG_BLACK,
+ TTY_FG_RED,
+ TTY_FG_GREEN,
+ TTY_FG_YELLOW,
+ TTY_FG_BLUE,
+ TTY_FG_MAGENTA,
+ TTY_FG_CYAN,
+ TTY_FG_WHITE,
+ TTY_FG_DEF,
+
+ /** background colors */
+ TTY_BG_BLACK,
+ TTY_BG_RED,
+ TTY_BG_GREEN,
+ TTY_BG_YELLOW,
+ TTY_BG_BLUE,
+ TTY_BG_MAGENTA,
+ TTY_BG_CYAN,
+ TTY_BG_WHITE,
+ TTY_BG_DEF,
+};
+
+/**
+ * Get the escape string for a given TTY color, empty string on non-tty fd
+ */
+char* tty_escape_get(int fd, tty_escape_t escape);
+
+/**
+ * deprecated pluto style return value:
+ * error message, NULL for success
+ */
+typedef const char *err_t;
+
+/**
+ * Handle struct timeval like an own type.
+ */
+typedef struct timeval timeval_t;
+
+/**
+ * Handle struct timespec like an own type.
+ */
+typedef struct timespec timespec_t;
+
+/**
+ * Handle struct chunk_t like an own type.
+ */
+typedef struct sockaddr sockaddr_t;
+
+/**
+ * Same as memcpy, but XORs src into dst instead of copy
+ */
+void memxor(u_int8_t dest[], u_int8_t src[], size_t n);
+
+/**
+ * Safely overwrite n bytes of memory at ptr with zero, non-inlining variant.
+ */
+void memwipe_noinline(void *ptr, size_t n);
+
+/**
+ * Safely overwrite n bytes of memory at ptr with zero, inlining variant.
+ */
+static inline void memwipe_inline(void *ptr, size_t n)
+{
+ volatile char *c = (volatile char*)ptr;
+ size_t m, i;
+
+ /* byte wise until long aligned */
+ for (i = 0; (uintptr_t)&c[i] % sizeof(long) && i < n; i++)
+ {
+ c[i] = 0;
+ }
+ /* word wise */
+ if (n >= sizeof(long))
+ {
+ for (m = n - sizeof(long); i <= m; i += sizeof(long))
+ {
+ *(volatile long*)&c[i] = 0;
+ }
+ }
+ /* byte wise of the rest */
+ for (; i < n; i++)
+ {
+ c[i] = 0;
+ }
+}
+
+/**
+ * Safely overwrite n bytes of memory at ptr with zero, auto-inlining variant.
+ */
+static inline void memwipe(void *ptr, size_t n)
+{
+ if (!ptr)
+ {
+ return;
+ }
+ if (__builtin_constant_p(n))
+ {
+ memwipe_inline(ptr, n);
+ }
+ else
+ {
+ memwipe_noinline(ptr, n);
+ }
+}
+
+/**
+ * A variant of strstr with the characteristics of memchr, where haystack is not
+ * a null-terminated string but simply a memory area of length n.
+ */
+void *memstr(const void *haystack, const char *needle, size_t n);
+
+/**
+ * Translates the characters in the given string, searching for characters
+ * in 'from' and mapping them to characters in 'to'.
+ * The two characters sets 'from' and 'to' must contain the same number of
+ * characters.
+ */
+char *translate(char *str, const char *from, const char *to);
+
+/**
+ * Creates a directory and all required parent directories.
+ *
+ * @param path path to the new directory
+ * @param mode permissions of the new directory/directories
+ * @return TRUE on success
+ */
+bool mkdir_p(const char *path, mode_t mode);
+
+/**
+ * Thread-safe wrapper around strerror and strerror_r.
+ *
+ * This is required because the first is not thread-safe (on some platforms)
+ * and the second uses two different signatures (POSIX/GNU) and is impractical
+ * to use anyway.
+ *
+ * @param errnum error code (i.e. errno)
+ * @return error message
+ */
+const char *safe_strerror(int errnum);
+
+/**
+ * Replace usages of strerror(3) with thread-safe variant.
+ */
+#define strerror(errnum) safe_strerror(errnum)
+
+#ifndef HAVE_CLOSEFROM
+/**
+ * Close open file descriptors greater than or equal to lowfd.
+ *
+ * @param lowfd start closing file descriptoros from here
+ */
+void closefrom(int lowfd);
+#endif
+
+/**
+ * Get a timestamp from a monotonic time source.
+ *
+ * While the time()/gettimeofday() functions are affected by leap seconds
+ * and system time changes, this function returns ever increasing monotonic
+ * time stamps.
+ *
+ * @param tv timeval struct receiving monotonic timestamps, or NULL
+ * @return monotonic timestamp in seconds
+ */
+time_t time_monotonic(timeval_t *tv);
+
+/**
+ * Add the given number of milliseconds to the given timeval struct
+ *
+ * @param tv timeval struct to modify
+ * @param ms number of milliseconds
+ */
+static inline void timeval_add_ms(timeval_t *tv, u_int ms)
+{
+ tv->tv_usec += ms * 1000;
+ while (tv->tv_usec >= 1000000 /* 1s */)
+ {
+ tv->tv_usec -= 1000000;
+ tv->tv_sec++;
+ }
+}
+
+/**
+ * returns null
+ */
+void *return_null();
+
+/**
+ * No-Operation function
+ */
+void nop();
+
+/**
+ * returns TRUE
+ */
+bool return_true();
+
+/**
+ * returns FALSE
+ */
+bool return_false();
+
+/**
+ * returns FAILED
+ */
+status_t return_failed();
+
+/**
+ * returns SUCCESS
+ */
+status_t return_success();
+
+/**
+ * Write a 16-bit host order value in network order to an unaligned address.
+ *
+ * @param host host order 16-bit value
+ * @param network unaligned address to write network order value to
+ */
+static inline void htoun16(void *network, u_int16_t host)
+{
+ char *unaligned = (char*)network;
+
+ host = htons(host);
+ memcpy(unaligned, &host, sizeof(host));
+}
+
+/**
+ * Write a 32-bit host order value in network order to an unaligned address.
+ *
+ * @param host host order 32-bit value
+ * @param network unaligned address to write network order value to
+ */
+static inline void htoun32(void *network, u_int32_t host)
+{
+ char *unaligned = (char*)network;
+
+ host = htonl(host);
+ memcpy((char*)unaligned, &host, sizeof(host));
+}
+
+/**
+ * Write a 64-bit host order value in network order to an unaligned address.
+ *
+ * @param host host order 64-bit value
+ * @param network unaligned address to write network order value to
+ */
+static inline void htoun64(void *network, u_int64_t host)
+{
+ char *unaligned = (char*)network;
+
+#ifdef be64toh
+ host = htobe64(host);
+ memcpy((char*)unaligned, &host, sizeof(host));
+#else
+ u_int32_t high_part, low_part;
+
+ high_part = host >> 32;
+ high_part = htonl(high_part);
+ low_part = host & 0xFFFFFFFFLL;
+ low_part = htonl(low_part);
+
+ memcpy(unaligned, &high_part, sizeof(high_part));
+ unaligned += sizeof(high_part);
+ memcpy(unaligned, &low_part, sizeof(low_part));
+#endif
+}
+
+/**
+ * Read a 16-bit value in network order from an unaligned address to host order.
+ *
+ * @param network unaligned address to read network order value from
+ * @return host order value
+ */
+static inline u_int16_t untoh16(void *network)
+{
+ char *unaligned = (char*)network;
+ u_int16_t tmp;
+
+ memcpy(&tmp, unaligned, sizeof(tmp));
+ return ntohs(tmp);
+}
+
+/**
+ * Read a 32-bit value in network order from an unaligned address to host order.
+ *
+ * @param network unaligned address to read network order value from
+ * @return host order value
+ */
+static inline u_int32_t untoh32(void *network)
+{
+ char *unaligned = (char*)network;
+ u_int32_t tmp;
+
+ memcpy(&tmp, unaligned, sizeof(tmp));
+ return ntohl(tmp);
+}
+
+/**
+ * Read a 64-bit value in network order from an unaligned address to host order.
+ *
+ * @param network unaligned address to read network order value from
+ * @return host order value
+ */
+static inline u_int64_t untoh64(void *network)
+{
+ char *unaligned = (char*)network;
+
+#ifdef be64toh
+ u_int64_t tmp;
+
+ memcpy(&tmp, unaligned, sizeof(tmp));
+ return be64toh(tmp);
+#else
+ u_int32_t high_part, low_part;
+
+ memcpy(&high_part, unaligned, sizeof(high_part));
+ unaligned += sizeof(high_part);
+ memcpy(&low_part, unaligned, sizeof(low_part));
+
+ high_part = ntohl(high_part);
+ low_part = ntohl(low_part);
+
+ return (((u_int64_t)high_part) << 32) + low_part;
+#endif
+}
+
+/**
+ * Round up size to be multiple of alignement
+ */
+static inline size_t round_up(size_t size, int alignement)
+{
+ int remainder;
+
+ remainder = size % alignement;
+ if (remainder)
+ {
+ size += alignement - remainder;
+ }
+ return size;
+}
+
+/**
+ * Round down size to be a multiple of alignement
+ */
+static inline size_t round_down(size_t size, int alignement)
+{
+ return size - (size % alignement);
+}
+
+/**
+ * Special type to count references
+ */
+typedef u_int refcount_t;
+
+#ifdef HAVE_GCC_ATOMIC_OPERATIONS
+
+#define ref_get(ref) __sync_add_and_fetch(ref, 1)
+#define ref_put(ref) (!__sync_sub_and_fetch(ref, 1))
+
+#define cas_bool(ptr, oldval, newval) \
+ (__sync_bool_compare_and_swap(ptr, oldval, newval))
+#define cas_ptr(ptr, oldval, newval) \
+ (__sync_bool_compare_and_swap(ptr, oldval, newval))
+
+#else /* !HAVE_GCC_ATOMIC_OPERATIONS */
+
+/**
+ * Get a new reference.
+ *
+ * Increments the reference counter atomic.
+ *
+ * @param ref pointer to ref counter
+ * @return new value of ref
+ */
+refcount_t ref_get(refcount_t *ref);
+
+/**
+ * Put back a unused reference.
+ *
+ * Decrements the reference counter atomic and
+ * says if more references available.
+ *
+ * @param ref pointer to ref counter
+ * @return TRUE if no more references counted
+ */
+bool ref_put(refcount_t *ref);
+
+/**
+ * Atomically replace value of ptr with newval if it currently equals oldval.
+ *
+ * @param ptr pointer to variable
+ * @param oldval old value of the variable
+ * @param newval new value set if possible
+ * @return TRUE if value equaled oldval and newval was written
+ */
+bool cas_bool(bool *ptr, bool oldval, bool newval);
+
+/**
+ * Atomically replace value of ptr with newval if it currently equals oldval.
+ *
+ * @param ptr pointer to variable
+ * @param oldval old value of the variable
+ * @param newval new value set if possible
+ * @return TRUE if value equaled oldval and newval was written
+ */
+bool cas_ptr(void **ptr, void *oldval, void *newval);
+
+#endif /* HAVE_GCC_ATOMIC_OPERATIONS */
+
+/**
+ * printf hook for time_t.
+ *
+ * Arguments are:
+ * time_t* time, bool utc
+ */
+int time_printf_hook(printf_hook_data_t *data, printf_hook_spec_t *spec,
+ const void *const *args);
+
+/**
+ * printf hook for time_t deltas.
+ *
+ * Arguments are:
+ * time_t* begin, time_t* end
+ */
+int time_delta_printf_hook(printf_hook_data_t *data, printf_hook_spec_t *spec,
+ const void *const *args);
+
+/**
+ * printf hook for memory areas.
+ *
+ * Arguments are:
+ * u_char *ptr, u_int len
+ */
+int mem_printf_hook(printf_hook_data_t *data, printf_hook_spec_t *spec,
+ const void *const *args);
+
+#endif /** UTILS_H_ @}*/